diff --git a/.forgejo/issue_template/bug.yaml b/.forgejo/issue_template/bug.yaml deleted file mode 100644 index 1b92658f7..000000000 --- a/.forgejo/issue_template/bug.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: 'Bug report' -about: 'Report a bug in Pleroma' -body: -- type: markdown - attributes: - value: | - ### Precheck - - * For support use https://git.pleroma.social/pleroma/pleroma-support or [community channels](https://git.pleroma.social/pleroma/pleroma#community-channels). - * Please do a quick search to ensure no similar bug has been reported before. If the bug has not been addressed after 2 weeks, it's fine to bump it. - * Try to ensure that the bug is actually related to the Pleroma backend. For example, if a bug happens in Pleroma-FE but not in Mastodon-FE or mobile clients, it's likely that the bug should be filed in [Pleroma-FE](https://git.pleroma.social/pleroma/pleroma-fe/issues/new) repository. -- type: textarea - id: environment - attributes: - label: Environment - value: | - * Installation type (OTP or From Source): - * Pleroma version (could be found in the "Version" tab of settings in Pleroma-FE): - * Elixir version (`elixir -v` for from source installations, N/A for OTP): - * Operating system: - * PostgreSQL version (`psql -V`): -- type: textarea - id: bug-description - attributes: - label: Bug description \ No newline at end of file diff --git a/.forgejo/pull_request_template.md b/.forgejo/pull_request_template.md deleted file mode 100644 index 5bb204a14..000000000 --- a/.forgejo/pull_request_template.md +++ /dev/null @@ -1,13 +0,0 @@ -### Checklist - -- [ ] Adding a changelog: In the `changelog.d` directory, create a file named `.`. - - diff --git a/.gitignore b/.gitignore index d8e5ed553..355cea069 100644 --- a/.gitignore +++ b/.gitignore @@ -56,9 +56,6 @@ pleroma.iml # asdf .tool-versions -# mise -mise.toml - # Editor temp files *~ *# diff --git a/.woodpecker/changelog.yaml b/.woodpecker/changelog.yaml deleted file mode 100644 index 64062f17e..000000000 --- a/.woodpecker/changelog.yaml +++ /dev/null @@ -1,19 +0,0 @@ -when: - - event: pull_request - -labels: - platform: linux/amd64 - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - -steps: - check-changelog: - image: docker.io/alpine:3.23 - entrypoint: *script_file_entrypoint - commands: - - apk add --no-cache git - - sh ./tools/check-changelog diff --git a/.woodpecker/docker-combine.yaml b/.woodpecker/docker-combine.yaml deleted file mode 100644 index 6c91d26e9..000000000 --- a/.woodpecker/docker-combine.yaml +++ /dev/null @@ -1,60 +0,0 @@ -when: - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**", "Dockerfile" ] - - event: tag - - event: manual - branch: ${CI_REPO_DEFAULT_BRANCH} - - event: manual - branch: stable - -depends_on: - - docker - -skip_clone: true - -labels: - platform: linux/amd64 - -steps: - docker-develop-combine: - image: git.fluffytail.org/phnt/wpc-docker-tagger:latest - when: - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - - event: manual - branch: ${CI_REPO_DEFAULT_BRANCH} - settings: &docker_settings - registry: "git.pleroma.social" - image: "pleroma/pleroma" - architectures: [amd64, arm64] - tags: - - latest - - develop - - ${CI_COMMIT_SHA:0:8} - username: - from_secret: pleroma-ci-user - password: - from_secret: pleroma-ci-password - - docker-stable-combine: - image: git.fluffytail.org/phnt/wpc-docker-tagger:latest - when: - - evaluate: 'CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG == ""' - settings: - <<: *docker_settings - tags: &stable_docker_tags - - latest - - stable - - ${CI_COMMIT_SHA:0:8} - - docker-stable-tag-combine: - image: git.fluffytail.org/phnt/wpc-docker-tagger:latest - when: - - event: tag - - evaluate: 'CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG != ""' - settings: - <<: *docker_settings - tags: - - <<: *stable_docker_tags - - ${CI_COMMIT_TAG} diff --git a/.woodpecker/docker.yaml b/.woodpecker/docker.yaml deleted file mode 100644 index abc6bfa3b..000000000 --- a/.woodpecker/docker.yaml +++ /dev/null @@ -1,96 +0,0 @@ -when: - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**", "Dockerfile" ] - - event: tag - - event: manual - branch: ${CI_REPO_DEFAULT_BRANCH} - - event: manual - branch: stable - -matrix: - platform: - - linux/amd64 - - linux/arm64 - -# This is needed for the when clauses below. -labels: - platform: ${platform} - memory: 'high' - -variables: - docker_variables: &docker_variables - repo: pleroma/pleroma - registry: git.pleroma.social - username: - from_secret: pleroma-ci-user - password: - from_secret: pleroma-ci-password - kaniko_image: &kaniko_image woodpeckerci/plugin-kaniko:2.3.1 - -steps: - docker-develop-amd64: - image: woodpeckerci/plugin-kaniko:2.3.1 - when: - - evaluate: 'platform == "linux/amd64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - settings: - <<: *docker_variables - tags: - - latest-amd64 - - develop-amd64 - - ${CI_COMMIT_SHA:0:8}-amd64 - - docker-develop-arm64: - image: woodpeckerci/plugin-kaniko:2.3.1 - when: - - evaluate: 'platform == "linux/arm64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - settings: - <<: *docker_variables - tags: - - latest-arm64 - - develop-arm64 - - ${CI_COMMIT_SHA:0:8}-arm64 - - docker-stable-amd64: - image: *kaniko_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG == ""' - settings: - <<: *docker_variables - tags: &amd64_tags - - latest-amd64 - - stable-amd64 - - ${CI_COMMIT_SHA:0:8}-amd64 - - docker-stable-tag-amd64: - image: *kaniko_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG != ""' - settings: - <<: *docker_variables - tags: - - <<: *amd64_tags - - ${CI_COMMIT_TAG}-amd64 - - docker-stable-arm64: - image: *kaniko_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG == ""' - settings: - <<: *docker_variables - tags: &arm64_tags - - latest-arm64 - - stable-arm64 - - ${CI_COMMIT_SHA:0:8}-arm64 - - docker-stable-tag-arm64: - image: *kaniko_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable" && CI_COMMIT_TAG != ""' - settings: - <<: *docker_variables - tags: - - <<: *arm64_tags - - ${CI_COMMIT_TAG}-arm64 diff --git a/.woodpecker/lint.yaml b/.woodpecker/lint.yaml deleted file mode 100644 index 0ab7441a8..000000000 --- a/.woodpecker/lint.yaml +++ /dev/null @@ -1,77 +0,0 @@ -when: - - event: pull_request - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - -labels: - platform: linux/amd64 - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - -steps: - mix-format: - image: &elixir-image - docker.io/elixir:1.15-alpine - entrypoint: *script_file_entrypoint - failure: ignore - commands: - - | - if ! mix format --check-formatted; then - touch fail.stamp - exit 1 - fi - - credo: - image: *elixir-image - entrypoint: *script_file_entrypoint - failure: ignore - environment: - MIX_ENV: test - commands: - - apk add --no-cache build-base cmake exiftool ffmpeg file-dev git openssl - - adduser -D -h /home/testuser testuser - - mkdir -p /home/testuser/.mix /home/testuser/.hex - - chown -R testuser:testuser . /home/testuser - - su testuser -c "HOME=/home/testuser mix local.hex --force" - - su testuser -c "HOME=/home/testuser mix local.rebar --force" - - su testuser -c "HOME=/home/testuser mix deps.get" - - | - if ! su testuser -c "HOME=/home/testuser mix analyze"; then - touch fail.stamp - exit 1 - fi - - # cycles: - # image: *elixir-image - # failure: ignore - # commands: - # - apk add --no-cache build-base cmake exiftool ffmpeg file-dev git openssl - # - adduser -D -h /home/testuser testuser - # - mkdir -p /home/testuser/.mix /home/testuser/.hex - # - chown -R testuser:testuser . /home/testuser - # - su testuser -c "HOME=/home/testuser mix local.hex --force" - # - su testuser -c "HOME=/home/testuser mix local.rebar --force" - # - su testuser -c "HOME=/home/testuser mix compile" - # - | - # if ! su testuser -c "HOME=/home/testuser mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != \"No cycles found\")}'"; then - # touch fail.stamp - # exit 1 - # fi - - ensure-status: - image: *elixir-image - entrypoint: *script_file_entrypoint - commands: | - if test -f fail.stamp; then - echo "One or more previous steps fails. Failing workflow..." - exit 1 - else - echo "All steps passed" - exit 0 - fi diff --git a/.woodpecker/otp-musl.yaml b/.woodpecker/otp-musl.yaml deleted file mode 100644 index 60558b893..000000000 --- a/.woodpecker/otp-musl.yaml +++ /dev/null @@ -1,292 +0,0 @@ -when: - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - - event: tag - - event: manual - branch: ${CI_REPO_DEFAULT_BRANCH} - - event: manual - branch: stable - -matrix: - platform: - - linux/amd64 - - linux/arm - - linux/arm64 - -# This is needed for the when clauses below. -# When the platform clause is fixed, this might not be needed anymore -labels: - platform: ${platform} - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - build_cmds: &build_cmds - - apk add git build-base cmake file-dev openssl vips-dev zip - - echo "import Config" > config/prod.secret.exs - - mix local.hex --force - - mix local.rebar --force - - mix deps.get --only prod - - mkdir release - - export PLEROMA_BUILD_BRANCH=${CI_COMMIT_BRANCH} - - mix release --path release - build_image_amd64: &build_image_amd64 docker.io/hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-alpine-3.22.1 - build_image_arm: &build_image_arm docker.io/arm32v7/elixir:1.17.3-alpine - build_image_arm64: &build_image_arm64 docker.io/hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-alpine-3.22.1 - artifacts_uploader_image: &artifacts_uploader_image docker.io/woodpeckercommunity/plugin-gitea-package:0.5.0 - artifacts_uploader_settings: &artifacts_uploader_settings - user: - from_secret: pleroma-ci-user - password: - from_secret: pleroma-ci-password - owner: 'pleroma' - env: &env - MIX_ENV: prod - VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS - -steps: - otp-develop-amd64-musl: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &amd64_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64-musl.zip release - - otp-stable-amd64-musl: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *amd64_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-amd64-musl: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-amd64-musl.zip release - - otp-develop-arm-musl: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &arm_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm-musl.zip release - - otp-stable-arm-musl: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *arm_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-arm-musl: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-arm-musl.zip release - - otp-develop-arm64-musl: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &arm64_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64-musl.zip release - - otp-stable-arm64-musl: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *arm64_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-arm64-musl: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-arm64-musl.zip release - - upload-artifacts-amd64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-amd64-musl - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64-musl - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - update: 'true' - - upload-latest-amd64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-amd64-musl - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-amd64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-amd64-musl - package_version: stable-${CI_COMMIT_SHA:0:8}-amd64-musl - file_source: ./stable-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-amd64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-amd64-musl - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-amd64-musl.zip - file_name: pleroma.zip - update: 'true' - - upload-artifacts-arm-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm-musl - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm-musl - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm-musl.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm-musl.zip - update: 'true' - - upload-latest-arm-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm-musl - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm-musl.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-arm-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm-musl - package_version: stable-${CI_COMMIT_SHA:0:8}-arm-musl - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm-musl.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-arm-musl.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-arm-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm-musl - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm-musl.zip - file_name: pleroma.zip - update: 'true' - - upload-artifacts-arm64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm64-musl - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64-musl - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - update: 'true' - - upload-latest-arm64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm64-musl - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-arm64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm64-musl - package_version: stable-${CI_COMMIT_SHA:0:8}-arm64-musl - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-arm64-musl: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm64-musl - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm64-musl.zip - file_name: pleroma.zip - update: 'true' diff --git a/.woodpecker/otp.yaml b/.woodpecker/otp.yaml deleted file mode 100644 index 9a33c228e..000000000 --- a/.woodpecker/otp.yaml +++ /dev/null @@ -1,293 +0,0 @@ -when: - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - - event: tag - - event: manual - branch: ${CI_REPO_DEFAULT_BRANCH} - - event: manual - branch: stable - -matrix: - platform: - - linux/amd64 - - linux/arm - - linux/arm64 - -# This is needed for the when clauses below. -# When the platform clause is fixed, this might not be needed anymore -labels: - platform: ${platform} - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - build_cmds: &build_cmds - - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git build-essential zip - - echo "import Config" > config/prod.secret.exs - - mix local.hex --force - - mix local.rebar --force - - mix deps.get --only prod - - mkdir release - - export PLEROMA_BUILD_BRANCH=${CI_COMMIT_BRANCH} - - mix release --path release - build_image_amd64: &build_image_amd64 docker.io/hexpm/elixir-amd64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716 - build_image_arm: &build_image_arm docker.io/arm32v7/elixir:1.17.3 - build_image_arm64: &build_image_arm64 docker.io/hexpm/elixir-arm64:1.17.3-erlang-27.3.4.2-ubuntu-noble-20250716 - artifacts_uploader_image: &artifacts_uploader_image docker.io/woodpeckercommunity/plugin-gitea-package:0.5.0 - artifacts_uploader_settings: &artifacts_uploader_settings - user: - from_secret: pleroma-ci-user - password: - from_secret: pleroma-ci-password - owner: 'pleroma' - env: &env - MIX_ENV: prod - VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS - DEBIAN_FRONTEND: noninteractive - -steps: - otp-develop-amd64: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &amd64_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64.zip release - - otp-stable-amd64: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *amd64_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-amd64: - image: *build_image_amd64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-amd64.zip release - - otp-develop-arm: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &arm_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm.zip release - - otp-stable-arm: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *arm_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-arm: - image: *build_image_arm - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-arm.zip release - - otp-develop-arm64: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - environment: *env - commands: &arm64_build - - <<: *build_cmds - - zip -9rq ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64.zip release - - otp-stable-arm64: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual" && CI_COMMIT_BRANCH == "stable"' - environment: *env - commands: *arm64_build - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - otp-stable-tag-arm64: - image: *build_image_arm64 - entrypoint: *script_file_entrypoint - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - environment: *env - commands: - - <<: *build_cmds - - zip -9rq stable-${CI_COMMIT_SHA:0:8}-arm64.zip release - - upload-artifacts-amd64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-amd64 - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64 - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64.zip - update: 'true' - - upload-latest-amd64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-amd64 - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-amd64.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-amd64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-amd64 - package_version: stable-${CI_COMMIT_SHA:0:8}-amd64 - file_source: ./stable-${CI_COMMIT_SHA:0:8}-amd64.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-amd64.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-amd64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/amd64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-amd64 - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-amd64.zip - file_name: pleroma.zip - update: 'true' - - upload-artifacts-arm: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm.zip - update: 'true' - - upload-latest-arm: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-arm: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm - package_version: stable-${CI_COMMIT_SHA:0:8}-arm - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-arm.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-arm: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm.zip - file_name: pleroma.zip - update: 'true' - - upload-artifacts-arm64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm64 - package_version: ${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64 - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64.zip - file_name: pleroma-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64.zip - update: 'true' - - upload-latest-arm64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "push" && CI_COMMIT_BRANCH == "${CI_REPO_DEFAULT_BRANCH}"' - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "manual"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-${CI_COMMIT_BRANCH}-arm64 - package_version: latest - file_source: ./${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:8}-arm64.zip - file_name: pleroma.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-artifacts-tag-arm64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm64 - package_version: stable-${CI_COMMIT_SHA:0:8}-arm64 - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm64.zip - file_name: pleroma-stable-${CI_COMMIT_SHA:0:8}-arm64.zip - update: 'true' - - # Tag events don't have CI_COMMIT_BRANCH set, hardcode stable - upload-latest-tag-arm64: - image: *artifacts_uploader_image - when: - - evaluate: 'platform == "linux/arm64" && CI_PIPELINE_EVENT == "tag"' - settings: - <<: *artifacts_uploader_settings - package_name: pleroma-otp-stable-arm64 - package_version: latest - file_source: ./stable-${CI_COMMIT_SHA:0:8}-arm64.zip - file_name: pleroma.zip - update: 'true' diff --git a/.woodpecker/unit-testing-elixir-1.15.yaml b/.woodpecker/unit-testing-elixir-1.15.yaml deleted file mode 100644 index a4a8fc266..000000000 --- a/.woodpecker/unit-testing-elixir-1.15.yaml +++ /dev/null @@ -1,44 +0,0 @@ -when: - - event: pull_request - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - -depends_on: - - lint - -labels: - platform: linux/amd64 - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - -steps: - unit-testing-elixir-1.15: - image: elixir:1.15-alpine - entrypoint: *script_file_entrypoint - environment: - MIX_ENV: test - DB_HOST: postgres - DB_PORT: 5432 - commands: - - apk add --no-cache build-base cmake exiftool ffmpeg file-dev git openssl - - adduser -D -h /home/testuser testuser - - mkdir -p /home/testuser/.mix /home/testuser/.hex - - chown -R testuser:testuser . /home/testuser - - su testuser -c "HOME=/home/testuser mix local.hex --force" - - su testuser -c "HOME=/home/testuser mix local.rebar --force" - - su testuser -c "HOME=/home/testuser mix deps.get" - - su testuser -c "HOME=/home/testuser mix pleroma.test_runner --preload-modules" - -services: - postgres: - image: postgres:13-alpine - environment: - POSTGRES_DB: pleroma_test - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres diff --git a/.woodpecker/unit-testing-elixir-1.18.yaml b/.woodpecker/unit-testing-elixir-1.18.yaml deleted file mode 100644 index 9ad9eebc9..000000000 --- a/.woodpecker/unit-testing-elixir-1.18.yaml +++ /dev/null @@ -1,44 +0,0 @@ -when: - - event: pull_request - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - - event: push - branch: ${CI_REPO_DEFAULT_BRANCH} - path: [ "**/*.ex", "**/*.eex", "**/*.exs", "mix.lock", ".woodpecker/**" ] - -depends_on: - - lint - -labels: - platform: linux/amd64 - -variables: - script_file_entrypoint: &script_file_entrypoint - - /bin/sh - - -c - - 'printf "%s" "$CI_SCRIPT" | base64 -d > /tmp/ci-script.sh && /bin/sh -xe /tmp/ci-script.sh' - -steps: - unit-testing-elixir-1.18: - image: elixir:1.18-otp-27-alpine - entrypoint: *script_file_entrypoint - environment: - MIX_ENV: test - DB_HOST: postgres - DB_PORT: 5432 - commands: - - apk add --no-cache build-base cmake exiftool ffmpeg file-dev git openssl - - adduser -D -h /home/testuser testuser - - mkdir -p /home/testuser/.mix /home/testuser/.hex - - chown -R testuser:testuser . /home/testuser - - su testuser -c "HOME=/home/testuser mix local.hex --force" - - su testuser -c "HOME=/home/testuser mix local.rebar --force" - - su testuser -c "HOME=/home/testuser mix deps.get" - - su testuser -c "HOME=/home/testuser mix pleroma.test_runner --preload-modules" - -services: - postgres: - image: postgres:13-alpine - environment: - POSTGRES_DB: pleroma_test - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres diff --git a/CHANGELOG.md b/CHANGELOG.md index f03be3f29..adc76c767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,60 +4,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## 2.10.2 - -### Security - -- ActivityPub: Fixed failed-signature inbox retry handling and signer identity checks to prevent spoofed remote activities from being processed - -## 2.10.1 - -### Changed - -- Move avatar_description and header_description fields to the account object -- Update Bandit to 1.10.4 -- No-op code correctness improvements detected by Elixir 1.19 compiler -- Downgrade Hackney to 1.20.1 -- Use a custom redirect handler to ensure MediaProxy redirects are followed with Hackney -- Update Hackney, the default HTTP client, to the latest release which supports Happy Eyeballs for improved IPv6 federation -- Paginate follow requests -- Moved Phoenix LiveDashboard to /pleroma/live_dashboard -- Add mute/block expiry to the relationship object -- Filter indexable activities before inserting indexing jobs into the queue. - -### Added - -- Allow assigning users to reports -- Allow fine-grained announce visibilities -- Add immutable tag on cache-control header for several endpoints that's serving the same exact things. -- Add reasonable defaults for :database_config_whitelist -- Support lists `exclusive` param -- Add v1/instance/domain_blocks endpoint -- Add /api/v2/instance profile fields limits info used by Mastodon -- Added Oban Web dashboard located at /pleroma/oban -- Add instructions on how to run a release in docker, to make it easier to run on older distros. - -### Fixed - -- Fix the daily email digest job which was not executing -- Encode custom emoji URLs in EmojiReact activity tags. -- Gopher: Fix Ranch listener not being stopped properly on Pleroma restart when database configuration is enabled -- Fix fetching Hubzilla Actors with alsoKnownAs as string -- Fix /phoenix/live_dashboard redirect not working when user added a path segment -- Fix 404 error codes for missing static files -- Fix OAuth app registration to accept `redirect_uris` as an array of strings (RFC 7591), while keeping backwards compatibility with string input. -- Correct old migrations for expiring activities and user access tokens. -- Federate `votersCount` correctly -- DB prune: Check if user follows hashtag with no objects before deletion -- Stop the rate limiter from crashing when run with wrong settings. -- Restore embeds route -- ReverseProxy: Recursively follow redirects until redirect_limit is reached -- Fix compilation with vips-8.18.0 with bumping to vix 0.36.0 - -### Removed - -- Docs: Removed outdated, incorrect, unmaintained and inappropriate installation documentation (Arch, NetBSD, NixOS) - ## 2.10 ### Security diff --git a/README.md b/README.md index 982a7249a..8a5eb238f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + ## About diff --git a/changelog.d/ci-artifacts.skip b/changelog.d/ci-artifacts.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/context-cleanup.skip b/changelog.d/context-cleanup.skip deleted file mode 100644 index ae609602d..000000000 --- a/changelog.d/context-cleanup.skip +++ /dev/null @@ -1 +0,0 @@ -litepub-0.1.jsonld cleanup diff --git a/changelog.d/emoji-reaction-url-escape.fix b/changelog.d/emoji-reaction-url-escape.fix new file mode 100644 index 000000000..c3a1c8823 --- /dev/null +++ b/changelog.d/emoji-reaction-url-escape.fix @@ -0,0 +1 @@ +Encode custom emoji URLs in EmojiReact activity tags. diff --git a/changelog.d/hackney-mediaproxy.change b/changelog.d/hackney-mediaproxy.change new file mode 100644 index 000000000..10dfb0775 --- /dev/null +++ b/changelog.d/hackney-mediaproxy.change @@ -0,0 +1 @@ +Use a custom redirect handler to ensure MediaProxy redirects are followed with Hackney diff --git a/changelog.d/hackney.change b/changelog.d/hackney.change new file mode 100644 index 000000000..3158cfc77 --- /dev/null +++ b/changelog.d/hackney.change @@ -0,0 +1 @@ +Update Hackney, the default HTTP client, to the latest release which supports Happy Eyeballs for improved IPv6 federation diff --git a/changelog.d/inappropriate-docs.remove b/changelog.d/inappropriate-docs.remove new file mode 100644 index 000000000..699c9186a --- /dev/null +++ b/changelog.d/inappropriate-docs.remove @@ -0,0 +1 @@ +Docs: Removed outdated, incorrect, unmaintained and inappropriate installation documentation (Arch, NetBSD, NixOS) diff --git a/changelog.d/instance-domain-blocks.add b/changelog.d/instance-domain-blocks.add new file mode 100644 index 000000000..85f01c5c2 --- /dev/null +++ b/changelog.d/instance-domain-blocks.add @@ -0,0 +1 @@ +Add v1/instance/domain_blocks endpoint diff --git a/changelog.d/mfm-backend.add b/changelog.d/mfm-backend.add deleted file mode 100644 index f815c6828..000000000 --- a/changelog.d/mfm-backend.add +++ /dev/null @@ -1 +0,0 @@ -Add backend support for Misskey Markdown (MFM) posts diff --git a/changelog.d/oauth-registration-redirect_uris.fix b/changelog.d/oauth-registration-redirect_uris.fix new file mode 100644 index 000000000..76ace55df --- /dev/null +++ b/changelog.d/oauth-registration-redirect_uris.fix @@ -0,0 +1 @@ +Fix OAuth app registration to accept `redirect_uris` as an array of strings (RFC 7591), while keeping backwards compatibility with string input. diff --git a/changelog.d/oban-web.add b/changelog.d/oban-web.add new file mode 100644 index 000000000..c59e2ebca --- /dev/null +++ b/changelog.d/oban-web.add @@ -0,0 +1 @@ +Added Oban Web dashboard located at /pleroma/oban diff --git a/changelog.d/paginate-follow-requests.change b/changelog.d/paginate-follow-requests.change new file mode 100644 index 000000000..1a88995b7 --- /dev/null +++ b/changelog.d/paginate-follow-requests.change @@ -0,0 +1 @@ +Paginate follow requests diff --git a/changelog.d/phoenix-livedashboard-move.change b/changelog.d/phoenix-livedashboard-move.change new file mode 100644 index 000000000..116b1523a --- /dev/null +++ b/changelog.d/phoenix-livedashboard-move.change @@ -0,0 +1 @@ +Moved Phoenix LiveDashboard to /pleroma/live_dashboard diff --git a/changelog.d/pleroma-fe-link.fix b/changelog.d/pleroma-fe-link.fix deleted file mode 100644 index de93f86dd..000000000 --- a/changelog.d/pleroma-fe-link.fix +++ /dev/null @@ -1 +0,0 @@ -Updated Pleroma-FE build URL after Forgejo migration diff --git a/changelog.d/poll-voters-count-inflation.fix b/changelog.d/poll-voters-count-inflation.fix deleted file mode 100644 index 7eae41f13..000000000 --- a/changelog.d/poll-voters-count-inflation.fix +++ /dev/null @@ -1 +0,0 @@ -Fix votersCount inflation when same voter picks multiple options diff --git a/changelog.d/reduce-flaky-tests.skip b/changelog.d/reduce-flaky-tests.skip new file mode 100644 index 000000000..0375762c0 --- /dev/null +++ b/changelog.d/reduce-flaky-tests.skip @@ -0,0 +1 @@ +Reduce the number of flaky tests by making them sync if they affect the global state, and silence noisy test output. diff --git a/changelog.d/release-to-docker.add b/changelog.d/release-to-docker.add new file mode 100644 index 000000000..5fbf611a5 --- /dev/null +++ b/changelog.d/release-to-docker.add @@ -0,0 +1 @@ +Add instructions on how to run a release in docker, to make it easier to run on older distros. diff --git a/changelog.d/vix-0.36.0.fix b/changelog.d/vix-0.36.0.fix new file mode 100644 index 000000000..43a8dd8f8 --- /dev/null +++ b/changelog.d/vix-0.36.0.fix @@ -0,0 +1 @@ +Fix compilation with vips-8.18.0 with bumping to vix 0.36.0 diff --git a/config/config.exs b/config/config.exs index 2d38e3ebe..8a76c6517 100644 --- a/config/config.exs +++ b/config/config.exs @@ -64,9 +64,9 @@ config :pleroma, Pleroma.Upload, link_name: false, proxy_remote: false, filename_display_max_length: 30, - default_description: nil, + default_description: :filename, base_url: nil, - allowed_mime_types: ["image", "audio", "video"] + allowed_mime_types: ["image", "audio", "video", "application"] config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads" @@ -167,18 +167,18 @@ config :pleroma, :http, adapter: [] config :pleroma, :instance, - name: "Pleroma", - email: "example@example.com", - notify_email: "noreply@example.com", - description: "Pleroma: An efficient and flexible fediverse server", - short_description: "", + name: "Shigusegubu", + email: "pleroma@hjkos.com", + notify_email: "pleroma@hjkos.com", + description: "SigSegV, a pleroma instance", + short_description: "HJ's semi-personal instance", background_image: "/images/city.jpg", instance_thumbnail: "/instance/thumbnail.jpeg", favicon: "/favicon.png", limit: 5_000, description_limit: 5_000, remote_limit: 100_000, - upload_limit: 16_000_000, + upload_limit: 200_000_000, avatar_upload_limit: 2_000_000, background_upload_limit: 4_000_000, banner_upload_limit: 4_000_000, @@ -196,20 +196,17 @@ config :pleroma, :instance, federation_incoming_replies_max_depth: 100, allow_relay: true, public: true, - quarantined_instances: [], + quarantined_instances: [{ "pleroma.rareome.ga", "leaks private posts or sumshit i dont rember" }], rejected_instances: [], static_dir: "instance/static/", allowed_post_formats: [ "text/plain", - "text/html", - "text/markdown", - "text/bbcode", - "text/x.misskeymarkdown" + "text/bbcode" ], autofollowed_nicknames: [], autofollowing_nicknames: [], max_pinned_statuses: 1, - attachment_links: false, + attachment_links: true, max_report_comment_size: 1000, report_strip_status: true, safe_dm_mentions: false, @@ -302,8 +299,8 @@ config :pleroma, :markup, config :pleroma, :frontend_configurations, pleroma_fe: %{ - alwaysShowSubjectInput: true, - background: "/images/city.jpg", + alwaysShowSubjectInput: false, + background: "/static/sigsegv_s.png", collapseMessageWithSubject: false, disableChat: false, greentext: false, @@ -317,18 +314,18 @@ config :pleroma, :frontend_configurations, logo: "/static/logo.svg", logoMargin: ".1em", logoMask: true, - minimalScopesMode: false, + minimalScopesMode: true, noAttachmentLinks: false, nsfwCensorImage: "", postContentType: "text/plain", redirectRootLogin: "/main/friends", redirectRootNoLogin: "/main/all", - scopeCopy: true, + scopeCopy: false, sidebarRight: false, showFeaturesPanel: true, - showInstanceSpecificPanel: false, - subjectLineBehavior: "email", - theme: "pleroma-dark", + showInstanceSpecificPanel: true, + subjectLineBehavior: "noop", + theme: "sigsegv2", webPushNotifications: false } @@ -387,8 +384,23 @@ config :pleroma, :mrf_hellthread, config :pleroma, :mrf_simple, media_removal: [], - media_nsfw: [], - federated_timeline_removal: [], + media_nsfw: [ + { "preteengirls.biz", "pron or even cp" }, + { "melalandia.tk", "i don't rember" }, + { "pl.smuglo.li", "instance is dead but i still remember, rip smuglo" }, + { "baraag.net", "pron" }, + { "humblr.social", "3dpd pron" }, + { "pawoo.net", "tasteful pron, mostly." }, + { "sinblr.com", "3dpd pron" } + ], + federated_timeline_removal: [ + { "preteengirls.biz", "pron or even cp" }, + { "melalandia.tk", "i don't rember" }, + { "baraag.net", "pron" }, + { "humblr.social", "3dpd pron" }, + { "pawoo.net", "tasteful pron, mostly." }, + { "sinblr.com", "3dpd pron" } + ], report_removal: [], reject: [], followers_only: [], @@ -499,7 +511,7 @@ config :pleroma, :media_preview_proxy, min_content_length: 100 * 1024 config :pleroma, :shout, - enabled: true, + enabled: false, limit: 5_000 config :phoenix, :format_encoders, json: Jason, "activity+json": Jason @@ -776,7 +788,7 @@ config :pleroma, :frontends, "name" => "pleroma-fe", "git" => "https://git.pleroma.social/pleroma/pleroma-fe", "build_url" => - "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-fe-builds/${ref}/latest.zip", + "https://git.pleroma.social/pleroma/pleroma-fe/-/jobs/artifacts/${ref}/download?job=build", "ref" => "develop" }, "fedi-fe" => %{ @@ -827,7 +839,7 @@ config :pleroma, :web_cache_ttl, config :pleroma, :modules, runtime_dir: "instance/modules" -config :pleroma, configurable_from_database: false +config :pleroma, configurable_from_database: true config :pleroma, Pleroma.Repo, parameters: [gin_fuzzy_search_limit: "500", jit: "off"], @@ -900,9 +912,13 @@ config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false config :pleroma, :mrf, policies: [ - Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy, + Pleroma.Web.ActivityPub.MRF.SimplePolicy, + Pleroma.Web.ActivityPub.MRF.HellthreadPolicy, + Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy, Pleroma.Web.ActivityPub.MRF.TagPolicy, - Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy + Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy, + Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy, + Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy ], transparency: true, transparency_exclusions: [] @@ -961,15 +977,6 @@ config :pleroma, Pleroma.Search.QdrantSearch, vectors: %{size: 384, distance: "Cosine"} } -config :pleroma, :database_config_whitelist, [ - {:pleroma}, - {:cors_plug}, - {:ex_aws, :s3}, - {:mime}, - {:prometheus, Pleroma.Web.Endpoint.MetricsExporter}, - {:web_push_encryption, :vapid_details} -] - # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/config/description.exs b/config/description.exs index 6e4348907..c388d17c3 100644 --- a/config/description.exs +++ b/config/description.exs @@ -815,8 +815,7 @@ config :pleroma, :config_description, [ "text/plain", "text/html", "text/markdown", - "text/bbcode", - "text/x.misskeymarkdown" + "text/bbcode" ] }, %{ @@ -1395,13 +1394,7 @@ config :pleroma, :config_description, [ label: "Post Content Type", type: {:dropdown, :atom}, description: "Default post formatting option", - suggestions: [ - "text/plain", - "text/html", - "text/markdown", - "text/bbcode", - "text/x.misskeymarkdown" - ] + suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode"] }, %{ key: :redirectRootNoLogin, diff --git a/docs/administration/CLI_tasks/config.md b/docs/administration/CLI_tasks/config.md index 35e02145e..13d671a7e 100644 --- a/docs/administration/CLI_tasks/config.md +++ b/docs/administration/CLI_tasks/config.md @@ -169,18 +169,4 @@ This forcibly removes any enabled MRF that does not exist and will fix the abili === "From Source" ```sh mix pleroma.config fix_mrf_policies - ``` - -## Remove non-whitelisted configs from the database - -This removes any configuration value that is not explicitly whitelisted by `:pleroma, :database_config_whitelist`. Might be useful after updating the whitelist. - -=== "OTP" - ```sh - ./bin/pleroma_ctl config filter_whitelisted - ``` - -=== "From Source" - ```sh - mix pleroma.config filter_whitelisted - ``` + ``` \ No newline at end of file diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 9efa1c8b3..54dd4a5f0 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -1132,9 +1132,8 @@ Boolean, enables/disables in-database configuration. Read [Transferring the conf List of valid configuration sections which are allowed to be configured from the database. Settings stored in the database before the whitelist is configured are -still applied. Consider running the `mix pleroma.config filter_whitelisted` task -after updating the whitelist. Read [Remove non-whitelisted configs from the database](../administration/CLI_tasks/config.md#remove-non-whitelisted-configs-from-the-database) -for more information. +still applied, so it is suggested to only use the whitelist on instances that +have not migrated the config to the database. Example: ```elixir diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md index 3719ceeb9..64c06ca2b 100644 --- a/docs/development/API/admin_api.md +++ b/docs/development/API/admin_api.md @@ -665,7 +665,6 @@ Status: 404 - *optional* `limit`: **integer** the number of records to retrieve - *optional* `page`: **integer** page number - *optional* `page_size`: **integer** number of log entries per page (default is `50`) - - *optional* `assigned_account`: **string** assigned account ID - Response: - On failure: 403 Forbidden error `{"error": "error_msg"}` when requested by anonymous or non-admin - On success: JSON, returns a list of reports, where: @@ -750,7 +749,6 @@ Status: 404 "url": "https://pleroma.example.org/users/lain", "username": "lain" }, - "assigned_account": null, "content": "Please delete it", "created_at": "2019-04-29T19:48:15.000Z", "id": "9iJGOv1j8hxuw19bcm", @@ -870,37 +868,6 @@ Status: 404 ] ``` -- Response: - - On failure: - - 400 Bad Request, JSON: - - ```json - [ - { - `id`, // report id - `error` // error message - } - ] - ``` - - - On success: `204`, empty response - -## `POST /api/v1/pleroma/admin/reports/assign_account` - -### Assign account to one or multiple reports - -- Params: - -```json - `reports`: [ - { - `id`, // required, report id - `nickname` // account nickname, use null to unassign account - }, - ... - ] -``` - - Response: - On failure: - 400 Bad Request, JSON: diff --git a/docs/development/API/differences_in_mastoapi_responses.md b/docs/development/API/differences_in_mastoapi_responses.md index 194c98e3f..052b2716b 100644 --- a/docs/development/API/differences_in_mastoapi_responses.md +++ b/docs/development/API/differences_in_mastoapi_responses.md @@ -74,7 +74,7 @@ Pleroma does not process remote images and therefore cannot include fields such The `GET /api/v1/bookmarks` endpoint accepts optional parameter `folder_id` for bookmark folder ID. -The `POST /api/v1/statuses/:id/bookmark` endpoint accepts optional parameter `folder_id` for bookmark folder ID. Bookmarking an already bookmarked post will update the folder association, or remove it if `folder_id` is omitted or `null`. +The `POST /api/v1/statuses/:id/bookmark` endpoint accepts optional parameter `folder_id` for bookmark folder ID. ## Accounts @@ -127,6 +127,8 @@ Has these additional fields under the `pleroma` object: - `notification_settings`: object, can be absent. See `/api/v1/pleroma/notification_settings` for the parameters/keys returned. - `accepts_chat_messages`: boolean, but can be null if we don't have that information about a user - `favicon`: nullable URL string, Favicon image of the user's instance +- `avatar_description`: string, image description for user avatar, defaults to empty string +- `header_description`: string, image description for user banner, defaults to empty string ### Source diff --git a/docs/development/API/pleroma_api.md b/docs/development/API/pleroma_api.md index b19523bce..7946ba1f6 100644 --- a/docs/development/API/pleroma_api.md +++ b/docs/development/API/pleroma_api.md @@ -690,7 +690,6 @@ Audio scrobbling in Pleroma is **deprecated**. * `album`: the album of the media playing [optional] * `artist`: the artist of the media playing [optional] * `length`: the length of the media playing [optional] - * `external_link`: a URL referencing the media playing [optional] * Response: the newly created media metadata entity representing the Listen activity # Emoji Reactions diff --git a/installation/pleroma.service b/installation/pleroma.service index 8338228d8..9e959e1ac 100644 --- a/installation/pleroma.service +++ b/installation/pleroma.service @@ -6,6 +6,7 @@ After=network.target postgresql.service ExecReload=/bin/kill $MAINPID KillMode=process Restart=on-failure +StandardOutput=journal ; Name of the user that runs the Pleroma service. User=pleroma @@ -14,9 +15,11 @@ Environment="MIX_ENV=prod" ; Make sure that all paths fit your installation. ; Path to the home directory of the user running the Pleroma service. -Environment="HOME=/var/lib/pleroma" +Environment="HOME=/home/pleroma" ; Path to the folder containing the Pleroma installation. -WorkingDirectory=/opt/pleroma +WorkingDirectory=/home/pleroma/pleroma +; Path to the environment file. the file contains RELEASE_COOKIE and etc +;EnvironmentFile=/opt/pleroma/config/pleroma.env ; Path to the Mix binary. ExecStart=/usr/bin/mix phx.server @@ -24,7 +27,7 @@ ExecStart=/usr/bin/mix phx.server ; Use private /tmp and /var/tmp folders inside a new file system namespace, which are discarded after the process stops. PrivateTmp=true ; The /home, /root, and /run/user folders can not be accessed by this service anymore. If your Pleroma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to false. -ProtectHome=true +ProtectHome=false ; Mount /usr, /boot, and /etc as read-only for processes invoked by this service. ProtectSystem=full ; Sets up a new /dev mount for the process and only adds API pseudo devices like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled by default because it may not work on devices like the Raspberry Pi. diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index c5f2e9b0a..834b4fe14 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -234,61 +234,6 @@ defmodule Mix.Tasks.Pleroma.Config do end) end - # Removes non-whitelisted configuration sections - def run(["filter_whitelisted" | rest]) do - {options, [], []} = - OptionParser.parse( - rest, - strict: [force: :boolean], - aliases: [f: :force] - ) - - force = Keyword.get(options, :force, false) - - start_pleroma() - - whitelisted_configs = Pleroma.Config.get(:database_config_whitelist) - - if whitelisted_configs in [nil, false] do - shell_error("No unwanted settings in ConfigDB. No changes made.") - else - whitelisted_groups = - whitelisted_configs - |> Enum.filter(fn - {_group} -> true - _ -> false - end) - |> Enum.map(fn {group} -> group end) - - whitelisted_keys = - whitelisted_configs - |> Enum.filter(fn - {_group, _key} -> true - _ -> false - end) - - filtered = - from(c in ConfigDB) - |> Repo.all() - |> Enum.filter(¬_whitelisted?(&1, whitelisted_groups, whitelisted_keys)) - - if not Enum.empty?(filtered) do - shell_info("The following settings will be removed from ConfigDB:\n") - Enum.each(filtered, &dump(&1)) - - if force or shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do - filtered_ids = Enum.map(filtered, fn %{id: id} -> id end) - - Repo.delete_all(from(c in ConfigDB, where: c.id in ^filtered_ids)) - else - shell_error("No changes made.") - end - else - shell_error("No unwanted settings in ConfigDB. No changes made.") - end - end - end - @spec migrate_to_db(Path.t() | nil) :: any() def migrate_to_db(file_path \\ nil) do with :ok <- Pleroma.Config.DeprecationWarnings.warn() do @@ -489,9 +434,4 @@ defmodule Mix.Tasks.Pleroma.Config do Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;") Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;") end - - defp not_whitelisted?(%{group: group, key: key}, whitelisted_groups, whitelisted_keys) do - not Enum.member?(whitelisted_groups, group) and - not Enum.member?(whitelisted_keys, {group, key}) - end end diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 396536827..e52b5e0a7 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -226,12 +226,7 @@ defmodule Mix.Tasks.Pleroma.Database do DELETE FROM hashtags AS ht WHERE NOT EXISTS ( SELECT 1 FROM hashtags_objects hto - WHERE ht.id = hto.hashtag_id - ) - AND NOT EXISTS ( - SELECT 1 FROM user_follows_hashtag ufh - WHERE ht.id = ufh.hashtag_id - ) + WHERE ht.id = hto.hashtag_id) """ |> Repo.query() diff --git a/lib/mix/tasks/pleroma/openapi_spec.ex b/lib/mix/tasks/pleroma/openapi_spec.ex index 852e1e9af..1ea468476 100644 --- a/lib/mix/tasks/pleroma/openapi_spec.ex +++ b/lib/mix/tasks/pleroma/openapi_spec.ex @@ -22,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do else {_, errors} -> IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"])) - Enum.each(errors, &IO.puts/1) + Enum.map(errors, &IO.puts/1) raise "Spec check failed" end diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex index facc38815..edce9e871 100644 --- a/lib/mix/tasks/pleroma/search/meilisearch.ex +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -72,7 +72,7 @@ defmodule Mix.Tasks.Pleroma.Search.Meilisearch do query, timeout: :infinity ) - |> Stream.map(&Pleroma.Search.object_to_search_data/1) + |> Stream.map(&Pleroma.Search.Meilisearch.object_to_search_data/1) |> Stream.filter(fn o -> not is_nil(o) end) |> Stream.chunk_every(chunk_size) |> Stream.transform(0, fn objects, acc -> diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex index c83889c87..ba284b4d5 100644 --- a/lib/pleroma/activity/html.ex +++ b/lib/pleroma/activity/html.ex @@ -38,7 +38,7 @@ defmodule Pleroma.Activity.HTML do def invalidate_cache_for(activity_id) do keys = get_cache_keys_for(activity_id) - Enum.each(keys, &@cachex.del(:scrubber_cache, &1)) + Enum.map(keys, &@cachex.del(:scrubber_cache, &1)) @cachex.del(:scrubber_management_cache, activity_id) end diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex index 1c78d495f..1a2a63b82 100644 --- a/lib/pleroma/bookmark.ex +++ b/lib/pleroma/bookmark.ex @@ -19,7 +19,7 @@ defmodule Pleroma.Bookmark do schema "bookmarks" do belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) - belongs_to(:folder, BookmarkFolder, type: FlakeId.Ecto.Type) + belongs_to(:folder, BookmarkFolder, type: FlakeId.Ecto.CompatType) timestamps() end @@ -38,7 +38,7 @@ defmodule Pleroma.Bookmark do |> validate_required([:user_id, :activity_id]) |> unique_constraint(:activity_id, name: :bookmarks_user_id_activity_id_index) |> Repo.insert( - on_conflict: [set: [folder_id: folder_id, updated_at: NaiveDateTime.utc_now()]], + on_conflict: [set: [folder_id: folder_id]], conflict_target: [:user_id, :activity_id] ) end @@ -76,4 +76,11 @@ defmodule Pleroma.Bookmark do |> Repo.one() |> Repo.delete() end + + def set_folder(bookmark, folder_id) do + bookmark + |> cast(%{folder_id: folder_id}, [:folder_id]) + |> validate_required([:folder_id]) + |> Repo.update() + end end diff --git a/lib/pleroma/bookmark_folder.ex b/lib/pleroma/bookmark_folder.ex index 65856bb29..14d37e197 100644 --- a/lib/pleroma/bookmark_folder.ex +++ b/lib/pleroma/bookmark_folder.ex @@ -14,7 +14,7 @@ defmodule Pleroma.BookmarkFolder do alias Pleroma.User @type t :: %__MODULE__{} - @primary_key {:id, FlakeId.Ecto.Type, autogenerate: true} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} schema "bookmark_folders" do field(:name, :string) diff --git a/lib/pleroma/config_db.ex b/lib/pleroma/config_db.ex index 2c3df773b..e9990fa35 100644 --- a/lib/pleroma/config_db.ex +++ b/lib/pleroma/config_db.ex @@ -10,7 +10,6 @@ defmodule Pleroma.ConfigDB do import Pleroma.Web.Gettext alias __MODULE__ - alias Pleroma.EctoType.Config.RateLimit alias Pleroma.Repo @type t :: %__MODULE__{} @@ -61,59 +60,8 @@ defmodule Pleroma.ConfigDB do |> cast(params, [:key, :group, :value]) |> validate_required([:key, :group, :value]) |> unique_constraint(:key, name: :config_group_key_index) - |> validate_rate_limit() end - defp validate_rate_limit(changeset) do - group = get_field(changeset, :group) - key = get_field(changeset, :key) - - if group == :pleroma and key == :rate_limit do - value = get_field(changeset, :value) - - case normalize_rate_limit(value) do - {:ok, normalized_value} -> - put_change(changeset, :value, normalized_value) - - {:error, {limiter_name, reason}} -> - add_error( - changeset, - :value, - "invalid :rate_limit value for #{inspect(limiter_name)}: #{reason}" - ) - end - else - changeset - end - end - - defp normalize_rate_limit(nil), do: {:ok, nil} - - defp normalize_rate_limit(%{} = value), do: normalize_rate_limit(Map.to_list(value)) - - defp normalize_rate_limit(value) when is_list(value) do - if Keyword.keyword?(value) do - value - |> Enum.reduce_while({:ok, []}, fn {limiter_name, limiter_value}, {:ok, acc} -> - case RateLimit.cast_with_error(limiter_value) do - {:ok, normalized_limiter_value} -> - {:cont, {:ok, [{limiter_name, normalized_limiter_value} | acc]}} - - {:error, reason} -> - {:halt, {:error, {limiter_name, reason}}} - end - end) - |> case do - {:ok, acc} -> {:ok, Enum.reverse(acc)} - {:error, _} = error -> error - end - else - {:error, {:rate_limit, "must be a keyword list"}} - end - end - - defp normalize_rate_limit(_), do: {:error, {:rate_limit, "must be a keyword list"}} - defp create(params) do %ConfigDB{} |> changeset(params) diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 178dd6094..ba775f430 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -22,14 +22,13 @@ defmodule Pleroma.Constants do "generator", "rules", "language", - "voters", - "assigned_account" + "voters" ] ) const(static_only_files, do: - ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js schemas doc embed.js embed.css) + ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css) ) const(status_updatable_fields, @@ -134,11 +133,15 @@ defmodule Pleroma.Constants do do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/ ) - # List of allowed chars in the path segment of a URI - # unreserved, sub-delims, ":", "@" and "/" allowed as the separator in path - # https://datatracker.ietf.org/doc/html/rfc3986 - const(uri_path_allowed_reserved_chars, - do: ~c"!$&'()*+,;=/:@" + const(activity_json_canonical_mime_type, + do: "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" + ) + + const(activity_json_mime_types, + do: [ + "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", + "application/activity+json" + ] ) const(upload_object_types, do: ["Document", "Image"]) diff --git a/lib/pleroma/ecto_type/config/rate_limit.ex b/lib/pleroma/ecto_type/config/rate_limit.ex deleted file mode 100644 index 0518ffd7e..000000000 --- a/lib/pleroma/ecto_type/config/rate_limit.ex +++ /dev/null @@ -1,71 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.EctoType.Config.RateLimit do - @moduledoc false - - use Ecto.Type - - @type t :: - nil - | {non_neg_integer(), non_neg_integer()} - | [{non_neg_integer(), non_neg_integer()}] - - @impl true - def type, do: :term - - @impl true - def cast(value) do - case cast_with_error(value) do - {:ok, normalized} -> {:ok, normalized} - {:error, _reason} -> :error - end - end - - @impl true - def load(value), do: cast(value) - - @impl true - def dump(value), do: cast(value) - - @spec cast_with_error(term()) :: {:ok, t()} | {:error, String.t()} - def cast_with_error(nil), do: {:ok, nil} - - def cast_with_error({scale, limit}) do - with {:ok, scale} <- parse_integer(scale, "scale"), - {:ok, limit} <- parse_integer(limit, "limit"), - true <- scale >= 1 and limit >= 1 do - {:ok, {scale, limit}} - else - false -> {:error, "scale and limit must be >= 1"} - {:error, reason} -> {:error, reason} - end - end - - def cast_with_error([{_, _} = unauth, {_, _} = auth]) do - with {:ok, unauth} <- cast_with_error(unauth), - {:ok, auth} <- cast_with_error(auth) do - {:ok, [unauth, auth]} - else - {:error, reason} -> {:error, reason} - end - end - - def cast_with_error(_), - do: - {:error, "must be a {scale, limit} tuple, a [{scale, limit}, {scale, limit}] list, or nil"} - - defp parse_integer(value, _label) when is_integer(value), do: {:ok, value} - - defp parse_integer(value, label) when is_binary(value) do - value = String.trim(value) - - case Integer.parse(value) do - {number, ""} -> {:ok, number} - _ -> {:error, "#{label} must be an integer"} - end - end - - defp parse_integer(_value, label), do: {:error, "#{label} must be an integer"} -end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 4bf2f6b95..11d5af2fb 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -127,13 +127,6 @@ defmodule Pleroma.Formatter do Earmark.as_html!(text, %Earmark.Options{compact_output: true, smartypants: false}) end - def markdown_to_html(text, opts) do - Earmark.as_html!( - text, - %Earmark.Options{compact_output: true, smartypants: false} |> Map.merge(opts) - ) - end - def html_escape({text, mentions, hashtags}, type) do {html_escape(text, type), mentions, hashtags} end @@ -142,10 +135,6 @@ defmodule Pleroma.Formatter do HTML.filter_tags(text) end - def html_escape(text, "text/x.misskeymarkdown") do - HTML.filter_tags(text) - end - def html_escape(text, "text/plain") do Regex.split(@link_regex, text, include_captures: true) |> Enum.map_every(2, fn chunk -> diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex index e37a3fefe..e651d7d9d 100644 --- a/lib/pleroma/frontend.ex +++ b/lib/pleroma/frontend.ex @@ -75,8 +75,8 @@ defmodule Pleroma.Frontend do end defp download_build(frontend_info, dest) do + Logger.info("Downloading pre-built bundle for #{frontend_info["name"]}") url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"]) - Logger.info("Downloading pre-built bundle for #{frontend_info["name"]} from #{url}") with {:ok, %{status: 200, body: zip_body}} <- Pleroma.HTTP.get(url, [], pool: :media, recv_timeout: 120_000) do diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index 7b6985efe..add3ba925 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -21,13 +21,10 @@ defmodule Pleroma.Gopher.Server do def init([ip, port]) do Logger.info("Starting gopher server on #{port}") - Process.flag(:trap_exit, true) - - listener = :gopher {:ok, _pid} = :ranch.start_listener( - listener, + :gopher, :ranch_tcp, %{ num_acceptors: 100, @@ -38,11 +35,7 @@ defmodule Pleroma.Gopher.Server do [] ) - {:ok, %{ip: ip, port: port, listener: listener}} - end - - def terminate(_reason, state) do - :ranch.stop_listener(state.listener) + {:ok, %{ip: ip, port: port}} end end diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex index cd23bd0a9..b446b91a0 100644 --- a/lib/pleroma/list.ex +++ b/lib/pleroma/list.ex @@ -17,14 +17,13 @@ defmodule Pleroma.List do field(:title, :string) field(:following, {:array, :string}, default: []) field(:ap_id, :string) - field(:exclusive, :boolean, default: false) timestamps() end - def update_changeset(list, attrs \\ %{}) do + def title_changeset(list, attrs \\ %{}) do list - |> cast(attrs, [:title, :exclusive]) + |> cast(attrs, [:title]) |> validate_required([:title]) end @@ -92,14 +91,14 @@ defmodule Pleroma.List do |> Repo.all() end - def update(%Pleroma.List{} = list, params) do + def rename(%Pleroma.List{} = list, title) do list - |> update_changeset(params) + |> title_changeset(%{title: title}) |> Repo.update() end - def create(params, %User{} = creator) do - changeset = update_changeset(%Pleroma.List{user_id: creator.id}, params) + def create(title, %User{} = creator) do + changeset = title_changeset(%Pleroma.List{user_id: creator.id}, %{title: title}) if changeset.valid? do Repo.transaction(fn -> @@ -150,14 +149,4 @@ defmodule Pleroma.List do end def member?(_, _), do: false - - def get_exclusive_list_members(%User{id: user_id}) do - Pleroma.List - |> where([l], l.user_id == ^user_id) - |> where([l], l.exclusive == true) - |> select([l], l.following) - |> Repo.all() - |> List.flatten() - |> Enum.uniq() - end end diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index fab24d183..68b054e4d 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -78,7 +78,7 @@ defmodule Pleroma.Marker do defp get_marker(user, timeline) do case Repo.find_resource(get_query(user, timeline)) do - {:ok, %__MODULE__{} = marker} -> %{marker | user: user} + {:ok, marker} -> %__MODULE__{marker | user: user} _ -> %__MODULE__{timeline: timeline, user_id: user.id} end end diff --git a/lib/pleroma/mfa/changeset.ex b/lib/pleroma/mfa/changeset.ex index 2045c3a7c..3ec3cfe91 100644 --- a/lib/pleroma/mfa/changeset.ex +++ b/lib/pleroma/mfa/changeset.ex @@ -8,8 +8,7 @@ defmodule Pleroma.MFA.Changeset do alias Pleroma.User def disable(%Ecto.Changeset{} = changeset, force \\ false) do - %Settings{} = - settings = + settings = changeset |> Ecto.Changeset.apply_changes() |> MFA.fetch_settings() @@ -21,20 +20,20 @@ defmodule Pleroma.MFA.Changeset do end end - def disable_totp(%User{multi_factor_authentication_settings: %Settings{} = settings} = user) do + def disable_totp(%User{multi_factor_authentication_settings: settings} = user) do user |> put_change(%Settings{settings | totp: %Settings.TOTP{}}) end - def confirm_totp(%User{multi_factor_authentication_settings: %Settings{} = settings} = user) do - totp_settings = %Settings.TOTP{(%Settings.TOTP{} = settings.totp) | confirmed: true} + def confirm_totp(%User{multi_factor_authentication_settings: settings} = user) do + totp_settings = %Settings.TOTP{settings.totp | confirmed: true} user |> put_change(%Settings{settings | totp: totp_settings, enabled: true}) end def setup_totp(%User{} = user, attrs) do - %Settings{} = mfa_settings = MFA.fetch_settings(user) + mfa_settings = MFA.fetch_settings(user) totp_settings = %Settings.TOTP{} @@ -47,7 +46,7 @@ defmodule Pleroma.MFA.Changeset do def cast_backup_codes(%User{} = user, codes) do user |> put_change(%Settings{ - (%Settings{} = user.multi_factor_authentication_settings) + user.multi_factor_authentication_settings | backup_codes: codes }) end diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 90219312c..52a71bc2d 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -132,18 +132,11 @@ defmodule Pleroma.ModerationLog do end def insert_log(%{actor: %User{}, action: action, subject: %Activity{} = subject} = attrs) - when action in [ - "report_note_delete", - "report_update", - "report_note", - "report_unassigned", - "report_assigned" - ] do + when action in ["report_note_delete", "report_update", "report_note"] do data = attrs |> prepare_log_data |> Pleroma.Maps.put_if_present("text", attrs[:text]) - |> Pleroma.Maps.put_if_present("assigned_account", attrs[:assigned_account]) |> Map.merge(%{"subject" => report_to_map(subject)}) insert_log_entry_with_message(%ModerationLog{data: data}) @@ -448,35 +441,6 @@ defmodule Pleroma.ModerationLog do " with '#{state}' state" end - def get_log_entry_message( - %ModerationLog{ - data: %{ - "actor" => %{"nickname" => actor_nickname}, - "action" => "report_assigned", - "subject" => %{"id" => subject_id, "type" => "report"}, - "assigned_account" => assigned_account - } - } = log - ) do - "@#{actor_nickname} assigned report ##{subject_id}" <> - subject_actor_nickname(log, " (on user ", ")") <> - " to user #{assigned_account}" - end - - def get_log_entry_message( - %ModerationLog{ - data: %{ - "actor" => %{"nickname" => actor_nickname}, - "action" => "report_unassigned", - "subject" => %{"id" => subject_id, "type" => "report"} - } - } = log - ) do - "@#{actor_nickname} unassigned report ##{subject_id}" <> - subject_actor_nickname(log, " (on user ", ")") <> - " from a user" - end - def get_log_entry_message( %ModerationLog{ data: %{ diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 5e9314446..d0cb16b79 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -372,28 +372,12 @@ defmodule Pleroma.Object do option end) - existing_voters = object.data["voters"] || [] - voters = [actor | existing_voters] |> Enum.uniq() - new_voter? = actor not in existing_voters - existing_voters_count = object.data["votersCount"] - - voters_count = - cond do - is_integer(existing_voters_count) and new_voter? -> - existing_voters_count + 1 - - is_integer(existing_voters_count) -> - existing_voters_count - - true -> - length(voters) - end + voters = [actor | object.data["voters"] || []] |> Enum.uniq() data = object.data |> Map.put(key, options) |> Map.put("voters", voters) - |> Map.put("votersCount", voters_count) object |> Object.change(%{data: data}) diff --git a/lib/pleroma/release_tasks.ex b/lib/pleroma/release_tasks.ex index 49400940f..af2d35c8f 100644 --- a/lib/pleroma/release_tasks.ex +++ b/lib/pleroma/release_tasks.ex @@ -5,10 +5,7 @@ defmodule Pleroma.ReleaseTasks do @repo Pleroma.Repo - # TODO: Kept for some backwards compatibility with buggy pleroma_ctl, - # if a mismatch between pleroma_ctl and Pleroma accidentaly happens. - # Remove in the future. - def run(args) when is_binary(args) do + def run(args) do [task | args] = String.split(args) case task do @@ -19,20 +16,6 @@ defmodule Pleroma.ReleaseTasks do end end - # HACK: Script arguments need to be received as a list, otherwise (quoted) arguments with - # whitespace will be broken. Previously the broken string form above was used, - # escaping in the shell does not help. - def run(args) when is_list(args) do - [task | args] = args - - case task do - "migrate" -> migrate(args) - "create" -> create() - "rollback" -> rollback(args) - task -> mix_task(task, args) - end - end - def find_module(task) do module_name = task diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index c7ee47c6e..bb55a4984 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -12,7 +12,7 @@ defmodule Pleroma.ReverseProxy do @keep_resp_headers @resp_cache_headers ++ ~w(content-length content-type content-disposition content-encoding) ++ ~w(content-range accept-ranges vary) - @default_cache_control_header "public, max-age=1209600, immutable" + @default_cache_control_header "public, max-age=1209600" @valid_resp_codes [200, 206, 304] @max_read_duration :timer.seconds(30) @max_body_length :infinity diff --git a/lib/pleroma/reverse_proxy/client/hackney.ex b/lib/pleroma/reverse_proxy/client/hackney.ex index 4c81a6225..7e1fca80d 100644 --- a/lib/pleroma/reverse_proxy/client/hackney.ex +++ b/lib/pleroma/reverse_proxy/client/hackney.ex @@ -4,9 +4,6 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do @behaviour Pleroma.ReverseProxy.Client - @redirect_limit 5 - - require Logger # In-app redirect handler to avoid Hackney redirect bugs: # - https://github.com/benoitc/hackney/issues/527 (relative/protocol-less redirects can crash Hackney) @@ -34,15 +31,26 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do if opts[:follow_redirect] != false do {_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end) - env = %{method: method, headers: headers, body: body, req_opts: req_opts} res = :hackney.request(method, url, headers, body, req_opts) case res do {:ok, code, resp_headers, _client} when code in @redirect_statuses -> - redirect(url, resp_headers, env, @redirect_limit) + :hackney.request( + method, + absolute_redirect_url(url, resp_headers), + headers, + body, + req_opts + ) {:ok, code, resp_headers} when code in @redirect_statuses -> - redirect(url, resp_headers, env, @redirect_limit) + :hackney.request( + method, + absolute_redirect_url(url, resp_headers), + headers, + body, + req_opts + ) _ -> res @@ -63,32 +71,4 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do @impl true def close(ref), do: :hackney.close(ref) - - defp redirect(url, resp_headers, env, limit) when limit == 0 do - new_url = absolute_redirect_url(url, resp_headers) - - Logger.debug( - "#{__MODULE__}: Handling redirect #{url} -> #{new_url}; redirect limit was reached - returning response after final redirect" - ) - - :hackney.request(env.method, new_url, env.headers, env.body, env.req_opts) - end - - defp redirect(url, resp_headers, env, limit) do - new_url = absolute_redirect_url(url, resp_headers) - Logger.debug("#{__MODULE__}: handling redirect #{url} -> #{new_url}; limit = #{limit}") - - res = :hackney.request(env.method, new_url, env.headers, env.body, env.req_opts) - - case res do - {:ok, code, new_resp_headers, _client} when code in @redirect_statuses -> - redirect(new_url, new_resp_headers, env, limit - 1) - - {:ok, code, new_resp_headers} when code in @redirect_statuses -> - redirect(new_url, new_resp_headers, env, limit - 1) - - _ -> - res - end - end end diff --git a/lib/pleroma/search.ex b/lib/pleroma/search.ex index 9cd2768c4..30b3ba958 100644 --- a/lib/pleroma/search.ex +++ b/lib/pleroma/search.ex @@ -1,28 +1,11 @@ defmodule Pleroma.Search do - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Workers.SearchIndexingWorker - @spec add_to_index(Activity.t()) :: {:ok, Oban.Job.t() | :noop} | {:error, Oban.Job.changeset()} - def add_to_index(%Activity{id: activity_id, object: %Object{} = object} = activity) do - with {_, true} <- {:indexable, indexable?(activity)}, - {_, "public"} <- {:visibility, Visibility.get_visibility(object)} do - SearchIndexingWorker.new(%{"op" => "add_to_index", "activity" => activity_id}) - |> Oban.insert() - else - _ -> {:ok, :noop} - end + def add_to_index(%Pleroma.Activity{id: activity_id}) do + SearchIndexingWorker.new(%{"op" => "add_to_index", "activity" => activity_id}) + |> Oban.insert() end - def add_to_index(%Activity{id: activity_id}) do - case Activity.get_by_id_with_object(activity_id) do - %Activity{} = preloaded -> add_to_index(preloaded) - _ -> {:ok, :noop} - end - end - - @spec remove_from_index(Object.t()) :: {:ok, Oban.Job.t()} | {:error, Oban.Job.changeset()} def remove_from_index(%Pleroma.Object{id: object_id}) do SearchIndexingWorker.new(%{"op" => "remove_from_index", "object" => object_id}) |> Oban.insert() @@ -37,44 +20,4 @@ defmodule Pleroma.Search do search_module = Pleroma.Config.get([Pleroma.Search, :module]) search_module.healthcheck_endpoints() end - - def object_to_search_data(%Object{} = object) do - data = object.data - - content_str = - case data["content"] do - [nil | rest] -> to_string(rest) - str -> str - end - - content = - with {:ok, scrubbed} <- - FastSanitize.Sanitizer.scrub(content_str, Pleroma.HTML.Scrubber.SearchIndexing), - trimmed <- String.trim(scrubbed) do - trimmed - end - - # Make sure we have a non-empty string - if content != "" do - {:ok, published, _} = DateTime.from_iso8601(data["published"]) - - %{ - id: object.id, - content: content, - ap: data["id"], - published: published |> DateTime.to_unix() - } - end - end - - defp indexable?(%Activity{ - data: %{"type" => "Create"}, - object: %Object{ - data: %{"content" => content, "published" => published, "type" => "Note"} - } - }) - when not is_nil(content) and content not in ["", "."] and not is_nil(published), - do: true - - defp indexable?(_), do: false end diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index dc10076e1..cafae8099 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -4,8 +4,6 @@ defmodule Pleroma.Search.Meilisearch do alias Pleroma.Activity alias Pleroma.Config.Getting, as: Config - alias Pleroma.Object - alias Pleroma.Search import Pleroma.Search.DatabaseSearch import Ecto.Query @@ -120,24 +118,66 @@ defmodule Pleroma.Search.Meilisearch do end end + def object_to_search_data(object) do + # Only index public or unlisted Notes + if not is_nil(object) and object.data["type"] == "Note" and + not is_nil(object.data["content"]) and + not is_nil(object.data["published"]) and + (Pleroma.Constants.as_public() in object.data["to"] or + Pleroma.Constants.as_public() in object.data["cc"]) and + object.data["content"] not in ["", "."] do + data = object.data + + content_str = + case data["content"] do + [nil | rest] -> to_string(rest) + str -> str + end + + content = + with {:ok, scrubbed} <- + FastSanitize.Sanitizer.scrub(content_str, Pleroma.HTML.Scrubber.SearchIndexing), + trimmed <- String.trim(scrubbed) do + trimmed + end + + # Make sure we have a non-empty string + if content != "" do + {:ok, published, _} = DateTime.from_iso8601(data["published"]) + + %{ + id: object.id, + content: content, + ap: data["id"], + published: published |> DateTime.to_unix() + } + end + end + end + @impl true - def add_to_index(%Activity{object: %Object{} = object} = activity) do - search_data = Search.object_to_search_data(object) + def add_to_index(activity) do + maybe_search_data = object_to_search_data(activity.object) - result = - meili_put( - "/indexes/objects/documents", - [search_data] - ) + if activity.data["type"] == "Create" and maybe_search_data do + result = + meili_put( + "/indexes/objects/documents", + [maybe_search_data] + ) - with {:ok, %{"status" => "enqueued"}} <- result do - # Added successfully - :ok + with {:ok, %{"status" => "enqueued"}} <- result do + # Added successfully + :ok + else + _ -> + # There was an error, report it + Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}") + {:error, result} + end else - _ -> - # There was an error, report it - Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}") - {:error, result} + # The post isn't something we can search, that's ok + :ok end end diff --git a/lib/pleroma/search/qdrant_search.ex b/lib/pleroma/search/qdrant_search.ex index 4d57cfa88..5142a273f 100644 --- a/lib/pleroma/search/qdrant_search.ex +++ b/lib/pleroma/search/qdrant_search.ex @@ -4,12 +4,11 @@ defmodule Pleroma.Search.QdrantSearch do alias Pleroma.Activity alias Pleroma.Config.Getting, as: Config - alias Pleroma.Object - alias Pleroma.Search alias __MODULE__.OpenAIClient alias __MODULE__.QdrantClient + import Pleroma.Search.Meilisearch, only: [object_to_search_data: 1] import Pleroma.Search.DatabaseSearch, only: [maybe_fetch: 3] @impl true @@ -83,18 +82,23 @@ defmodule Pleroma.Search.QdrantSearch do end @impl true - def add_to_index(%Activity{object: %Object{} = object} = activity) do - search_data = Search.object_to_search_data(object) + def add_to_index(activity) do + # This will only index public or unlisted notes + maybe_search_data = object_to_search_data(activity.object) - with {:ok, embedding} <- get_embedding(search_data.content), - {:ok, %{status: 200}} <- - QdrantClient.put( - "/collections/posts/points", - build_index_payload(activity, embedding) - ) do - :ok + if activity.data["type"] == "Create" and maybe_search_data do + with {:ok, embedding} <- get_embedding(maybe_search_data.content), + {:ok, %{status: 200}} <- + QdrantClient.put( + "/collections/posts/points", + build_index_payload(activity, embedding) + ) do + :ok + else + e -> {:error, e} + end else - e -> {:error, e} + :ok end end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 350ff6cb3..06d8005bc 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -93,7 +93,7 @@ defmodule Pleroma.Upload do def store(upload, opts \\ []) do opts = get_opts(opts) - with {:ok, %__MODULE__{} = upload} <- prepare_upload(upload, opts), + with {:ok, upload} <- prepare_upload(upload, opts), upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"}, {:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload), description = get_description(upload), diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex index 35535528b..3f67cdf0c 100644 --- a/lib/pleroma/user/backup.ex +++ b/lib/pleroma/user/backup.ex @@ -342,7 +342,7 @@ defmodule Pleroma.User.Backup do dir, "outbox", fn a -> - with {:ok, activity} <- Transmogrifier.prepare_activity(a.data) do + with {:ok, activity} <- Transmogrifier.prepare_outgoing(a.data) do {:ok, Map.delete(activity, "@context")} end end diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex index cf5025670..07b6e46f7 100644 --- a/lib/pleroma/user_relationship.ex +++ b/lib/pleroma/user_relationship.ex @@ -45,7 +45,7 @@ defmodule Pleroma.UserRelationship do do: exists?(unquote(relationship_type), source, target) # `def get_block_expire_date/2`, `def get_mute_expire_date/2`, - # `def get_reblog_mute_expire_date/2`, `def get_notification_mute_expire_date/2`, + # `def get_reblog_mute_expire_date/2`, `def get_notification_mute_exists?/2`, # `def get_inverse_subscription_expire_date/2`, `def get_inverse_endorsement_expire_date/2` def unquote(:"get_#{relationship_type}_expire_date")(source, target), do: get_expire_date(unquote(relationship_type), source, target) diff --git a/lib/pleroma/utils.ex b/lib/pleroma/utils.ex index 61d122a47..73001c987 100644 --- a/lib/pleroma/utils.ex +++ b/lib/pleroma/utils.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Utils do dir |> File.ls!() |> Enum.map(&Path.join(dir, &1)) - |> Kernel.ParallelCompiler.compile(return_diagnostics: true) + |> Kernel.ParallelCompiler.compile() end @doc """ diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 0b513ee16..e58e3dd57 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1003,14 +1003,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_state(query, _), do: query - defp restrict_assigned_account(query, %{assigned_account: assigned_account}) do - from(activity in query, - where: fragment("?->>'assigned_account' = ?", activity.data, ^assigned_account) - ) - end - - defp restrict_assigned_account(query, _), do: query - defp restrict_favorited_by(query, %{favorited_by: ap_id}) do from( [_activity, object] in query, @@ -1479,7 +1471,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_actor(opts) |> restrict_type(opts) |> restrict_state(opts) - |> restrict_assigned_account(opts) |> restrict_favorited_by(opts) |> restrict_blocked(restrict_blocked_opts) |> restrict_blockers_visibility(opts) @@ -1618,10 +1609,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image() defp normalize_image(_), do: nil - defp normalize_also_known_as(urls) when is_list(urls), do: urls - defp normalize_also_known_as(url) when is_binary(url), do: [url] - defp normalize_also_known_as(nil), do: [] - defp maybe_put_description(map, %{"name" => description}) when is_binary(description) do Map.put(map, "name", description) end @@ -1677,80 +1664,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do show_birthday = !!birthday - with {:ok, nickname} <- nickname_from_actor(data, additional) do - {:ok, - %{ - ap_id: data["id"], - uri: get_actor_url(data["url"]), - banner: normalize_image(data["image"]), - fields: fields, - emoji: emojis, - is_locked: is_locked, - is_discoverable: is_discoverable, - invisible: invisible, - avatar: normalize_image(data["icon"]), - name: data["name"], - follower_address: data["followers"], - following_address: data["following"], - featured_address: featured_address, - bio: data["summary"] || "", - actor_type: actor_type, - also_known_as: normalize_also_known_as(data["alsoKnownAs"]), - public_key: public_key, - inbox: data["inbox"], - shared_inbox: shared_inbox, - accepts_chat_messages: accepts_chat_messages, - birthday: birthday, - show_birthday: show_birthday, - pinned_objects: pinned_objects, - nickname: nickname - }} - end - end + # if WebFinger request was already done, we probably have acct, otherwise + # we request WebFinger here + nickname = additional[:nickname_from_acct] || generate_nickname(data) - defp nickname_from_actor(data, additional) do - generated = generated_nickname(data) - - case additional[:nickname_from_acct] do - ^generated when is_binary(generated) -> - {:ok, generated} - - acct when is_binary(acct) -> - with ^acct <- webfinger_nickname(data) do - {:ok, acct} - else - _ -> {:error, {:webfinger_actor_mismatch, acct, data["id"]}} - end - - _ -> - {:ok, generate_nickname(data)} - end - end - - defp generated_nickname(%{"preferredUsername" => username, "id" => ap_id}) - when is_binary(username) and is_binary(ap_id) do - case URI.parse(ap_id) do - %URI{host: host} when is_binary(host) -> "#{username}@#{host}" - _ -> nil - end - end - - defp generated_nickname(_), do: nil - - defp webfinger_nickname(data) do - with generated when is_binary(generated) <- generated_nickname(data), - {:ok, %{"subject" => "acct:" <> acct, "ap_id" => ap_id}} <- WebFinger.finger(generated), - true <- ap_id == data["id"] do - acct - end + %{ + ap_id: data["id"], + uri: get_actor_url(data["url"]), + banner: normalize_image(data["image"]), + fields: fields, + emoji: emojis, + is_locked: is_locked, + is_discoverable: is_discoverable, + invisible: invisible, + avatar: normalize_image(data["icon"]), + name: data["name"], + follower_address: data["followers"], + following_address: data["following"], + featured_address: featured_address, + bio: data["summary"] || "", + actor_type: actor_type, + also_known_as: Map.get(data, "alsoKnownAs", []), + public_key: public_key, + inbox: data["inbox"], + shared_inbox: shared_inbox, + accepts_chat_messages: accepts_chat_messages, + birthday: birthday, + show_birthday: show_birthday, + pinned_objects: pinned_objects, + nickname: nickname + } end defp generate_nickname(%{"preferredUsername" => username} = data) when is_binary(username) do - generated = generated_nickname(data) + generated = "#{username}@#{URI.parse(data["id"]).host}" if Config.get([WebFinger, :update_nickname_on_user_fetch]) do - case webfinger_nickname(data) do - acct when is_binary(acct) -> acct + case WebFinger.finger(generated) do + {:ok, %{"subject" => "acct:" <> acct}} -> acct _ -> generated end else @@ -1830,11 +1781,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp collection_private(_data), do: {:ok, true} def user_data_from_user_object(data, additional \\ []) do - with {:ok, data} <- MRF.filter(data), - {:ok, data} <- object_to_user_data(data, additional) do - {:ok, data} + with {:ok, data} <- MRF.filter(data) do + {:ok, object_to_user_data(data, additional)} else - {:error, _} = e -> e e -> {:error, e} end end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 2bfff6968..4f1613a07 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -348,7 +348,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def inbox(%{assigns: %{valid_signature: false}} = conn, params) do - Federator.incoming_failed_signature_ap_doc(%{ + Federator.incoming_ap_doc(%{ method: conn.method, req_headers: conn.req_headers, request_path: conn.request_path, diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex index 3b208ab77..167c769a9 100644 --- a/lib/pleroma/web/activity_pub/builder.ex +++ b/lib/pleroma/web/activity_pub/builder.ex @@ -332,18 +332,21 @@ defmodule Pleroma.Web.ActivityPub.Builder do @spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()} def announce(actor, object, options \\ []) do - visibility = Keyword.get(options, :visibility, "public") + public? = Keyword.get(options, :public, false) - {to, cc} = - if actor.ap_id == Relay.ap_id() do - {[actor.follower_address], []} - else - Pleroma.Web.CommonAPI.Utils.get_to_and_cc_for_visibility( - visibility, - actor.follower_address, - nil, - [object.data["actor"]] - ) + to = + cond do + actor.ap_id == Relay.ap_id() -> + [actor.follower_address] + + public? and Visibility.local_public?(object) -> + [actor.follower_address, object.data["actor"], Utils.as_local_public()] + + public? -> + [actor.follower_address, object.data["actor"], Pleroma.Constants.as_public()] + + true -> + [actor.follower_address, object.data["actor"]] end {:ok, @@ -352,7 +355,6 @@ defmodule Pleroma.Web.ActivityPub.Builder do "actor" => actor.ap_id, "object" => object.data["id"], "to" => to, - "cc" => cc, "context" => object.data["context"], "type" => "Announce", "published" => Utils.make_date() diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 844ad2c8f..c0626ce4d 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -6,12 +6,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do use Ecto.Schema alias Pleroma.EctoType.ActivityPub.ObjectValidators - alias Pleroma.HTML - alias Pleroma.User alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI.Utils import Ecto.Changeset @@ -29,7 +26,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do end field(:replies, {:array, ObjectValidators.ObjectID}, default: []) - field(:source, :map) end def cast_and_apply(data) do @@ -84,113 +80,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do def fix_attachments(data), do: data - defp remote_mention_resolver( - %{"id" => ap_id, "tag" => tags}, - "@" <> nickname = mention, - buffer, - opts, - acc - ) - when is_binary(ap_id) and is_list(tags) do - initial_host = - ap_id - |> URI.parse() - |> Map.get(:host) - - with mention_tag when not is_nil(mention_tag) <- - Enum.find(tags, &mention_tag?(&1, mention, initial_host)), - href when is_binary(href) <- mention_tag["href"], - %User{} = user <- User.get_cached_by_ap_id(href) do - link = Pleroma.Formatter.mention_from_user(user, opts) - {link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}} - else - _ -> {buffer, acc} - end - end - - defp remote_mention_resolver(_object, _mention, buffer, _opts, acc), do: {buffer, acc} - - defp mention_tag?(%{"type" => "Mention", "name" => name}, mention, initial_host) - when is_binary(name) do - name == mention || mention == "#{name}@#{initial_host}" - end - - defp mention_tag?(_tag, _mention, _initial_host), do: false - - defp scrub_content(%{"content" => content} = object) when is_binary(content) do - Map.put(object, "content", HTML.filter_tags(content)) - end - - defp scrub_content(object), do: object - - defp mfm_parse_limit do - min(Pleroma.Config.get([:instance, :limit]), Pleroma.Config.get([:instance, :remote_limit])) - end - - defp normalize_source(%{"source" => source} = object) when is_binary(source) do - object - |> Map.put("source", %{"content" => source}) - |> normalize_source() - end - - defp normalize_source(%{"source" => source} = object) when is_map(source) do - source = - case source["content"] do - content when is_binary(content) -> - if String.length(content) <= mfm_parse_limit() do - source - else - Map.delete(source, "content") - end - - nil -> - source - - _ -> - Map.delete(source, "content") - end - - Map.put(object, "source", source) - end - - defp normalize_source(object), do: object - - defp fix_misskey_content(%{"htmlMfm" => true, "content" => content} = object) - when is_binary(content) do - Map.put(object, "content", HTML.filter_tags(content)) - end - - defp fix_misskey_content(%{"htmlMfm" => true} = object), do: object - - defp fix_misskey_content( - %{"source" => %{"mediaType" => "text/x.misskeymarkdown", "content" => content}} = object - ) - when is_binary(content) do - mention_handler = fn nick, buffer, opts, acc -> - remote_mention_resolver(object, nick, buffer, opts, acc) - end - - {linked, _mentions, _tags} = - Utils.format_input(content, "text/x.misskeymarkdown", mention_handler: mention_handler) - - Map.put(object, "content", linked) - end - - defp fix_misskey_content(%{"source" => %{"mediaType" => "text/x.misskeymarkdown"}} = object), - do: scrub_content(object) - - defp fix_misskey_content(%{"_misskey_content" => content} = object) when is_binary(content) do - object - |> Map.put("source", %{ - "content" => content, - "mediaType" => "text/x.misskeymarkdown" - }) - |> Map.delete("_misskey_content") - |> fix_misskey_content() - end - - defp fix_misskey_content(object), do: object - defp fix(data) do data |> CommonFixes.fix_actor() @@ -199,8 +88,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> fix_tag() |> fix_replies() |> fix_attachments() - |> normalize_source() - |> fix_misskey_content() |> CommonFixes.fix_quote_url() |> CommonFixes.fix_likes() |> Transmogrifier.fix_emoji() diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 9b8580200..22cf0cc05 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -32,7 +32,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do quote bind_quoted: binding() do field(:content, :string) field(:contentMap, ObjectValidators.ContentLanguageMap) - field(:htmlMfm, :boolean) field(:published, ObjectValidators.DateTime) field(:updated, ObjectValidators.DateTime) diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex index 065c75910..21940f4f1 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex @@ -28,7 +28,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do end field(:closed, ObjectValidators.DateTime) - field(:votersCount, :integer) field(:voters, {:array, ObjectValidators.ObjectID}, default: []) field(:nonAnonymous, :boolean) embeds_many(:anyOf, QuestionOptionsValidator) diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex index 4c0d9dff7..aab90235f 100644 --- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex @@ -75,40 +75,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do end end - # For remote Updates, verify the Actor is the same + # For remote Updates, verify the host is the same. def validate_updating_rights_remote(cng) do with actor = get_field(cng, :actor), object = get_field(cng, :object), {:ok, object_id} <- ObjectValidators.ObjectID.cast(object), - entity <- - Object.normalize(object_id, fetch: false) || User.get_cached_by_ap_id(object_id) do - case entity do - # Actor must own Object to update it - %Object{} -> - if actor == entity.data["actor"] do - cng - else - cng - |> add_error(:object, "Can't be updated by this actor") - end - - # Actor must only be allowed to update itself - %User{} -> - if actor == entity.ap_id do - cng - else - cng - |> add_error(:object, "Can't be updated by this actor") - end - - nil -> - cng - |> add_error(:object, "Can't be updated by this actor") - - _ -> - cng - |> add_error(:object, "Update is neither for Object or Actor") - end + actor_uri <- URI.parse(actor), + object_uri <- URI.parse(object_id), + true <- actor_uri.host == object_uri.host do + cng else _e -> cng diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index e3c4e01a4..b6c814aed 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -79,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do Determine if an activity can be represented by running it through Transmogrifier. """ def representable?(%Activity{} = activity) do - with {:ok, _data} <- @transmogrifier_impl.prepare_activity(activity.data) do + with {:ok, _data} <- @transmogrifier_impl.prepare_outgoing(activity.data) do true else _e -> @@ -102,14 +102,14 @@ defmodule Pleroma.Web.ActivityPub.Publisher do Logger.debug("Federating #{ap_id} to #{inbox}") uri = %{path: path} = URI.parse(inbox) - {:ok, data} = @transmogrifier_impl.prepare_activity(activity.data) + {:ok, data} = @transmogrifier_impl.prepare_outgoing(activity.data) {actor, data} = with {_, false} <- {:actor_changed?, data["actor"] != activity.data["actor"]} do {actor, data} else {:actor_changed?, true} -> - # If prepare_activity changes the actor, re-get it from the db + # If prepare_outgoing changes the actor, re-get it from the db new_actor = User.get_cached_by_ap_id(data["actor"]) {new_actor, data} end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 4421da26c..ba6f4030d 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -783,13 +783,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def set_replies(obj_data), do: obj_data - defp set_voters_count(%{"voters" => [_ | _] = voters} = obj) do - Map.merge(obj, %{"votersCount" => length(voters)}) - end - - defp set_voters_count(obj), do: obj - - # Prepares and sanitizes the object for federation. + # Prepares the object of an outgoing create activity. def prepare_object(object) do object |> add_hashtags @@ -801,7 +795,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> set_reply_to_uri |> set_quote_url |> set_replies - |> set_voters_count |> CommonFixes.maybe_add_content_map() |> strip_internal_fields |> strip_internal_tags @@ -831,7 +824,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # internal -> Mastodon # """ - def prepare_activity(%{"type" => activity_type, "object" => object_id} = data) + def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data) when activity_type in ["Create", "Listen"] do object = object_id @@ -847,7 +840,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do {:ok, data} end - def prepare_activity(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) + def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) when objtype in Pleroma.Constants.updatable_object_types() do data = data @@ -858,7 +851,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do {:ok, data} end - def prepare_activity(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) + def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) when objtype in Pleroma.Constants.actor_types() do object = object @@ -875,11 +868,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do {:ok, data} end - def prepare_activity(%{"type" => "Update", "object" => %{}} = data) do + def prepare_outgoing(%{"type" => "Update", "object" => %{}} = data) do raise "Requested to serve an Update for non-updateable object type: #{inspect(data)}" end - def prepare_activity(%{"type" => "Announce", "actor" => ap_id, "object" => object_id} = data) do + def prepare_outgoing(%{"type" => "Announce", "actor" => ap_id, "object" => object_id} = data) do object = object_id |> Object.normalize(fetch: false) @@ -902,7 +895,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # Mastodon Accept/Reject requires a non-normalized object containing the actor URIs, # because of course it does. - def prepare_activity(%{"type" => "Accept"} = data) do + def prepare_outgoing(%{"type" => "Accept"} = data) do with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, @@ -920,7 +913,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end - def prepare_activity(%{"type" => "Reject"} = data) do + def prepare_outgoing(%{"type" => "Reject"} = data) do with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, @@ -938,7 +931,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end - def prepare_activity(%{"type" => "Flag"} = data) do + def prepare_outgoing(%{"type" => "Flag"} = data) do with {:ok, stripped_activity} <- Utils.strip_report_status_data(data), stripped_activity <- Utils.maybe_anonymize_reporter(stripped_activity), stripped_activity <- Map.merge(stripped_activity, Utils.make_json_ld_header()) do @@ -946,7 +939,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end - def prepare_activity(%{"type" => _type} = data) do + def prepare_outgoing(%{"type" => _type} = data) do data = data |> strip_internal_fields diff --git a/lib/pleroma/web/activity_pub/transmogrifier/api.ex b/lib/pleroma/web/activity_pub/transmogrifier/api.ex index f2e416575..b9f65d17c 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier/api.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier/api.ex @@ -7,5 +7,5 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.API do Behaviour for the subset of Transmogrifier used by Publisher. """ - @callback prepare_activity(map()) :: {:ok, map()} | {:error, term()} + @callback prepare_outgoing(map()) :: {:ok, map()} | {:error, term()} end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 0af4ceaf5..c5a6901d4 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -120,8 +120,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do "https://www.w3.org/ns/activitystreams", "#{Endpoint.url()}/schemas/litepub-0.1.jsonld", %{ - "@language" => get_language(data), - "htmlMfm" => "https://w3id.org/fep/c16b#htmlMfm" + "@language" => get_language(data) } ] } @@ -864,34 +863,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do def update_report_state(_, _), do: {:error, "Unsupported state"} - def assign_report_to_account(%Activity{} = activity, nil = _account) do - new_data = Map.delete(activity.data, "assigned_account") - - activity - |> Changeset.change(data: new_data) - |> Repo.update() - end - - def assign_report_to_account(%Activity{} = activity, account) do - new_data = Map.put(activity.data, "assigned_account", account) - - activity - |> Changeset.change(data: new_data) - |> Repo.update() - end - - def assign_report_to_account(activity_ids, account) do - activities_num = length(activity_ids) - - from(a in Activity, where: a.id in ^activity_ids) - |> update(set: [data: fragment("jsonb_set(data, '{assigned_account}', ?)", ^account)]) - |> Repo.update_all([]) - |> case do - {^activities_num, _} -> :ok - _ -> {:error, activity_ids} - end - end - def strip_report_status_data(%Activity{} = activity) do with {:ok, new_data} <- strip_report_status_data(activity.data) do {:ok, %{activity | data: new_data}} diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 9334b797a..a672ccc8b 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do end def render("object.json", %{object: %Activity{} = activity}) do - {:ok, ap_data} = Transmogrifier.prepare_activity(activity.data) + {:ok, ap_data} = Transmogrifier.prepare_outgoing(activity.data) ap_data end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 8847692c8..4362db324 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -35,14 +35,32 @@ defmodule Pleroma.Web.ActivityPub.UserView do def render("endpoints.json", _), do: %{} def render("service.json", %{user: user}) do - Map.merge(common_actor_fields(user), %{ + {:ok, _, public_key} = Keys.keys_from_pem(user.keys) + public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) + public_key = :public_key.pem_encode([public_key]) + + endpoints = render("endpoints.json", %{user: user}) + + %{ + "id" => user.ap_id, "type" => "Application", + "following" => "#{user.ap_id}/following", + "followers" => "#{user.ap_id}/followers", + "inbox" => "#{user.ap_id}/inbox", + "outbox" => "#{user.ap_id}/outbox", "name" => "Pleroma", "summary" => "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", + "url" => user.ap_id, "manuallyApprovesFollowers" => false, + "publicKey" => %{ + "id" => "#{user.ap_id}#main-key", + "owner" => user.ap_id, + "publicKeyPem" => public_key + }, + "endpoints" => endpoints, "invisible" => User.invisible?(user) - }) + } |> Map.merge(Utils.make_json_ld_header()) end @@ -59,8 +77,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do end def render("user.json", %{user: user}) do + {:ok, _, public_key} = Keys.keys_from_pem(user.keys) + public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) + public_key = :public_key.pem_encode([public_key]) user = User.sanitize_html(user) + endpoints = render("endpoints.json", %{user: user}) + emoji_tags = Transmogrifier.take_emoji_tags(user) fields = Enum.map(user.fields, &Map.put(&1, "type", "PropertyValue")) @@ -79,9 +102,25 @@ defmodule Pleroma.Web.ActivityPub.UserView do do: Date.to_iso8601(user.birthday), else: nil - Map.merge(common_actor_fields(user), %{ + %{ + "id" => user.ap_id, + "type" => user.actor_type, + "following" => "#{user.ap_id}/following", + "followers" => "#{user.ap_id}/followers", + "inbox" => "#{user.ap_id}/inbox", + "outbox" => "#{user.ap_id}/outbox", "featured" => "#{user.ap_id}/collections/featured", "preferredUsername" => user.nickname, + "name" => user.name, + "summary" => user.bio, + "url" => user.ap_id, + "manuallyApprovesFollowers" => user.is_locked, + "publicKey" => %{ + "id" => "#{user.ap_id}#main-key", + "owner" => user.ap_id, + "publicKeyPem" => public_key + }, + "endpoints" => endpoints, "attachment" => fields, "tag" => emoji_tags, # Note: key name is indeed "discoverable" (not an error) @@ -91,7 +130,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do "vcard:bday" => birthday, "webfinger" => "acct:#{User.full_nickname(user)}", "published" => Pleroma.Web.CommonAPI.Utils.to_masto_date(user.inserted_at) - }) + } |> Map.merge( maybe_make_image( &User.avatar_url/2, @@ -244,7 +283,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do }) do collection = Enum.map(activities, fn activity -> - {:ok, data} = Transmogrifier.prepare_activity(activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) data end) @@ -270,33 +309,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do |> Map.merge(Utils.make_json_ld_header()) end - defp common_actor_fields(%User{} = user) do - endpoints = render("endpoints.json", %{user: user}) - - {:ok, _, public_key} = Keys.keys_from_pem(user.keys) - public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) - public_key = :public_key.pem_encode([public_key]) - - %{ - "id" => user.ap_id, - "type" => user.actor_type, - "following" => "#{user.ap_id}/following", - "followers" => "#{user.ap_id}/followers", - "inbox" => "#{user.ap_id}/inbox", - "outbox" => "#{user.ap_id}/outbox", - "name" => user.name, - "summary" => user.bio, - "url" => user.ap_id, - "manuallyApprovesFollowers" => user.is_locked, - "endpoints" => endpoints, - "publicKey" => %{ - "id" => "#{user.ap_id}#main-key", - "owner" => user.ap_id, - "publicKeyPem" => public_key - } - } - end - defp maybe_put_total_items(map, false, _total), do: map defp maybe_put_total_items(map, true, total) do diff --git a/lib/pleroma/web/admin_api/controllers/config_controller.ex b/lib/pleroma/web/admin_api/controllers/config_controller.ex index 3eba03525..2c9c27294 100644 --- a/lib/pleroma/web/admin_api/controllers/config_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/config_controller.ex @@ -174,8 +174,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do end end - defp whitelisted_config?(":pleroma", ":database_config_whitelist"), do: false - defp whitelisted_config?(group, key) do if whitelisted_configs = Config.get(:database_config_whitelist) do Enum.any?(whitelisted_configs, fn diff --git a/lib/pleroma/web/admin_api/controllers/report_controller.ex b/lib/pleroma/web/admin_api/controllers/report_controller.ex index dbac03ef4..89d8cc820 100644 --- a/lib/pleroma/web/admin_api/controllers/report_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/report_controller.ex @@ -10,7 +10,6 @@ defmodule Pleroma.Web.AdminAPI.ReportController do alias Pleroma.Activity alias Pleroma.ModerationLog alias Pleroma.ReportNote - alias Pleroma.User alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.AdminAPI alias Pleroma.Web.AdminAPI.Report @@ -25,7 +24,7 @@ defmodule Pleroma.Web.AdminAPI.ReportController do plug( OAuthScopesPlug, %{scopes: ["admin:write:reports"]} - when action in [:update, :assign_account, :notes_create, :notes_delete] + when action in [:update, :notes_create, :notes_delete] ) action_fallback(AdminAPI.FallbackController) @@ -80,22 +79,6 @@ defmodule Pleroma.Web.AdminAPI.ReportController do end end - def assign_account( - %{ - assigns: %{user: admin}, - private: %{open_api_spex: %{body_params: %{reports: reports}}} - } = conn, - _ - ) do - result = Enum.map(reports, &do_assign_account(&1, admin)) - - if Enum.any?(result, &Map.has_key?(&1, :error)) do - json_response(conn, :bad_request, result) - else - json_response(conn, :no_content, "") - end - end - def notes_create( %{ assigns: %{user: user}, @@ -148,40 +131,4 @@ defmodule Pleroma.Web.AdminAPI.ReportController do _ -> json_response(conn, :bad_request, "") end end - - defp do_assign_account(%{assigned_account: nil, id: id}, admin) do - with {:ok, activity} <- CommonAPI.assign_report_to_account(id, nil), - report <- Activity.get_by_id_with_user_actor(activity.id) do - ModerationLog.insert_log(%{ - action: "report_unassigned", - actor: admin, - subject: activity, - subject_actor: report.user_actor - }) - - activity - else - {:error, message} -> - %{id: id, error: message} - end - end - - defp do_assign_account(%{assigned_account: assigned_account, id: id}, admin) do - with %User{id: account} = user <- User.get_cached_by_nickname(assigned_account), - {:ok, activity} <- CommonAPI.assign_report_to_account(id, account), - report <- Activity.get_by_id_with_user_actor(activity.id) do - ModerationLog.insert_log(%{ - action: "report_assigned", - actor: admin, - subject: activity, - subject_actor: report.user_actor, - assigned_account: user.nickname - }) - - activity - else - {:error, message} -> - %{id: id, error: message} - end - end end diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index 753b92d88..fa89e3405 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -13,11 +13,6 @@ defmodule Pleroma.Web.AdminAPI.Report do user = User.get_cached_by_ap_id(actor) account = User.get_cached_by_ap_id(account_ap_id) - assigned_account = - if Map.has_key?(report.data, "assigned_account") do - User.get_cached_by_id(report.data["assigned_account"]) - end - statuses = status_ap_ids |> Enum.reject(&is_nil(&1)) @@ -31,13 +26,7 @@ defmodule Pleroma.Web.AdminAPI.Report do Activity.get_by_ap_id_with_object(act) end) - %{ - report: report, - user: user, - account: account, - statuses: statuses, - assigned_account: assigned_account - } + %{report: report, user: user, account: account, statuses: statuses} end defp make_fake_activity(act, user) do diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index da6166050..b4b0be267 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -26,13 +26,7 @@ defmodule Pleroma.Web.AdminAPI.ReportView do } end - def render("show.json", %{ - report: report, - user: user, - account: account, - statuses: statuses, - assigned_account: assigned_account - }) do + def render("show.json", %{report: report, user: user, account: account, statuses: statuses}) do created_at = Utils.to_masto_date(report.data["published"]) content = @@ -42,11 +36,6 @@ defmodule Pleroma.Web.AdminAPI.ReportView do nil end - assigned_account = - if assigned_account do - merge_account_views(assigned_account) - end - %{ id: report.id, account: merge_account_views(account), @@ -60,8 +49,7 @@ defmodule Pleroma.Web.AdminAPI.ReportView do }), state: report.data["state"], notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes}), - rules: rules(Map.get(report.data, "rules", nil)), - assigned_account: assigned_account + rules: rules(Map.get(report.data, "rules", nil)) } end diff --git a/lib/pleroma/web/api_spec/cast_and_validate.ex b/lib/pleroma/web/api_spec/cast_and_validate.ex index 95bd4d9cf..672d1c4a1 100644 --- a/lib/pleroma/web/api_spec/cast_and_validate.ex +++ b/lib/pleroma/web/api_spec/cast_and_validate.ex @@ -106,14 +106,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts) end - defp cast_and_validate( - spec, - operation, - %Conn{} = conn, - content_type, - false = _strict, - cast_opts - ) do + defp cast_and_validate(spec, operation, conn, content_type, false = _strict, cast_opts) do case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do {:ok, conn} -> {:ok, conn} diff --git a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex index 58669a1fc..25a604beb 100644 --- a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex @@ -53,12 +53,6 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do :query, %Schema{type: :integer, default: 50}, "Number number of log entries per page" - ), - Operation.parameter( - :assigned_account, - :query, - %Schema{type: :string}, - "Filter by assigned account ID" ) | admin_api_params() ], @@ -109,22 +103,6 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do } end - def assign_account_operation do - %Operation{ - tags: ["Report management"], - summary: "Assign account to specified reports", - operationId: "AdminAPI.ReportController.assign_account", - security: [%{"oAuth" => ["admin:write:reports"]}], - parameters: admin_api_params(), - requestBody: request_body("Parameters", assign_account_request(), required: true), - responses: %{ - 204 => no_content_response(), - 400 => Operation.response("Bad Request", "application/json", update_400_response()), - 403 => Operation.response("Forbidden", "application/json", ApiError) - } - } - end - def notes_create_operation do %Operation{ tags: ["Report management"], @@ -208,10 +186,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do hint: %Schema{type: :string, nullable: true} } } - }, - assigned_account: - account_admin() - |> Map.put(:nullable, true) + } } } end @@ -267,34 +242,6 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do } end - defp assign_account_request do - %Schema{ - type: :object, - required: [:reports], - properties: %{ - reports: %Schema{ - type: :array, - items: %Schema{ - type: :object, - properties: %{ - id: %Schema{allOf: [FlakeID], description: "Required, report ID"}, - assigned_account: %Schema{ - type: :string, - description: "User nickname", - nullable: true - } - } - }, - example: %{ - "reports" => [ - %{"id" => "123", "assigned_account" => "pleroma"} - ] - } - } - } - } - end - defp update_400_response do %Schema{ type: :array, diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex index 6be4ea996..d8b2901d3 100644 --- a/lib/pleroma/web/api_spec/operations/instance_operation.ex +++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex @@ -342,18 +342,6 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do max_pinned_statuses: %Schema{ type: :integer, description: "The maximum number of pinned statuses for each account." - }, - max_profile_fields: %Schema{ - type: :integer, - description: "The maximum number of custom profile fields allowed to be set." - }, - profile_field_name_limit: %Schema{ - type: :integer, - description: "The maximum size of a profile field name, in characters." - }, - profile_field_value_limit: %Schema{ - type: :integer, - description: "The maximum size of a profile field value, in characters." } } }, diff --git a/lib/pleroma/web/api_spec/operations/list_operation.ex b/lib/pleroma/web/api_spec/operations/list_operation.ex index 87189edc2..7d876ae2d 100644 --- a/lib/pleroma/web/api_spec/operations/list_operation.ex +++ b/lib/pleroma/web/api_spec/operations/list_operation.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do summary: "Create a list", description: "Fetch the list with the given ID. Used for verifying the title of a list.", operationId: "ListController.create", - requestBody: create_request(), + requestBody: create_update_request(), security: [%{"oAuth" => ["write:lists"]}], responses: %{ 200 => Operation.response("List", "application/json", List), @@ -68,7 +68,7 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do description: "Change the title of a list", operationId: "ListController.update", parameters: [id_param()], - requestBody: update_request(), + requestBody: create_update_request(), security: [%{"oAuth" => ["write:lists"]}], responses: %{ 200 => Operation.response("List", "application/json", List), @@ -164,18 +164,14 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do ) end - defp create_request do + defp create_update_request do request_body( "Parameters", %Schema{ - description: "POST body for creating a List", + description: "POST body for creating or updating a List", type: :object, properties: %{ - title: %Schema{type: :string, description: "List title"}, - exclusive: %Schema{ - type: :boolean, - description: "Whether members of the list should be removed from the “Home” feed" - } + title: %Schema{type: :string, description: "List title"} }, required: [:title] }, @@ -183,24 +179,6 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do ) end - defp update_request do - request_body( - "Parameters", - %Schema{ - description: "PUT body for updating a List", - type: :object, - properties: %{ - title: %Schema{type: :string, description: "List title"}, - exclusive: %Schema{ - type: :boolean, - description: "Whether members of the list should be removed from the “Home” feed" - } - } - }, - required: true - ) - end - defp add_remove_accounts_request(required) when is_boolean(required) do request_body( "Parameters", diff --git a/lib/pleroma/web/api_spec/operations/remote_interaction_operation.ex b/lib/pleroma/web/api_spec/operations/remote_interaction_operation.ex deleted file mode 100644 index 54edbcf32..000000000 --- a/lib/pleroma/web/api_spec/operations/remote_interaction_operation.ex +++ /dev/null @@ -1,99 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ApiSpec.RemoteInteractionOperation do - alias OpenApiSpex.Operation - alias OpenApiSpex.Schema - - import Pleroma.Web.ApiSpec.Helpers - - def open_api_operation(action) do - operation = String.to_existing_atom("#{action}_operation") - apply(__MODULE__, operation, []) - end - - def remote_interaction_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Remote interaction", - operationId: "RemoteInteractionController.remote_interaction", - requestBody: request_body("Parameters", remote_interaction_request(), required: true), - responses: %{ - 200 => - Operation.response("Remote interaction URL", "application/json", %Schema{type: :object}) - } - } - end - - defp remote_interaction_request do - %Schema{ - title: "RemoteInteractionRequest", - description: "POST body for remote interaction", - type: :object, - required: [:ap_id, :profile], - properties: %{ - ap_id: %Schema{type: :string, description: "Profile or status ActivityPub ID"}, - profile: %Schema{type: :string, description: "Remote profile webfinger"} - } - } - end - - def follow_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Display follow form", - operationId: "RemoteInteractionController.follow", - parameters: [], - responses: %{ - 200 => Operation.response("Web Page", "text/html", %Schema{type: :string}), - 302 => Operation.response("Redirect to the status page", nil, nil) - } - } - end - - def do_follow_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Perform follow activity", - operationId: "RemoteInteractionController.do_follow", - parameters: [], - responses: %{ - 200 => Operation.response("Web page", "text/html", %Schema{type: :string}), - 302 => Operation.response("Redirect to the account page", nil, nil) - } - } - end - - def authorize_interaction_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Authorize remote interaction", - operationId: "RemoteInteractionController.authorize_interaction", - parameters: [], - responses: %{ - 302 => Operation.response("Redirect to remote_interaction path", nil, nil) - } - } - end - - def show_subscribe_form_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Show remote subscribe form", - operationId: "RemoteInteractionController.show_subscribe_form", - parameters: [], - responses: %{200 => Operation.response("Web Page", "text/html", %Schema{type: :string})} - } - end - - def remote_subscribe_operation do - %Operation{ - tags: ["Remote interaction"], - summary: "Remote Subscribe", - operationId: "RemoteInteractionController.remote_subscribe", - parameters: [], - responses: %{200 => Operation.response("Web Page", "text/html", %Schema{type: :string})} - } - end -end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex similarity index 84% rename from lib/pleroma/web/api_spec/operations/pleroma_util_operation.ex rename to lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 4bb4f112c..724d873c0 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do +defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do alias OpenApiSpex.Operation alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.Schemas.ApiError @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do %Operation{ tags: ["Custom emojis"], summary: "List all custom emojis", - operationId: "PleromaAPI.UtilController.emoji", + operationId: "UtilController.emoji", parameters: [], responses: %{ 200 => @@ -48,7 +48,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do %Operation{ tags: ["Others"], summary: "Dump frontend configurations", - operationId: "PleromaAPI.UtilController.frontend_configurations", + operationId: "UtilController.frontend_configurations", parameters: [], responses: %{ 200 => @@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Change account password", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.change_password", + operationId: "UtilController.change_password", requestBody: request_body("Parameters", change_password_request(), required: true), responses: %{ 200 => @@ -106,7 +106,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Change account email", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.change_email", + operationId: "UtilController.change_email", requestBody: request_body("Parameters", change_email_request(), required: true), responses: %{ 200 => @@ -141,7 +141,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Settings"], summary: "Update Notification Settings", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.update_notification_settings", + operationId: "UtilController.update_notification_settings", parameters: [ Operation.parameter( :block_from_strangers, @@ -173,7 +173,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Disable Account", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.disable_account", + operationId: "UtilController.disable_account", parameters: [ Operation.parameter(:password, :query, :string, "Password") ], @@ -193,7 +193,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Delete Account", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.delete_account", + operationId: "UtilController.delete_account", parameters: [ Operation.parameter(:password, :query, :string, "Password") ], @@ -212,7 +212,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do def captcha_operation do %Operation{ summary: "Get a captcha", - operationId: "PleromaAPI.UtilController.captcha", + operationId: "UtilController.captcha", tags: ["Others"], parameters: [], responses: %{ @@ -226,7 +226,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Move account", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.move_account", + operationId: "UtilController.move_account", requestBody: request_body("Parameters", move_account_request(), required: true), responses: %{ 200 => @@ -262,7 +262,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "List account aliases", security: [%{"oAuth" => ["read:accounts"]}], - operationId: "PleromaAPI.UtilController.list_aliases", + operationId: "UtilController.list_aliases", responses: %{ 200 => Operation.response("Success", "application/json", %Schema{ @@ -286,7 +286,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Add an alias to this account", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.add_alias", + operationId: "UtilController.add_alias", requestBody: request_body("Parameters", add_alias_request(), required: true), responses: %{ 200 => @@ -326,7 +326,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Account credentials"], summary: "Delete an alias from this account", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.delete_alias", + operationId: "UtilController.delete_alias", requestBody: request_body("Parameters", delete_alias_request(), required: true), responses: %{ 200 => @@ -366,7 +366,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do tags: ["Others"], summary: "Quick status check on the instance", security: [%{"oAuth" => ["write:accounts"]}], - operationId: "PleromaAPI.UtilController.healthcheck", + operationId: "UtilController.healthcheck", parameters: [], responses: %{ 200 => Operation.response("Healthy", "application/json", %Schema{type: :object}), @@ -376,6 +376,52 @@ defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do } end + def remote_subscribe_operation do + %Operation{ + tags: ["Remote interaction"], + summary: "Remote Subscribe", + operationId: "UtilController.remote_subscribe", + parameters: [], + responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})} + } + end + + def remote_interaction_operation do + %Operation{ + tags: ["Remote interaction"], + summary: "Remote interaction", + operationId: "UtilController.remote_interaction", + requestBody: request_body("Parameters", remote_interaction_request(), required: true), + responses: %{ + 200 => + Operation.response("Remote interaction URL", "application/json", %Schema{type: :object}) + } + } + end + + defp remote_interaction_request do + %Schema{ + title: "RemoteInteractionRequest", + description: "POST body for remote interaction", + type: :object, + required: [:ap_id, :profile], + properties: %{ + ap_id: %Schema{type: :string, description: "Profile or status ActivityPub ID"}, + profile: %Schema{type: :string, description: "Remote profile webfinger"} + } + } + end + + def show_subscribe_form_operation do + %Operation{ + tags: ["Remote interaction"], + summary: "Show remote subscribe form", + operationId: "UtilController.show_subscribe_form", + parameters: [], + responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})} + } + end + defp delete_account_request do %Schema{ title: "AccountDeleteRequest", diff --git a/lib/pleroma/web/api_spec/render_error.ex b/lib/pleroma/web/api_spec/render_error.ex index 2ba76f250..3539af6e4 100644 --- a/lib/pleroma/web/api_spec/render_error.ex +++ b/lib/pleroma/web/api_spec/render_error.ex @@ -17,11 +17,11 @@ defmodule Pleroma.Web.ApiSpec.RenderError do def call(conn, errors) do errors = Enum.map(errors, fn - %OpenApiSpex.Cast.Error{name: nil, reason: :invalid_enum} = err -> - %{err | name: err.value} + %{name: nil, reason: :invalid_enum} = err -> + %OpenApiSpex.Cast.Error{err | name: err.value} - %OpenApiSpex.Cast.Error{name: nil} = err -> - %{err | name: List.last(err.path)} + %{name: nil} = err -> + %OpenApiSpex.Cast.Error{err | name: List.last(err.path)} err -> err diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index efdced316..7d0b83afe 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -21,7 +21,6 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do acct: %Schema{type: :string}, avatar_static: %Schema{type: :string, format: :uri}, avatar: %Schema{type: :string, format: :uri}, - avatar_description: %Schema{type: :string}, bot: %Schema{type: :boolean}, created_at: %Schema{type: :string, format: "date-time"}, display_name: %Schema{type: :string}, @@ -32,7 +31,6 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do following_count: %Schema{type: :integer}, header_static: %Schema{type: :string, format: :uri}, header: %Schema{type: :string, format: :uri}, - header_description: %Schema{type: :string}, id: FlakeID, locked: %Schema{type: :boolean}, note: %Schema{type: :string, format: :html}, @@ -113,8 +111,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do nullable: true, description: "Favicon image of the user's instance" }, - avatar_description: %Schema{type: :string, deprecated: true}, - header_description: %Schema{type: :string, deprecated: true} + avatar_description: %Schema{type: :string}, + header_description: %Schema{type: :string} } }, source: %Schema{ diff --git a/lib/pleroma/web/api_spec/schemas/account_relationship.ex b/lib/pleroma/web/api_spec/schemas/account_relationship.ex index 247a94bb9..68219a099 100644 --- a/lib/pleroma/web/api_spec/schemas/account_relationship.ex +++ b/lib/pleroma/web/api_spec/schemas/account_relationship.ex @@ -26,9 +26,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountRelationship do requested: %Schema{type: :boolean}, showing_reblogs: %Schema{type: :boolean}, subscribing: %Schema{type: :boolean}, - notifying: %Schema{type: :boolean}, - mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true}, - block_expires_at: %Schema{type: :string, format: "date-time", nullable: true} + notifying: %Schema{type: :boolean} }, example: %{ "blocked_by" => false, diff --git a/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex b/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex index f5ce9e8a1..e8b4f43b7 100644 --- a/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex +++ b/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex @@ -15,18 +15,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.BookmarkFolder do properties: %{ id: FlakeID, name: %Schema{type: :string, description: "Folder name"}, - emoji: %Schema{type: :string, description: "Folder emoji", nullable: true}, - emoji_url: %Schema{ - type: :string, - description: "URL of the folder emoji if it's a custom emoji, null otherwise", - nullable: true - } + emoji: %Schema{type: :string, description: "Folder emoji", nullable: true} }, example: %{ "id" => "9toJCu5YZW7O7gfvH6", "name" => "Read later", - "emoji" => nil, - "emoji_url" => nil + "emoji" => nil } }) end diff --git a/lib/pleroma/web/api_spec/schemas/list.ex b/lib/pleroma/web/api_spec/schemas/list.ex index 5df674894..e57de7917 100644 --- a/lib/pleroma/web/api_spec/schemas/list.ex +++ b/lib/pleroma/web/api_spec/schemas/list.ex @@ -13,11 +13,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.List do type: :object, properties: %{ id: %Schema{type: :string, description: "The internal database ID of the list"}, - title: %Schema{type: :string, description: "The user-defined title of the list"}, - exclusive: %Schema{ - type: :boolean, - description: "Whether members of the list should be removed from the “Home” feed" - } + title: %Schema{type: :string, description: "The user-defined title of the list"} }, example: %{ "id" => "12249", diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index cb9d521b3..8e96ef5b6 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -222,8 +222,8 @@ defmodule Pleroma.Web.CommonAPI do with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id), object = %Object{} <- Object.normalize(activity, fetch: false), {_, nil} <- {:existing_announce, Utils.get_existing_announce(user.ap_id, object)}, - visibility = announce_visibility(object, params), - {:ok, announce, _} <- Builder.announce(user, object, visibility: visibility), + public = public_announce?(object, params), + {:ok, announce, _} <- Builder.announce(user, object, public: public), {:ok, activity, _} <- Pipeline.common_pipeline(announce, local: true) do {:ok, activity} else @@ -407,11 +407,13 @@ defmodule Pleroma.Web.CommonAPI do end end - def announce_visibility(_, %{visibility: visibility}) - when visibility in ~w{public unlisted private direct local}, - do: visibility + defp public_announce?(_, %{visibility: visibility}) + when visibility in ~w{public unlisted private direct}, + do: visibility in ~w(public unlisted) - def announce_visibility(object, _), do: Visibility.get_visibility(object) + defp public_announce?(object, _) do + Visibility.public?(object) + end @spec get_visibility(map(), map() | nil, Participation.t() | nil) :: {String.t() | nil, String.t() | nil} @@ -707,22 +709,6 @@ defmodule Pleroma.Web.CommonAPI do end end - def assign_report_to_account(activity_ids, user) when is_list(activity_ids) do - case Utils.assign_report_to_account(activity_ids, user) do - :ok -> {:ok, activity_ids} - _ -> {:error, dgettext("errors", "Could not assign account")} - end - end - - def assign_report_to_account(activity_id, user) do - with %Activity{} = activity <- Activity.get_by_id(activity_id) do - Utils.assign_report_to_account(activity, user) - else - nil -> {:error, :not_found} - _ -> {:error, dgettext("errors", "Could not assign account")} - end - end - @spec update_activity_scope(String.t(), map()) :: {:ok, any()} | {:error, any()} def update_activity_scope(activity_id, opts \\ %{}) do with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 6072fff6b..c0b98508c 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -88,7 +88,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do |> validate() end - defp listen_object(%__MODULE__{} = draft) do + defp listen_object(draft) do object = draft.params |> Map.take([:album, :artist, :title, :length]) @@ -99,34 +99,34 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do |> Map.put("cc", draft.cc) |> Map.put("actor", draft.user.ap_id) - %{draft | object: object} + %__MODULE__{draft | object: object} end - defp put_params(%__MODULE__{} = draft, params) do + defp put_params(draft, params) do params = Map.put_new(params, :in_reply_to_status_id, params[:in_reply_to_id]) - %{draft | params: params} + %__MODULE__{draft | params: params} end - defp status(%__MODULE__{params: %{status: status}} = draft) do - %{draft | status: String.trim(status)} + defp status(%{params: %{status: status}} = draft) do + %__MODULE__{draft | status: String.trim(status)} end - defp summary(%__MODULE__{params: params} = draft) do - %{draft | summary: Map.get(params, :spoiler_text, "")} + defp summary(%{params: params} = draft) do + %__MODULE__{draft | summary: Map.get(params, :spoiler_text, "")} end - defp full_payload(%__MODULE__{status: status, summary: summary} = draft) do + defp full_payload(%{status: status, summary: summary} = draft) do full_payload = String.trim(status <> summary) case Utils.validate_character_limit(full_payload, draft.attachments) do - :ok -> %{draft | full_payload: full_payload} + :ok -> %__MODULE__{draft | full_payload: full_payload} {:error, message} -> add_error(draft, message) end end - defp attachments(%__MODULE__{params: params} = draft) do + defp attachments(%{params: params} = draft) do attachments = Utils.attachments_from_ids(params, draft.user) - draft = %{draft | attachments: attachments} + draft = %__MODULE__{draft | attachments: attachments} case Utils.validate_attachments_count(attachments) do :ok -> draft @@ -134,10 +134,9 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do end end - defp in_reply_to(%__MODULE__{params: %{in_reply_to_status_id: ""}} = draft), do: draft + defp in_reply_to(%{params: %{in_reply_to_status_id: ""}} = draft), do: draft - defp in_reply_to(%__MODULE__{params: %{in_reply_to_status_id: id}} = draft) - when is_binary(id) do + defp in_reply_to(%{params: %{in_reply_to_status_id: id}} = draft) when is_binary(id) do # If a post was deleted all its activities (except the newly added Delete) are purged too, # thus lookup by Create db ID will yield nil just as if it never existed in the first place. # @@ -149,7 +148,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, draft.user), {_, type} when type in ["Create", "Announce"] <- {:type, activity.data["type"]} do - %{draft | in_reply_to: activity} + %__MODULE__{draft | in_reply_to: activity} else nil -> add_error(draft, dgettext("errors", "Cannot reply to a deleted status")) @@ -167,43 +166,40 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do end end - defp in_reply_to( - %__MODULE__{params: %{in_reply_to_status_id: %Activity{} = in_reply_to}} = draft - ) do - %{draft | in_reply_to: in_reply_to} + defp in_reply_to(%{params: %{in_reply_to_status_id: %Activity{} = in_reply_to}} = draft) do + %__MODULE__{draft | in_reply_to: in_reply_to} end defp in_reply_to(draft), do: draft - defp quote_post(%__MODULE__{params: %{quoted_status_id: id}} = draft) - when not_empty_string(id) do + defp quote_post(%{params: %{quoted_status_id: id}} = draft) when not_empty_string(id) do case Activity.get_by_id_with_object(id) do %Activity{} = activity -> - %{draft | quote_post: activity} + %__MODULE__{draft | quote_post: activity} _ -> draft end end - defp quote_post(%__MODULE__{params: %{quote_id: id}} = draft) when not_empty_string(id) do + defp quote_post(%{params: %{quote_id: id}} = draft) when not_empty_string(id) do quote_post(%{draft | params: Map.put(draft.params, :quoted_status_id, id)}) end defp quote_post(draft), do: draft - defp in_reply_to_conversation(%__MODULE__{} = draft) do + defp in_reply_to_conversation(draft) do in_reply_to_conversation = Participation.get(draft.params[:in_reply_to_conversation_id]) - %{draft | in_reply_to_conversation: in_reply_to_conversation} + %__MODULE__{draft | in_reply_to_conversation: in_reply_to_conversation} end - defp visibility(%__MODULE__{params: params} = draft) do + defp visibility(%{params: params} = draft) do case CommonAPI.get_visibility(params, draft.in_reply_to, draft.in_reply_to_conversation) do {visibility, "direct"} when visibility != "direct" -> add_error(draft, dgettext("errors", "The message visibility must be direct")) {visibility, _} -> - %{draft | visibility: visibility} + %__MODULE__{draft | visibility: visibility} end end @@ -219,7 +215,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do false end - defp quoting_visibility(%__MODULE__{quote_post: %Activity{}} = draft) do + defp quoting_visibility(%{quote_post: %Activity{}} = draft) do with %Object{} = object <- Object.normalize(draft.quote_post, fetch: false), true <- can_quote?(draft, object, Visibility.get_visibility(object)) do draft @@ -230,24 +226,24 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do defp quoting_visibility(draft), do: draft - defp expires_at(%__MODULE__{} = draft) do + defp expires_at(draft) do case CommonAPI.check_expiry_date(draft.params[:expires_in]) do - {:ok, expires_at} -> %{draft | expires_at: expires_at} + {:ok, expires_at} -> %__MODULE__{draft | expires_at: expires_at} {:error, message} -> add_error(draft, message) end end - defp poll(%__MODULE__{} = draft) do + defp poll(draft) do case Utils.make_poll_data(draft.params) do {:ok, {poll, poll_emoji}} -> - %{draft | extra: poll, emoji: Map.merge(draft.emoji, poll_emoji)} + %__MODULE__{draft | extra: poll, emoji: Map.merge(draft.emoji, poll_emoji)} {:error, message} -> add_error(draft, message) end end - defp content(%__MODULE__{mentions: mentions} = draft) do + defp content(%{mentions: mentions} = draft) do {content_html, mentioned_users, tags} = Utils.make_content_html(draft) mentioned_ap_ids = @@ -258,25 +254,25 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do |> Kernel.++(mentioned_ap_ids) |> Utils.get_addressed_users(draft.params[:to]) - %{draft | content_html: content_html, mentions: mentions, tags: tags} + %__MODULE__{draft | content_html: content_html, mentions: mentions, tags: tags} end - defp to_and_cc(%__MODULE__{} = draft) do + defp to_and_cc(draft) do {to, cc} = Utils.get_to_and_cc(draft) - %{draft | to: to, cc: cc} + %__MODULE__{draft | to: to, cc: cc} end - defp context(%__MODULE__{} = draft) do + defp context(draft) do context = Utils.make_context(draft.in_reply_to, draft.in_reply_to_conversation) - %{draft | context: context} + %__MODULE__{draft | context: context} end - defp sensitive(%__MODULE__{} = draft) do + defp sensitive(draft) do sensitive = draft.params[:sensitive] - %{draft | sensitive: sensitive} + %__MODULE__{draft | sensitive: sensitive} end - defp language(%__MODULE__{} = draft) do + defp language(draft) do language = with language <- draft.params[:language], true <- good_locale_code?(language) do @@ -285,10 +281,10 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do _ -> LanguageDetector.detect(draft.content_html <> " " <> draft.summary) end - %{draft | language: language} + %__MODULE__{draft | language: language} end - defp object(%__MODULE__{} = draft) do + defp object(draft) do emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji) # Sometimes people create posts with subject containing emoji, @@ -317,7 +313,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do emoji = Map.merge(emoji, summary_emoji) - media_type = Utils.get_content_type(draft.params[:content_type]) {:ok, note_data, _meta} = Builder.note(draft) object = @@ -325,24 +320,20 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do |> Map.put("emoji", emoji) |> Map.put("source", %{ "content" => draft.status, - "mediaType" => media_type + "mediaType" => Utils.get_content_type(draft.params[:content_type]) }) - |> maybe_put("htmlMfm", true, media_type == "text/x.misskeymarkdown") |> Map.put("generator", draft.params[:generator]) |> Map.put("language", draft.language) - %{draft | object: object} + %__MODULE__{draft | object: object} end - defp maybe_put(map, key, value, true), do: Map.put(map, key, value) - defp maybe_put(map, _key, _value, _condition), do: map - - defp preview?(%__MODULE__{} = draft) do + defp preview?(draft) do preview? = Pleroma.Web.Utils.Params.truthy_param?(draft.params[:preview]) - %{draft | preview?: preview?} + %__MODULE__{draft | preview?: preview?} end - defp changes(%__MODULE__{} = draft) do + defp changes(draft) do direct? = draft.visibility == "direct" additional = %{"cc" => draft.cc, "directMessage" => direct?} @@ -362,14 +353,14 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do } |> Utils.maybe_add_list_data(draft.user, draft.visibility) - %{draft | changes: changes} + %__MODULE__{draft | changes: changes} end defp with_valid(%{valid?: true} = draft, func), do: func.(draft) defp with_valid(draft, _func), do: draft - defp add_error(%__MODULE__{} = draft, message) do - %{draft | valid?: false, errors: [message | draft.errors]} + defp add_error(draft, message) do + %__MODULE__{draft | valid?: false, errors: [message | draft.errors]} end defp validate(%{valid?: true} = draft), do: {:ok, draft} diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 26034d685..91bf9c502 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -75,70 +75,48 @@ defmodule Pleroma.Web.CommonAPI.Utils do {Enum.map(participation.recipients, & &1.ap_id), []} end - def get_to_and_cc(%{visibility: visibility} = draft) do - # If the OP is a DM already, add the implicit actor - mentions = - if visibility == "direct" && draft.in_reply_to && Visibility.direct?(draft.in_reply_to) do - Enum.uniq([draft.in_reply_to.data["actor"] | draft.mentions]) - else - draft.mentions + def get_to_and_cc(%{visibility: visibility} = draft) when visibility in ["public", "local"] do + to = + case visibility do + "public" -> [Pleroma.Constants.as_public() | draft.mentions] + "local" -> [Utils.as_local_public() | draft.mentions] end - get_to_and_cc_for_visibility( - visibility, - draft.user.follower_address, - draft.in_reply_to && draft.in_reply_to.data["actor"], - mentions - ) + cc = [draft.user.follower_address] + + if draft.in_reply_to do + {Enum.uniq([draft.in_reply_to.data["actor"] | to]), cc} + else + {to, cc} + end end - def get_to_and_cc_for_visibility("public", follower_collection, parent_actor, mentions) do - scope_addr = Pleroma.Constants.as_public() + def get_to_and_cc(%{visibility: "unlisted"} = draft) do + to = [draft.user.follower_address | draft.mentions] + cc = [Pleroma.Constants.as_public()] - to = - if parent_actor, - do: Enum.uniq([parent_actor, scope_addr | mentions]), - else: [scope_addr | mentions] - - {to, [follower_collection]} + if draft.in_reply_to do + {Enum.uniq([draft.in_reply_to.data["actor"] | to]), cc} + else + {to, cc} + end end - def get_to_and_cc_for_visibility("local", follower_collection, parent_actor, mentions) do - recipients = - if parent_actor, - do: Enum.uniq([parent_actor | mentions]), - else: mentions - - to = [ - Utils.as_local_public() - | Enum.filter(recipients, fn addr -> - String.starts_with?(addr, Pleroma.Web.Endpoint.url() <> "/") - end) - ] - - {to, [follower_collection]} + def get_to_and_cc(%{visibility: "private"} = draft) do + {to, cc} = get_to_and_cc(struct(draft, visibility: "direct")) + {[draft.user.follower_address | to], cc} end - def get_to_and_cc_for_visibility("unlisted", follower_collection, parent_actor, mentions) do - to = - if parent_actor, - do: Enum.uniq([parent_actor, follower_collection | mentions]), - else: [follower_collection | mentions] - - {to, [Pleroma.Constants.as_public()]} + def get_to_and_cc(%{visibility: "direct"} = draft) do + # If the OP is a DM already, add the implicit actor. + if draft.in_reply_to && Visibility.direct?(draft.in_reply_to) do + {Enum.uniq([draft.in_reply_to.data["actor"] | draft.mentions]), []} + else + {draft.mentions, []} + end end - def get_to_and_cc_for_visibility("private", follower_collection, _, mentions) do - {[follower_collection | mentions], []} - end - - def get_to_and_cc_for_visibility("direct", _, _, mentions) do - {mentions, []} - end - - def get_to_and_cc_for_visibility({:list, _}, _, _, mentions) do - {mentions, []} - end + def get_to_and_cc(%{visibility: {:list, _}, mentions: mentions}), do: {mentions, []} def get_addressed_users(_, to) when is_list(to) do User.get_ap_ids_by_nicknames(to) @@ -322,14 +300,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do |> Formatter.linkify(options) end - def format_input(text, "text/x.misskeymarkdown", options) do - text - |> Formatter.markdown_to_html(%{breaks: true}) - |> safe_mfm_to_html() - |> Formatter.linkify(options) - |> Formatter.html_escape("text/x.misskeymarkdown") - end - def format_input(text, "text/markdown", options) do text |> Formatter.mentions_escape(options) @@ -338,16 +308,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do |> Formatter.html_escape("text/html") end - defp safe_mfm_to_html(html) do - html - |> MfmParser.Parser.parse() - |> MfmParser.Encoder.to_html() - rescue - _ -> html - catch - _, _ -> html - end - def format_naive_asctime(date) do date |> DateTime.from_naive!("Etc/UTC") |> format_asctime end diff --git a/lib/pleroma/web/embed_controller.ex b/lib/pleroma/web/embed_controller.ex index 8420f17a5..2ca4501a6 100644 --- a/lib/pleroma/web/embed_controller.ex +++ b/lib/pleroma/web/embed_controller.ex @@ -20,7 +20,6 @@ defmodule Pleroma.Web.EmbedController do conn |> delete_resp_header("x-frame-options") |> delete_resp_header("content-security-policy") - |> put_layout({Pleroma.Web.LayoutView, :embed}) |> render("show.html", activity: activity, author: User.sanitize_html(author), diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index a5c04a0c4..bab3c9fd0 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -46,10 +46,8 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Web.Plugs.HTTPSecurityPlug) plug(Pleroma.Web.Plugs.UploadedMedia) - @static_cache_control "public, max-age=1209600, immutable" + @static_cache_control "public, max-age=1209600" @static_cache_disabled "public, no-cache" - # cache for a day - @favicon_cache_control "public, max=age=86400, immutable" # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well @@ -66,15 +64,6 @@ defmodule Pleroma.Web.Endpoint do } ) - plug(Pleroma.Web.Plugs.FaviconPlug, - at: "/", - only: ["favicon.png"], - cache_control_for_etags: @favicon_cache_control, - headers: %{ - "cache-control" => @favicon_cache_control - } - ) - plug(Pleroma.Web.Plugs.InstanceStatic, at: "/", gzip: true, diff --git a/lib/pleroma/web/fallback/redirect_controller.ex b/lib/pleroma/web/fallback/redirect_controller.ex index c7f80ad77..d75a95fb3 100644 --- a/lib/pleroma/web/fallback/redirect_controller.ex +++ b/lib/pleroma/web/fallback/redirect_controller.ex @@ -29,18 +29,9 @@ defmodule Pleroma.Web.Fallback.RedirectController do ) end - def live_dashboard(conn, %{"path" => path}) do - query_params = conn.query_string - - redirect_path = - if query_params == "" do - "/pleroma/live_dashboard/#{path}" - else - "/pleroma/live_dashboard/#{path}?#{query_params}" - end - + def live_dashboard(conn, _params) do conn - |> redirect(to: redirect_path) + |> redirect(to: "/pleroma/live_dashboard") end def redirector(conn, _params, code \\ 200) do diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index 90cd2e54a..676fc5137 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Workers.PublisherWorker alias Pleroma.Workers.ReceiverWorker - alias Pleroma.Workers.SignatureRetryWorker require Logger @@ -36,21 +35,12 @@ defmodule Pleroma.Web.Federator do end # Client API - def incoming_failed_signature_ap_doc(%{ - method: method, - params: params, - req_headers: req_headers, - request_path: request_path, - query_string: query_string - }) do - SignatureRetryWorker.new( + def incoming_ap_doc(%{params: params, req_headers: req_headers}) do + ReceiverWorker.new( %{ - "op" => "incoming_failed_signature_ap_doc", - "method" => method, + "op" => "incoming_ap_doc", "req_headers" => req_headers, "params" => params, - "request_path" => request_path, - "query_string" => query_string, "timeout" => :timer.seconds(20) }, priority: 2 diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 6d5851029..6dc731ed4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do alias Pleroma.Web.OAuth.OAuthController alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.RateLimiter - alias Pleroma.Web.Registration + alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.Utils.Params plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false) @@ -111,8 +111,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do _params ) do with :ok <- validate_email_param(params), - :ok <- Registration.validate_captcha(app, params), - {:ok, user} <- Registration.register_user(params), + :ok <- TwitterAPI.validate_captcha(app, params), + {:ok, user} <- TwitterAPI.register_user(params), {_, {:ok, token}} <- {:login, OAuthController.login(user, app, app.scopes)} do OAuthController.after_token_exchange(conn, %{user: user, token: token}) diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index 653b5fc29..fbb54a171 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do import Pleroma.Web.ControllerHelper, only: [json_response: 3] - alias Pleroma.Web.Registration + alias Pleroma.Web.TwitterAPI.TwitterAPI action_fallback(Pleroma.Web.MastodonAPI.FallbackController) @@ -17,7 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do def password_reset(conn, params) do nickname_or_email = params["email"] || params["nickname"] - Registration.password_reset(nickname_or_email) + TwitterAPI.password_reset(nickname_or_email) json_response(conn, :no_content, "") end diff --git a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex index 048012ae6..3bfc365a5 100644 --- a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex @@ -28,27 +28,27 @@ defmodule Pleroma.Web.MastodonAPI.ListController do # POST /api/v1/lists def create( - %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: params}}} = + %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: %{title: title}}}} = conn, _ ) do - with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(params, user) do + with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do render(conn, "show.json", list: list) end end - # GET /api/v1/lists/:id + # GET /api/v1/lists/:idOB def show(%{assigns: %{list: list}} = conn, _) do render(conn, "show.json", list: list) end # PUT /api/v1/lists/:id def update( - %{assigns: %{list: list}, private: %{open_api_spex: %{body_params: params}}} = + %{assigns: %{list: list}, private: %{open_api_spex: %{body_params: %{title: title}}}} = conn, _ ) do - with {:ok, list} <- Pleroma.List.update(list, params) do + with {:ok, list} <- Pleroma.List.rename(list, title) do render(conn, "show.json", list: list) end end diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 26e38aac8..db2b61b3c 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -81,8 +81,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action in [:pin, :unpin]) + # Note: scope not present in Mastodon: read:bookmarks plug(OAuthScopesPlug, %{scopes: ["read:bookmarks"]} when action == :bookmarks) + # Note: scope not present in Mastodon: write:bookmarks plug( OAuthScopesPlug, %{scopes: ["write:bookmarks"]} when action in [:bookmark, :unbookmark] diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 99a5b6957..5ee74a80e 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -45,10 +45,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> User.followed_hashtags() |> Enum.map(& &1.id) - excluded_list_members = - user - |> Pleroma.List.get_exclusive_list_members() - params = params |> Map.put(:type, ["Create", "Announce"]) @@ -62,7 +58,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.delete(:local) activities = - [user.ap_id | User.following(user) -- excluded_list_members] + [user.ap_id | User.following(user)] |> ActivityPub.fetch_activities(params) |> Enum.reverse() diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 5386c5a6c..e215b073e 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -96,24 +96,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do followed_by = FollowingRelationship.following?(target, reading_user) following = FollowingRelationship.following?(reading_user, target) - blocking = - UserRelationship.exists?( - user_relationships, - :block, - reading_user, - target, - &User.blocks_user?(&1, &2) - ) - - muting = - UserRelationship.exists?( - user_relationships, - :mute, - reading_user, - target, - &User.mutes?(&1, &2) - ) - requested = cond do following -> false @@ -134,7 +116,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do id: to_string(target.id), following: following, followed_by: followed_by, - blocking: blocking, + blocking: + UserRelationship.exists?( + user_relationships, + :block, + reading_user, + target, + &User.blocks_user?(&1, &2) + ), + block_expires_at: maybe_put_block_expires_at(user_relationships, target, reading_user), blocked_by: UserRelationship.exists?( user_relationships, @@ -143,8 +133,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do reading_user, &User.blocks_user?(&1, &2) ), - block_expires_at: nil, - muting: muting, + muting: + UserRelationship.exists?( + user_relationships, + :mute, + reading_user, + target, + &User.mutes?(&1, &2) + ), + mute_expires_at: maybe_put_mute_expires_at(user_relationships, target, reading_user), muting_notifications: UserRelationship.exists?( user_relationships, @@ -153,7 +150,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do target, &User.muted_notifications?(&1, &2) ), - mute_expires_at: nil, subscribing: subscribing, notifying: subscribing, requested: requested, @@ -180,8 +176,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do &User.endorses?(&1, &2) ) } - |> maybe_put_mute_expires_at(target, reading_user, %{mutes: muting}) - |> maybe_put_block_expires_at(target, reading_user, %{blocks: blocking}) end def render("relationships.json", %{user: user, targets: targets} = opts) do @@ -300,10 +294,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do note: user.bio, url: user.uri || user.ap_id, avatar: avatar, - avatar_description: avatar_description, avatar_static: avatar_static, header: header, - header_description: header_description, header_static: header_static, emojis: emojis, fields: user.fields, @@ -353,8 +345,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do |> maybe_put_unread_conversation_count(user, opts[:for]) |> maybe_put_unread_notification_count(user, opts[:for]) |> maybe_put_email_address(user, opts[:for]) - |> maybe_put_mute_expires_at(user, opts[:for], opts, relationship) - |> maybe_put_block_expires_at(user, opts[:for], opts, relationship) + |> maybe_put_mute_expires_at(user, opts[:for], relationship) + |> maybe_put_block_expires_at(user, opts[:for], relationship) |> maybe_show_birthday(user, opts[:for]) end @@ -482,47 +474,61 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do defp maybe_put_email_address(data, _, _), do: data - defp maybe_put_mute_expires_at(data, target, user, opts, relationship \\ nil) + defp maybe_put_mute_expires_at(user_relationships, %User{} = target, %User{} = user) do + cond do + UserRelationship.exists?(user_relationships, :mute, user, target, &User.mutes_user?(&1, &2)) -> + UserRelationship.get_mute_expire_date(user, target) - defp maybe_put_mute_expires_at(data, _target, _user, %{mutes: true}, %{ - mute_expires_at: mute_expires_at - }) do - Map.put(data, :mute_expires_at, mute_expires_at) + true -> + nil + end end - defp maybe_put_mute_expires_at(data, %User{} = target, user, %{mutes: true}, _relationship) do - Map.put( - data, - :mute_expires_at, - UserRelationship.get_mute_expire_date(user, target) - ) + defp maybe_put_mute_expires_at(data, %User{} = target, %User{} = user, relationship) do + cond do + Map.has_key?(relationship, :mute_expires_at) -> + Map.put(data, :mute_expires_at, relationship.mute_expires_at) + + User.mutes_user?(user, target) -> + Map.put(data, :mute_expires_at, UserRelationship.get_mute_expire_date(user, target)) + + true -> + Map.put(data, :mute_expires_at, nil) + end end - defp maybe_put_mute_expires_at(data, _, _, _, _), do: data + defp maybe_put_mute_expires_at(data, _, _, _), do: data - defp maybe_put_block_expires_at(data, target, user, opts, relationship \\ nil) + defp maybe_put_block_expires_at(user_relationships, %User{} = target, %User{} = user) do + cond do + UserRelationship.exists?( + user_relationships, + :block, + user, + target, + &User.blocks_user?(&1, &2) + ) -> + UserRelationship.get_block_expire_date(user, target) - defp maybe_put_block_expires_at(data, _target, _user, %{blocks: true}, %{ - block_expires_at: block_expires_at - }) do - Map.put(data, :block_expires_at, block_expires_at) + true -> + nil + end end - defp maybe_put_block_expires_at( - data, - %User{} = target, - %User{} = user, - %{blocks: true}, - _relationship - ) do - Map.put( - data, - :block_expires_at, - UserRelationship.get_block_expire_date(user, target) - ) + defp maybe_put_block_expires_at(data, %User{} = target, %User{} = user, relationship) do + cond do + Map.has_key?(relationship, :block_expires_at) -> + Map.put(data, :block_expires_at, relationship.block_expires_at) + + User.blocks_user?(user, target) -> + Map.put(data, :block_expires_at, UserRelationship.get_block_expire_date(user, target)) + + true -> + Map.put(data, :block_expires_at, nil) + end end - defp maybe_put_block_expires_at(data, _, _, _, _), do: data + defp maybe_put_block_expires_at(data, _, _, _), do: data defp maybe_show_birthday(data, %User{id: user_id} = user, %User{id: user_id}) do data diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index d64ce4fb5..0dc7a5fea 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -303,15 +303,6 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do defp configuration2 do configuration() |> put_in([:accounts, :max_pinned_statuses], Config.get([:instance, :max_pinned_statuses], 0)) - |> put_in([:accounts, :max_profile_fields], Config.get([:instance, :max_account_fields])) - |> put_in( - [:accounts, :profile_field_name_limit], - Config.get([:instance, :account_field_name_length]) - ) - |> put_in( - [:accounts, :profile_field_value_limit], - Config.get([:instance, :account_field_value_length]) - ) |> put_in([:statuses, :characters_reserved_per_url], 0) |> Map.merge(%{ urls: %{ diff --git a/lib/pleroma/web/mastodon_api/views/list_view.ex b/lib/pleroma/web/mastodon_api/views/list_view.ex index 740f458d4..a7ae7c5f7 100644 --- a/lib/pleroma/web/mastodon_api/views/list_view.ex +++ b/lib/pleroma/web/mastodon_api/views/list_view.ex @@ -13,8 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.ListView do def render("show.json", %{list: list}) do %{ id: to_string(list.id), - title: list.title, - exclusive: list.exclusive + title: list.title } end end diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex index f047804e2..1e3c9f36d 100644 --- a/lib/pleroma/web/mastodon_api/views/poll_view.ex +++ b/lib/pleroma/web/mastodon_api/views/poll_view.ex @@ -71,8 +71,6 @@ defmodule Pleroma.Web.MastodonAPI.PollView do end) end - defp voters_count(%{data: %{"votersCount" => voters}}) when is_integer(voters), do: voters - defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do length(voters) end diff --git a/lib/pleroma/web/pleroma_api/controllers/bookmark_folder_controller.ex b/lib/pleroma/web/pleroma_api/controllers/bookmark_folder_controller.ex index 55f323a16..6d6e2e940 100644 --- a/lib/pleroma/web/pleroma_api/controllers/bookmark_folder_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/bookmark_folder_controller.ex @@ -10,8 +10,10 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderController do plug(Pleroma.Web.ApiSpec.CastAndValidate) + # Note: scope not present in Mastodon: read:bookmarks plug(OAuthScopesPlug, %{scopes: ["read:bookmarks"]} when action == :index) + # Note: scope not present in Mastodon: write:bookmarks plug( OAuthScopesPlug, %{scopes: ["write:bookmarks"]} when action in [:create, :update, :delete] diff --git a/lib/pleroma/web/pleroma_api/controllers/password_controller.ex b/lib/pleroma/web/pleroma_api/controllers/password_controller.ex deleted file mode 100644 index 444477245..000000000 --- a/lib/pleroma/web/pleroma_api/controllers/password_controller.ex +++ /dev/null @@ -1,52 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.PasswordController do - @moduledoc """ - The module contains functions for password reset. - """ - - use Pleroma.Web, :controller - - require Logger - - import Pleroma.Web.ControllerHelper, only: [json_response: 3] - - alias Pleroma.PasswordResetToken - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.Registration - - plug(Pleroma.Web.Plugs.RateLimiter, [name: :request] when action == :request) - - @doc "POST /auth/password" - def request(conn, params) do - nickname_or_email = params["email"] || params["nickname"] - - Registration.password_reset(nickname_or_email) - - json_response(conn, :no_content, "") - end - - def reset(conn, %{"token" => token}) do - with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), - false <- PasswordResetToken.expired?(token), - %User{} = user <- User.get_cached_by_id(token.user_id) do - render(conn, "reset.html", %{ - token: token, - user: user - }) - else - _e -> render(conn, "invalid_token.html") - end - end - - def do_reset(conn, %{"data" => data}) do - with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do - render(conn, "reset_success.html") - else - _e -> render(conn, "reset_failed.html") - end - end -end diff --git a/lib/pleroma/web/pleroma_api/controllers/token_controller.ex b/lib/pleroma/web/pleroma_api/controllers/token_controller.ex deleted file mode 100644 index 10eeb907e..000000000 --- a/lib/pleroma/web/pleroma_api/controllers/token_controller.ex +++ /dev/null @@ -1,59 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.TokenController do - use Pleroma.Web, :controller - - alias Pleroma.User - alias Pleroma.Web.OAuth.Token - alias Pleroma.Web.PleromaAPI.TokenView - alias Pleroma.Web.Plugs.OAuthScopesPlug - - require Logger - - plug(:skip_auth when action == :confirm_email) - plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token]) - - action_fallback(:errors) - - def confirm_email(conn, %{"user_id" => uid, "token" => token}) do - with %User{} = user <- User.get_cached_by_id(uid), - true <- user.local and !user.is_confirmed and user.confirmation_token == token, - {:ok, _} <- User.confirm(user) do - redirect(conn, to: "/") - end - end - - def oauth_tokens(%{assigns: %{user: user}} = conn, _params) do - with oauth_tokens <- Token.get_user_tokens(user) do - conn - |> put_view(TokenView) - |> render("index.json", %{tokens: oauth_tokens}) - end - end - - def revoke_token(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do - Token.delete_user_token(user, id) - - json_reply(conn, 201, "") - end - - defp errors(conn, {:param_cast, _}) do - conn - |> put_status(400) - |> json("Invalid parameters") - end - - defp errors(conn, _) do - conn - |> put_status(500) - |> json("Something went wrong") - end - - defp json_reply(conn, status, json) do - conn - |> put_resp_content_type("application/json") - |> send_resp(status, json) - end -end diff --git a/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex b/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex index ddffa25d3..29028781f 100644 --- a/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex +++ b/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex @@ -9,13 +9,11 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do alias Pleroma.Emoji def render("show.json", %{folder: %BookmarkFolder{} = folder}) do - {emoji, emoji_url} = get_emoji(folder.emoji) - %{ id: folder.id |> to_string(), name: folder.name, - emoji: emoji, - emoji_url: emoji_url + emoji: folder.emoji, + emoji_url: get_emoji_url(folder.emoji) } end @@ -23,15 +21,20 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do render_many(folders, __MODULE__, "show.json", Map.delete(opts, :folders)) end - defp get_emoji(nil), do: {nil, nil} + defp get_emoji_url(nil) do + nil + end - defp get_emoji(emoji) do + defp get_emoji_url(emoji) do if Emoji.unicode?(emoji) do - {emoji, nil} + nil else - case Emoji.get(emoji) do - nil -> {nil, nil} - emoji_data -> {emoji, Emoji.local_url(emoji_data.file)} + emoji = Emoji.get(emoji) + + if emoji != nil do + Emoji.local_url(emoji.file) + else + nil end end end diff --git a/lib/pleroma/web/pleroma_api/views/util_view.ex b/lib/pleroma/web/pleroma_api/views/util_view.ex deleted file mode 100644 index b5e07c006..000000000 --- a/lib/pleroma/web/pleroma_api/views/util_view.ex +++ /dev/null @@ -1,13 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.UtilView do - use Pleroma.Web, :view - alias Pleroma.Config - - def render("frontend_configurations.json", _) do - Config.get(:frontend_configurations, %{}) - |> Enum.into(%{}) - end -end diff --git a/lib/pleroma/web/plugs/favicon_plug.ex b/lib/pleroma/web/plugs/favicon_plug.ex deleted file mode 100644 index e2e1f1adb..000000000 --- a/lib/pleroma/web/plugs/favicon_plug.ex +++ /dev/null @@ -1,71 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2026 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Plugs.FaviconPlug do - @behaviour Plug - - @moduledoc """ - This is a shim to call `Plug.Static` but with runtime `from` configuration for instance favicon. - - Serves default or custom favicon.png with cacheable cache-control. - """ - - import Plug.Conn, only: [put_resp_header: 3, send_resp: 3, halt: 1] - - require Logger - - def init(opts) do - opts - |> Keyword.put(:from, "__unconfigured_favicon_static_plug") - |> Plug.Static.init() - end - - def call(%{request_path: "/favicon.png"} = conn, opts) do - case find_favicon_dir() do - {:ok, dir} -> - call_static(conn, opts, dir) - - :error -> - # Favicon should always be available and this should never occur. - # If it does, halt the pipeline before having unintended side-effects. - Logger.error("No favicon.png found! Is the default favicon deleted?") - - conn - |> send_resp(404, "Not found") - |> halt() - end - end - - def call(conn, _) do - conn - end - - defp find_favicon_dir do - instance_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static") - instance_path = Path.join(instance_dir, "favicon.png") - - priv_dir = Application.app_dir(:pleroma, "priv/static") - priv_path = Path.join(priv_dir, "favicon.png") - - cond do - File.exists?(instance_path) -> {:ok, instance_dir} - File.exists?(priv_path) -> {:ok, priv_dir} - true -> :error - end - end - - defp call_static(conn, opts, from) do - opts = - opts - |> Map.put(:from, from) - |> Map.put(:content_types, false) - - conn = set_content_type(conn) - Plug.Static.call(conn, opts) - end - - defp set_content_type(conn) do - put_resp_header(conn, "content-type", "image/png") - end -end diff --git a/lib/pleroma/web/plugs/instance_static.ex b/lib/pleroma/web/plugs/instance_static.ex index 948188287..d2a674d39 100644 --- a/lib/pleroma/web/plugs/instance_static.ex +++ b/lib/pleroma/web/plugs/instance_static.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Web.Plugs.InstanceStatic do require Pleroma.Constants - import Plug.Conn, only: [put_resp_header: 3, put_status: 2, send_resp: 3, halt: 1] + import Plug.Conn, only: [put_resp_header: 3] @moduledoc """ This is a shim to call `Plug.Static` but with runtime `from` configuration. @@ -51,37 +51,10 @@ defmodule Pleroma.Web.Plugs.InstanceStatic do |> Map.put(:from, from) |> Map.put(:content_types, false) - conn = - conn - |> set_content_type(conn.request_path) - |> Plug.Static.call(opts) + conn = set_content_type(conn, conn.request_path) - if conn.halted do - conn - else - path = String.trim_leading(conn.request_path, "/") - - if not File.exists?(file_path(path)) do - conn - |> put_status(:not_found) - |> send_404() - |> halt() - else - conn - end - end - end - - defp send_404(conn) do - if String.ends_with?(String.downcase(conn.request_path), ".json") do - conn - |> put_resp_header("content-type", "application/json") - |> send_resp(404, Jason.encode!(%{error: "not found"})) - else - conn - |> put_resp_header("content-type", "text/plain") - |> send_resp(404, "Not found") - end + # Call Plug.Static with our sanitized content-type + Plug.Static.call(conn, opts) end defp set_content_type(conn, "/emoji/" <> filepath) do diff --git a/lib/pleroma/web/plugs/mapped_signature_to_identity_plug.ex b/lib/pleroma/web/plugs/mapped_signature_to_identity_plug.ex index a688b1780..c6d531086 100644 --- a/lib/pleroma/web/plugs/mapped_signature_to_identity_plug.ex +++ b/lib/pleroma/web/plugs/mapped_signature_to_identity_plug.ex @@ -32,8 +32,8 @@ defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do # remove me once testsuite uses mapped capabilities instead of what we do now {:user, nil} -> Logger.debug("Failed to map identity from signature (lookup failure)") - Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{inspect(actor)}") - assign(conn, :valid_signature, false) + Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}") + conn end end diff --git a/lib/pleroma/web/plugs/rate_limiter.ex b/lib/pleroma/web/plugs/rate_limiter.ex index 0ebb73bbc..aa79dbf6b 100644 --- a/lib/pleroma/web/plugs/rate_limiter.ex +++ b/lib/pleroma/web/plugs/rate_limiter.ex @@ -67,8 +67,6 @@ defmodule Pleroma.Web.Plugs.RateLimiter do import Plug.Conn alias Pleroma.Config - alias Pleroma.Config.Holder - alias Pleroma.EctoType.Config.RateLimit alias Pleroma.User alias Pleroma.Web.Plugs.RateLimiter.LimiterSupervisor @@ -145,7 +143,7 @@ defmodule Pleroma.Web.Plugs.RateLimiter do def action_settings(plug_opts) do with limiter_name when is_atom(limiter_name) <- plug_opts[:name], - {:ok, limits} <- fetch_and_normalize_limits(limiter_name) do + limits when not is_nil(limits) <- Config.get([:rate_limit, limiter_name]) do bucket_name_root = Keyword.get(plug_opts, :bucket_name, limiter_name) %{ @@ -153,72 +151,6 @@ defmodule Pleroma.Web.Plugs.RateLimiter do limits: limits, opts: plug_opts } - else - :disabled -> nil - end - end - - defp fetch_and_normalize_limits(limiter_name) do - limits = Config.get([:rate_limit, limiter_name]) - - case normalize_limits(limits) do - {:ok, limits} -> - {:ok, limits} - - :disabled -> - :disabled - - :error -> - default_limits = - Holder.default_config(:pleroma, :rate_limit) - |> get_default_limits(limiter_name) - - case normalize_limits(default_limits) do - {:ok, normalized_limits} -> - warn_invalid_limits_once(limiter_name, limits) - {:ok, normalized_limits} - - _ -> - warn_invalid_limits_once(limiter_name, limits) - :disabled - end - end - end - - defp get_default_limits(%{} = rate_limit, limiter_name), do: Map.get(rate_limit, limiter_name) - - defp get_default_limits(rate_limit, limiter_name) when is_list(rate_limit) do - if Keyword.keyword?(rate_limit) do - Keyword.get(rate_limit, limiter_name) - else - nil - end - end - - defp get_default_limits(_, _), do: nil - - @invalid_limits_warned_key {__MODULE__, :invalid_limits_warned} - - defp warn_invalid_limits_once(limiter_name, limits) do - warned = :persistent_term.get(@invalid_limits_warned_key, MapSet.new()) - - if MapSet.member?(warned, limiter_name) do - :ok - else - :persistent_term.put(@invalid_limits_warned_key, MapSet.put(warned, limiter_name)) - - Logger.warning( - "Invalid rate limiter config for #{inspect(limiter_name)}: #{inspect(limits)}. Falling back to defaults or disabling this limiter." - ) - end - end - - defp normalize_limits(nil), do: :disabled - - defp normalize_limits(limits) do - case RateLimit.cast(limits) do - {:ok, normalized_limits} -> {:ok, normalized_limits} - :error -> :error end end diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex index 5a3ea12aa..abacf965b 100644 --- a/lib/pleroma/web/plugs/uploaded_media.ex +++ b/lib/pleroma/web/plugs/uploaded_media.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do # no slashes @path "media" - @default_cache_control_header "public, max-age=1209600, immutable" + @default_cache_control_header "public, max-age=1209600" def init(_opts) do static_plug_opts = diff --git a/lib/pleroma/web/preload/providers/instance.ex b/lib/pleroma/web/preload/providers/instance.ex index f2a60393f..6183f7b70 100644 --- a/lib/pleroma/web/preload/providers/instance.ex +++ b/lib/pleroma/web/preload/providers/instance.ex @@ -5,9 +5,9 @@ defmodule Pleroma.Web.Preload.Providers.Instance do alias Pleroma.Web.MastodonAPI.InstanceView alias Pleroma.Web.Nodeinfo.Nodeinfo - alias Pleroma.Web.PleromaAPI.UtilView alias Pleroma.Web.Plugs.InstanceStatic alias Pleroma.Web.Preload.Providers.Provider + alias Pleroma.Web.TwitterAPI.UtilView @behaviour Provider @instance_url "/api/v1/instance" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c91ca8c97..008f48575 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -226,28 +226,23 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.StaticFEPlug) end - scope "/api/v1/pleroma", Pleroma.Web.OAuth do + scope "/api/v1/pleroma", Pleroma.Web.TwitterAPI do pipe_through(:pleroma_api) get("/password_reset/:token", PasswordController, :reset, as: :reset_password) post("/password_reset", PasswordController, :do_reset, as: :reset_password) + get("/emoji", UtilController, :emoji) + get("/captcha", UtilController, :captcha) + get("/healthcheck", UtilController, :healthcheck) + post("/remote_interaction", UtilController, :remote_interaction) end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through(:pleroma_api) - get("/emoji", UtilController, :emoji) - get("/captcha", UtilController, :captcha) - get("/healthcheck", UtilController, :healthcheck) get("/federation_status", InstancesController, :show) end - scope "/api/v1/pleroma", Pleroma.Web.RemoteInteraction do - pipe_through(:pleroma_api) - - post("/remote_interaction", RemoteInteractionController, :remote_interaction) - end - scope "/api/v1/pleroma", Pleroma.Web do pipe_through(:pleroma_api) post("/uploader_callback/:upload_path", UploaderController, :callback) @@ -400,7 +395,6 @@ defmodule Pleroma.Web.Router do get("/reports", ReportController, :index) get("/reports/:id", ReportController, :show) patch("/reports", ReportController, :update) - post("/reports/assign_account", ReportController, :assign_account) post("/reports/:id/notes", ReportController, :notes_create) delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) end @@ -489,18 +483,18 @@ defmodule Pleroma.Web.Router do end end - scope "/", Pleroma.Web.RemoteInteraction do + scope "/", Pleroma.Web.TwitterAPI do pipe_through(:pleroma_html) - post("/main/ostatus", RemoteInteractionController, :remote_subscribe) - get("/main/ostatus", RemoteInteractionController, :show_subscribe_form) - get("/ostatus_subscribe", RemoteInteractionController, :follow) - post("/ostatus_subscribe", RemoteInteractionController, :do_follow) + post("/main/ostatus", UtilController, :remote_subscribe) + get("/main/ostatus", UtilController, :show_subscribe_form) + get("/ostatus_subscribe", RemoteFollowController, :follow) + post("/ostatus_subscribe", RemoteFollowController, :do_follow) - get("/authorize_interaction", RemoteInteractionController, :authorize_interaction) + get("/authorize_interaction", RemoteFollowController, :authorize_interaction) end - scope "/api/pleroma", Pleroma.Web.PleromaAPI do + scope "/api/pleroma", Pleroma.Web.TwitterAPI do pipe_through(:authenticated_api) post("/change_email", UtilController, :change_email) @@ -858,7 +852,7 @@ defmodule Pleroma.Web.Router do scope "/api", Pleroma.Web do pipe_through(:config) - get("/pleroma/frontend_configurations", PleromaAPI.UtilController, :frontend_configurations) + get("/pleroma/frontend_configurations", TwitterAPI.UtilController, :frontend_configurations) end scope "/api", Pleroma.Web do @@ -866,7 +860,7 @@ defmodule Pleroma.Web.Router do get( "/account/confirm_email/:user_id/:token", - OAuth.TokenController, + TwitterAPI.Controller, :confirm_email, as: :confirm_email ) @@ -878,11 +872,11 @@ defmodule Pleroma.Web.Router do get("/openapi", OpenApiSpex.Plug.RenderSpec, []) end - scope "/api", Pleroma.Web, as: :authenticated_pleroma_api do + scope "/api", Pleroma.Web, as: :authenticated_twitter_api do pipe_through(:authenticated_api) - get("/oauth_tokens", OAuth.TokenController, :oauth_tokens) - delete("/oauth_tokens/:id", OAuth.TokenController, :revoke_token) + get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens) + delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token) end scope "/", Pleroma.Web do @@ -1031,9 +1025,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do pipe_through(:pleroma_html) - post("/auth/password", OAuth.PasswordController, :request) - - get("/embed/:id", EmbedController, :show) + post("/auth/password", TwitterAPI.PasswordController, :request) end scope "/proxy/", Pleroma.Web do @@ -1095,7 +1087,7 @@ defmodule Pleroma.Web.Router do get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) match(:*, "/api/pleroma/*path", LegacyPleromaApiRerouterPlug, []) get("/api/*path", RedirectController, :api_not_implemented) - get("/phoenix/live_dashboard/*path", RedirectController, :live_dashboard) + get("/phoenix/live_dashboard", RedirectController, :live_dashboard) get("/*path", RedirectController, :redirector_with_preload) options("/*path", RedirectController, :empty) diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index e33bada85..99ab0ddad 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -13,8 +13,10 @@

<%= Pleroma.Config.get([:instance, :name]) %>

-
- <%= @inner_content %> +
+
+ <%= @inner_content %> +
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex index 310bf2358..fb34b551d 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex @@ -5,10 +5,19 @@ <% # Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> <%= if scope in @scopes do %>
- <%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> - <%= label @form, :"scope_#{scope}", String.capitalize(scope) %> + + <%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> + <%= label @form, :"scope_#{scope}", "" %> + <%= if scope in @scopes && scope do %> - <%= scope %> <%= :"Elixir.Gettext".dgettext(Gettext, "oauth_scopes", scope) %> +
+
+ <%= :"Elixir.Gettext".dgettext(Gettext, "oauth_scopes", scope) %> +
+
+ <%= scope %> +
+
<% end %>
<% else %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 6bc8eb602..aadddf1f4 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -8,17 +8,20 @@ <%= form_for @conn, Routes.o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %> <%= if @user do %> - diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index 85bfd7b3a..a14ca305e 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -2,7 +2,7 @@

<%= link instance_name(), to: "/" %>

-
+ diff --git a/lib/pleroma/web/templates/o_auth/password/invalid_token.html.eex b/lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex similarity index 100% rename from lib/pleroma/web/templates/o_auth/password/invalid_token.html.eex rename to lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex diff --git a/lib/pleroma/web/templates/o_auth/password/reset.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex similarity index 100% rename from lib/pleroma/web/templates/o_auth/password/reset.html.eex rename to lib/pleroma/web/templates/twitter_api/password/reset.html.eex diff --git a/lib/pleroma/web/templates/o_auth/password/reset_failed.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex similarity index 100% rename from lib/pleroma/web/templates/o_auth/password/reset_failed.html.eex rename to lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex diff --git a/lib/pleroma/web/templates/o_auth/password/reset_success.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex similarity index 100% rename from lib/pleroma/web/templates/o_auth/password/reset_success.html.eex rename to lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex similarity index 83% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/follow.html.eex rename to lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex index 00cc7d383..e2d251fac 100644 --- a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex @@ -4,7 +4,7 @@

<%= Gettext.dpgettext("static_pages", "remote follow header", "Remote follow") %>

<%= @followee.nickname %>

- <%= form_for @conn, Routes.remote_interaction_path(@conn, :do_follow), [as: "user"], fn f -> %> + <%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %> <%= hidden_input f, :id, value: @followee.id %> <%= submit Gettext.dpgettext("static_pages", "remote follow authorization button", "Authorize") %> <% end %> diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex similarity index 88% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_login.html.eex rename to lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex index e5fe720e8..26340a906 100644 --- a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_login.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex @@ -4,7 +4,7 @@

<%= Gettext.dpgettext("static_pages", "remote follow header, need login", "Log in to follow") %>

<%= @followee.nickname %>

-<%= form_for @conn, Routes.remote_interaction_path(@conn, :do_follow), [as: "authorization"], fn f -> %> +<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %> <%= text_input f, :name, placeholder: Gettext.dpgettext("static_pages", "placeholder text for username entry", "Username"), required: true, autocomplete: "username" %>
<%= password_input f, :password, placeholder: Gettext.dpgettext("static_pages", "placeholder text for password entry", "Password"), required: true, autocomplete: "password" %> diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_mfa.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex similarity index 86% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_mfa.html.eex rename to lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex index e5f26f104..638212c1e 100644 --- a/lib/pleroma/web/templates/remote_interaction/remote_interaction/follow_mfa.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex @@ -4,7 +4,7 @@

<%= Gettext.dpgettext("static_pages", "remote follow mfa header", "Two-factor authentication") %>

<%= @followee.nickname %>

-<%= form_for @conn, Routes.remote_interaction_path(@conn, :do_follow), [as: "mfa"], fn f -> %> +<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "mfa"], fn f -> %> <%= text_input f, :code, placeholder: Gettext.dpgettext("static_pages", "placeholder text for auth code entry", "Authentication code"), required: true %>
<%= hidden_input f, :id, value: @followee.id %> diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/followed.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex similarity index 100% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/followed.html.eex rename to lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex similarity index 88% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/status_interact.html.eex rename to lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex index b3d590186..d77174967 100644 --- a/lib/pleroma/web/templates/remote_interaction/remote_interaction/status_interact.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -2,7 +2,7 @@

<%= Gettext.dpgettext("static_pages", "status interact error", "Error: %{error}", error: @error) %>

<% else %>

<%= raw Gettext.dpgettext("static_pages", "status interact header", "Interacting with %{nickname}'s %{status_link}", nickname: safe_to_string(html_escape(@nickname)), status_link: safe_to_string(link(Gettext.dpgettext("static_pages", "status interact header - status link text", "status"), to: @status_link))) %>

- <%= form_for @conn, Routes.remote_interaction_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> + <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> <%= hidden_input f, :status_id, value: @status_id %> <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %> <%= submit Gettext.dpgettext("static_pages", "status interact authorization button", "Interact") %> diff --git a/lib/pleroma/web/templates/remote_interaction/remote_interaction/subscribe.html.eex b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex similarity index 85% rename from lib/pleroma/web/templates/remote_interaction/remote_interaction/subscribe.html.eex rename to lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex index 7e1dd723c..848660f26 100644 --- a/lib/pleroma/web/templates/remote_interaction/remote_interaction/subscribe.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex @@ -2,7 +2,7 @@

<%= Gettext.dpgettext("static_pages", "remote follow error", "Error: %{error}", error: @error) %>

<% else %>

<%= Gettext.dpgettext("static_pages", "remote follow header", "Remotely follow %{nickname}", nickname: @nickname) %>

- <%= form_for @conn, Routes.remote_interaction_path(@conn, :remote_subscribe), [as: "user"], fn f -> %> + <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "user"], fn f -> %> <%= hidden_input f, :nickname, value: @nickname %> <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %> <%= submit Gettext.dpgettext("static_pages", "remote follow authorization button for following with a remote account", "Follow") %> diff --git a/lib/pleroma/web/o_auth/token_controller.ex b/lib/pleroma/web/twitter_api/controller.ex similarity index 94% rename from lib/pleroma/web/o_auth/token_controller.ex rename to lib/pleroma/web/twitter_api/controller.ex index d2313a9cc..6db3d6067 100644 --- a/lib/pleroma/web/o_auth/token_controller.ex +++ b/lib/pleroma/web/twitter_api/controller.ex @@ -2,13 +2,13 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.TokenController do +defmodule Pleroma.Web.TwitterAPI.Controller do use Pleroma.Web, :controller alias Pleroma.User alias Pleroma.Web.OAuth.Token - alias Pleroma.Web.OAuth.TokenView alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.TwitterAPI.TokenView require Logger diff --git a/lib/pleroma/web/o_auth/password_controller.ex b/lib/pleroma/web/twitter_api/controllers/password_controller.ex similarity index 90% rename from lib/pleroma/web/o_auth/password_controller.ex rename to lib/pleroma/web/twitter_api/controllers/password_controller.ex index b209e7564..e5482de9d 100644 --- a/lib/pleroma/web/o_auth/password_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/password_controller.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.PasswordController do +defmodule Pleroma.Web.TwitterAPI.PasswordController do @moduledoc """ The module contains functions for password reset. """ @@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.PasswordController do alias Pleroma.PasswordResetToken alias Pleroma.Repo alias Pleroma.User - alias Pleroma.Web.Registration + alias Pleroma.Web.TwitterAPI.TwitterAPI plug(Pleroma.Web.Plugs.RateLimiter, [name: :request] when action == :request) @@ -24,7 +24,7 @@ defmodule Pleroma.Web.OAuth.PasswordController do def request(conn, params) do nickname_or_email = params["email"] || params["nickname"] - Registration.password_reset(nickname_or_email) + TwitterAPI.password_reset(nickname_or_email) json_response(conn, :no_content, "") end diff --git a/lib/pleroma/web/remote_interaction/remote_interaction_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex similarity index 57% rename from lib/pleroma/web/remote_interaction/remote_interaction_controller.ex rename to lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index 90f15cdb6..38ebc8c5d 100644 --- a/lib/pleroma/web/remote_interaction/remote_interaction_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionController do +defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do use Pleroma.Web, :controller require Logger @@ -14,27 +14,18 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionController do alias Pleroma.Web.Auth.TOTPAuthenticator alias Pleroma.Web.Auth.WrapperAuthenticator alias Pleroma.Web.CommonAPI - alias Pleroma.Web.WebFinger @status_types ["Article", "Event", "Note", "Video", "Page", "Question"] - plug( - Pleroma.Web.ApiSpec.CastAndValidate, - [replace_params: false] - when action == :remote_interaction - ) - plug(Pleroma.Web.Plugs.FederatingPlug) # Note: follower can submit the form (with password auth) not being signed in (having no token) plug( Pleroma.Web.Plugs.OAuthScopesPlug, %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]} - when action == :do_follow + when action in [:do_follow] ) - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.RemoteInteractionOperation - # GET /ostatus_subscribe # def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do @@ -134,7 +125,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionController do # def authorize_interaction(conn, %{"uri" => uri}) do conn - |> redirect(to: Routes.remote_interaction_path(conn, :follow, %{acct: uri})) + |> redirect(to: Routes.remote_follow_path(conn, :follow, %{acct: uri})) end defp handle_follow_error(conn, {:mfa_token, followee, _} = _) do @@ -171,122 +162,4 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionController do Logger.debug("Remote follow failed with error #{inspect(error)}") render(conn, "followed.html", %{error: "Something went wrong."}) end - - def show_subscribe_form(conn, %{"nickname" => nick}) do - with %User{} = user <- User.get_cached_by_nickname(nick), - avatar = User.avatar_url(user) do - conn - |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false}) - else - _e -> - render(conn, "subscribe.html", %{ - nickname: nick, - avatar: nil, - error: - Pleroma.Web.Gettext.dpgettext( - "static_pages", - "remote follow error message - user not found", - "Could not find user" - ) - }) - end - end - - def show_subscribe_form(conn, %{"status_id" => id}) do - with %Activity{} = activity <- Activity.get_by_id(id), - {:ok, ap_id} <- get_ap_id(activity), - %User{} = user <- User.get_cached_by_ap_id(activity.actor), - avatar = User.avatar_url(user) do - conn - |> render("status_interact.html", %{ - status_link: ap_id, - status_id: id, - nickname: user.nickname, - avatar: avatar, - error: false - }) - else - _e -> - render(conn, "status_interact.html", %{ - status_id: id, - avatar: nil, - error: - Pleroma.Web.Gettext.dpgettext( - "static_pages", - "status interact error message - status not found", - "Could not find status" - ) - }) - end - end - - def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do - show_subscribe_form(conn, %{"nickname" => nick}) - end - - def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do - show_subscribe_form(conn, %{"status_id" => id}) - end - - def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do - with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), - %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do - conn - |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) - else - _e -> - render(conn, "subscribe.html", %{ - nickname: nick, - avatar: nil, - error: - Pleroma.Web.Gettext.dpgettext( - "static_pages", - "remote follow error message - unknown error", - "Something went wrong." - ) - }) - end - end - - def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do - with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), - %Activity{} = activity <- Activity.get_by_id(id), - {:ok, ap_id} <- get_ap_id(activity) do - conn - |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) - else - _e -> - render(conn, "status_interact.html", %{ - status_id: id, - avatar: nil, - error: - Pleroma.Web.Gettext.dpgettext( - "static_pages", - "status interact error message - unknown error", - "Something went wrong." - ) - }) - end - end - - def remote_interaction( - %{private: %{open_api_spex: %{body_params: %{ap_id: ap_id, profile: profile}}}} = conn, - _params - ) do - with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile) do - conn - |> json(%{url: String.replace(template, "{uri}", ap_id)}) - else - _e -> json(conn, %{error: "Couldn't find user"}) - end - end - - defp get_ap_id(activity) do - object = Pleroma.Object.normalize(activity, fetch: false) - - case object do - %{data: %{"id" => ap_id}} -> {:ok, ap_id} - _ -> {:no_ap_id, nil} - end - end end diff --git a/lib/pleroma/web/pleroma_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex similarity index 65% rename from lib/pleroma/web/pleroma_api/controllers/util_controller.ex rename to lib/pleroma/web/twitter_api/controllers/util_controller.ex index 882e9476e..1c072f98a 100644 --- a/lib/pleroma/web/pleroma_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -2,11 +2,12 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PleromaAPI.UtilController do +defmodule Pleroma.Web.TwitterAPI.UtilController do use Pleroma.Web, :controller require Logger + alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Emoji alias Pleroma.Healthcheck @@ -16,8 +17,19 @@ defmodule Pleroma.Web.PleromaAPI.UtilController do alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator alias Pleroma.Web.CommonAPI alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.WebFinger - plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false) + plug( + Pleroma.Web.ApiSpec.CastAndValidate, + [replace_params: false] + when action != :remote_subscribe and action != :show_subscribe_form + ) + + plug( + Pleroma.Web.Plugs.FederatingPlug + when action == :remote_subscribe + when action == :show_subscribe_form + ) plug( OAuthScopesPlug, @@ -42,7 +54,125 @@ defmodule Pleroma.Web.PleromaAPI.UtilController do ] ) - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaUtilOperation + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation + + def show_subscribe_form(conn, %{"nickname" => nick}) do + with %User{} = user <- User.get_cached_by_nickname(nick), + avatar = User.avatar_url(user) do + conn + |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false}) + else + _e -> + render(conn, "subscribe.html", %{ + nickname: nick, + avatar: nil, + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "remote follow error message - user not found", + "Could not find user" + ) + }) + end + end + + def show_subscribe_form(conn, %{"status_id" => id}) do + with %Activity{} = activity <- Activity.get_by_id(id), + {:ok, ap_id} <- get_ap_id(activity), + %User{} = user <- User.get_cached_by_ap_id(activity.actor), + avatar = User.avatar_url(user) do + conn + |> render("status_interact.html", %{ + status_link: ap_id, + status_id: id, + nickname: user.nickname, + avatar: avatar, + error: false + }) + else + _e -> + render(conn, "status_interact.html", %{ + status_id: id, + avatar: nil, + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "status interact error message - status not found", + "Could not find status" + ) + }) + end + end + + def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do + show_subscribe_form(conn, %{"nickname" => nick}) + end + + def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do + show_subscribe_form(conn, %{"status_id" => id}) + end + + def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do + with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), + %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do + conn + |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) + else + _e -> + render(conn, "subscribe.html", %{ + nickname: nick, + avatar: nil, + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "remote follow error message - unknown error", + "Something went wrong." + ) + }) + end + end + + def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do + with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), + %Activity{} = activity <- Activity.get_by_id(id), + {:ok, ap_id} <- get_ap_id(activity) do + conn + |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) + else + _e -> + render(conn, "status_interact.html", %{ + status_id: id, + avatar: nil, + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "status interact error message - unknown error", + "Something went wrong." + ) + }) + end + end + + def remote_interaction( + %{private: %{open_api_spex: %{body_params: %{ap_id: ap_id, profile: profile}}}} = conn, + _params + ) do + with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile) do + conn + |> json(%{url: String.replace(template, "{uri}", ap_id)}) + else + _e -> json(conn, %{error: "Couldn't find user"}) + end + end + + defp get_ap_id(activity) do + object = Pleroma.Object.normalize(activity, fetch: false) + + case object do + %{data: %{"id" => ap_id}} -> {:ok, ap_id} + _ -> {:no_ap_id, nil} + end + end def frontend_configurations(conn, _params) do render(conn, "frontend_configurations.json") diff --git a/lib/pleroma/web/registration.ex b/lib/pleroma/web/twitter_api/twitter_api.ex similarity index 98% rename from lib/pleroma/web/registration.ex rename to lib/pleroma/web/twitter_api/twitter_api.ex index df71300ce..ef2eb75f4 100644 --- a/lib/pleroma/web/registration.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.Registration do +defmodule Pleroma.Web.TwitterAPI.TwitterAPI do import Pleroma.Web.Gettext alias Pleroma.Emails.Mailer diff --git a/lib/pleroma/web/o_auth/password_view.ex b/lib/pleroma/web/twitter_api/views/password_view.ex similarity index 83% rename from lib/pleroma/web/o_auth/password_view.ex rename to lib/pleroma/web/twitter_api/views/password_view.ex index 0b85c76e8..55790941f 100644 --- a/lib/pleroma/web/o_auth/password_view.ex +++ b/lib/pleroma/web/twitter_api/views/password_view.ex @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.PasswordView do +defmodule Pleroma.Web.TwitterAPI.PasswordView do use Pleroma.Web, :view import Phoenix.HTML.Form alias Pleroma.Web.Gettext diff --git a/lib/pleroma/web/remote_interaction/remote_interaction_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex similarity index 75% rename from lib/pleroma/web/remote_interaction/remote_interaction_view.ex rename to lib/pleroma/web/twitter_api/views/remote_follow_view.ex index 6e7f40749..8902261b0 100644 --- a/lib/pleroma/web/remote_interaction/remote_interaction_view.ex +++ b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex @@ -2,11 +2,9 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionView do +defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do use Pleroma.Web, :view - import Phoenix.HTML import Phoenix.HTML.Form - import Phoenix.HTML.Link alias Pleroma.Web.Gettext def avatar_url(user) do diff --git a/lib/pleroma/web/o_auth/token_view.ex b/lib/pleroma/web/twitter_api/views/token_view.ex similarity index 81% rename from lib/pleroma/web/o_auth/token_view.ex rename to lib/pleroma/web/twitter_api/views/token_view.ex index f9894399a..36776ce3b 100644 --- a/lib/pleroma/web/o_auth/token_view.ex +++ b/lib/pleroma/web/twitter_api/views/token_view.ex @@ -2,12 +2,12 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.TokenView do +defmodule Pleroma.Web.TwitterAPI.TokenView do use Pleroma.Web, :view def render("index.json", %{tokens: tokens}) do tokens - |> render_many(Pleroma.Web.OAuth.TokenView, "show.json") + |> render_many(Pleroma.Web.TwitterAPI.TokenView, "show.json") |> Enum.filter(&Enum.any?/1) end diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex new file mode 100644 index 000000000..31b7c0c0c --- /dev/null +++ b/lib/pleroma/web/twitter_api/views/util_view.ex @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.UtilView do + use Pleroma.Web, :view + import Phoenix.HTML + import Phoenix.HTML.Form + import Phoenix.HTML.Link + alias Pleroma.Config + alias Pleroma.Web.Endpoint + alias Pleroma.Web.Gettext + + def status_net_config(instance) do + """ + + + #{Keyword.get(instance, :name)} + #{Endpoint.url()} + #{Keyword.get(instance, :limit)} + #{!Keyword.get(instance, :registrations_open)} + + + """ + end + + def render("frontend_configurations.json", _) do + Config.get(:frontend_configurations, %{}) + |> Enum.into(%{}) + end +end diff --git a/lib/pleroma/workers/cron/digest_emails_worker.ex b/lib/pleroma/workers/cron/digest_emails_worker.ex index 5cb13f5f9..b50b52a7b 100644 --- a/lib/pleroma/workers/cron/digest_emails_worker.ex +++ b/lib/pleroma/workers/cron/digest_emails_worker.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Workers.Cron.DigestEmailsWorker do The worker to send digest emails. """ - use Oban.Worker, queue: :background + use Oban.Worker, queue: "mailer" alias Pleroma.Config alias Pleroma.Emails diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index 3afbe138d..e2c950967 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -4,37 +4,40 @@ defmodule Pleroma.Workers.ReceiverWorker do alias Pleroma.Instances + alias Pleroma.Signature + alias Pleroma.User alias Pleroma.Web.Federator - alias Pleroma.Workers.SignatureRetryWorker use Oban.Worker, queue: :federator_incoming, max_attempts: 5, unique: [period: :infinity] @impl true - def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params} = args} = job) do - if signature_retry_job?(args) do - perform_signature_retry(job) - else - perform_incoming(params) - end - end - def perform(%Job{args: %{"op" => "incoming_ap_doc"} = args} = job) do - if signature_retry_job?(args) do - perform_signature_retry(job) - else - process_errors(:missing_incoming_ap_doc_params) - end - end + def perform(%Job{ + args: %{ + "op" => "incoming_ap_doc", + "method" => method, + "params" => params, + "req_headers" => req_headers, + "request_path" => request_path, + "query_string" => query_string + } + }) do + # Oban's serialization converts our tuple headers to lists. + # Revert it for the signature validation. + req_headers = Enum.into(req_headers, [], &List.to_tuple(&1)) - defp perform_signature_retry(%Job{args: args} = job) do - SignatureRetryWorker.perform(%Job{ - job - | args: Map.put(args, "op", "incoming_failed_signature_ap_doc") - }) - end + conn_data = %Plug.Conn{ + method: method, + params: params, + req_headers: req_headers, + request_path: request_path, + query_string: query_string + } - defp perform_incoming(params) do - with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do + with {:ok, %User{}} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]), + {:ok, _public_key} <- Signature.refetch_public_key(conn_data), + {:signature, true} <- {:signature, Signature.validate_signature(conn_data)}, + {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do unless Instances.reachable?(params["actor"]) do domain = URI.parse(params["actor"]).host Oban.insert(Pleroma.Workers.ReachabilityWorker.new(%{"domain" => domain})) @@ -46,8 +49,17 @@ defmodule Pleroma.Workers.ReceiverWorker do end end - defp signature_retry_job?(args) do - Enum.any?(~w(method req_headers request_path query_string), &Map.has_key?(args, &1)) + def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do + with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do + unless Instances.reachable?(params["actor"]) do + domain = URI.parse(params["actor"]).host + Oban.insert(Pleroma.Workers.ReachabilityWorker.new(%{"domain" => domain})) + end + + {:ok, res} + else + e -> process_errors(e) + end end @impl true @@ -73,12 +85,10 @@ defmodule Pleroma.Workers.ReceiverWorker do {:error, {:reject, _} = reason} -> {:cancel, reason} # HTTP Sigs {:signature, false} -> {:cancel, :invalid_signature} - {:same_actor, false} -> {:cancel, :actor_signature_mismatch} # Origin / URL validation failed somewhere possibly due to spoofing {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed} # Unclear if this can be reached {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason} - :missing_incoming_ap_doc_params -> {:cancel, :missing_incoming_ap_doc_params} # Catchall {:error, _} = e -> e e -> {:error, e} diff --git a/lib/pleroma/workers/signature_retry_worker.ex b/lib/pleroma/workers/signature_retry_worker.ex deleted file mode 100644 index 2c4c097dd..000000000 --- a/lib/pleroma/workers/signature_retry_worker.ex +++ /dev/null @@ -1,254 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.SignatureRetryWorker do - alias Pleroma.Instances - alias Pleroma.Signature - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.Federator - alias Pleroma.Web.Plugs.MappedSignatureToIdentityPlug - - require Logger - - use Oban.Worker, queue: :federator_incoming, max_attempts: 5, unique: [period: :infinity] - - @impl true - def perform(%Job{ - args: %{ - "op" => "incoming_failed_signature_ap_doc", - "method" => method, - "params" => params, - "req_headers" => req_headers, - "request_path" => request_path, - "query_string" => query_string - } - }) - when is_binary(method) and is_map(params) and is_list(req_headers) and - is_binary(request_path) and is_binary(query_string) do - case normalize_req_headers(req_headers) do - {:ok, req_headers} -> - conn_data = %Plug.Conn{ - assigns: %{valid_signature: true}, - method: method, - params: params, - req_headers: req_headers, - request_path: request_path, - query_string: query_string - } - - signature_actor_result = signature_actor_id(conn_data) - - with actor_id = Utils.get_ap_id(params["actor"]), - {:signature_actor, {:ok, signature_actor_id}} <- - {:signature_actor, signature_actor_result}, - {:same_actor, true} <- {:same_actor, signature_actor_id == actor_id}, - {:ok, %User{}} <- User.get_or_fetch_by_ap_id(actor_id), - {:ok, _public_key} <- Signature.refetch_public_key(conn_data), - {:signature, true} <- {:signature, validate_signature(conn_data)}, - {:same_actor, true} <- {:same_actor, validate_same_actor(conn_data)}, - {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do - unless Instances.reachable?(params["actor"]) do - domain = URI.parse(params["actor"]).host - Oban.insert(Pleroma.Workers.ReachabilityWorker.new(%{"domain" => domain})) - end - - {:ok, res} - else - e -> process_errors(e, retry_log_context(params, request_path, signature_actor_result)) - end - - e -> - process_errors(e, retry_log_context(params, request_path, nil)) - end - end - - def perform(%Job{args: %{"op" => "incoming_failed_signature_ap_doc"} = args}) do - process_errors( - :missing_signature_retry_metadata, - retry_log_context(Map.get(args, "params"), Map.get(args, "request_path"), nil) - ) - end - - def perform(%Job{args: args}) when is_map(args) do - process_errors( - :missing_signature_retry_metadata, - retry_log_context(Map.get(args, "params"), Map.get(args, "request_path"), nil) - ) - end - - def perform(%Job{}), do: process_errors(:missing_signature_retry_metadata) - - @impl true - def timeout(%_{args: %{"timeout" => timeout}}), do: timeout - - def timeout(_job), do: :timer.seconds(5) - - defp normalize_req_headers(req_headers) do - req_headers - |> Enum.reduce_while({:ok, []}, fn - {key, value}, {:ok, acc} when is_binary(key) and is_binary(value) -> - {:cont, {:ok, [{key, value} | acc]}} - - [key, value], {:ok, acc} when is_binary(key) and is_binary(value) -> - {:cont, {:ok, [{key, value} | acc]}} - - _, _ -> - {:halt, {:error, :invalid_signature_retry_metadata}} - end) - |> case do - {:ok, headers} -> {:ok, Enum.reverse(headers)} - error -> error - end - end - - defp validate_same_actor(conn_data) do - case MappedSignatureToIdentityPlug.call(conn_data, []) do - %Plug.Conn{assigns: %{valid_signature: true}} -> - true - - _ -> - false - end - end - - defp validate_signature(conn_data) do - Signature.validate_signature(conn_data) - rescue - _ -> false - catch - _, _ -> false - end - - defp signature_actor_id(conn_data) do - Signature.get_actor_id(conn_data) - rescue - _ -> {:error, :invalid_signature} - catch - _, _ -> {:error, :invalid_signature} - end - - defp process_errors(errors, context \\ %{}) - - defp process_errors({:error, {:error, _} = error}, context), do: process_errors(error, context) - - defp process_errors(errors, context) do - result = - case errors do - # User fetch failures - {:error, :not_found} = reason -> - {:cancel, reason} - - {:error, :forbidden} = reason -> - {:cancel, reason} - - # Inactive user - {:error, {:user_active, false} = reason} -> - {:cancel, reason} - - # Validator will error and return a changeset error - # e.g., duplicate activities or if the object was deleted - {:error, {:validate, {:error, _changeset} = reason}} -> - {:cancel, reason} - - # Duplicate detection during Normalization - {:error, :already_present} -> - {:cancel, :already_present} - - # MRFs will return a reject - {:error, {:reject, _} = reason} -> - {:cancel, reason} - - # HTTP Sigs - {:signature_actor, {:error, _}} -> - {:cancel, :invalid_signature} - - {:signature, false} -> - {:cancel, :invalid_signature} - - {:same_actor, false} -> - {:cancel, :actor_signature_mismatch} - - # Origin / URL validation failed somewhere possibly due to spoofing - {:error, :origin_containment_failed} -> - {:cancel, :origin_containment_failed} - - # Unclear if this can be reached - {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> - {:cancel, reason} - - # Fail closed if the retry cannot reconstruct the original request. - :missing_signature_retry_metadata -> - {:cancel, :missing_signature_retry_metadata} - - {:error, :invalid_signature_retry_metadata} -> - {:cancel, :invalid_signature_retry_metadata} - - # Catchall - {:error, _} = e -> - e - - e -> - {:error, e} - end - - log_signature_retry_rejection(result, context) - result - end - - defp retry_log_context(params, request_path, signature_actor_result) when is_map(params) do - signature_actor = - case signature_actor_result do - {:ok, actor} when is_binary(actor) -> actor - actor when is_binary(actor) -> actor - _ -> nil - end - - %{ - activity_id: params["id"], - payload_actor: Utils.get_ap_id(params["actor"]), - request_path: request_path, - signature_actor: signature_actor, - type: params["type"] - } - end - - defp retry_log_context(_params, request_path, signature_actor_result) do - signature_actor = - case signature_actor_result do - {:ok, actor} when is_binary(actor) -> actor - actor when is_binary(actor) -> actor - _ -> nil - end - - %{ - activity_id: nil, - payload_actor: nil, - request_path: request_path, - signature_actor: signature_actor, - type: nil - } - end - - defp log_signature_retry_rejection({:cancel, reason}, context) - when reason in [ - :actor_signature_mismatch, - :invalid_signature, - :invalid_signature_retry_metadata, - :missing_signature_retry_metadata, - :origin_containment_failed - ] do - Logger.warning( - "Failed-signature inbox retry rejected " <> - "reason=#{inspect(reason)} " <> - "payload_actor=#{inspect(context[:payload_actor])} " <> - "signature_actor=#{inspect(context[:signature_actor])} " <> - "activity_id=#{inspect(context[:activity_id])} " <> - "type=#{inspect(context[:type])} " <> - "request_path=#{inspect(context[:request_path])}" - ) - end - - defp log_signature_retry_rejection(_result, _context), do: :ok -end diff --git a/mix.exs b/mix.exs index 88f98d54e..a4415fddc 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("2.10.2"), + version: version("2.10.0"), elixir: "~> 1.15", elixirc_paths: elixirc_paths(Mix.env()), compilers: Mix.compilers(), @@ -114,7 +114,7 @@ defmodule Pleroma.Mixfile do if Version.match?(System.version(), "<1.15.0-rc.0") do [] else - [{:logger_backends, "~> 1.0.0"}] + [{:logger_backends, "~> 1.0"}] end end @@ -125,64 +125,61 @@ defmodule Pleroma.Mixfile do [ {:phoenix, git: "https://github.com/feld/phoenix", branch: "v1.7.14-websocket-headers", override: true}, - {:phoenix_ecto, "~> 4.6"}, - {:ecto_sql, "~> 3.13"}, + {:phoenix_ecto, "~> 4.4"}, + {:ecto_sql, "~> 3.10"}, {:ecto_enum, "~> 1.4"}, - {:postgrex, ">= 0.21.1"}, + {:postgrex, ">= 0.20.0"}, {:phoenix_html, "~> 3.3"}, - {:phoenix_live_view, "~> 1.1.19"}, - {:phoenix_live_dashboard, "~> 0.8.7"}, + {:phoenix_live_view, "~> 1.1.0"}, + {:phoenix_live_dashboard, "~> 0.8.0"}, {:telemetry_metrics, "~> 0.6"}, - {:telemetry_poller, "~> 1.3"}, - {:tzdata, "~> 1.0.5"}, + {:telemetry_poller, "~> 1.0"}, + {:tzdata, "~> 1.0.3"}, {:plug_cowboy, "~> 2.7"}, - {:oban, "~> 2.19.4"}, + {:oban, "~> 2.19.0"}, {:oban_plugins_lazarus, git: "https://git.pleroma.social/pleroma/elixir-libraries/oban_plugins_lazarus.git", ref: "e49fc355baaf0e435208bf5f534d31e26e897711"}, {:oban_web, "~> 2.11"}, - {:gettext, "~> 0.24"}, - {:bcrypt_elixir, "~> 2.3"}, + {:gettext, "~> 0.20"}, + {:bcrypt_elixir, "~> 2.2"}, {:trailing_format_plug, "~> 0.0.7"}, - {:fast_sanitize, "~> 0.2.3"}, + {:fast_sanitize, "~> 0.2.0"}, {:html_entities, "~> 0.5", override: true}, {:calendar, "~> 1.0"}, - {:cachex, "~> 3.6"}, - {:tesla, "~> 1.15"}, + {:cachex, "~> 3.2"}, + {:tesla, "~> 1.11"}, {:castore, "~> 1.0"}, {:cowlib, "~> 2.15"}, {:gun, "~> 2.2"}, - {:finch, "~> 0.20"}, - {:jason, "~> 1.4"}, - {:mogrify, "~> 0.9.3", override: true}, - {:ex_aws, "~> 2.1.9"}, - {:ex_aws_s3, "~> 2.5"}, - {:sweet_xml, "~> 0.7.5"}, + {:finch, "~> 0.15"}, + {:jason, "~> 1.2"}, + {:mogrify, "~> 0.9.0", override: "true"}, + {:ex_aws, "~> 2.1.6"}, + {:ex_aws_s3, "~> 2.0"}, + {:sweet_xml, "~> 0.7.2"}, {:earmark, "1.4.46"}, {:bbcode_pleroma, "~> 0.2.0"}, - {:mfm_parser, - git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", - ref: "360a30267a847810a63ab48f606ba227b2ca05f0"}, {:cors_plug, "~> 2.0"}, {:web_push_encryption, "~> 0.3.1"}, - {:swoosh, "~> 1.16.12"}, - {:phoenix_swoosh, "~> 1.2"}, - {:gen_smtp, "~> 0.15"}, - {:mua, "~> 0.2.4"}, - {:mail, "~> 0.3.1"}, - {:ex_syslogger, "~> 1.5"}, - {:floki, "~> 0.38"}, - {:timex, "~> 3.7"}, - {:ueberauth, "~> 0.10"}, + {:swoosh, "~> 1.16.9"}, + {:phoenix_swoosh, "~> 1.1"}, + {:gen_smtp, "~> 0.13"}, + {:mua, "~> 0.2.0"}, + {:mail, "~> 0.3.0"}, + {:ex_syslogger, "~> 1.4"}, + {:floki, "~> 0.35"}, + {:timex, "~> 3.6"}, + {:ueberauth, "~> 0.4"}, {:linkify, "~> 0.5.3"}, {:http_signatures, "~> 0.1.2"}, {:telemetry, "~> 1.0.0", override: true}, {:poolboy, "~> 1.5"}, {:prom_ex, "~> 1.9"}, {:recon, "~> 2.5"}, - {:joken, "~> 2.6"}, + {:joken, "~> 2.0"}, {:pot, "~> 1.0"}, - {:ex_const, "~> 0.3"}, + {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, {:flake_id, "~> 0.1.0"}, {:concurrent_limiter, "~> 0.1.1"}, @@ -193,31 +190,31 @@ defmodule Pleroma.Mixfile do git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"}, {:restarter, path: "./restarter"}, - {:majic, "~> 1.1"}, - {:open_api_spex, "~> 3.22"}, + {:majic, "~> 1.0"}, + {:open_api_spex, "~> 3.16"}, {:ecto_psql_extras, "~> 0.8"}, {:vix, "~> 0.36"}, - {:elixir_make, "~> 0.7.8", override: true}, + {:elixir_make, "~> 0.7.7", override: true}, {:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash}, {:exile, "~> 0.10.0"}, - {:bandit, "~> 1.10"}, - {:websock_adapter, "~> 0.5.8"}, + {:bandit, "~> 1.5.2"}, + {:websock_adapter, "~> 0.5.6"}, {:oban_live_dashboard, "~> 0.1.1"}, {:multipart, "~> 0.4.0", optional: true}, - {:argon2_elixir, "~> 4.1"}, + {:argon2_elixir, "~> 4.0"}, ## dev & test {:phoenix_live_reload, "~> 1.3.3", only: :dev}, - {:poison, "~> 3.1", only: :test}, - {:ex_doc, "~> 0.38", only: :dev, runtime: false}, - {:ex_machina, "~> 2.8", only: :test}, + {:poison, "~> 3.0", only: :test}, + {:ex_doc, "~> 0.22", only: :dev, runtime: false}, + {:ex_machina, "~> 2.4", only: :test}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, - {:mock, "~> 0.3.9", only: :test}, + {:mock, "~> 0.3.5", only: :test}, {:covertool, "~> 2.0", only: :test}, - {:hackney, "~> 1.20.1", override: true}, - {:mox, "~> 1.2", only: :test}, + {:hackney, "~> 1.25.0", override: true}, + {:mox, "~> 1.0", only: :test}, {:websockex, "~> 0.4.3", only: :test}, - {:benchee, "~> 1.4", only: :benchmark}, + {:benchee, "~> 1.0", only: :benchmark}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false} ] ++ oauth_deps() ++ logger_deps() end diff --git a/mix.lock b/mix.lock index 976a856b0..8e1f684dc 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{ "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"}, "argon2_elixir": {:hex, :argon2_elixir, "4.1.3", "4f28318286f89453364d7fbb53e03d4563fd7ed2438a60237eba5e426e97785f", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "7c295b8d8e0eaf6f43641698f962526cdf87c6feb7d14bd21e599271b510608c"}, - "bandit": {:hex, :bandit, "1.10.4", "02b9734c67c5916a008e7eb7e2ba68aaea6f8177094a5f8d95f1fb99069aac17", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "a5faf501042ac1f31d736d9d4a813b3db4ef812e634583b6a457b0928798a51d"}, + "bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"}, "base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"}, "bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"}, @@ -13,7 +13,7 @@ "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e7b7cc34cc16b383461b966484c297e4ec9aeef6", [ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"]}, "castore": {:hex, :castore, "1.0.15", "8aa930c890fe18b6fe0a0cff27b27d0d4d231867897bd23ea772dee561f032a3", [:mix], [], "hexpm", "96ce4c69d7d5d7a0761420ef743e2f4096253931a3ba69e5ff8ef1844fe446d3"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"}, - "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"}, "concurrent_limiter": {:hex, :concurrent_limiter, "0.1.1", "43ae1dc23edda1ab03dd66febc739c4ff710d047bb4d735754909f9a474ae01c", [:mix], [{:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "53968ff238c0fbb4d7ed76ddb1af0be6f3b2f77909f6796e249e737c505a16eb"}, @@ -59,7 +59,7 @@ "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, "gun": {:hex, :gun, "2.2.0", "b8f6b7d417e277d4c2b0dc3c07dfdf892447b087f1cc1caff9c0f556b884e33d", [:make, :rebar3], [{:cowlib, ">= 2.15.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "76022700c64287feb4df93a1795cff6741b83fb37415c40c34c38d2a4645261a"}, - "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, + "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "http_signatures": {:hex, :http_signatures, "0.1.2", "ed1cc7043abcf5bb4f30d68fb7bad9d618ec1a45c4ff6c023664e78b67d9c406", [:mix], [], "hexpm", "f08aa9ac121829dae109d608d83c84b940ef2f183ae50f2dd1e9a8bc619d8be7"}, @@ -79,9 +79,8 @@ "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "360a30267a847810a63ab48f606ba227b2ca05f0", [ref: "360a30267a847810a63ab48f606ba227b2ca05f0"]}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, - "mimerl": {:hex, :mimerl, "1.5.0", "f35aca6f23242339b3666e0ac0702379e362b469d0aea167f6cc713547e777ed", [:rebar3], [], "hexpm", "db648ce065bae14ea84ca8b5dd123f42f49417cef693541110bf6f9e9be9ecc4"}, + "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "mock": {:hex, :mock, "0.3.9", "10e44ad1f5962480c5c9b9fa779c6c63de9bd31997c8e04a853ec990a9d841af", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "9e1b244c4ca2551bb17bb8415eed89e40ee1308e0fbaed0a4fdfe3ec8a4adbd3"}, @@ -129,7 +128,6 @@ "prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, "quantile_estimator": {:hex, :quantile_estimator, "0.2.1", "ef50a361f11b5f26b5f16d0696e46a9e4661756492c981f7b2229ef42ff1cd15", [:rebar3], [], "hexpm", "282a8a323ca2a845c9e6f787d166348f776c1d4a41ede63046d72d422e3da946"}, - "quic": {:hex, :quic, "0.10.2", "4b390507a85f65ce47808f3df1a864e0baf9adb7a1b4ea9f4dcd66fe9d0cb166", [:rebar3], [], "hexpm", "7c196a66973c877a59768a5687f0a0610ff11817254d0a4e45cc4e3a16b1d00b"}, "ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"}, "recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"}, "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]}, @@ -146,7 +144,7 @@ "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.1", "c9755987d7b959b557084e6990990cb96a50d6482c683fb9622a63837f3cd3d8", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5e2c599da4983c4f88a33e9571f1458bf98b0cf6ba930f1dc3a6e8cf45d5afb6"}, "telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"}, "tesla": {:hex, :tesla, "1.15.3", "3a2b5c37f09629b8dcf5d028fbafc9143c0099753559d7fe567eaabfbd9b8663", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "98bb3d4558abc67b92fb7be4cd31bb57ca8d80792de26870d362974b58caeda7"}, - "thousand_island": {:hex, :thousand_island, "1.4.3", "2158209580f633be38d43ec4e3ce0a01079592b9657afff9080d5d8ca149a3af", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6e4ce09b0fd761a58594d02814d40f77daff460c48a7354a15ab353bb998ea0b"}, + "thousand_island": {:hex, :thousand_island, "1.3.14", "ad45ebed2577b5437582bcc79c5eccd1e2a8c326abf6a3464ab6c06e2055a34a", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d0d24a929d31cdd1d7903a4fe7f2409afeedff092d277be604966cd6aa4307ef"}, "timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, diff --git a/priv/repo/migrations/20200825061316_move_activity_expirations_to_oban.exs b/priv/repo/migrations/20200825061316_move_activity_expirations_to_oban.exs index b512313c7..f15876180 100644 --- a/priv/repo/migrations/20200825061316_move_activity_expirations_to_oban.exs +++ b/priv/repo/migrations/20200825061316_move_activity_expirations_to_oban.exs @@ -23,12 +23,10 @@ defmodule Pleroma.Repo.Migrations.MoveActivityExpirationsToOban do |> Pleroma.Repo.stream() |> Stream.each(fn expiration -> with {:ok, expires_at} <- DateTime.from_naive(expiration.scheduled_at, "Etc/UTC") do - Pleroma.Workers.PurgeExpiredActivity.enqueue( - %{ - activity_id: FlakeId.to_string(expiration.activity_id) - }, - scheduled_at: expires_at - ) + Pleroma.Workers.PurgeExpiredActivity.enqueue(%{ + activity_id: FlakeId.to_string(expiration.activity_id), + expires_at: expires_at + }) end end) |> Stream.run() diff --git a/priv/repo/migrations/20200907092050_move_tokens_expiration_into_oban.exs b/priv/repo/migrations/20200907092050_move_tokens_expiration_into_oban.exs index 0a55e4f71..c140bc66a 100644 --- a/priv/repo/migrations/20200907092050_move_tokens_expiration_into_oban.exs +++ b/priv/repo/migrations/20200907092050_move_tokens_expiration_into_oban.exs @@ -21,7 +21,7 @@ defmodule Pleroma.Repo.Migrations.MoveTokensExpirationIntoOban do from(t in Pleroma.Web.OAuth.Token, where: t.valid_until > ^NaiveDateTime.utc_now()) |> Pleroma.Repo.stream() |> Stream.each(fn token -> - enqueue(%{ + Pleroma.Workers.PurgeExpiredToken.enqueue(%{ token_id: token.id, valid_until: DateTime.from_naive!(token.valid_until, "Etc/UTC"), mod: Pleroma.Web.OAuth.Token @@ -33,7 +33,7 @@ defmodule Pleroma.Repo.Migrations.MoveTokensExpirationIntoOban do from(t in Pleroma.MFA.Token, where: t.valid_until > ^NaiveDateTime.utc_now()) |> Pleroma.Repo.stream() |> Stream.each(fn token -> - enqueue(%{ + Pleroma.Workers.PurgeExpiredToken.enqueue(%{ token_id: token.id, valid_until: DateTime.from_naive!(token.valid_until, "Etc/UTC"), mod: Pleroma.MFA.Token @@ -41,14 +41,4 @@ defmodule Pleroma.Repo.Migrations.MoveTokensExpirationIntoOban do end) |> Stream.run() end - - @spec enqueue(%{token_id: integer(), valid_until: DateTime.t()}) :: - {:ok, Oban.Job.t()} | {:error, Ecto.Changeset.t()} - defp enqueue(args) do - {scheduled_at, args} = Map.pop(args, :valid_until) - - args - |> Pleroma.Workers.PurgeExpiredToken.new(scheduled_at: scheduled_at) - |> Oban.insert() - end end diff --git a/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs b/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs deleted file mode 100644 index b54daf43d..000000000 --- a/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs +++ /dev/null @@ -1,11 +0,0 @@ -defmodule Pleroma.Repo.Migrations.AddActivityAssignedAccountIndex do - use Ecto.Migration - - def change do - create_if_not_exists( - index(:activities, ["(data->>'assigned_account')"], - name: :activities_assigned_account_index - ) - ) - end -end diff --git a/priv/repo/migrations/20260218000000_add_exclusive_to_lists.exs b/priv/repo/migrations/20260218000000_add_exclusive_to_lists.exs deleted file mode 100644 index 253a8acb7..000000000 --- a/priv/repo/migrations/20260218000000_add_exclusive_to_lists.exs +++ /dev/null @@ -1,9 +0,0 @@ -defmodule Pleroma.Repo.Migrations.AddExclusiveToLists do - use Ecto.Migration - - def change do - alter table(:lists) do - add(:exclusive, :boolean, default: false) - end - end -end diff --git a/priv/repo/migrations/20260401185429_cleanup_stale_digest_email_jobs.exs b/priv/repo/migrations/20260401185429_cleanup_stale_digest_email_jobs.exs deleted file mode 100644 index 882c7ec66..000000000 --- a/priv/repo/migrations/20260401185429_cleanup_stale_digest_email_jobs.exs +++ /dev/null @@ -1,9 +0,0 @@ -defmodule Pleroma.Repo.Migrations.CleanupStaleDigestEmailJobs do - use Ecto.Migration - - def up do - execute( - "DELETE from oban_jobs WHERE queue = 'mailer' AND worker = 'Pleroma.Workers.Cron.DigestEmailsWorker'" - ) - end -end diff --git a/priv/scrubbers/default.ex b/priv/scrubbers/default.ex index 342ef9944..0defdc74e 100644 --- a/priv/scrubbers/default.ex +++ b/priv/scrubbers/default.ex @@ -82,50 +82,12 @@ defmodule Pleroma.HTML.Scrubber.Default do "recipients-inline", "quote-inline", "invisible", - "ellipsis", - "mfm-center", - "mfm-flip", - "mfm-font", - "mfm-blur", - "mfm-rotate", - "mfm-x2", - "mfm-x3", - "mfm-x4", - "mfm-position", - "mfm-scale", - "mfm-fg", - "mfm-bg", - "mfm-jelly", - "mfm-twitch", - "mfm-shake", - "mfm-spin", - "mfm-jump", - "mfm-bounce", - "mfm-rainbow", - "mfm-tada", - "mfm-sparkle" + "ellipsis" ]) Meta.allow_tag_with_this_attribute_values(:p, "class", ["quote-inline"]) - Meta.allow_tag_with_these_attributes(:span, [ - "lang", - "data-mfm-h", - "data-mfm-v", - "data-mfm-x", - "data-mfm-y", - "data-mfm-alternate", - "data-mfm-speed", - "data-mfm-deg", - "data-mfm-left", - "data-mfm-serif", - "data-mfm-monospace", - "data-mfm-cursive", - "data-mfm-fantasy", - "data-mfm-emoji", - "data-mfm-math", - "data-mfm-color" - ]) + Meta.allow_tag_with_these_attributes(:span, ["lang"]) Meta.allow_tag_with_this_attribute_values(:code, "class", ["inline"]) diff --git a/priv/static/instance/static.css b/priv/static/instance/static.css index 48c74c125..32f56d510 100644 --- a/priv/static/instance/static.css +++ b/priv/static/instance/static.css @@ -3,206 +3,84 @@ } :root { - --brand-color: #d8a070; - --background-color: #121a24; - --foreground-color: #182230; - --primary-text-color: #b9b9ba; - --muted-text-color: #89898a; + font-size: 16px; + + --bg: rgba(18, 26, 36, 1); + --fg: rgba(24, 34, 48, 1); + --text: rgba(185, 185, 186, 1); + --link: rgba(216, 160, 112, 1); + --accent: rgba(216, 160, 112, 1); + --cRed: rgba(211, 16, 20, 1); + --cBlue: rgba(0, 149, 255, 1); + --cGreen: rgba(15, 160, 15, 1); + --cOrange: rgba(255, 165, 0, 1); + --font: sans-serif; + --monoFont: monospace; + --wallpaper: rgba(14, 21, 29, 1); + --selectionBackground: rgba(216, 160, 112, 1); + --selectionText: rgba(0, 0, 0, 1); + --badgeNotification: rgba(211, 16, 20, 1); } body { - background-color: var(--background-color); + background-color: var(--wallpaper); font-family: sans-serif; - color: var(--primary-text-color); + color: var(--text); padding: 0; margin: 0; -} - -.instance-header { - height: 60px; - padding: 10px; - background: var(--foreground-color); - box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5); -} - -.instance-header__content { display: flex; - align-items: center; - max-width: 400px; - margin: 0 auto; -} - -.instance-header__thumbnail { - max-width: 40px; - border-radius: 4px; - margin-right: 12px; -} - -.instance-header__title { - font-size: 16px; - font-weight: bold; - color: var(--primary-text-color); -} - -.container { - max-width: 400px; - background-color: var(--foreground-color); - border-radius: 4px; - overflow: hidden; - margin: 35px auto; - box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5); - padding: 0em 1em 0em 1em; -} - -.container__content { - padding: 0 20px; -} - -h1 { - margin: 0; - font-size: 24px; - text-align: center; -} - -h2 { - color: var(--primary-text-color); - font-weight: normal; - font-size: 18px; - margin-bottom: 20px; + flex-direction: column; + align-items: stretch; } a { - color: var(--brand-color); + color: var(--link); text-decoration: none; } -form { - width: 100%; -} - -.input { - color: var(--muted-text-color); - display: flex; - flex-direction: column; -} - -input { - padding: 10px; - margin-top: 5px; - margin-bottom: 10px; - background-color: var(--background-color); - color: var(--primary-text-color); - border: 0; - transition-property: border-bottom; - transition-duration: 0.35s; - border-bottom: 2px solid #2a384a; - font-size: 14px; - width: inherit; - box-sizing: border-box; -} - -.scopes-input { - display: flex; - flex-direction: column; - margin: 1em 0; - color: var(--muted-text-color); -} - -.scopes-input label:first-child { - height: 2em; -} - -.scopes { - display: flex; - flex-wrap: wrap; - color: var(--primary-text-color); -} - -.scope { - display: flex; - flex-basis: 100%; - height: 2em; - align-items: center; -} - -.scope:before { - color: var(--primary-text-color); - content: "✔\fe0e"; - margin-left: 1em; - margin-right: 1em; -} - -[type="checkbox"] + label { - display: none; - cursor: pointer; - margin: 0.5em; -} - -[type="checkbox"] { - display: none; -} - -[type="checkbox"] + label:before { - cursor: pointer; - display: inline-block; - color: white; - background-color: var(--background-color); - border: 4px solid var(--background-color); - box-shadow: 0px 0px 1px 0 var(--brand-color); - width: 1.2em; - height: 1.2em; - margin-right: 1.0em; - content: ""; - transition-property: background-color; - transition-duration: 0.35s; - color: var(--background-color); - margin-bottom: -0.2em; - border-radius: 2px; -} - -[type="checkbox"]:checked + label:before { - background-color: var(--brand-color); -} - -input:focus { - outline: none; - border-bottom: 2px solid var(--brand-color); -} - -.actions { - display: flex; - justify-content: flex-end; -} - -.actions button, -.actions a.button { - width: auto; - margin-left: 10px; -} - -a.button, -button { +.button { width: 100%; background-color: #1c2a3a; color: var(--primary-text-color); border-radius: 4px; border: none; - padding: 10px 16px; - margin-top: 20px; - margin-bottom: 20px; - text-transform: uppercase; - font-size: 16px; - box-shadow: 0px 0px 2px 0px black, - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + padding: 0 1em; + line-height: 2; + margin-top: 2em; + font-size: 1em; + cursor: pointer; + box-shadow: + 0 0 2px 0 black, + 0 1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 -1px 0 0 rgba(0, 0, 0, 0.2) inset; } -a.button:hover, -button:hover { - cursor: pointer; - box-shadow: 0px 0px 0px 1px var(--brand-color), - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; +.button:hover { + box-shadow: + 0 0 1px 2px rgba(185, 185, 186, 0.4), + 0 1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 -1px 0 0 rgba(0, 0, 0, 0.2) inset; +} + +.button:active { + transform: translate(1px, 1px); + box-shadow: + 0 0 2px 0 black, + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset; +} + +.button:hover:active { + box-shadow: + 0 0 1px 2px rgba(185, 185, 186, 0.4), + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset; +} + +.input { + color: var(--text); + display: flex; + flex-direction: column; } .alert-danger { @@ -226,73 +104,222 @@ button:hover { font-size: 16px; } -.account-header__banner { +.instance-header { + display: flex; + height: 3.5rem; + padding: 0 1em; + background: var(--fg); + box-shadow: + 0 1px 4px 0 rgba(0, 0, 0, 0.4), + 0 2px 7px 0 rgba(0, 0, 0, 0.3); + justify-content: center; + align-self: stretch; + margin-bottom: 1rem; +} + +.instance-header__content { + line-height: 3.5rem; + display: flex; + flex: 1 1 45em; + max-width: 45em; + align-items: center; +} + +.instance-header__thumbnail { + max-width: 3.5em; + border-radius: 0.25em; + margin-right: 0.75em; +} + +.instance-header__title { + font-weight: bold; + color: var(--text); + font-size: 1rem; +} + +.contents { + display: flex; + align-items: stretch; + justify-content: center; +} + +.panel { + color: var(--text); + background-color: var(--bg); + position: relative; + max-width: 45em; + border-radius: 0.5em; + overflow: hidden; + margin: 0; + box-shadow: + 0 0 3px 0 rgba(0, 0, 0, 0.5), + 0 4px 6px 3px rgba(0, 0, 0, 0.3); + padding: 0; + flex: 1 1 45em; +} + +.button { + width: auto; +} + +.panel-body { + padding: 0 1em 1em; + background-color: var(--bg); +} + +.actions { + display: flex; + justify-content: flex-end; +} + +.actions .button { + margin-left: 0.5em; +} + +.account-header { + position: relative; + display: flex; + align-items: end; + width: 100%; + aspect-ratio: 3; + gap: 1em; + padding: 0 1em; +} + +.account-header_container { + position: absolute; + inset: 0; + z-index: 0; + mask: linear-gradient(to top,transparent 0,white 5em) bottom no-repeat; +} + +.account-header__overlay, +.account-header__banner { + position: absolute; + width: 100%; + inset: 0; +} + +.account-header__overlay { + background-color: rgba(18, 26, 36, 0.5); + z-index: -1; +} + +.account-header__banner { + z-index: -2; + object-fit: cover; width: 100%; - height: 112px; - background-size: cover; - background-position: center; } .account-header__avatar { - width: 94px; - height: 94px; + width: 6em; + height: 6em; + flex: 0 0 6em; + z-index: 1; background-size: cover; background-position: center; - margin: -47px 10px 0; - border: 6px solid var(--foreground-color); - border-radius: 999px; } .account-header__meta { - padding: 6px 20px 17px; + z-index: 1; + flex: 1 1 0; + display: flex; + flex-direction: column; + min-width: 10em; + font-size: 125%; } +.account-header__nickname, .account-header__display-name { - font-size: 20px; + font-size: 1.25em; + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; +} + +.acocunt-header__display-name { font-weight: bold; } .account-header__nickname { - font-size: 14px; - color: var(--muted-text-color); + font-size: 0.75em; + color: var(--link); } -@media all and (max-width: 420px) { - .container { - margin: 0 auto; - border-radius: 0; - } - - .scope { - flex-basis: 0%; - } - - .scope:before { - content: ""; - margin-left: 0em; - margin-right: 1em; - } - - .scope:first-child:before { - margin-left: 1em; - content: "✔\fe0e"; - } - - .scope:after { - content: ","; - } - - .scope:last-child:after { - content: ""; - } +input { + display: inline-block; + background-color: var(--background); + outline: none; + color: var(--text); + line-height: 2; + border-radius: 0.5em; + box-shadow: var(--shadow); + border: none; + padding: 0 0.5em; } -.form-row { + +input[type="checkbox"] { + display: none; +} + +input, label, label::before { + --background: rgba(15, 21, 30, 1); + --shadow: + 0 0 2px 0 rgba(0, 0, 0, 1), + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, + 0 0 2px 0 rgba(0, 0, 0, 0.15) inset, + 1px 0 1px 1px rgba(185, 185, 186, 0.15), + -1px 0 1px 1px rgba(185, 185, 186, 0.15); + --shadowHover: + 0 0 4px 0 rgba(185, 185, 186, 0.5), + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, + 0 0 2px 0 rgba(0, 0, 0, 0.15) inset, + 1px 0 1px 1px rgba(185, 185, 186, 0.15), + -1px 0 1px 1px rgba(185, 185, 186, 0.15); +} + + +label[type="checkbox"]::before { + content: "" +} + +input[type="checkbox"]:checked + label::before { + content: "✓" +} + +label { + padding: 1em; + display: inline-block; +} + +input[type="checkbox"] + label::before { + content: ""; + + box-shadow: + min-width: 1em; + min-height: 1em; + text-align: center; + box-shadow: var(--shadow); +} + +label:hover::before { + box-shadow: var(--shadowHover); +} + +.scope { display: flex; -} -.form-row > label { - line-height: 47px; - flex: 1; -} -.form-row > input { - flex: 2; + align-items: center; + + dl { + margin: 0.75em; + + display: flex; + flex-direction: column; + + dt, dd { + margin: 0; + } + } } diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld index 4e82d4b01..3569165a4 100644 --- a/priv/static/schemas/litepub-0.1.jsonld +++ b/priv/static/schemas/litepub-0.1.jsonld @@ -4,55 +4,46 @@ "https://w3id.org/security/v1", "https://purl.archive.org/socialweb/webfinger", { - "as": "https://www.w3.org/ns/activitystreams#", - "ostatus": "http://ostatus.org#", - "schema": "http://schema.org#", - "vcard": "http://www.w3.org/2006/vcard/ns#", - - "fedibird": "http://fedibird.com/ns#", - "litepub": "http://litepub.social/ns#", - "sm": "http://smithereen.software/ns#", - "toot": "http://joinmastodon.org/ns#", - - "alsoKnownAs": { - "@id": "as:alsoKnownAs", - "@type": "@id" - }, + "Emoji": "toot:Emoji", "Hashtag": "as:Hashtag", - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "quoteUrl": "as:quoteUrl", - "sensitive": "as:sensitive", - + "PropertyValue": "schema:PropertyValue", "atomUri": "ostatus:atomUri", "conversation": { "@id": "ostatus:conversation", "@type": "@id" }, - - "PropertyValue": "schema:PropertyValue", - "value": "schema:value", - - "quoteUri": "fedibird:quoteUri", - + "discoverable": "toot:discoverable", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "capabilities": "litepub:capabilities", - "ChatMessage": "litepub:ChatMessage", - "directMessage": "litepub:directMessage", - "EmojiReact": "litepub:EmojiReact", - "formerRepresentations": "litepub:formerRepresentations", + "ostatus": "http://ostatus.org#", + "schema": "http://schema.org#", + "toot": "http://joinmastodon.org/ns#", + "fedibird": "http://fedibird.com/ns#", + "value": "schema:value", + "sensitive": "as:sensitive", + "litepub": "http://litepub.social/ns#", "invisible": "litepub:invisible", + "directMessage": "litepub:directMessage", "listMessage": { "@id": "litepub:listMessage", "@type": "@id" }, + "quoteUrl": "as:quoteUrl", + "quoteUri": "fedibird:quoteUri", "oauthRegistrationEndpoint": { "@id": "litepub:oauthRegistrationEndpoint", "@type": "@id" }, - - "nonAnonymous": "sm:nonAnonymous", - - "discoverable": "toot:discoverable", - "Emoji": "toot:Emoji" + "EmojiReact": "litepub:EmojiReact", + "ChatMessage": "litepub:ChatMessage", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + }, + "vcard": "http://www.w3.org/2006/vcard/ns#", + "formerRepresentations": "litepub:formerRepresentations", + "sm": "http://smithereen.software/ns#", + "nonAnonymous": "sm:nonAnonymous" } ] -} \ No newline at end of file +} diff --git a/rel/files/bin/pleroma_ctl b/rel/files/bin/pleroma_ctl index f5d3f321b..6f0dba3a8 100755 --- a/rel/files/bin/pleroma_ctl +++ b/rel/files/bin/pleroma_ctl @@ -78,19 +78,14 @@ update() { RELEASE_ROOT=$(dirname "$SCRIPTPATH") uri="https://git.pleroma.social" - project_name="pleroma" - package_base="${uri}/api/packages/${project_name}/generic" - if [ -n "$FULL_URI" ]; then - full_uri="$FULL_URI" - else - project_branch="${BRANCH:-$(detect_branch)}" - flavour="${FLAVOUR:-$(detect_flavour)}" - full_uri="${package_base}"/pleroma-otp-"${project_branch}"-"${flavour}"/latest/pleroma.zip - fi + project_id="2" + project_branch="${BRANCH:-$(detect_branch)}" + flavour="${FLAVOUR:-$(detect_flavour)}" tmp="${TMP_DIR:-/tmp}" artifact="$tmp/pleroma.zip" + full_uri="${FULL_URI:-${uri}/api/v4/projects/${project_id}/jobs/artifacts/${project_branch}/download?job=${flavour}}" echo "Downloading the artifact from ${full_uri} to ${artifact}" - curl -fL "$full_uri" -o "${artifact}" + curl "$full_uri" -o "${artifact}" echo "Unpacking ${artifact} to ${tmp}" unzip -q "$artifact" -d "$tmp" echo "Copying files over to $RELEASE_ROOT" @@ -142,14 +137,7 @@ else SCRIPT=$(realpath "$0") SCRIPTPATH=$(dirname "$SCRIPT") - # HACK: Script arguments need to be sent as an array to Mix tasks, otherwise they will break (quoted) arguments with whitespace. - # Previously it was sent as string, which would get split on whitespace on the task side. - # Encode as Elixir binary literals to avoid string escaping and interpolation issues. - PREPARED_ARGS="" - for arg in "$@"; do - bytes=$(printf '%s' "$arg" | od -An -v -tu1 | tr -s '[:space:]' ',' | sed 's/^,//; s/,$//') - PREPARED_ARGS="$PREPARED_ARGS <<$bytes>>," - done + FULL_ARGS="$*" ACTION="$1" if [ $# -gt 0 ]; then @@ -166,8 +154,8 @@ else if [ "$ACTION" = "update" ]; then update "$@" elif [ "$ACTION" = "migrate" ] || [ "$ACTION" = "rollback" ] || [ "$ACTION" = "create" ] || [ "$ACTION $SUBACTION" = "instance gen" ] || [ "$PLEROMA_CTL_RPC_DISABLED" = true ]; then - "$SCRIPTPATH"/pleroma eval 'Pleroma.ReleaseTasks.run(['"${PREPARED_ARGS%%,}"'])' + "$SCRIPTPATH"/pleroma eval 'Pleroma.ReleaseTasks.run("'"$FULL_ARGS"'")' else - "$SCRIPTPATH"/pleroma rpc 'Pleroma.ReleaseTasks.run(['"${PREPARED_ARGS%%,}"'])' + "$SCRIPTPATH"/pleroma rpc 'Pleroma.ReleaseTasks.run("'"$FULL_ARGS"'")' fi fi diff --git a/test/fixtures/users_mock/hubzilla-actor-alsoknownas-string.json b/test/fixtures/users_mock/hubzilla-actor-alsoknownas-string.json deleted file mode 100644 index 086db73b1..000000000 --- a/test/fixtures/users_mock/hubzilla-actor-alsoknownas-string.json +++ /dev/null @@ -1 +0,0 @@ -{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://purl.archive.org/socialweb/webfinger",{"zot":"https://hub.netzgemeinde.eu/apschema#","contextHistory":"https://w3id.org/fep/171b/contextHistory","schema":"http://schema.org#","ostatus":"http://ostatus.org#","diaspora":"https://diasporafoundation.org/ns/","litepub":"http://litepub.social/ns#","toot":"http://joinmastodon.org/ns#","commentPolicy":"zot:commentPolicy","Bookmark":"zot:Bookmark","Category":"zot:Category","Emoji":"toot:Emoji","directMessage":"litepub:directMessage","PropertyValue":"schema:PropertyValue","value":"schema:value","uuid":"schema:identifier","conversation":"ostatus:conversation","manuallyApprovesFollowers":"as:manuallyApprovesFollowers","Hashtag":"as:Hashtag","quoteUrl":"as:quoteUrl","quoteUri":"http://fedibird.com/ns#quoteUri"}],"type":"Person","manuallyApprovesFollowers":true,"id":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","preferredUsername":"jupiter_rowland","name":"Jupiter Rowland","updated":"0001-01-01T00:00:00Z","icon":{"type":"Image","mediaType":"image/png","updated":"2024-10-15T21:10:02Z","url":"https://hub.netzgemeinde.eu/photo/profile/l/1035?rev=1729019402","height":300,"width":300},"url":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","publicKey":{"id":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","owner":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","signatureAlgorithm":"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmDB9nkcdhjzcfSPQG5q3\nxRVAYaWa+pKC38NhhRMbmd7+P8+8be3HUuX97bwhLdSA3+IRMz9JmX8bqqtKPK8A\nKxWFdUxoZKefwAAVpT+R89hHvi6Ib56Tp5lNlUSTIg3QXfm2gyRc3ehYbI9i6+Wr\nuFgCzdYT9bIeLqhZdFabPP4NORnyPgBQtktXcQUoDOKSaaKuitxFP1dhM9Dco3uX\nLcpQOLdY6yct5J+1Y6+/GUZgtO2pjMtkoEo6Ro0+Wlo7xfvdPnk5moljDVzPFoQE\nhUao5amorPhm1/iEpQXI0eEUW8IXdObFS8gyQJLmS30AjMkaWfwM9HFGmUmn8CSw\nKGBaKDN2C93fvmLOLpaoIRqgVTHBxfv3bN/CtvTRP83/eWvmhnlYo0fmE49tj2ZH\neCHCvRPJ+XM44WntbrUmwJ61+6nO/Io7qe7zmLm+0ew1VD9xTWAd96isW8HEmhcu\nO2iP2GALb0PqE7mgQmV1x/WAYB40+29C03UINHAnZY+nvBW6xd0wAOFiYXqjJF/4\nxEOWPvwcwOtltX+dTerFBC2KzLQQVk/CK2JdKtD2ssiYrvdC/IqPQzVMz3EAtVoP\n8sq/lzffCD3T+zhhnLhgxu7p9JNjRq83jMOOB3DUSd5izO+u6TBn5lasfoa7Eh+X\nQezGvMXhRQR4mnzrSLwZZ1ECAwEAAQ==\n-----END PUBLIC KEY-----\n"},"tag":[{"type":"PropertyValue","name":"Protocol","value":"zot6"},{"type":"PropertyValue","name":"Protocol","value":"activitypub"}],"outbox":"https://hub.netzgemeinde.eu/outbox/jupiter_rowland","webfinger":"jupiter_rowland@hub.netzgemeinde.eu","inbox":"https://hub.netzgemeinde.eu/inbox/jupiter_rowland","followers":"https://hub.netzgemeinde.eu/followers/jupiter_rowland","following":"https://hub.netzgemeinde.eu/following/jupiter_rowland","endpoints":{"sharedInbox":"https://hub.netzgemeinde.eu/inbox"},"discoverable":true,"assertionMethod":[{"id":"https://hub.netzgemeinde.eu/channel/jupiter_rowland#z6Mkw5vE2YnuCwke9VY6Xn1jnaXqLgDCKoJsRE2PjDmAUw9w","type":"Multikey","controller":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","publicKeyMultibase":"z6Mkw5vE2YnuCwke9VY6Xn1jnaXqLgDCKoJsRE2PjDmAUw9w"}],"copiedTo":"https://hub.hubzilla.de/channel/jupiter_rowland","alsoKnownAs":"https://hub.hubzilla.de/channel/jupiter_rowland","image":{"type":"Image","mediaType":"image/jpeg","url":"https://hub.netzgemeinde.eu/photo/5bd87e54-e328-47d3-a8ed-7a33547ad882-7"},"summary":"An avatar roaming the decentralised and federated 3-D virtual worlds based on OpenSimulator, a free and open-source server-side re-implementation of Second Life. Mostly talking about OpenSim, sometimes about other virtual worlds, occasionally about the Fediverse beyond Mastodon. No, the Fediverse is not only Mastodon.

If you're looking for real-life people posting about real-life topics, go look somewhere else. This channel is never about real life.

Even if you see me on Mastodon, I'm not on Mastodon myself. I'm on Hubzilla which is neither a Mastodon instance nor a Mastodon fork. In fact, it's older and much more powerful than Mastodon. And it has always been connected to Mastodon.

I regularly write posts with way more than 500 characters. If that disturbs you, block me now, but don't complain. I'm not on Mastodon, I don't have a character limit here.

I rather give too many content warnings than too few. But I have absolutely no means of blanking out pictures for Mastodon users.

I always describe my images, no matter how long it takes. My posts with image descriptions tend to be my longest. Don't go looking for my image descriptions in the alt-text; they're always in the post text which is always hidden behind a content warning due to being over 500 characters long.

If you follow me, and I "follow" you back, I don't actually follow you and receive your posts. Unless you've got something to say that's interesting to me within the scope of this channel, or I know you from OpenSim, I'll most likely deny you the permission to send me your posts. I only "follow" you back because Hubzilla requires me to do that to allow you to follow me. But I do let you send me your comments and direct messages. If you boost a lot of uninteresting stuff, I'll block you boosts.

My "birthday" isn't my actual birthday but my rezday. My first avatar has been around since that day.

If you happen to know German, maybe my "homepage" is something for you, a blog which, much like this channel, is about OpenSim and generally virtual worlds.

#OpenSim #OpenSimulator #VirtualWorlds #Metaverse #SocialVR  #fedi22","proof":{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","created":"2026-02-12T17:18:56Z","verificationMethod":"https://hub.netzgemeinde.eu/channel/jupiter_rowland#z6Mkw5vE2YnuCwke9VY6Xn1jnaXqLgDCKoJsRE2PjDmAUw9w","proofPurpose":"assertionMethod","proofValue":"z65hrf1X7c2kZgiyAvBnZ1pd16LGRaLYN4zt6kLdPQtYoYpxuVYgL7zZGFEh3h6gcsq8f6FL5XDjXVNivwg9eJL3u"},"signature":{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],"type":"RsaSignature2017","nonce":"87c52f614ebea65c8ea41d99487e8f8c8883bd5bc65b2538438df3870c532823","creator":"https://hub.netzgemeinde.eu/channel/jupiter_rowland","created":"2026-02-12T17:18:56Z","signatureValue":"FtiD/BaezB1SFiYj18hfAuyLgYQ0c+Mjc9CXiB+ikd8re/uXV5jr+kMgpYzY+nUB3vpU03XnWVi+lHkJ55vzcTjfbUi7puspF7e88yjIFJcHhs+fc9/+bzBbL2PSQ026bTgH3N1Hj2I7qQ3NcmvKmDF/OovWDks/HPGFiiS9uUezZHRF5be7KfUgEJjESk+5zKGkr7yG4M+f23xaScGxT+/uGK69/RT7QbgSiF2A1IiD2gtwVqxWe9eP//HeoXPCT+O+MdKLWtSZwwzfboO/iwNehMtSAAq+POBW7emHTcM1FEZD6abEQAQwpTq28qAnjuYNCU4TzBdKg1q4akhqnTWEyqpscS9xVUUv/iRiyXvWh9WtcGSCvcMb6avUsxGmdk0nO8hv2zigR/s/ZZJhjXUrID+/bwP2o9Uie6ibdwmt1bCHR8U6z7NCQXEJXw9qZuZYpiTFeuNSftICVRuE/NIYpSOPyqERlRnjU6AX6qEQXHQsOnvhB8BUKcRXpWv0xuzWN3Sr2MZyul8A98nvla9Uwqh9BYn70nRcpRGfiY3m41N4kn5WbPw5PezOB8RSFZjji963oum8tu0/NjzKQ/5UOh3aPO+h+AJsnjau2KOeRHLeChalOOLrt3KFalkyGxLzxt5o/OcRvyM37nnih14lqeTNo60PmR/l/QpiwBs="}} \ No newline at end of file diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index f672d8c13..942cfa83d 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -144,13 +144,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do quarantined_instances: [], managed_config: true, static_dir: "instance/static/", - allowed_post_formats: [ - "text/plain", - "text/html", - "text/markdown", - "text/bbcode", - "text/x.misskeymarkdown" - ], + allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], autofollowed_nicknames: [], max_pinned_statuses: 1, attachment_links: false, @@ -335,39 +329,5 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do assert config_records() == [] end - - test "filters non-whitelisted settings" do - clear_config(:database_config_whitelist, [ - {:pleroma}, - {:web_push_encryption, :vapid_details} - ]) - - insert_config_record(:web_push_encryption, :non_whitelisted_key, a: 1) - insert_config_record(:web_push_encryption, :vapid_details, b: 1) - - MixTask.run(["filter_whitelisted", "--force"]) - - assert [ - %ConfigDB{group: :pleroma, key: :instance}, - %ConfigDB{group: :pleroma, key: Pleroma.Captcha}, - %ConfigDB{group: :web_push_encryption, key: :vapid_details} - ] = config_records() - end - - test "filter_whitelisted doesn't crash when whitelist is unset" do - clear_config(:database_config_whitelist, nil) - - existing = config_records() - MixTask.run(["filter_whitelisted", "--force"]) - assert config_records() == existing - end - - test "filter_whitelisted doesn't crash when whitelist is disabled" do - clear_config(:database_config_whitelist, false) - - existing = config_records() - MixTask.run(["filter_whitelisted", "--force"]) - assert config_records() == existing - end end end diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 5b567325c..19df17b60 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -8,7 +8,6 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.Hashtag alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -551,39 +550,6 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do assert length(activities) == 3 end - - test "it prunes hashtags with no objects associated", %{old_insert_date: old_insert_date} do - user = insert(:user) - - {:ok, hashtag_post_activity} = - CommonAPI.post(user, %{status: "morning #cofe", local: true}) - - hashtag_post_object = Object.normalize(hashtag_post_activity) - - {:ok, hashtag_post2_activity} = - CommonAPI.post(user, %{status: "morning #cawfee", local: true}) - - hashtag_post2_object = Object.normalize(hashtag_post2_activity) - - hashtag_post_object - |> Ecto.Changeset.change(%{updated_at: old_insert_date}) - |> Repo.update!() - - hashtag_post2_object - |> Ecto.Changeset.change(%{updated_at: old_insert_date}) - |> Repo.update!() - - # Test whether hashtags with follow relationships are kept - User.follow_hashtag(user, Hashtag.get_by_name("cofe")) - - assert length(Repo.all(Hashtag)) == 2 - assert length(Repo.all(Object)) == 2 - - Mix.Tasks.Pleroma.Database.run(["prune_objects"]) - assert length(Repo.all(Hashtag)) == 1 - assert length(Repo.all(Object)) == 0 - assert Repo.one(Hashtag) |> Map.fetch!(:name) == "cofe" - end end describe "running update_users_following_followers_counts" do diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index 9d70e6d54..d68e4e6fa 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -174,22 +174,6 @@ defmodule Pleroma.ConfigDBTest do assert updated1.value == [groups: [c: 3, d: 4], key: [a: 1, b: 2]] assert updated2.value == [mascots: [c: 3, d: 4], key: [a: 1, b: 2]] end - - test "rejects invalid :rate_limit values (e.g. empty-string scale from AdminFE)" do - assert {:error, _changeset} = - ConfigDB.update_or_create(%{ - group: ":pleroma", - key: ":rate_limit", - value: [ - %{ - "tuple" => [ - ":statuses_actions", - [%{"tuple" => ["", 0]}, %{"tuple" => ["", ""]}] - ] - } - ] - }) - end end describe "delete/1" do @@ -289,28 +273,24 @@ defmodule Pleroma.ConfigDBTest do end test "sigil" do - assert ConfigDB.to_elixir_types("~r[comp[lL][aA][iI][nN]er]").source == - ~r/comp[lL][aA][iI][nN]er/.source + assert ConfigDB.to_elixir_types("~r[comp[lL][aA][iI][nN]er]") == ~r/comp[lL][aA][iI][nN]er/ end test "link sigil" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/").source == - ~r/https:\/\/example.com/.source + assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/") == ~r/https:\/\/example.com/ end test "link sigil with um modifiers" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/um").source == - ~r/https:\/\/example.com/um.source + assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/um") == + ~r/https:\/\/example.com/um end test "link sigil with i modifier" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/i").source == - ~r/https:\/\/example.com/i.source + assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/i") == ~r/https:\/\/example.com/i end test "link sigil with s modifier" do - assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/s").source == - ~r/https:\/\/example.com/s.source + assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/s") == ~r/https:\/\/example.com/s end test "raise if valid delimiter not found" do @@ -480,11 +460,11 @@ defmodule Pleroma.ConfigDBTest do test "complex keyword with sigil" do assert ConfigDB.to_elixir_types([ %{"tuple" => [":federated_timeline_removal", []]}, - %{"tuple" => [":reject", [~r/comp[lL][aA][iI][nN]er/.source]]}, + %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]}, %{"tuple" => [":replace", []]} ]) == [ federated_timeline_removal: [], - reject: [~r/comp[lL][aA][iI][nN]er/.source], + reject: [~r/comp[lL][aA][iI][nN]er/], replace: [] ] end diff --git a/test/pleroma/http/hackney_follow_redirect_regression_test.exs b/test/pleroma/http/hackney_follow_redirect_regression_test.exs index 4fef26af6..71fda4479 100644 --- a/test/pleroma/http/hackney_follow_redirect_regression_test.exs +++ b/test/pleroma/http/hackney_follow_redirect_regression_test.exs @@ -88,49 +88,6 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do Pleroma.ReverseProxy.Client.Hackney.close(ref) end - test "hackney reverse proxy follows nested redirects via proxy", %{ - tls_server: tls_server, - proxy: proxy - } do - url = "#{tls_server.base_url}/nested_redirect" - - opts = [ - pool: :media, - proxy: proxy.proxy_url, - insecure: true, - connect_timeout: 1_000, - recv_timeout: 1_000, - follow_redirect: true - ] - - assert {:ok, 200, _headers, ref} = - Pleroma.ReverseProxy.Client.Hackney.request(:get, url, [], "", opts) - - assert collect_body(ref) == "ok" - Pleroma.ReverseProxy.Client.Hackney.close(ref) - end - - test "hackney reverse proxy stops following redirects after limit is reached", %{ - tls_server: tls_server, - proxy: proxy - } do - url = "#{tls_server.base_url}/infinite_redirect" - - opts = [ - pool: :media, - proxy: proxy.proxy_url, - insecure: true, - connect_timeout: 1_000, - recv_timeout: 1_000, - follow_redirect: true - ] - - assert {:ok, 302, _headers, ref} = - Pleroma.ReverseProxy.Client.Hackney.request(:get, url, [], "", opts) - - Pleroma.ReverseProxy.Client.Hackney.close(ref) - end - defp collect_body(ref, acc \\ "") do case Pleroma.ReverseProxy.Client.Hackney.stream_body(ref) do :done -> acc @@ -191,12 +148,6 @@ defmodule Pleroma.HTTP.HackneyFollowRedirectRegressionTest do {:ok, data} <- recv_ssl_headers(ssl_socket), {:ok, path} <- parse_path(data) do case path do - "/infinite_redirect" -> - send_ssl_response(ssl_socket, 302, "Found", [{"Location", "/infinite_redirect"}], "") - - "/nested_redirect" -> - send_ssl_response(ssl_socket, 302, "Found", [{"Location", "/redirect"}], "") - "/redirect" -> send_ssl_response(ssl_socket, 302, "Found", [{"Location", "/final"}], "") diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs index 47f6f5f76..88f32762d 100644 --- a/test/pleroma/integration/mastodon_websocket_test.exs +++ b/test/pleroma/integration/mastodon_websocket_test.exs @@ -363,7 +363,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do test "accepts the 'list' stream", %{token: token, user: user} do posting_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "test"}, user) + {:ok, list} = Pleroma.List.create("test", user) Pleroma.List.follow(list, posting_user) assert {:ok, _} = start_socket("?stream=list&access_token=#{token.token}&list=#{list.id}") diff --git a/test/pleroma/list_test.exs b/test/pleroma/list_test.exs index d44310689..a68146b0d 100644 --- a/test/pleroma/list_test.exs +++ b/test/pleroma/list_test.exs @@ -10,23 +10,22 @@ defmodule Pleroma.ListTest do test "creating a list" do user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, user) - %Pleroma.List{title: title, exclusive: exclusive} = Pleroma.List.get(list.id, user) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user) + %Pleroma.List{title: title} = Pleroma.List.get(list.id, user) assert title == "title" - assert exclusive == false end test "validates title" do user = insert(:user) - assert {:error, changeset} = Pleroma.List.create(%{title: ""}, user) + assert {:error, changeset} = Pleroma.List.create("", user) assert changeset.errors == [title: {"can't be blank", [validation: :required]}] end test "getting a list not belonging to the user" do user = insert(:user) other_user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user) ret = Pleroma.List.get(list.id, other_user) assert is_nil(ret) end @@ -34,7 +33,7 @@ defmodule Pleroma.ListTest do test "adding an user to a list" do user = insert(:user) other_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, list} = Pleroma.List.create("title", user) {:ok, %{following: following}} = Pleroma.List.follow(list, other_user) assert [other_user.follower_address] == following end @@ -42,7 +41,7 @@ defmodule Pleroma.ListTest do test "removing an user from a list" do user = insert(:user) other_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, list} = Pleroma.List.create("title", user) {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) {:ok, %{following: following}} = Pleroma.List.unfollow(list, other_user) assert [] == following @@ -50,27 +49,14 @@ defmodule Pleroma.ListTest do test "renaming a list" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "title"}, user) - {:ok, %{title: title}} = Pleroma.List.update(list, %{title: "new"}) + {:ok, list} = Pleroma.List.create("title", user) + {:ok, %{title: title}} = Pleroma.List.rename(list, "new") assert "new" == title end - test "updating a list exclusivity" do - user = insert(:user) - - {:ok, %{exclusive: exclusive} = list} = - Pleroma.List.create(%{title: "title", exclusive: true}, user) - - assert exclusive == true - {:ok, %{exclusive: exclusive} = list} = Pleroma.List.update(list, %{exclusive: false}) - assert exclusive == false - {:ok, %{exclusive: exclusive}} = Pleroma.List.update(list, %{exclusive: true}) - assert exclusive == true - end - test "deleting a list" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, list} = Pleroma.List.create("title", user) {:ok, list} = Pleroma.List.delete(list) assert is_nil(Repo.get(Pleroma.List, list.id)) end @@ -79,7 +65,7 @@ defmodule Pleroma.ListTest do user = insert(:user) other_user = insert(:user) third_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, list} = Pleroma.List.create("title", user) {:ok, list} = Pleroma.List.follow(list, other_user) {:ok, list} = Pleroma.List.follow(list, third_user) {:ok, following} = Pleroma.List.get_following(list) @@ -90,9 +76,9 @@ defmodule Pleroma.ListTest do test "getting all lists by an user" do user = insert(:user) other_user = insert(:user) - {:ok, list_one} = Pleroma.List.create(%{title: "title"}, user) - {:ok, list_two} = Pleroma.List.create(%{title: "other title"}, user) - {:ok, list_three} = Pleroma.List.create(%{title: "third title"}, other_user) + {:ok, list_one} = Pleroma.List.create("title", user) + {:ok, list_two} = Pleroma.List.create("other title", user) + {:ok, list_three} = Pleroma.List.create("third title", other_user) lists = Pleroma.List.for_user(user, %{}) assert list_one in lists assert list_two in lists @@ -102,9 +88,9 @@ defmodule Pleroma.ListTest do test "getting all lists the user is a member of" do user = insert(:user) other_user = insert(:user) - {:ok, list_one} = Pleroma.List.create(%{title: "title"}, user) - {:ok, list_two} = Pleroma.List.create(%{title: "other title"}, user) - {:ok, list_three} = Pleroma.List.create(%{title: "third title"}, other_user) + {:ok, list_one} = Pleroma.List.create("title", user) + {:ok, list_two} = Pleroma.List.create("other title", user) + {:ok, list_three} = Pleroma.List.create("third title", other_user) {:ok, list_one} = Pleroma.List.follow(list_one, other_user) {:ok, list_two} = Pleroma.List.follow(list_two, other_user) {:ok, list_three} = Pleroma.List.follow(list_three, user) @@ -120,8 +106,8 @@ defmodule Pleroma.ListTest do not_owner = insert(:user) member_1 = insert(:user) member_2 = insert(:user) - {:ok, owned_list} = Pleroma.List.create(%{title: "owned"}, owner) - {:ok, not_owned_list} = Pleroma.List.create(%{title: "not owned"}, not_owner) + {:ok, owned_list} = Pleroma.List.create("owned", owner) + {:ok, not_owned_list} = Pleroma.List.create("not owned", not_owner) {:ok, owned_list} = Pleroma.List.follow(owned_list, member_1) {:ok, owned_list} = Pleroma.List.follow(owned_list, member_2) {:ok, not_owned_list} = Pleroma.List.follow(not_owned_list, member_1) @@ -137,14 +123,14 @@ defmodule Pleroma.ListTest do test "get by ap_id" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) assert Pleroma.List.get_by_ap_id(list.ap_id) == list end test "memberships" do user = insert(:user) member = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, list} = Pleroma.List.follow(list, member) assert Pleroma.List.memberships(member) == [list.ap_id] @@ -154,7 +140,7 @@ defmodule Pleroma.ListTest do user = insert(:user) member = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, list} = Pleroma.List.follow(list, member) assert Pleroma.List.member?(list, member) diff --git a/test/pleroma/marker_test.exs b/test/pleroma/marker_test.exs index 7f573ac7a..819dde9be 100644 --- a/test/pleroma/marker_test.exs +++ b/test/pleroma/marker_test.exs @@ -36,12 +36,11 @@ defmodule Pleroma.MarkerTest do insert(:notification, user: user, activity: insert(:note_activity)) insert(:notification, user: user, activity: insert(:note_activity)) insert(:marker, timeline: "home", user: user) - %Marker{} = refreshed_marker = refresh_record(marker) assert Marker.get_markers( user, ["notifications"] - ) == [%{refreshed_marker | unread_count: 2}] + ) == [%Marker{refresh_record(marker) | unread_count: 2}] end end diff --git a/test/pleroma/pleroma_ctl_test.exs b/test/pleroma/pleroma_ctl_test.exs deleted file mode 100644 index d96396399..000000000 --- a/test/pleroma/pleroma_ctl_test.exs +++ /dev/null @@ -1,293 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.PleromaCtlTest do - use ExUnit.Case, async: false - - @pleroma_ctl Path.expand("../../rel/files/bin/pleroma_ctl", __DIR__) - - setup do - tmp_dir = - Path.join(System.tmp_dir!(), "pleroma_ctl_test_#{System.unique_integer([:positive])}") - - release_root = Path.join(tmp_dir, "release") - bin_dir = Path.join(release_root, "bin") - - File.mkdir_p!(bin_dir) - File.cp!(@pleroma_ctl, Path.join(bin_dir, "pleroma_ctl")) - File.chmod!(Path.join(bin_dir, "pleroma_ctl"), 0o755) - - on_exit(fn -> File.rm_rf!(tmp_dir) end) - - {:ok, tmp_dir: tmp_dir, release_root: release_root, bin_dir: bin_dir} - end - - test "update downloads branch-scoped latest OTP package", %{ - tmp_dir: tmp_dir, - bin_dir: bin_dir, - release_root: release_root - } do - stubs_dir = Path.join(tmp_dir, "stubs") - curl_args_path = Path.join(tmp_dir, "curl.args") - File.mkdir_p!(stubs_dir) - write_update_stubs(stubs_dir, curl_args_path, "unused", "glibc") - - update_tmp_dir = Path.join(tmp_dir, "update_tmp") - File.mkdir_p!(update_tmp_dir) - - {output, status} = - System.cmd( - Path.join(bin_dir, "pleroma_ctl"), - [ - "update", - "--branch", - "develop", - "--flavour", - "amd64", - "--tmp-dir", - update_tmp_dir, - "--no-rm" - ], - env: [{"PATH", stubs_dir <> ":" <> System.get_env("PATH", "")}], - stderr_to_stdout: true - ) - - assert status == 0, output - assert File.exists?(Path.join(release_root, "bin/marker")) - - assert ["-fL", url, "-o", artifact_path] = - curl_args_path - |> File.read!() - |> String.split("\n", trim: true) - - assert url == - "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-develop-amd64/latest/pleroma.zip" - - assert artifact_path == Path.join(update_tmp_dir, "pleroma.zip") - end - - test "update detects stable branch and local flavour", %{ - tmp_dir: tmp_dir, - bin_dir: bin_dir, - release_root: release_root - } do - stubs_dir = Path.join(tmp_dir, "stubs") - curl_args_path = Path.join(tmp_dir, "curl.args") - File.mkdir_p!(stubs_dir) - write_update_stubs(stubs_dir, curl_args_path, "x86_64", "glibc") - write_start_erl_data(release_root, "2.10.0") - - {output, status} = - System.cmd( - Path.join(bin_dir, "pleroma_ctl"), - ["update", "--tmp-dir", create_update_tmp_dir(tmp_dir), "--no-rm"], - env: [{"PATH", stubs_dir <> ":" <> System.get_env("PATH", "")}], - stderr_to_stdout: true - ) - - assert status == 0, output - - assert curl_url(curl_args_path) == - "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-stable-amd64/latest/pleroma.zip" - end - - test "update detects develop branch and musl arm flavour", %{ - tmp_dir: tmp_dir, - bin_dir: bin_dir, - release_root: release_root - } do - stubs_dir = Path.join(tmp_dir, "stubs") - curl_args_path = Path.join(tmp_dir, "curl.args") - File.mkdir_p!(stubs_dir) - write_update_stubs(stubs_dir, curl_args_path, "armv7l", "musl") - write_start_erl_data(release_root, "2.10.0.develop") - - {output, status} = - System.cmd( - Path.join(bin_dir, "pleroma_ctl"), - ["update", "--tmp-dir", create_update_tmp_dir(tmp_dir), "--no-rm"], - env: [{"PATH", stubs_dir <> ":" <> System.get_env("PATH", "")}], - stderr_to_stdout: true - ) - - assert status == 0, output - - assert curl_url(curl_args_path) == - "https://git.pleroma.social/api/packages/pleroma/generic/pleroma-otp-develop-arm-musl/latest/pleroma.zip" - end - - test "update with zip URL bypasses branch and flavour detection", %{ - tmp_dir: tmp_dir, - bin_dir: bin_dir, - release_root: release_root - } do - stubs_dir = Path.join(tmp_dir, "stubs") - curl_args_path = Path.join(tmp_dir, "curl.args") - File.mkdir_p!(stubs_dir) - write_update_stubs(stubs_dir, curl_args_path, "unsupported-arch", "unsupported-libc") - write_start_erl_data(release_root, "2.10.0.custombranch") - - custom_url = "https://example.test/custom.zip" - - {output, status} = - System.cmd( - Path.join(bin_dir, "pleroma_ctl"), - [ - "update", - "--zip-url", - custom_url, - "--tmp-dir", - create_update_tmp_dir(tmp_dir), - "--no-rm" - ], - env: [{"PATH", stubs_dir <> ":" <> System.get_env("PATH", "")}], - stderr_to_stdout: true - ) - - assert status == 0, output - assert curl_url(curl_args_path) == custom_url - end - - test "passes arguments with spaces and Elixir string metacharacters", %{ - tmp_dir: tmp_dir, - bin_dir: bin_dir - } do - capture_path = Path.join(tmp_dir, "captured_args") - eval_path = Path.join(tmp_dir, "pleroma_ctl_eval.exs") - - write_executable(Path.join(bin_dir, "pleroma"), """ - #!/bin/sh - { - printf '%s\n' 'defmodule Pleroma.ReleaseTasks do' - printf '%s\n' ' def run(args), do: File.write!(System.fetch_env!("PLEROMA_CTL_CAPTURE"), :erlang.term_to_binary(args))' - printf '%s\n' 'end' - printf '%s\n' "$2" - } > "$PLEROMA_CTL_EVAL_FILE" - - exec elixir "$PLEROMA_CTL_EVAL_FILE" - """) - - {output, status} = - System.cmd( - Path.join(bin_dir, "pleroma_ctl"), - [ - "user", - "", - "has space", - ~s(has "quote"), - ~s(has \\ backslash), - ~S(#{:not_interpolated}) - ], - env: [ - {"PLEROMA_CTL_CAPTURE", capture_path}, - {"PLEROMA_CTL_EVAL_FILE", eval_path} - ], - stderr_to_stdout: true - ) - - assert status == 0, output - - assert capture_path - |> File.read!() - |> :erlang.binary_to_term() == [ - "user", - "", - "has space", - ~s(has "quote"), - ~s(has \\ backslash), - ~S(#{:not_interpolated}) - ] - end - - defp write_executable(path, contents) do - File.write!(path, contents) - File.chmod!(path, 0o755) - end - - defp write_start_erl_data(release_root, version) do - releases_dir = Path.join(release_root, "releases") - File.mkdir_p!(releases_dir) - File.write!(Path.join(releases_dir, "start_erl.data"), "erts-15.0 #{version}\n") - end - - defp create_update_tmp_dir(tmp_dir) do - update_tmp_dir = Path.join(tmp_dir, "update_tmp") - File.mkdir_p!(update_tmp_dir) - update_tmp_dir - end - - defp write_update_stubs(stubs_dir, curl_args_path, arch, libc) do - write_executable(Path.join(stubs_dir, "curl"), """ - #!/bin/sh - printf '%s\n' "$@" > "#{curl_args_path}" - - while [ $# -gt 0 ]; do - case "$1" in - -o) - artifact="$2" - shift 2 - ;; - *) - shift - ;; - esac - done - - : > "$artifact" - """) - - write_executable(Path.join(stubs_dir, "unzip"), """ - #!/bin/sh - while [ $# -gt 0 ]; do - case "$1" in - -d) - dest="$2" - shift 2 - ;; - *) - shift - ;; - esac - done - - mkdir -p "$dest/release/bin" - printf 'marker' > "$dest/release/bin/marker" - """) - - write_executable(Path.join(stubs_dir, "uname"), """ - #!/bin/sh - printf '%s\n' '#{arch}' - """) - - write_executable(Path.join(stubs_dir, "getconf"), getconf_stub(libc)) - - write_executable(Path.join(stubs_dir, "ldd"), """ - #!/bin/sh - printf '%s\n' 'musl libc (mock)' - """) - end - - defp getconf_stub("glibc") do - """ - #!/bin/sh - printf '%s\n' 'glibc 2.40' - """ - end - - defp getconf_stub(_libc) do - """ - #!/bin/sh - exit 1 - """ - end - - defp curl_url(curl_args_path) do - ["-fL", url, "-o", _artifact_path] = - curl_args_path - |> File.read!() - |> String.split("\n", trim: true) - - url - end -end diff --git a/test/pleroma/repo_test.exs b/test/pleroma/repo_test.exs index 721175bda..9c0f5d028 100644 --- a/test/pleroma/repo_test.exs +++ b/test/pleroma/repo_test.exs @@ -24,8 +24,7 @@ defmodule Pleroma.RepoTest do describe "get_assoc/2" do test "get assoc from preloaded data" do user = %User{name: "Agent Smith"} - %Pleroma.Web.OAuth.Token{} = token = insert(:oauth_token) - token = %{token | user: user} + token = %Pleroma.Web.OAuth.Token{insert(:oauth_token) | user: user} assert Repo.get_assoc(token, :user) == {:ok, user} end diff --git a/test/pleroma/reverse_proxy_test.exs b/test/pleroma/reverse_proxy_test.exs index ec4470379..8dbe9c6bf 100644 --- a/test/pleroma/reverse_proxy_test.exs +++ b/test/pleroma/reverse_proxy_test.exs @@ -294,7 +294,7 @@ defmodule Pleroma.ReverseProxyTest do |> expect(:stream_body, fn _ -> :done end) conn = ReverseProxy.call(conn, "/cache") - assert {"cache-control", "public, max-age=1209600, immutable"} in conn.resp_headers + assert {"cache-control", "public, max-age=1209600"} in conn.resp_headers end end diff --git a/test/pleroma/search/meilisearch_test.exs b/test/pleroma/search/meilisearch_test.exs index ff32491c5..eea454323 100644 --- a/test/pleroma/search/meilisearch_test.exs +++ b/test/pleroma/search/meilisearch_test.exs @@ -74,6 +74,29 @@ defmodule Pleroma.Search.MeilisearchTest do assert_received("posted_to_meilisearch") end + test "doesn't index posts that are not public" do + user = insert(:user) + + Enum.each(["private", "direct"], fn visibility -> + {:ok, activity} = + CommonAPI.post(user, %{ + status: "guys i just don't wanna leave the swamp", + visibility: visibility + }) + + args = %{"op" => "add_to_index", "activity" => activity.id} + + Config + |> expect(:get, fn + [Pleroma.Search, :module], nil -> + Meilisearch + end) + + assert_enqueued(worker: SearchIndexingWorker, args: args) + assert :ok = perform_job(SearchIndexingWorker, args) + end) + end + test "deletes posts from index when deleted locally" do user = insert(:user) diff --git a/test/pleroma/search_test.exs b/test/pleroma/search_test.exs deleted file mode 100644 index d777bcda2..000000000 --- a/test/pleroma/search_test.exs +++ /dev/null @@ -1,69 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.SearchTest do - use Pleroma.DataCase, async: true - use Oban.Testing, repo: Pleroma.Repo - - import Pleroma.Factory - - alias Pleroma.Web.CommonAPI - alias Pleroma.Workers.SearchIndexingWorker - - test "indexes posts that are public" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Well this is a story all about how my life got flipped turned upside down", - visibility: "public" - }) - - args = %{"op" => "add_to_index", "activity" => activity.id} - - assert_enqueued(worker: SearchIndexingWorker, args: args) - end - - test "doesn't index posts that are not public" do - user = insert(:user) - - Enum.each(["private", "direct"], fn visibility -> - {:ok, activity} = - CommonAPI.post(user, %{ - status: "guys i just don't wanna leave the swamp", - visibility: visibility - }) - - args = %{"op" => "add_to_index", "activity" => activity.id} - - refute_enqueued(worker: SearchIndexingWorker, args: args) - end) - end - - test "Indexes appropriate activity types" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "I'm my own hype man", - visibility: "public" - }) - - args = %{"op" => "add_to_index", "activity" => activity.id} - - assert_enqueued(worker: SearchIndexingWorker, args: args) - - {:ok, fav_activity} = CommonAPI.favorite(activity.id, user) - - args = %{"op" => "add_to_index", "activity" => fav_activity.id} - - refute_enqueued(worker: SearchIndexingWorker, args: args) - - {:ok, repeat_activity} = CommonAPI.repeat(activity.id, user) - - args = %{"op" => "add_to_index", "activity" => repeat_activity.id} - - refute_enqueued(worker: SearchIndexingWorker, args: args) - end -end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index de735cdb7..b2533e9f1 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -876,17 +876,17 @@ defmodule Pleroma.UserTest do describe "get_or_fetch/1 remote users with tld, while BE is running on a subdomain" do setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true) - test "fetches a mastodon split-domain nickname" do - nickname = "a@mastodon.example" - {:ok, fetched_user} = User.get_or_fetch(nickname) + test "for mastodon" do + ap_id = "a@mastodon.example" + {:ok, fetched_user} = User.get_or_fetch(ap_id) assert fetched_user.ap_id == "https://sub.mastodon.example/users/a" assert fetched_user.nickname == "a@mastodon.example" end - test "fetches a pleroma split-domain nickname" do - nickname = "a@pleroma.example" - {:ok, fetched_user} = User.get_or_fetch(nickname) + test "for pleroma" do + ap_id = "a@pleroma.example" + {:ok, fetched_user} = User.get_or_fetch(ap_id) assert fetched_user.ap_id == "https://sub.pleroma.example/users/a" assert fetched_user.nickname == "a@pleroma.example" @@ -936,89 +936,6 @@ defmodule Pleroma.UserTest do assert fetched_user == "not found nonexistent" end - test "does not rename an existing remote actor from rogue WebFinger data" do - clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true) - - actor_id = "https://legit-actor.example/users/alice" - - Tesla.Mock.mock(fn - %{url: "https://evil-webfinger.example/.well-known/host-meta"} -> - {:ok, %Tesla.Env{status: 404}} - - %{ - url: - "https://evil-webfinger.example/.well-known/webfinger?resource=acct:claimed@evil-webfinger.example" - } -> - Tesla.Mock.json(%{ - "subject" => "acct:claimed@evil-webfinger.example", - "links" => [ - %{ - "rel" => "self", - "type" => "application/activity+json", - "href" => actor_id - } - ] - }) - - %{url: ^actor_id} -> - {:ok, - %Tesla.Env{ - status: 200, - headers: [{"content-type", "application/activity+json"}], - body: - Jason.encode!(%{ - "id" => actor_id, - "type" => "Person", - "preferredUsername" => "alice", - "name" => "Alice", - "summary" => "", - "inbox" => "https://legit-actor.example/users/alice/inbox", - "outbox" => "https://legit-actor.example/users/alice/outbox", - "followers" => "https://legit-actor.example/users/alice/followers", - "following" => "https://legit-actor.example/users/alice/following" - }) - }} - - %{url: "https://legit-actor.example/.well-known/host-meta"} -> - {:ok, %Tesla.Env{status: 404}} - - %{ - url: - "https://legit-actor.example/.well-known/webfinger?resource=acct:alice@legit-actor.example" - } -> - Tesla.Mock.json(%{ - "subject" => "acct:alice@legit-actor.example", - "links" => [ - %{ - "rel" => "self", - "type" => "application/activity+json", - "href" => actor_id - } - ] - }) - end) - - assert {:error, {:webfinger_actor_mismatch, "claimed@evil-webfinger.example", ^actor_id}} = - ActivityPub.make_user_from_nickname("claimed@evil-webfinger.example") - - refute User.get_by_ap_id(actor_id) - refute User.get_by_nickname("claimed@evil-webfinger.example") - - orig_user = - insert(:user, - local: false, - nickname: "alice@legit-actor.example", - ap_id: actor_id - ) - - assert {:error, {:webfinger_actor_mismatch, "claimed@evil-webfinger.example", ^actor_id}} = - ActivityPub.make_user_from_nickname("claimed@evil-webfinger.example") - - assert {:error, _} = User.get_or_fetch_by_nickname("claimed@evil-webfinger.example") - assert User.get_by_id(orig_user.id).nickname == "alice@legit-actor.example" - refute User.get_by_nickname("claimed@evil-webfinger.example") - end - test "updates an existing user, if stale" do a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800) diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index 3988c3912..d5947186f 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -19,7 +19,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do alias Pleroma.Web.CommonAPI alias Pleroma.Web.Endpoint alias Pleroma.Workers.ReceiverWorker - alias Pleroma.Workers.SignatureRetryWorker import Pleroma.Factory @@ -37,36 +36,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do setup do: clear_config([:instance, :federating], true) - defp assign_valid_signature_for_actor(conn, %User{ap_id: actor_id}) do - assign_valid_signature_for_actor(conn, actor_id) - end - - defp assign_valid_signature_for_actor(conn, actor) do - actor_id = Utils.get_ap_id(actor) - - conn - |> assign(:valid_signature, true) - |> put_req_header("signature", "keyId=\"#{actor_id}#main-key\"") - end - - defp expect_signature_retry_from(%User{} = signer) do - signer_json = UserView.render("user.json", %{user: signer}) |> Map.delete("featured") - - Tesla.Mock.mock(fn - %{url: url} when url == signer.ap_id -> - %Tesla.Env{ - status: 200, - body: Jason.encode!(signer_json), - headers: HttpRequestMock.activitypub_object_headers() - } - - env -> - apply(HttpRequestMock, :request, [env]) - end) - - Mox.expect(Pleroma.StubbedHTTPSignaturesMock, :validate_conn, fn _conn -> true end) - end - describe "/relay" do setup do: clear_config([:instance, :allow_relay]) @@ -719,7 +688,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) @@ -747,7 +716,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) @@ -757,199 +726,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Activity.get_by_ap_id(data["id"]) end - test "does not create a forged post after failed signature retry", %{conn: conn} do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - object_id = "https://two.com/objects/inbox-forged-note" - - data = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/inbox-forged-create", - "context" => "https://two.com/contexts/inbox-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => object_id, - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "context" => "https://two.com/contexts/inbox-forged-create", - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - expect_signature_retry_from(alice) - - conn = - conn - |> assign(:valid_signature, false) - |> put_req_header("content-type", "application/activity+json") - |> put_req_header("signature", "keyId=\"https://one.com/users/alice#main-key\"") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - - assert [{:cancel, :actor_signature_mismatch}] = - ObanHelpers.perform(all_enqueued(worker: SignatureRetryWorker)) - - refute Activity.get_by_ap_id(data["id"]) - refute Object.get_by_ap_id(object_id) - end - - test "does not create a forged like after failed signature retry", %{conn: conn} do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - - data = %{ - "type" => "Like", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/inbox-forged-like", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data["id"] - } - - expect_signature_retry_from(alice) - - conn = - conn - |> assign(:valid_signature, false) - |> put_req_header("content-type", "application/activity+json") - |> put_req_header("signature", "keyId=\"https://one.com/users/alice#main-key\"") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - - assert [{:cancel, :actor_signature_mismatch}] = - ObanHelpers.perform(all_enqueued(worker: SignatureRetryWorker)) - - refute Activity.get_by_ap_id(data["id"]) - end - - test "does not delete an object after failed signature retry", %{conn: conn} do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - object_id = note.data["id"] - - data = %{ - "type" => "Delete", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/inbox-forged-delete", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => object_id - } - - expect_signature_retry_from(alice) - - conn = - conn - |> assign(:valid_signature, false) - |> put_req_header("content-type", "application/activity+json") - |> put_req_header("signature", "keyId=\"https://one.com/users/alice#main-key\"") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - - assert [{:cancel, :actor_signature_mismatch}] = - ObanHelpers.perform(all_enqueued(worker: SignatureRetryWorker)) - - refute Activity.get_by_ap_id(data["id"]) - assert %Object{data: %{"type" => "Note"}} = Object.get_by_ap_id(object_id) - end - - test "does not create a forged post signed by a different actor", %{conn: conn} do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - object_id = "https://two.com/objects/inbox-signed-forged-note" - - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/inbox-signed-forged-create", - "context" => "https://two.com/contexts/inbox-signed-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => object_id, - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "context" => "https://two.com/contexts/inbox-signed-forged-create", - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - expect_signature_retry_from(alice) - - conn = - conn - |> put_req_header("content-type", "application/activity+json") - |> put_req_header("date", "Thu, 25 Jul 2024 13:33:31 GMT") - |> put_req_header("digest", "SHA-256=fake-digest") - |> put_req_header( - "signature", - "keyId=\"#{alice.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\"" - ) - |> post("/inbox", data) - - assert conn.assigns.valid_signature == false - assert "ok" == json_response(conn, 200) - - assert [{:cancel, :actor_signature_mismatch}] = - ObanHelpers.perform(all_enqueued(worker: SignatureRetryWorker)) - - refute Activity.get_by_ap_id(data["id"]) - refute Object.get_by_ap_id(object_id) - end - - test "does not create a forged like signed by a different actor", %{conn: conn} do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Like", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/inbox-signed-forged-like", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data["id"] - } - - expect_signature_retry_from(alice) - - conn = - conn - |> put_req_header("content-type", "application/activity+json") - |> put_req_header("date", "Thu, 25 Jul 2024 13:33:31 GMT") - |> put_req_header("digest", "SHA-256=fake-digest") - |> put_req_header( - "signature", - "keyId=\"#{alice.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\"" - ) - |> post("/inbox", data) - - assert conn.assigns.valid_signature == false - assert "ok" == json_response(conn, 200) - - assert [{:cancel, :actor_signature_mismatch}] = - ObanHelpers.perform(all_enqueued(worker: SignatureRetryWorker)) - - refute Activity.get_by_ap_id(data["id"]) - end - test "accept follow activity", %{conn: conn} do clear_config([:instance, :federating], true) relay = Relay.get_actor() @@ -966,7 +742,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == conn - |> assign_valid_signature_for_actor(followed_relay) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", accept) |> json_response(200) @@ -1046,19 +822,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "Unknown activity types are discarded", %{conn: conn} do unknown_types = ["Poke", "Read", "Dazzle"] - actor = - insert(:user, local: false, ap_id: "https://unknown.mastodon.instance/users/somebody") - Enum.each(unknown_types, fn bad_type -> params = %{ "type" => bad_type, - "actor" => actor.ap_id + "actor" => "https://unknown.mastodon.instance/users/somebody" } |> Jason.encode!() conn - |> assign_valid_signature_for_actor(actor) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", params) |> json_response(400) @@ -1127,7 +900,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) |> json_response(200) @@ -1148,7 +921,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) |> json_response(200) @@ -1217,7 +990,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) |> json_response(200) @@ -1236,7 +1009,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/inbox", data) |> json_response(200) @@ -1267,7 +1040,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1288,7 +1061,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1309,7 +1082,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1333,7 +1106,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1360,7 +1133,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1390,7 +1163,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{recipient.nickname}/inbox", data) @@ -1455,7 +1228,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do } conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{recipient.nickname}/inbox", data) |> json_response(200) @@ -1545,7 +1318,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do } conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{reported_user.nickname}/inbox", data) |> json_response(200) @@ -1599,7 +1372,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do } conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{reported_user.nickname}/inbox", data) |> json_response(200) @@ -1632,7 +1405,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1655,7 +1428,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -1678,7 +1451,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do conn = conn - |> assign_valid_signature_for_actor(data["actor"]) + |> assign(:valid_signature, true) |> put_req_header("content-type", "application/activity+json") |> post("/users/#{user.nickname}/inbox", data) @@ -2798,8 +2571,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do setup do: clear_config([:media_proxy]) setup do: clear_config([Pleroma.Upload]) - # majic's libmagic port is unavailable on local Darwin runs; Linux CI still runs this test. - @tag :skip_darwin test "POST /api/ap/upload_media", %{conn: conn} do user = insert(:user) diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 9aafc41a5..73f53db56 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -499,35 +499,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do "https://queef.in/storage/banner.gif" end - test "works with alsoKnownAs as string" do - user_id = "https://hub.netzgemeinde.eu/channel/jupiter_rowland" - - user_data = - "test/fixtures/users_mock/hubzilla-actor-alsoknownas-string.json" - |> File.read!() - - user_data_decoded = - user_data - |> Jason.decode!() - - Tesla.Mock.mock(fn - %{ - method: :get, - url: ^user_id - } -> - %Tesla.Env{ - status: 200, - body: user_data, - headers: [{"content-type", "application/activity+json"}] - } - end) - - {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) - - assert is_list(user.also_known_as) - assert user.also_known_as == [user_data_decoded["alsoKnownAs"]] - end - test "it fetches the appropriate tag-restricted posts" do user = insert(:user) @@ -1524,8 +1495,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do %{test_file: test_file} end - test "strips / from filename", %{test_file: %Plug.Upload{} = file} do - file = %{file | filename: "../../../../../nested/bad.jpg"} + test "strips / from filename", %{test_file: file} do + file = %Plug.Upload{file | filename: "../../../../../nested/bad.jpg"} {:ok, %Object{} = object} = ActivityPub.upload(file) [%{"href" => href}] = object.data["url"] assert Regex.match?(~r"/bad.jpg$", href) @@ -1783,14 +1754,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do test "fetch_activities/2 returns activities addressed to a list " do user = insert(:user) member = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, list} = Pleroma.List.follow(list, member) - {:ok, %Activity{} = activity} = - CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) + {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) activity = Repo.preload(activity, :bookmark) - activity = %{activity | thread_muted?: !!activity.thread_muted?} + activity = %Activity{activity | thread_muted?: !!activity.thread_muted?} assert ActivityPub.fetch_activities([], %{user: user}) == [activity] end @@ -1990,7 +1960,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert User.following?(follower, old_user) assert User.following?(follower_move_opted_out, old_user) - assert {:ok, %Activity{} = activity} = ActivityPub.move(old_user, new_user) + assert {:ok, activity} = ActivityPub.move(old_user, new_user) assert %Activity{ actor: ^old_ap_id, @@ -2022,7 +1992,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert User.following?(follower_move_opted_out, old_user) refute User.following?(follower_move_opted_out, new_user) - activity = %{activity | object: nil} + activity = %Activity{activity | object: nil} assert [%Notification{activity: ^activity}] = Notification.for_user(follower) diff --git a/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs index e231f88a8..32991c966 100644 --- a/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicyTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["object"]["sensitive"] end @@ -94,7 +94,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicyTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "#cofe hey"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) refute modified["object"]["sensitive"] end diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index 2d0f3b317..25548e3da 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -10,25 +10,18 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do alias Pleroma.Web.ActivityPub.MRF - defp regexes_match!([], []), do: true - - defp regexes_match!([authority | authority_rest], [checked | checked_rest]) do - authority.source == checked.source and regexes_match!(authority_rest, checked_rest) - end - - defp regexes_match!(_, _), do: false - test "subdomains_regex/1" do - regexes = MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) - - assert regexes_match!(regexes, [~r/^unsafe.tld$/i, ~r/^(.*\.)*unsafe.tld$/i]) + assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [ + ~r/^unsafe.tld$/i, + ~r/^(.*\.)*unsafe.tld$/i + ] end describe "subdomain_match/2" do test "common domains" do regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"]) - assert regexes_match!(regexes, [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i]) + assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "unsafe2.tld") @@ -39,7 +32,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "wildcard domains with one subdomain" do regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - assert regexes_match!(regexes, [~r/^(.*\.)*unsafe.tld$/i]) + assert regexes == [~r/^(.*\.)*unsafe.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.unsafe.tld") @@ -50,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "wildcard domains with two subdomains" do regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - assert regexes_match!(regexes, [~r/^(.*\.)*unsafe.tld$/i]) + assert regexes == [~r/^(.*\.)*unsafe.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld") @@ -61,7 +54,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "matches are case-insensitive" do regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"]) - assert regexes_match!(regexes, [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i]) + assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i] assert MRF.subdomain_match?(regexes, "UNSAFE.TLD") assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD") diff --git a/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs index 1ca4f04f6..5b2fcb26d 100644 --- a/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs @@ -86,32 +86,23 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidationTest do object = Object.normalize(post_activity, fetch: false) # Another user can't announce it - {:ok, announce, []} = Builder.announce(announcer, object, visibility: "private") + {:ok, announce, []} = Builder.announce(announcer, object, public: false) {:error, cng} = ObjectValidator.validate(announce, []) assert {:actor, {"can not announce this object", []}} in cng.errors - # The actor of the object can announce it with a restrictive scope - {:ok, announce, []} = Builder.announce(user, object, visibility: "private") - assert {:ok, _, _} = ObjectValidator.validate(announce, []) + # The actor of the object can announce it + {:ok, announce, []} = Builder.announce(user, object, public: false) - {:ok, announce, []} = Builder.announce(user, object, visibility: "direct") assert {:ok, _, _} = ObjectValidator.validate(announce, []) # The actor of the object can not announce it publicly - {:ok, announce, []} = Builder.announce(user, object, visibility: "public") - {:error, cng1} = ObjectValidator.validate(announce, []) + {:ok, announce, []} = Builder.announce(user, object, public: true) - {:ok, announce, []} = Builder.announce(user, object, visibility: "unlisted") - {:error, cng2} = ObjectValidator.validate(announce, []) + {:error, cng} = ObjectValidator.validate(announce, []) - {:ok, announce, []} = Builder.announce(user, object, visibility: "local") - {:error, cng3} = ObjectValidator.validate(announce, []) - - for cng <- [cng1, cng2, cng3] do - assert {:actor, {"can not announce this object publicly", []}} in cng.errors - end + assert {:actor, {"can not announce this object publicly", []}} in cng.errors end end end diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index bf9c70fb6..3c7ff0eeb 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -67,7 +67,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest {:ok, edit} = Pleroma.Web.CommonAPI.update(activity, user, %{status: "edited :blank:"}) {:ok, %{"object" => external_rep}} = - Pleroma.Web.ActivityPub.Transmogrifier.prepare_activity(edit.data) + Pleroma.Web.ActivityPub.Transmogrifier.prepare_outgoing(edit.data) %{external_rep: external_rep} end @@ -149,171 +149,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) end - test "a Misskey MFM note is rendered from source content" do - user = insert(:user, ap_id: "https://misskey.example/users/alice") - - note = %{ - "id" => "https://misskey.example/notes/1", - "type" => "Note", - "actor" => user.ap_id, - "attributedTo" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => "original content", - "context" => Utils.generate_context_id(), - "source" => %{ - "content" => "$[spin.speed=1s mfm goes here] ", - "mediaType" => "text/x.misskeymarkdown" - } - } - - %{valid?: true, changes: %{content: content, source: source}} = - ArticleNotePageValidator.cast_and_validate(note) - - assert source["mediaType"] == "text/x.misskeymarkdown" - assert content =~ ~s(class="mfm-spin") - assert content =~ ~s(data-mfm-speed="1s") - assert content =~ "mfm goes here" - refute content =~ "original content" - refute content =~ " "https://misskey.example/notes/3", - "type" => "Note", - "actor" => remote_user.ap_id, - "attributedTo" => remote_user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => "original content", - "context" => Utils.generate_context_id(), - "tag" => [ - %{ - "type" => "Mention", - "name" => "@local_user", - "href" => local_user.ap_id - }, - %{ - "type" => "Mention", - "name" => "@uncached", - "href" => "https://misskey.example/users/uncached" - } - ], - "source" => %{ - "content" => "@local_user @uncached $[spin hello]", - "mediaType" => "text/x.misskeymarkdown" - } - } - - %{valid?: true, changes: %{content: content}} = - ArticleNotePageValidator.cast_and_validate(note) - - assert content =~ local_user.ap_id - assert content =~ "@uncached" - end - - test "a Misskey MFM note drops oversized source content instead of parsing it" do - user = insert(:user, ap_id: "https://misskey.example/users/oversized") - - note = %{ - "id" => "https://misskey.example/notes/4", - "type" => "Note", - "actor" => user.ap_id, - "attributedTo" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => "safe fallback", - "context" => Utils.generate_context_id(), - "source" => %{ - "content" => String.duplicate("x", 5_001), - "mediaType" => "text/x.misskeymarkdown" - } - } - - %{valid?: true, changes: %{content: content, source: source}} = - ArticleNotePageValidator.cast_and_validate(note) - - assert content == "safe fallback" - refute Map.has_key?(source, "content") - end - - test "a note drops oversized non-MFM source content" do - user = insert(:user, ap_id: "https://example.com/users/source") - - note = %{ - "id" => "https://example.com/notes/1", - "type" => "Note", - "actor" => user.ap_id, - "attributedTo" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => "regular content", - "context" => Utils.generate_context_id(), - "source" => %{ - "content" => String.duplicate("x", 5_001), - "mediaType" => "text/markdown" - } - } - - %{valid?: true, changes: %{source: source}} = ArticleNotePageValidator.cast_and_validate(note) - - assert source == %{"mediaType" => "text/markdown"} - end - - test "a Misskey MFM note with legacy _misskey_content is rendered" do - user = insert(:user, ap_id: "https://misskey.example/users/legacy") - - note = %{ - "id" => "https://misskey.example/notes/5", - "type" => "Note", - "actor" => user.ap_id, - "attributedTo" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => "original content", - "context" => Utils.generate_context_id(), - "_misskey_content" => "$[spin legacy]" - } - - %{valid?: true, changes: %{content: content, source: source}} = - ArticleNotePageValidator.cast_and_validate(note) - - assert source == %{"content" => "$[spin legacy]", "mediaType" => "text/x.misskeymarkdown"} - assert content =~ ~s(class="mfm-spin") - assert content =~ "legacy" - end - - test "a Misskey MFM note with htmlMfm is scrubbed but not rendered from source content" do - user = insert(:user, ap_id: "https://misskey.example/users/bob") - - note = %{ - "id" => "https://misskey.example/notes/2", - "type" => "Note", - "actor" => user.ap_id, - "attributedTo" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "content" => - "already rendered", - "htmlMfm" => true, - "context" => Utils.generate_context_id(), - "source" => %{ - "content" => String.duplicate("x", 5_001), - "mediaType" => "text/x.misskeymarkdown" - } - } - - %{valid?: true, changes: %{content: content, htmlMfm: true, source: source}} = - ArticleNotePageValidator.cast_and_validate(note) - - assert content == "already renderedalert('xss')" - refute Map.has_key?(source, "content") - end - test "a Note with validated likes collection validates" do insert(:user, ap_id: "https://pol.social/users/mkljczk") diff --git a/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs index 9dec315b3..c88339d14 100644 --- a/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs @@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do assert {:ok, _update, []} = ObjectValidator.validate(valid_update, []) end - test "returns an error if the object can't be updated by the actor (different domain)", %{ + test "returns an error if the object can't be updated by the actor", %{ valid_update: valid_update } do other_user = insert(:user, local: false) @@ -41,72 +41,27 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do assert {:error, _cng} = ObjectValidator.validate(update, []) end - test "returns an error if the object can't be updated by the actor (same domain)", %{ - user: user, + test "validates as long as the object is same-origin with the actor", %{ valid_update: valid_update } do - user_ap_id = user.ap_id - user_domain = URI.parse(user_ap_id).host - other_user = insert(:user, local: false, domain: user_domain) + other_user = insert(:user) update = valid_update |> Map.put("actor", other_user.ap_id) - assert {:error, _cng} = ObjectValidator.validate(update, []) + assert {:ok, _update, []} = ObjectValidator.validate(update, []) end - test "validates if the object is not of an Actor type", %{user: user} do - note = insert(:note, user: user) + test "validates if the object is not of an Actor type" do + note = insert(:note) updated_note = note.data |> Map.put("content", "edited content") + other_user = insert(:user) - {:ok, update, _} = Builder.update(user, updated_note) + {:ok, update, _} = Builder.update(other_user, updated_note) assert {:ok, _update, _} = ObjectValidator.validate(update, []) end - - test "returns an error if the remote update target is unknown" do - remote_user = insert(:user, local: false, ap_id: "https://example.com/users/alice") - - update = %{ - "type" => "Update", - "actor" => remote_user.ap_id, - "id" => "https://example.com/activities/update-unknown-object", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://example.com/objects/unknown", - "actor" => remote_user.ap_id, - "content" => "edited content", - "published" => "2024-07-25T13:33:31Z", - "updated" => "2024-07-25T13:34:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert {:error, %Ecto.Changeset{} = cng} = ObjectValidator.validate(update, local: false) - refute cng.valid? - assert Keyword.has_key?(cng.errors, :object) - end - - test "returns an error if the remote update target IRI is unknown" do - remote_user = insert(:user, local: false, ap_id: "https://example.com/users/alice") - - update = %{ - "type" => "Update", - "actor" => remote_user.ap_id, - "id" => "https://example.com/activities/update-unknown-object-iri", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => "https://example.com/objects/unknown-iri" - } - - assert {:error, %Ecto.Changeset{} = cng} = ObjectValidator.validate(update, local: false) - refute cng.valid? - assert Keyword.has_key?(cng.errors, :object) - end end describe "update note" do @@ -178,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do user = insert(:user) {:ok, activity} = Pleroma.Web.CommonAPI.post(user, %{status: "mew mew :dinosaur:"}) {:ok, edit} = Pleroma.Web.CommonAPI.update(activity, user, %{status: "edited :blank:"}) - {:ok, external_rep} = Pleroma.Web.ActivityPub.Transmogrifier.prepare_activity(edit.data) + {:ok, external_rep} = Pleroma.Web.ActivityPub.Transmogrifier.prepare_outgoing(edit.data) %{external_rep: external_rep} end diff --git a/test/pleroma/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs index 447ffda1b..1f9e0bfe5 100644 --- a/test/pleroma/web/activity_pub/publisher_test.exs +++ b/test/pleroma/web/activity_pub/publisher_test.exs @@ -259,7 +259,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do ) end - test "Publishes with the new actor if prepare_activity changes the actor." do + test "Publishes with the new actor if prepare_outgoing changes the actor." do mock(fn %{method: :post, url: "https://domain.com/users/nick1/inbox", body: body} -> {:ok, %Tesla.Env{status: 200, body: body}} @@ -281,7 +281,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do ) Pleroma.Web.ActivityPub.TransmogrifierMock - |> Mox.expect(:prepare_activity, fn data -> + |> Mox.expect(:prepare_outgoing, fn data -> {:ok, Map.put(data, "actor", replaced_actor.ap_id)} end) @@ -334,7 +334,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do test "activity with BCC is published to a list member." do actor = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "list"}, actor) + {:ok, list} = Pleroma.List.create("list", actor) list_member = insert(:user, %{local: false}) Pleroma.List.follow(list, list_member) diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index 6d20c591c..4a18cab68 100644 --- a/test/pleroma/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -784,15 +784,13 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"}) - {:ok, announce_data, _meta} = Builder.announce(user, post.object, visibility: "public") + {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true) {:ok, private_announce_data, _meta} = - Builder.announce(user, private_post.object, visibility: "private") + Builder.announce(user, private_post.object, public: false) {:ok, relay_announce_data, _meta} = - Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, - visibility: "public" - ) + Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true) {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true) {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true) diff --git a/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs index 913d143a5..39a1598a8 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs @@ -72,7 +72,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do |> Kernel.put_in(["object", "to"], user.ap_id) {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - {:ok, data} = Transmogrifier.prepare_activity(activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) assert data["object"]["type"] == "Note" end diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index 31b9a699d..403c98a2d 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -508,7 +508,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do {:ok, activity} = Transmogrifier.handle_incoming(message) - {:ok, _} = Transmogrifier.prepare_activity(activity.data) + {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) end test "successfully reserializes a message with AS2 objects in IR" do @@ -537,7 +537,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do {:ok, activity} = Transmogrifier.handle_incoming(message) - {:ok, _} = Transmogrifier.prepare_activity(activity.data) + {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) end end diff --git a/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs index 2a4e78cf0..d31070546 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs @@ -170,23 +170,4 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do assert {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) end - - test "it displays voters count for a poll" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "???", - poll: %{expires_in: 10, options: ["yes", "no"]} - }) - - object = Object.normalize(activity, fetch: false) - {:ok, _, _} = CommonAPI.vote(object, other_user, [1]) - - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) - - refute Map.has_key?(modified["object"], "voters") - assert modified["object"]["votersCount"] == 1 - end end diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs index c1e01557d..b54196a3c 100644 --- a/test/pleroma/web/activity_pub/transmogrifier_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs @@ -433,7 +433,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) - {:ok, modified} = Transmogrifier.prepare_activity(announce_activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) assert modified["object"]["content"] == "hey" assert modified["object"]["actor"] == modified["object"]["attributedTo"] @@ -448,7 +448,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do with_mock Pleroma.Notification, get_notified_from_activity: fn _, _ -> [] end do - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) object = modified["object"] @@ -474,7 +474,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["@context"] == Utils.make_json_ld_header()["@context"] @@ -485,7 +485,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["object"]["actor"] == modified["object"]["attributedTo"] end @@ -501,7 +501,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do "name" => "#2hu" } - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["object"]["tag"] == [expected_tag] end @@ -524,7 +524,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do url: "https://pleroma.social" } == activity.object.data["generator"] - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert length(modified["object"]["tag"]) == 2 @@ -541,7 +541,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do test "it strips internal fields of article" do activity = insert(:article_activity) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert length(modified["object"]["tag"]) == 2 @@ -558,13 +558,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["directMessage"] == false {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["directMessage"] == false @@ -574,18 +574,18 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do visibility: "direct" }) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert modified["directMessage"] == true end test "it strips BCC field" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert is_nil(modified["bcc"]) end @@ -594,7 +594,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do listen_activity = insert(:listen) # This has an inlined object as in ObjectView - {:ok, modified} = Transmogrifier.prepare_activity(listen_activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) assert modified["type"] == "Listen" @@ -610,7 +610,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do object_type = activity.object.data["type"] # This does not have an inlined object - {:ok, modified2} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified2} = Transmogrifier.prepare_outgoing(activity.data) assert match?( %{ @@ -640,7 +640,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, activity} = CommonAPI.post(user, %{status: "everybody do the dinosaur :dinosaur:"}) - {:ok, prepared} = Transmogrifier.prepare_activity(activity.data) + {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data) assert length(prepared["object"]["tag"]) == 1 @@ -655,7 +655,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, activity} = CommonAPI.post(user, %{status: "everybody do the dinosaur :dinosaur:"}) {:ok, update} = CommonAPI.update(activity, user, %{status: "mew mew :blank:"}) - {:ok, prepared} = Transmogrifier.prepare_activity(update.data) + {:ok, prepared} = Transmogrifier.prepare_outgoing(update.data) assert %{ "content" => "mew mew :blank:", @@ -689,7 +689,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user_update_changeset: changeset ) - assert {:ok, prepared} = Transmogrifier.prepare_activity(activity.data) + assert {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data) assert prepared["type"] == "Update" assert prepared["@context"] assert prepared["object"]["type"] == user.actor_type @@ -704,7 +704,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, %Activity{} = block_activity} = CommonAPI.block(blocked, blocker) {:ok, %Activity{} = undo_activity} = CommonAPI.unblock(blocked, blocker) - {:ok, data} = Transmogrifier.prepare_activity(undo_activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(undo_activity.data) block_ap_id = block_activity.data["id"] assert is_binary(block_ap_id) @@ -738,7 +738,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do assert is_binary(note_ap_id) {:ok, react_activity} = CommonAPI.react_with_emoji(note_activity.id, user, "🐈") - {:ok, data} = Transmogrifier.prepare_activity(react_activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(react_activity.data) assert match?( %{ @@ -764,7 +764,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do note_activity = insert(:note_activity) {:ok, react_activity} = CommonAPI.react_with_emoji(note_activity.id, user, ":dinosaur:") - {:ok, data} = Transmogrifier.prepare_activity(react_activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(react_activity.data) assert length(data["tag"]) == 1 @@ -781,7 +781,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do {:ok, quoted_post} = CommonAPI.post(user, %{status: "hey"}) {:ok, quote_post} = CommonAPI.post(user, %{status: "hey", quoted_status_id: quoted_post.id}) - {:ok, modified} = Transmogrifier.prepare_activity(quote_post.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(quote_post.data) %{data: %{"id" => quote_id}} = Object.normalize(quoted_post) @@ -793,7 +793,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.object.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.object.data) assert [_, _, %{"@language" => "pl"}] = modified["@context"] end @@ -802,7 +802,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "Cześć", language: "pl"}) - {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) assert [_, _, %{"@language" => "pl"}] = modified["@context"] end @@ -825,7 +825,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do content: content }) - {:ok, data} = Transmogrifier.prepare_activity(activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) expected_data = activity.data @@ -859,7 +859,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do clear_config([:activitypub, :anonymize_reporter], true) clear_config([:activitypub, :anonymize_reporter_local_nickname], placeholder.nickname) - {:ok, data} = Transmogrifier.prepare_activity(activity.data) + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) expected_data = activity.data diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs index 93234a015..f162f3684 100644 --- a/test/pleroma/web/activity_pub/utils_test.exs +++ b/test/pleroma/web/activity_pub/utils_test.exs @@ -180,8 +180,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do "https://www.w3.org/ns/activitystreams", "http://localhost:4001/schemas/litepub-0.1.jsonld", %{ - "@language" => "und", - "htmlMfm" => "https://w3id.org/fep/c16b#htmlMfm" + "@language" => "und" } ] } @@ -193,8 +192,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do "https://www.w3.org/ns/activitystreams", "http://localhost:4001/schemas/litepub-0.1.jsonld", %{ - "@language" => "pl", - "htmlMfm" => "https://w3id.org/fep/c16b#htmlMfm" + "@language" => "pl" } ] } @@ -673,19 +671,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do end end - describe "assign_report_to_account/2" do - test "assigns report to an account" do - reporter = insert(:user) - target_account = insert(:user) - %{id: assigned_id} = insert(:user) - - {:ok, report} = CommonAPI.report(reporter, %{account_id: target_account.id}) - {:ok, report} = Utils.assign_report_to_account(report, assigned_id) - - assert %{data: %{"assigned_account" => ^assigned_id}} = report - end - end - describe "maybe_anonymize_reporter/1" do setup do reporter = insert(:user) diff --git a/test/pleroma/web/activity_pub/visibility_test.exs b/test/pleroma/web/activity_pub/visibility_test.exs index f92f2df16..fd3dc83a1 100644 --- a/test/pleroma/web/activity_pub/visibility_test.exs +++ b/test/pleroma/web/activity_pub/visibility_test.exs @@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do following = insert(:user) unrelated = insert(:user) {:ok, following, user} = Pleroma.User.follow(following, user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) Pleroma.List.follow(list, unrelated) diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs index e62d95fad..e12115ea1 100644 --- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs @@ -194,16 +194,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do setup do: clear_config(:configurable_from_database, true) - setup do: - clear_config(:database_config_whitelist, [ - {:pleroma}, - {:http}, - {:idna}, - {:oban}, - {:tesla}, - {:ueberauth} - ]) - test "create new config setting in db", %{conn: conn} do ueberauth = Application.get_env(:ueberauth, Ueberauth) on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) @@ -817,7 +807,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "tuple" => [ "/websocket", - ":sth", + "Phoenix.Endpoint.CowboyWebSocket", %{ "tuple" => [ "Phoenix.Transports.WebSocket", @@ -881,7 +871,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do %{ "tuple" => [ "/websocket", - ":sth", + "Phoenix.Endpoint.CowboyWebSocket", %{ "tuple" => [ "Phoenix.Transports.WebSocket", @@ -1220,31 +1210,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do assert Application.get_env(:not_real, :anything) == "value6" end - test "doesn't allow updating the database_config_whitelist itself", %{conn: conn} do - original_whitelist = Pleroma.Config.get(:database_config_whitelist) - - refute ConfigDB.get_by_group_and_key(:pleroma, :database_config_whitelist) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":database_config_whitelist", - value: [%{"tuple" => [":pleroma", ":key1"]}] - } - ] - }) - - %{"configs" => configs} = json_response_and_validate_schema(conn, 200) - - assert configs == [] - assert Pleroma.Config.get(:database_config_whitelist) == original_whitelist - refute ConfigDB.get_by_group_and_key(:pleroma, :database_config_whitelist) - end - test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do assert conn |> put_req_header("content-type", "application/json") @@ -1507,13 +1472,5 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) assert web_endpoint["children"] end - - test "all keys from description are whitelisted", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/config/descriptions") - - assert response = json_response_and_validate_schema(conn, 200) - - assert length(response) == length(Pleroma.Docs.JSON.compiled_descriptions()) - end end end diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 9fbb608c4..b626ddf55 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -388,38 +388,6 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do |> json_response_and_validate_schema(:ok) end - test "returns reports with specified assigned user", %{conn: conn, admin: admin} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, _report} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - {:ok, %{id: second_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I don't like this user" - }) - - CommonAPI.assign_report_to_account(second_report_id, admin.id) - - response = - conn - |> get(report_path(conn, :index, %{assigned_account: admin.id})) - |> json_response_and_validate_schema(:ok) - - assert [open_report] = response["reports"] - - assert length(response["reports"]) == 1 - assert open_report["id"] == second_report_id - - assert response["total"] == 1 - end - test "renders content correctly", %{conn: conn} do [reporter, target_user] = insert_pair(:user) note = insert(:note, user: target_user, data: %{"content" => "mew 1"}) @@ -499,66 +467,6 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do end end - describe "POST /api/pleroma/admin/reports/assign_account" do - test "assigns account to report", %{conn: conn, admin: admin} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - status_ids: [activity.id] - }) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/assign_account", %{ - "reports" => [ - %{"assigned_account" => admin.nickname, "id" => report_id} - ] - }) - |> json_response_and_validate_schema(:no_content) - - activity = Activity.get_by_id_with_user_actor(report_id) - assert activity.data["assigned_account"] == admin.id - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} assigned report ##{report_id} (on user @#{activity.user_actor.nickname}) to user #{admin.nickname}" - end - - test "unassigns account from report", %{conn: conn, admin: admin} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - status_ids: [activity.id] - }) - - CommonAPI.assign_report_to_account(report_id, admin.id) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/assign_account", %{ - "reports" => [ - %{"assigned_account" => nil, "id" => report_id} - ] - }) - |> json_response_and_validate_schema(:no_content) - - activity = Activity.get_by_id_with_user_actor(report_id) - assert activity.data["assigned_account"] == nil - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} unassigned report ##{report_id} (on user @#{activity.user_actor.nickname}) from a user" - end - end - describe "POST /api/pleroma/admin/reports/:id/notes" do setup %{conn: conn, admin: admin} do clear_config([:instance, :admin_privileges], [:reports_manage_reports]) diff --git a/test/pleroma/web/admin_api/views/report_view_test.exs b/test/pleroma/web/admin_api/views/report_view_test.exs index 6e155ef58..1b16aca6a 100644 --- a/test/pleroma/web/admin_api/views/report_view_test.exs +++ b/test/pleroma/web/admin_api/views/report_view_test.exs @@ -36,7 +36,6 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do }), AdminAPI.AccountView.render("show.json", %{user: other_user}) ), - assigned_account: nil, statuses: [], notes: [], state: "open", @@ -76,7 +75,6 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do }), AdminAPI.AccountView.render("show.json", %{user: other_user}) ), - assigned_account: nil, statuses: [StatusView.render("show.json", %{activity: activity})], state: "open", notes: [], diff --git a/test/pleroma/web/common_api/utils_test.exs b/test/pleroma/web/common_api/utils_test.exs index d0cbc3111..27b1da1e3 100644 --- a/test/pleroma/web/common_api/utils_test.exs +++ b/test/pleroma/web/common_api/utils_test.exs @@ -647,7 +647,7 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do describe "maybe_add_list_data/3" do test "adds list params when found user list" do user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, user) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user) assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == %{ @@ -658,7 +658,7 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do test "returns original params when list not found" do user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, insert(:user)) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user)) assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == %{additional: %{}, object: %{}} diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index ea1795c0b..52829b734 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -709,47 +709,6 @@ defmodule Pleroma.Web.CommonAPITest do assert object.data["source"]["content"] == post end - test "it renders MFM posts and marks their ActivityPub representation" do - user = insert(:user) - - post = "

$[spin.speed=1s 13:37]

" - - {:ok, activity} = - CommonAPI.post(user, %{ - status: post, - content_type: "text/x.misskeymarkdown" - }) - - object = Object.normalize(activity, fetch: false) - - assert object.data["htmlMfm"] == true - - assert object.data["source"] == %{ - "content" => post, - "mediaType" => "text/x.misskeymarkdown" - } - - assert object.data["content"] =~ ~s(class="mfm-spin") - assert object.data["content"] =~ ~s(data-mfm-speed="1s") - assert object.data["content"] =~ "13:37" - refute object.data["content"] =~ "scrub-this" - end - - test "it falls back safely for malformed MFM" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "$[spin.speed=1s=boom malformed]", - content_type: "text/x.misskeymarkdown" - }) - - object = Object.normalize(activity, fetch: false) - - refute object.data["content"] =~ ~s(class="mfm-spin") - assert object.data["content"] =~ "malformed" - end - test "it does not allow replies to direct messages that are not direct messages themselves" do user = insert(:user) @@ -800,7 +759,7 @@ defmodule Pleroma.Web.CommonAPITest do test "it allows to address a list" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) @@ -1499,29 +1458,6 @@ defmodule Pleroma.Web.CommonAPITest do } } = flag_activity end - - test "assigns report to an account" do - [reporter, target_user] = insert_pair(:user) - %{id: assigned} = insert(:user) - - {:ok, %Activity{id: report_id}} = CommonAPI.report(reporter, %{account_id: target_user.id}) - - {:ok, activity} = CommonAPI.assign_report_to_account(report_id, assigned) - - assert %{data: %{"assigned_account" => ^assigned}} = activity - end - - test "unassigns report from account" do - [reporter, target_user] = insert_pair(:user) - %{id: assigned} = insert(:user) - - {:ok, %Activity{id: report_id}} = CommonAPI.report(reporter, %{account_id: target_user.id}) - - CommonAPI.assign_report_to_account(report_id, assigned) - {:ok, activity} = CommonAPI.assign_report_to_account(report_id, nil) - - refute Map.has_key?(activity.data, "assigned_account") - end end describe "reblog muting" do diff --git a/test/pleroma/web/fallback_test.exs b/test/pleroma/web/fallback_test.exs index bc3052959..6d0ba3d2a 100644 --- a/test/pleroma/web/fallback_test.exs +++ b/test/pleroma/web/fallback_test.exs @@ -79,12 +79,6 @@ defmodule Pleroma.Web.FallbackTest do test "GET /phoenix/live_dashboard -> /pleroma/live_dashboard", %{conn: conn} do assert redirected_to(get(conn, "/phoenix/live_dashboard")) =~ "/pleroma/live_dashboard" - assert redirected_to(get(conn, "/phoenix/live_dashboard/")) =~ "/pleroma/live_dashboard/" - end - - test "GET /phoenix/live_dashboard/* -> /pleroma/live_dashboard/*", %{conn: conn} do - assert redirected_to(get(conn, "/phoenix/live_dashboard/ecto_stats?nav=diagnose")) =~ - "/pleroma/live_dashboard/ecto_stats?nav=diagnose" end test "OPTIONS /*path", %{conn: conn} do diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index 01e195842..ea98b53a8 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -1815,10 +1815,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do test "returns lists to which the account belongs" do %{user: user, conn: conn} = oauth_access(["read:lists"]) other_user = insert(:user) - - assert {:ok, %Pleroma.List{id: _list_id} = list} = - Pleroma.List.create(%{title: "Test List"}, user) - + assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user) {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) assert [%{"id" => _list_id, "title" => "Test List"}] = @@ -2099,7 +2096,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do result = conn |> assign(:user, user) - |> get("/api/v1/blocks") + |> get("api/v1/blocks") |> json_response_and_validate_schema(200) assert [ diff --git a/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs index bfda48be4..430b8b89d 100644 --- a/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs @@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do %{user: user, conn: conn} = oauth_access(["write:lists"]) other_user = insert(:user) third_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) assert %{} == conn @@ -77,7 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do other_user = insert(:user) third_user = insert(:user) fourth_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) {:ok, list} = Pleroma.List.follow(list, third_user) {:ok, list} = Pleroma.List.follow(list, fourth_user) @@ -98,7 +98,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do %{user: user, conn: conn} = oauth_access(["write:lists"]) other_user = insert(:user) third_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) {:ok, list} = Pleroma.List.follow(list, third_user) @@ -115,7 +115,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "listing users in a list" do %{user: user, conn: conn} = oauth_access(["read:lists"]) other_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) conn = @@ -129,7 +129,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "retrieving a list" do %{user: user, conn: conn} = oauth_access(["read:lists"]) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) conn = conn @@ -150,7 +150,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "renaming a list" do %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) assert %{"title" => "newname"} = conn @@ -161,7 +161,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "validates title when renaming a list" do %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) conn = conn @@ -175,7 +175,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do test "deleting a list" do %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) conn = delete(conn, "/api/v1/lists/#{list.id}") diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs index fc083fd0e..ae86078d7 100644 --- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs @@ -129,8 +129,8 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do assert :ok == File.rm(Path.absname("test/tmp/large_binary.data")) end - test "Do not allow nested filename", %{conn: conn, image: %Plug.Upload{} = image} do - image = %{ + test "Do not allow nested filename", %{conn: conn, image: image} do + image = %Plug.Upload{ image | filename: "../../../../../nested/file.jpg" } diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index 11e96a6ac..298e92366 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -3068,11 +3068,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> json_response_and_validate_schema(:ok) {:ok, a_expires_at, 0} = DateTime.from_iso8601(a_expires_at) - - assert DateTime.diff( - DateTime.truncate(expires_at, :second), - DateTime.truncate(a_expires_at, :second) - ) == 0 + assert DateTime.diff(expires_at, a_expires_at) == 0 %{conn: conn} = oauth_access(["read:statuses"]) diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index b685f4ff8..4d646509c 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -149,31 +149,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do |> get("/api/v1/timelines/home?remote=true&local=true") |> json_response_and_validate_schema(200) == [] end - - test "the home timeline excludes posts from users in exclusive lists", %{ - user: user, - conn: conn - } do - other_user1 = insert(:user) - other_user2 = insert(:user) - - {:ok, user, other_user1} = User.follow(user, other_user1) - {:ok, user, other_user2} = User.follow(user, other_user2) - - {:ok, list} = Pleroma.List.create(%{title: "foo", exclusive: true}, user) - {:ok, _list} = Pleroma.List.follow(list, other_user1) - - {:ok, _activity} = CommonAPI.post(other_user1, %{status: "hi"}) - {:ok, %{id: activity2_id}} = CommonAPI.post(other_user2, %{status: "hi too"}) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/timelines/home") - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^activity2_id}] = response - end end describe "public" do @@ -631,7 +606,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do {:ok, activity_two} = CommonAPI.post(other_user, %{status: "Marisa is stupid."}) {:ok, _} = CommonAPI.repeat(activity_one.id, other_user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) conn = get(conn, "/api/v1/timelines/list/#{list.id}") @@ -643,7 +618,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do test "works with pagination", %{user: user, conn: conn} do other_user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) Enum.each(1..30, fn i -> @@ -669,7 +644,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do other_user = insert(:user) {:ok, _activity_one} = CommonAPI.post(user, %{status: "Marisa is cute."}) {:ok, activity_two} = CommonAPI.post(other_user, %{status: "Marisa is cute."}) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) conn = get(conn, "/api/v1/timelines/list/#{list.id}") @@ -692,7 +667,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do visibility: "private" }) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, other_user) conn = get(conn, "/api/v1/timelines/list/#{list.id}") @@ -710,7 +685,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅") User.mute(user, user3) - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) {:ok, list} = Pleroma.List.follow(list, user2) result = @@ -741,7 +716,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do end test "filtering", %{user: user, conn: conn} do - {:ok, list} = Pleroma.List.create(%{title: "name"}, user) + {:ok, list} = Pleroma.List.create("name", user) local_user = insert(:user) {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Marisa is stupid."}) diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index f34a801c1..6984442cc 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -54,10 +54,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do note: "valid html. a
b
c
d
f '&<>"", url: user.ap_id, avatar: "http://localhost:4001/images/avi.png", - avatar_description: "", avatar_static: "http://localhost:4001/images/avi.png", header: "http://localhost:4001/images/banner.png", - header_description: "", header_static: "http://localhost:4001/images/banner.png", emojis: [ %{ @@ -328,10 +326,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do note: user.bio, url: user.ap_id, avatar: "http://localhost:4001/images/avi.png", - avatar_description: "", avatar_static: "http://localhost:4001/images/avi.png", header: "http://localhost:4001/images/banner.png", - header_description: "", header_static: "http://localhost:4001/images/banner.png", emojis: [], fields: [], @@ -913,7 +909,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do relationship: %{ mute_expires_at: mute_expires_at } - } + }, + mute_expires_at: mute_expires_at } = AccountView.render("show.json", %{user: other_user, for: user, embed_relationships: true}) assert DateTime.diff( @@ -934,7 +931,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do relationship: %{ block_expires_at: block_expires_at } - } + }, + block_expires_at: block_expires_at } = AccountView.render("show.json", %{user: other_user, for: user, embed_relationships: true}) assert DateTime.diff( diff --git a/test/pleroma/web/mastodon_api/views/list_view_test.exs b/test/pleroma/web/mastodon_api/views/list_view_test.exs index ae0593b6b..bbf87bab2 100644 --- a/test/pleroma/web/mastodon_api/views/list_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/list_view_test.exs @@ -10,12 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.ListViewTest do test "show" do user = insert(:user) title = "mortal enemies" - {:ok, list} = Pleroma.List.create(%{title: title}, user) + {:ok, list} = Pleroma.List.create(title, user) expected = %{ id: to_string(list.id), - title: title, - exclusive: false + title: title } assert expected == ListView.render("show.json", %{list: list}) @@ -24,13 +23,10 @@ defmodule Pleroma.Web.MastodonAPI.ListViewTest do test "index" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "my list", exclusive: false}, user) - {:ok, list2} = Pleroma.List.create(%{title: "cofe", exclusive: true}, user) + {:ok, list} = Pleroma.List.create("my list", user) + {:ok, list2} = Pleroma.List.create("cofe", user) - assert [ - %{id: _, title: "my list", exclusive: false}, - %{id: _, title: "cofe", exclusive: true} - ] = + assert [%{id: _, title: "my list"}, %{id: _, title: "cofe"}] = ListView.render("index.json", lists: [list, list2]) end end diff --git a/test/pleroma/web/mastodon_api/views/poll_view_test.exs b/test/pleroma/web/mastodon_api/views/poll_view_test.exs index 6cb5934de..6de001421 100644 --- a/test/pleroma/web/mastodon_api/views/poll_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/poll_view_test.exs @@ -167,192 +167,10 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } = PollView.render("show.json", %{object: object}) end - test "displays correct voters count" do - object = Object.normalize("https://friends.grishka.me/posts/54642", fetch: true) - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 14 - end - - test "detects that poll is non anonymous" do + test "that poll is non anonymous" do object = Object.normalize("https://friends.grishka.me/posts/54642", fetch: true) result = PollView.render("show.json", %{object: object}) assert result[:pleroma][:non_anonymous] == true end - - test "prefers votersCount over voters list when both are present" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Which flavor?", - poll: %{options: ["chocolate", "vanilla"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - voter = insert(:user) - {:ok, _, object} = CommonAPI.vote(object, voter, [0]) - - assert object.data["votersCount"] == 1 - assert length(object.data["voters"]) == 1 - - object = %{ - object - | data: Map.put(object.data, "votersCount", 42) - } - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 42 - end - - test "falls back to voters list when votersCount is absent" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Which flavor?", - poll: %{options: ["chocolate", "vanilla"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - voter = insert(:user) - {:ok, _, object} = CommonAPI.vote(object, voter, [0]) - - assert length(object.data["voters"]) == 1 - - data = Map.delete(object.data, "votersCount") - object = %{object | data: data} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 1 - end - - test "returns 0 when both votersCount and voters are absent" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Which flavor?", - poll: %{options: ["chocolate", "vanilla"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - data = - object.data - |> Map.delete("votersCount") - |> Map.delete("voters") - - object = %{object | data: data} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 0 - end - - test "returns 0 when voters list is empty" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Which flavor?", - poll: %{options: ["chocolate", "vanilla"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - data = - object.data - |> Map.delete("votersCount") - |> Map.put("voters", []) - - object = %{object | data: data} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 0 - end - - test "does not inflate votersCount when same voter picks multiple options" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Pick several", - poll: %{options: ["a", "b", "c"], expires_in: 20, multiple: true} - }) - - object = Object.normalize(activity, fetch: false) - - voter = insert(:user) - {:ok, _, object} = CommonAPI.vote(object, voter, [0, 2]) - - assert object.data["votersCount"] == 1 - assert length(object.data["voters"]) == 1 - end - - test "preserves votersCount from remote source when existing voter picks another option" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Pick several", - poll: %{options: ["a", "b"], expires_in: 20, multiple: true} - }) - - object = Object.normalize(activity, fetch: false) - - voter = insert(:user) - {:ok, _, object} = CommonAPI.vote(object, voter, [0, 1]) - - object = %{object | data: Map.put(object.data, "votersCount", 14)} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 14 - end - - test "returns 0 when votersCount is explicitly 0" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Pick one", - poll: %{options: ["a", "b"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - object = %{object | data: Map.put(object.data, "votersCount", 0)} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == 0 - end - - test "falls back to voters list when votersCount is nil" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Pick one", - poll: %{options: ["a", "b"], expires_in: 20} - }) - - object = Object.normalize(activity, fetch: false) - - voter = insert(:user) - {:ok, _, object} = CommonAPI.vote(object, voter, [0]) - - object = %{object | data: Map.put(object.data, "votersCount", nil)} - - result = PollView.render("show.json", %{object: object}) - - assert result[:voters_count] == length(object.data["voters"]) - end end diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index 76123cd0f..73cab817b 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -909,7 +909,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do test "visibility/list" do user = insert(:user) - {:ok, list} = Pleroma.List.create(%{title: "foo"}, user) + {:ok, list} = Pleroma.List.create("foo", user) {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"}) diff --git a/test/pleroma/web/plugs/favicon_plug_test.exs b/test/pleroma/web/plugs/favicon_plug_test.exs deleted file mode 100644 index 520501250..000000000 --- a/test/pleroma/web/plugs/favicon_plug_test.exs +++ /dev/null @@ -1,63 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2026 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Plugs.FaviconPlugTest do - use Pleroma.Web.ConnCase - - @dir "test/tmp/favicon_static" - - setup do - Pleroma.Backports.mkdir_p!(@dir) - - on_exit(fn -> File.rm_rf!(@dir) end) - end - - describe "default favicon" do - test "returns favicon", %{conn: conn} do - conn = get(conn, "/favicon.png") - body_size = byte_size(conn.resp_body) - - assert conn.status == 200 - assert body_size == 1583 - assert response_content_type(conn, :png) - end - - test "returns correct cache-control", %{conn: conn} do - conn = get(conn, "/favicon.png") - cache = get_resp_header(conn, "cache-control") - - assert conn.status == 200 - assert cache == ["public, max=age=86400, immutable"] - end - end - - describe "custom favicon" do - setup do - favicon_path = Path.join(@dir, "favicon.png") - donor_image = "test/fixtures/image.png" - - File.cp!(donor_image, favicon_path) - clear_config([:instance, :static_dir], @dir) - - on_exit(fn -> File.rm!(favicon_path) end) - end - - test "returns favicon", %{conn: conn} do - conn = get(conn, "/favicon.png") - body_size = byte_size(conn.resp_body) - - assert conn.status == 200 - assert body_size == 104_426 - assert response_content_type(conn, :png) - end - - test "returns correct cache-control", %{conn: conn} do - conn = get(conn, "/favicon.png") - cache = get_resp_header(conn, "cache-control") - - assert conn.status == 200 - assert cache == ["public, max=age=86400, immutable"] - end - end -end diff --git a/test/pleroma/web/plugs/frontend_static_plug_test.exs b/test/pleroma/web/plugs/frontend_static_plug_test.exs index b7c06eacd..e1e331c06 100644 --- a/test/pleroma/web/plugs/frontend_static_plug_test.exs +++ b/test/pleroma/web/plugs/frontend_static_plug_test.exs @@ -105,7 +105,6 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do "nodeinfo", "manifest.json", "auth", - "embed", "proxy", "test", "user_exists", diff --git a/test/pleroma/web/plugs/instance_static_test.exs b/test/pleroma/web/plugs/instance_static_test.exs index 017c49d1e..b5a5a3334 100644 --- a/test/pleroma/web/plugs/instance_static_test.exs +++ b/test/pleroma/web/plugs/instance_static_test.exs @@ -137,47 +137,4 @@ defmodule Pleroma.Web.Plugs.InstanceStaticTest do # It should be preserved because "image" is in the allowed_mime_types list assert content_type == "image/jpeg" end - - describe "404s for missing files in static-only paths" do - test "returns 404 for non-existent static-only JSON files" do - conn = get(build_conn(), "/static/non-existent.json") - - assert conn.status == 404 - assert ["application/json"] = get_resp_header(conn, "content-type") - assert Jason.decode!(conn.resp_body) == %{"error" => "not found"} - end - - test "returns 404 for non-existent static-only non-JSON files" do - conn = get(build_conn(), "/static/non-existent.txt") - - assert conn.status == 404 - assert conn.resp_body == "Not found" - assert ["text/plain"] = get_resp_header(conn, "content-type") - end - - test "returns 404 for non-existent .css files" do - conn = get(build_conn(), "/static/non-existent.css") - - assert conn.status == 404 - assert conn.resp_body == "Not found" - # Verifies that we forced text/plain for the error body, even though the path was .css - assert ["text/plain"] = get_resp_header(conn, "content-type") - end - - test "returns 404 for non-existent files without an extension" do - conn = get(build_conn(), "/static/non-existent") - - assert conn.status == 404 - assert conn.resp_body == "Not found" - assert ["text/plain"] = get_resp_header(conn, "content-type") - end - - test "returns 200 (falls through to SPA) for non-static-only paths" do - # /some-route is NOT in static_only_files, so it should still fall through to the SPA. - conn = get(build_conn(), "/some-route") - - assert conn.status == 200 - assert ["text/html; charset=utf-8"] = get_resp_header(conn, "content-type") - end - end end diff --git a/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs index df713762c..33eff1bc5 100644 --- a/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs +++ b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs @@ -47,27 +47,13 @@ defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do assert %{valid_signature: false} == conn.assigns end + @tag skip: "known breakage; the testsuite presently depends on it" test "it considers a mapped identity to be invalid when the identity cannot be found" do - actor = "http://niu.moe/users/rye" - conn = - build_conn(:post, "/doesntmattter", %{"actor" => actor}) - |> set_signature(actor) + build_conn(:post, "/doesntmattter", %{"actor" => "http://mastodon.example.org/users/admin"}) + |> set_signature("http://niu.moe/users/rye") |> MappedSignatureToIdentityPlug.call(%{}) - assert conn.assigns.valid_signature == false - refute Map.has_key?(conn.assigns, :user) - end - - test "it considers a mapped identity to be invalid when embedded actor identity cannot be found" do - actor = "http://niu.moe/users/rye" - - conn = - build_conn(:post, "/doesntmattter", %{"actor" => %{"id" => actor}}) - |> set_signature(actor) - |> MappedSignatureToIdentityPlug.call(%{}) - - assert conn.assigns.valid_signature == false - refute Map.has_key?(conn.assigns, :user) + assert %{valid_signature: false} == conn.assigns end end diff --git a/test/pleroma/web/plugs/rate_limiter_test.exs b/test/pleroma/web/plugs/rate_limiter_test.exs index 10c93fa73..19cee8aee 100644 --- a/test/pleroma/web/plugs/rate_limiter_test.exs +++ b/test/pleroma/web/plugs/rate_limiter_test.exs @@ -268,23 +268,6 @@ defmodule Pleroma.Web.Plugs.RateLimiterTest do refute {:err, :not_found} == RateLimiter.inspect_bucket(conn, limiter_name, opts) end - test "doesn't crash if rate limit scale is invalid (e.g. broken DB config)" do - limiter_name = :test_invalid_rate_limit_config - - clear_config([:rate_limit, limiter_name], [{"", 0}, {"", ""}]) - clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) - - opts = RateLimiter.init(name: limiter_name) - - conn = %{build_conn(:get, "/") | remote_ip: {127, 0, 0, 1}} - - conn_limited = RateLimiter.call(conn, opts) - - refute conn_limited.status == Conn.Status.code(:too_many_requests) - refute conn_limited.resp_body - refute conn_limited.halted - end - def expire_ttl(%{remote_ip: remote_ip} = _conn, bucket_name_root) do bucket_name = "anon:#{bucket_name_root}" |> String.to_atom() key_name = "ip::#{remote_ip |> Tuple.to_list() |> Enum.join(".")}" diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index b26bd1847..f5008f6b9 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -220,7 +220,7 @@ defmodule Pleroma.Web.StreamerTest do } do %{token: read_lists_token} = oauth_access(["read:lists"], user: user) %{token: invalid_token} = oauth_access(["irrelevant:scope"], user: user) - {:ok, list} = List.create(%{title: "Test"}, user) + {:ok, list} = List.create("Test", user) assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, read_oauth_token) @@ -233,7 +233,7 @@ defmodule Pleroma.Web.StreamerTest do test "disallows list stream that are not owned by the user", %{user: user, token: oauth_token} do another_user = insert(:user) - {:ok, list} = List.create(%{title: "Test"}, another_user) + {:ok, list} = List.create("Test", another_user) assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, oauth_token) assert {:error, _} = Streamer.get_topic("list", user, oauth_token, %{"list" => list.id}) @@ -803,7 +803,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, user_a, user_b} = User.follow(user_a, user_b) - {:ok, list} = List.create(%{title: "Test"}, user_a) + {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) @@ -820,7 +820,7 @@ defmodule Pleroma.Web.StreamerTest do test "it doesn't send unwanted private posts to list", %{user: user_a, token: user_a_token} do user_b = insert(:user) - {:ok, list} = List.create(%{title: "Test"}, user_a) + {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) @@ -839,7 +839,7 @@ defmodule Pleroma.Web.StreamerTest do {:ok, user_a, user_b} = User.follow(user_a, user_b) - {:ok, list} = List.create(%{title: "Test"}, user_a) + {:ok, list} = List.create("Test", user_a) {:ok, list} = List.follow(list, user_b) Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id}) diff --git a/test/pleroma/web/o_auth/token_controller_test.exs b/test/pleroma/web/twitter_api/controller_test.exs similarity index 97% rename from test/pleroma/web/o_auth/token_controller_test.exs rename to test/pleroma/web/twitter_api/controller_test.exs index 5c64cb394..494be9ec7 100644 --- a/test/pleroma/web/o_auth/token_controller_test.exs +++ b/test/pleroma/web/twitter_api/controller_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.TokenControllerTest do +defmodule Pleroma.Web.TwitterAPI.ControllerTest do use Pleroma.Web.ConnCase, async: true alias Pleroma.Repo diff --git a/test/pleroma/web/o_auth/password_controller_test.exs b/test/pleroma/web/twitter_api/password_controller_test.exs similarity index 99% rename from test/pleroma/web/o_auth/password_controller_test.exs rename to test/pleroma/web/twitter_api/password_controller_test.exs index bb61b24fd..26cca1345 100644 --- a/test/pleroma/web/o_auth/password_controller_test.exs +++ b/test/pleroma/web/twitter_api/password_controller_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.OAuth.PasswordControllerTest do +defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Config diff --git a/test/pleroma/web/remote_interaction/remote_interaction_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs similarity index 68% rename from test/pleroma/web/remote_interaction/remote_interaction_controller_test.exs rename to test/pleroma/web/twitter_api/remote_follow_controller_test.exs index 9236d1bf8..f762b1356 100644 --- a/test/pleroma/web/remote_interaction/remote_interaction_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do +defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do use Pleroma.Web.ConnCase alias Pleroma.MFA @@ -16,11 +16,6 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do import Mox import Pleroma.Factory - setup do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - setup_all do: clear_config([:instance, :federating], true) setup do: clear_config([:user, :deny_follow_blocked]) @@ -54,7 +49,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do assert conn |> get( - remote_interaction_path(conn, :follow, %{ + remote_follow_path(conn, :follow, %{ acct: "https://mastodon.social/users/emelie/statuses/101849165031453009" }) ) @@ -83,9 +78,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> get( - remote_interaction_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}) - ) + |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) |> html_response(200) assert response =~ "Log in to follow" @@ -116,9 +109,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn |> assign(:user, user) - |> get( - remote_interaction_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}) - ) + |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) |> html_response(200) assert response =~ "Remote follow" @@ -139,7 +130,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn |> assign(:user, user) |> get( - remote_interaction_path(conn, :follow, %{ + remote_follow_path(conn, :follow, %{ acct: "https://mastodon.social/users/not_found" }) ) @@ -161,9 +152,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn |> assign(:user, user) |> assign(:token, read_token) - |> post(remote_interaction_path(conn, :do_follow), %{ - "user" => %{"id" => user2.id} - }) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -178,7 +167,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn |> assign(:user, user) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_interaction_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) assert redirected_to(conn) == "/users/#{user2.id}" end @@ -190,7 +179,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn |> assign(:user, user) - |> post(remote_interaction_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -206,7 +195,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn |> assign(:user, user) - |> post(remote_interaction_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -218,7 +207,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn |> assign(:user, user) - |> post(remote_interaction_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}}) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}}) |> response(200) assert response =~ "Error following account" @@ -233,7 +222,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn |> assign(:user, refresh_record(user)) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_interaction_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) assert redirected_to(conn) == "/users/#{user2.id}" end @@ -255,7 +244,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) |> response(200) @@ -283,7 +272,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test1", "id" => user2.id} }) |> response(200) @@ -311,7 +300,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn = conn |> post( - remote_interaction_path(conn, :do_follow), + remote_follow_path(conn, :do_follow), %{ "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} } @@ -340,7 +329,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn |> post( - remote_interaction_path(conn, :do_follow), + remote_follow_path(conn, :do_follow), %{ "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} } @@ -359,7 +348,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) @@ -372,7 +361,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"} }) |> response(200) @@ -385,7 +374,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id} }) |> response(200) @@ -399,7 +388,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id} }) |> response(200) @@ -415,7 +404,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do response = conn - |> post(remote_interaction_path(conn, :do_follow), %{ + |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) |> response(200) @@ -434,7 +423,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do avatar: %{"url" => [%{"href" => "https://remote.org/avatar.png"}]} }) - avatar_url = Pleroma.Web.RemoteInteraction.RemoteInteractionView.avatar_url(user) + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) assert avatar_url == "https://remote.org/avatar.png" end @@ -451,7 +440,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do avatar: %{"url" => [%{"href" => "https://remote.org/avatar.png"}]} }) - avatar_url = Pleroma.Web.RemoteInteraction.RemoteInteractionView.avatar_url(user) + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) url = Pleroma.Web.Endpoint.url() assert String.starts_with?(avatar_url, url) @@ -466,7 +455,7 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do avatar: %{"url" => [%{"href" => "#{Pleroma.Web.Endpoint.url()}/localuser/avatar.png"}]} }) - avatar_url = Pleroma.Web.RemoteInteraction.RemoteInteractionView.avatar_url(user) + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) assert avatar_url == "#{Pleroma.Web.Endpoint.url()}/localuser/avatar.png" end @@ -496,162 +485,13 @@ defmodule Pleroma.Web.RemoteInteraction.RemoteInteractionControllerTest do conn = conn |> get( - remote_interaction_path(conn, :authorize_interaction, %{ + remote_follow_path(conn, :authorize_interaction, %{ uri: "https://mastodon.social/users/emelie" }) ) assert redirected_to(conn) == - remote_interaction_path(conn, :follow, %{ - acct: "https://mastodon.social/users/emelie" - }) - end - end - - describe "POST /main/ostatus - remote_subscribe/2" do - setup do: clear_config([:instance, :federating], true) - - test "renders subscribe form", %{conn: conn} do - user = insert(:user) - - response = - conn - |> post("/main/ostatus", %{"nickname" => user.nickname, "profile" => ""}) - |> response(:ok) - - refute response =~ "Could not find user" - assert response =~ "Remotely follow #{user.nickname}" - end - - test "renders subscribe form with error when user not found", %{conn: conn} do - response = - conn - |> post("/main/ostatus", %{"nickname" => "nickname", "profile" => ""}) - |> response(:ok) - - assert response =~ "Could not find user" - refute response =~ "Remotely follow" - end - - test "it redirect to webfinger url", %{conn: conn} do - user = insert(:user) - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - conn = - conn - |> post("/main/ostatus", %{ - "user" => %{"nickname" => user.nickname, "profile" => user2.ap_id} - }) - - assert redirected_to(conn) == - "https://social.heldscal.la/main/ostatussub?profile=#{user.ap_id}" - end - - test "it renders form with error when user not found", %{conn: conn} do - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - response = - conn - |> post("/main/ostatus", %{"user" => %{"nickname" => "jimm", "profile" => user2.ap_id}}) - |> response(:ok) - - assert response =~ "Something went wrong." - end - end - - describe "POST /main/ostatus - remote_subscribe/2 - with statuses" do - setup do: clear_config([:instance, :federating], true) - - test "renders subscribe form", %{conn: conn} do - user = insert(:user) - status = insert(:note_activity, %{user: user}) - status_id = status.id - - assert is_binary(status_id) - - response = - conn - |> post("/main/ostatus", %{"status_id" => status_id, "profile" => ""}) - |> response(:ok) - - refute response =~ "Could not find status" - assert response =~ "Interacting with" - end - - test "renders subscribe form with error when status not found", %{conn: conn} do - response = - conn - |> post("/main/ostatus", %{"status_id" => "somerandomid", "profile" => ""}) - |> response(:ok) - - assert response =~ "Could not find status" - refute response =~ "Interacting with" - end - - test "it redirect to webfinger url", %{conn: conn} do - user = insert(:user) - status = insert(:note_activity, %{user: user}) - status_id = status.id - status_ap_id = status.data["object"] - - assert is_binary(status_id) - assert is_binary(status_ap_id) - - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - conn = - conn - |> post("/main/ostatus", %{ - "status" => %{"status_id" => status_id, "profile" => user2.ap_id} - }) - - assert redirected_to(conn) == - "https://social.heldscal.la/main/ostatussub?profile=#{status_ap_id}" - end - - test "it renders form with error when status not found", %{conn: conn} do - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - response = - conn - |> post("/main/ostatus", %{ - "status" => %{"status_id" => "somerandomid", "profile" => user2.ap_id} - }) - |> response(:ok) - - assert response =~ "Something went wrong." - end - end - - describe "GET /main/ostatus - show_subscribe_form/2" do - setup do: clear_config([:instance, :federating], true) - - test "it works with users", %{conn: conn} do - user = insert(:user) - - response = - conn - |> get("/main/ostatus", %{"nickname" => user.nickname}) - |> response(:ok) - - refute response =~ "Could not find user" - assert response =~ "Remotely follow #{user.nickname}" - end - - test "it works with statuses", %{conn: conn} do - user = insert(:user) - status = insert(:note_activity, %{user: user}) - status_id = status.id - - assert is_binary(status_id) - - response = - conn - |> get("/main/ostatus", %{"status_id" => status_id}) - |> response(:ok) - - refute response =~ "Could not find status" - assert response =~ "Interacting with" + remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}) end end end diff --git a/test/pleroma/web/registration_test.exs b/test/pleroma/web/twitter_api/twitter_api_test.exs similarity index 90% rename from test/pleroma/web/registration_test.exs rename to test/pleroma/web/twitter_api/twitter_api_test.exs index 896e1a600..b3cd80146 100644 --- a/test/pleroma/web/registration_test.exs +++ b/test/pleroma/web/twitter_api/twitter_api_test.exs @@ -2,14 +2,14 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.RegistrationTest do +defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do use Pleroma.DataCase import Pleroma.Factory alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.UserInviteToken - alias Pleroma.Web.Registration + alias Pleroma.Web.TwitterAPI.TwitterAPI setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -25,7 +25,7 @@ defmodule Pleroma.Web.RegistrationTest do :confirm => "bear" } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("lain") end @@ -40,7 +40,7 @@ defmodule Pleroma.Web.RegistrationTest do :confirm => "bear" } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("lain") end @@ -57,7 +57,7 @@ defmodule Pleroma.Web.RegistrationTest do :confirm => "bear" } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) ObanHelpers.perform_all() refute user.is_confirmed @@ -89,7 +89,7 @@ defmodule Pleroma.Web.RegistrationTest do :reason => "I love anime" } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) ObanHelpers.perform_all() refute user.is_approved @@ -125,7 +125,7 @@ defmodule Pleroma.Web.RegistrationTest do :confirm => "bear" } - {:ok, user1} = Registration.register_user(data1) + {:ok, user1} = TwitterAPI.register_user(data1) data2 = %{ :username => "lain", @@ -136,7 +136,7 @@ defmodule Pleroma.Web.RegistrationTest do :confirm => "bear" } - {:ok, user2} = Registration.register_user(data2) + {:ok, user2} = TwitterAPI.register_user(data2) expected_text = ~s(@john test) @@ -160,7 +160,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("vinny") @@ -179,7 +179,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => "DudeLetMeInImAFairy" } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Invalid token" refute User.get_cached_by_nickname("GrimReaper") @@ -199,7 +199,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("GrimReaper") @@ -221,7 +221,7 @@ defmodule Pleroma.Web.RegistrationTest do check_fn = fn invite -> data = Map.put(data, :token, invite.token) - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("vinny") end @@ -254,7 +254,7 @@ defmodule Pleroma.Web.RegistrationTest do data = Map.put(data, "token", invite.token) - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("vinny") @@ -282,7 +282,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("vinny") invite = Repo.get_by(UserInviteToken, token: invite.token) @@ -298,7 +298,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("GrimReaper") @@ -321,7 +321,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("vinny") invite = Repo.get_by(UserInviteToken, token: invite.token) @@ -343,7 +343,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:ok, user} = Registration.register_user(data) + {:ok, user} = TwitterAPI.register_user(data) assert user == User.get_cached_by_nickname("vinny") invite = Repo.get_by(UserInviteToken, token: invite.token) @@ -359,7 +359,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("GrimReaper") @@ -379,7 +379,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("GrimReaper") @@ -401,7 +401,7 @@ defmodule Pleroma.Web.RegistrationTest do :token => invite.token } - {:error, msg} = Registration.register_user(data) + {:error, msg} = TwitterAPI.register_user(data) assert msg == "Expired token" refute User.get_cached_by_nickname("GrimReaper") @@ -416,7 +416,7 @@ defmodule Pleroma.Web.RegistrationTest do :bio => "close the world." } - {:error, error} = Registration.register_user(data) + {:error, error} = TwitterAPI.register_user(data) assert is_binary(error) refute User.get_cached_by_nickname("lain") diff --git a/test/pleroma/web/pleroma_api/controllers/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs similarity index 85% rename from test/pleroma/web/pleroma_api/controllers/util_controller_test.exs rename to test/pleroma/web/twitter_api/util_controller_test.exs index 6e817df56..d06ae71aa 100644 --- a/test/pleroma/web/pleroma_api/controllers/util_controller_test.exs +++ b/test/pleroma/web/twitter_api/util_controller_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PleromaAPI.UtilControllerTest do +defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo @@ -182,6 +182,153 @@ defmodule Pleroma.Web.PleromaAPI.UtilControllerTest do end end + describe "POST /main/ostatus - remote_subscribe/2" do + setup do: clear_config([:instance, :federating], true) + + test "renders subscribe form", %{conn: conn} do + user = insert(:user) + + response = + conn + |> post("/main/ostatus", %{"nickname" => user.nickname, "profile" => ""}) + |> response(:ok) + + refute response =~ "Could not find user" + assert response =~ "Remotely follow #{user.nickname}" + end + + test "renders subscribe form with error when user not found", %{conn: conn} do + response = + conn + |> post("/main/ostatus", %{"nickname" => "nickname", "profile" => ""}) + |> response(:ok) + + assert response =~ "Could not find user" + refute response =~ "Remotely follow" + end + + test "it redirect to webfinger url", %{conn: conn} do + user = insert(:user) + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + conn = + conn + |> post("/main/ostatus", %{ + "user" => %{"nickname" => user.nickname, "profile" => user2.ap_id} + }) + + assert redirected_to(conn) == + "https://social.heldscal.la/main/ostatussub?profile=#{user.ap_id}" + end + + test "it renders form with error when user not found", %{conn: conn} do + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + response = + conn + |> post("/main/ostatus", %{"user" => %{"nickname" => "jimm", "profile" => user2.ap_id}}) + |> response(:ok) + + assert response =~ "Something went wrong." + end + end + + describe "POST /main/ostatus - remote_subscribe/2 - with statuses" do + setup do: clear_config([:instance, :federating], true) + + test "renders subscribe form", %{conn: conn} do + user = insert(:user) + status = insert(:note_activity, %{user: user}) + status_id = status.id + + assert is_binary(status_id) + + response = + conn + |> post("/main/ostatus", %{"status_id" => status_id, "profile" => ""}) + |> response(:ok) + + refute response =~ "Could not find status" + assert response =~ "Interacting with" + end + + test "renders subscribe form with error when status not found", %{conn: conn} do + response = + conn + |> post("/main/ostatus", %{"status_id" => "somerandomid", "profile" => ""}) + |> response(:ok) + + assert response =~ "Could not find status" + refute response =~ "Interacting with" + end + + test "it redirect to webfinger url", %{conn: conn} do + user = insert(:user) + status = insert(:note_activity, %{user: user}) + status_id = status.id + status_ap_id = status.data["object"] + + assert is_binary(status_id) + assert is_binary(status_ap_id) + + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + conn = + conn + |> post("/main/ostatus", %{ + "status" => %{"status_id" => status_id, "profile" => user2.ap_id} + }) + + assert redirected_to(conn) == + "https://social.heldscal.la/main/ostatussub?profile=#{status_ap_id}" + end + + test "it renders form with error when status not found", %{conn: conn} do + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + response = + conn + |> post("/main/ostatus", %{ + "status" => %{"status_id" => "somerandomid", "profile" => user2.ap_id} + }) + |> response(:ok) + + assert response =~ "Something went wrong." + end + end + + describe "GET /main/ostatus - show_subscribe_form/2" do + setup do: clear_config([:instance, :federating], true) + + test "it works with users", %{conn: conn} do + user = insert(:user) + + response = + conn + |> get("/main/ostatus", %{"nickname" => user.nickname}) + |> response(:ok) + + refute response =~ "Could not find user" + assert response =~ "Remotely follow #{user.nickname}" + end + + test "it works with statuses", %{conn: conn} do + user = insert(:user) + status = insert(:note_activity, %{user: user}) + status_id = status.id + + assert is_binary(status_id) + + response = + conn + |> get("/main/ostatus", %{"status_id" => status_id}) + |> response(:ok) + + refute response =~ "Could not find status" + assert response =~ "Interacting with" + end + end + test "it returns new captcha", %{conn: conn} do with_mock Pleroma.Captcha, new: fn -> "test_captcha" end do diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs index ea05f38f1..12abc1a27 100644 --- a/test/pleroma/workers/receiver_worker_test.exs +++ b/test/pleroma/workers/receiver_worker_test.exs @@ -11,27 +11,9 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do alias Pleroma.User alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Federator alias Pleroma.Workers.ReceiverWorker - defp signature_headers_for(%User{} = signer) do - [ - {"host", "local.test"}, - {"date", "Thu, 25 Jul 2024 13:33:31 GMT"}, - {"digest", "SHA-256=fake-digest"}, - {"content-type", "application/activity+json"}, - { - "signature", - "keyId=\"#{signer.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\"" - } - ] - end - - defp perform_incoming(params) do - ReceiverWorker.perform(%Oban.Job{ - args: %{"op" => "incoming_ap_doc", "params" => params} - }) - end - test "it does not retry MRF reject" do params = insert(:note).data @@ -99,7 +81,16 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do insert(:note_activity).data |> Map.put("actor", "https://springfield.social/users/bart") - assert {:cancel, {:error, :forbidden}} = perform_incoming(params) + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, {:error, :forbidden}} = ReceiverWorker.perform(oban_job) end test "when request returns a 404" do @@ -107,7 +98,16 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do insert(:note_activity).data |> Map.put("actor", "https://springfield.social/users/troymcclure") - assert {:cancel, {:error, :not_found}} = perform_incoming(params) + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job) end test "when request returns a 410" do @@ -115,7 +115,16 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do insert(:note_activity).data |> Map.put("actor", "https://springfield.social/users/hankscorpio") - assert {:cancel, {:error, :not_found}} = perform_incoming(params) + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job) end test "when user account is disabled" do @@ -129,16 +138,86 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do {:ok, %User{}} = User.set_activation(user, false) - assert {:cancel, {:user_active, false}} = perform_incoming(params) + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, {:user_active, false}} = ReceiverWorker.perform(oban_job) end end + test "it can validate the signature" do + Tesla.Mock.mock(fn + %{url: "https://phpc.social/users/denniskoch"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/denniskoch.json"), + headers: [{"content-type", "application/activity+json"}] + } + + %{url: "https://phpc.social/users/denniskoch/collections/featured"} -> + %Tesla.Env{ + status: 200, + headers: [{"content-type", "application/activity+json"}], + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "phpc.social") + |> String.replace("{{nickname}}", "denniskoch") + } + end) + + params = + File.read!("test/fixtures/receiver_worker_signature_activity.json") |> Jason.decode!() + + req_headers = [ + ["accept-encoding", "gzip"], + ["content-length", "5184"], + ["content-type", "application/activity+json"], + ["date", "Thu, 25 Jul 2024 13:33:31 GMT"], + ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="], + ["host", "bikeshed.party"], + [ + "signature", + "keyId=\"https://mastodon.social/users/bastianallgeier#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"ymE3vn5Iw50N6ukSp8oIuXJB5SBjGAGjBasdTDvn+ahZIzq2SIJfmVCsIIzyqIROnhWyQoTbavTclVojEqdaeOx+Ejz2wBnRBmhz5oemJLk4RnnCH0lwMWyzeY98YAvxi9Rq57Gojuv/1lBqyGa+rDzynyJpAMyFk17XIZpjMKuTNMCbjMDy76ILHqArykAIL/v1zxkgwxY/+ELzxqMpNqtZ+kQ29znNMUBB3eVZ/mNAHAz6o33Y9VKxM2jw+08vtuIZOusXyiHbRiaj2g5HtN2WBUw1MzzfRfHF2/yy7rcipobeoyk5RvP5SyHV3WrIeZ3iyoNfmv33y8fxllF0EA==\"" + ], + [ + "user-agent", + "http.rb/5.2.0 (Mastodon/4.3.0-nightly.2024-07-25; +https://mastodon.social/)" + ] + ] + + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: req_headers, + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job) + end + test "cancels due to origin containment" do params = insert(:note_activity).data |> Map.put("id", "https://notorigindomain.com/activity") - assert {:cancel, :origin_containment_failed} = perform_incoming(params) + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) + + assert {:cancel, :origin_containment_failed} = ReceiverWorker.perform(oban_job) end test "canceled due to deleted object" do @@ -154,114 +233,16 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do } end) - assert {:cancel, _} = perform_incoming(params) - end + {:ok, oban_job} = + Federator.incoming_ap_doc(%{ + method: "POST", + req_headers: [], + request_path: "/inbox", + params: params, + query_string: "" + }) - test "delegates legacy failed-signature metadata jobs instead of processing them as trusted" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - object_id = "https://two.com/objects/legacy-forged-note" - - create = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/legacy-forged-create", - "context" => "https://two.com/contexts/legacy-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => object_id, - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "context" => "https://two.com/contexts/legacy-forged-create", - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert {:cancel, :actor_signature_mismatch} = - ReceiverWorker.perform(%Oban.Job{ - args: %{ - "op" => "incoming_ap_doc", - "method" => "POST", - "params" => create, - "req_headers" => signature_headers_for(alice), - "request_path" => "/inbox", - "query_string" => "" - } - }) - - refute Pleroma.Activity.get_by_ap_id(create["id"]) - refute Pleroma.Object.get_by_ap_id(object_id) - end - - test "fails closed for the old persisted failed-signature job shape" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - object_id = "https://two.com/objects/old-shape-forged-note" - - create = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/old-shape-forged-create", - "context" => "https://two.com/contexts/old-shape-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => object_id, - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "context" => "https://two.com/contexts/old-shape-forged-create", - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert {:cancel, :missing_signature_retry_metadata} = - ReceiverWorker.perform(%Oban.Job{ - args: %{ - "op" => "incoming_ap_doc", - "params" => create, - "req_headers" => signature_headers_for(alice), - "timeout" => 20_000 - } - }) - - refute Pleroma.Activity.get_by_ap_id(create["id"]) - refute Pleroma.Object.get_by_ap_id(object_id) - end - - test "fails closed for legacy retry jobs missing one metadata field" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - params = insert(:note_activity).data - - assert {:cancel, :missing_signature_retry_metadata} = - ReceiverWorker.perform(%Oban.Job{ - args: %{ - "op" => "incoming_ap_doc", - "method" => "POST", - "params" => params, - "req_headers" => signature_headers_for(alice), - "request_path" => "/inbox" - } - }) - end - - test "fails closed for malformed legacy metadata jobs without params" do - assert {:cancel, :missing_signature_retry_metadata} = - ReceiverWorker.perform(%Oban.Job{ - args: %{ - "op" => "incoming_ap_doc", - "req_headers" => [], - "timeout" => 20_000 - } - }) + assert {:cancel, _} = ReceiverWorker.perform(oban_job) end describe "Server reachability:" do diff --git a/test/pleroma/workers/signature_retry_worker_test.exs b/test/pleroma/workers/signature_retry_worker_test.exs deleted file mode 100644 index 94dd5f6c1..000000000 --- a/test/pleroma/workers/signature_retry_worker_test.exs +++ /dev/null @@ -1,574 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.SignatureRetryWorkerTest do - use Pleroma.DataCase, async: false - use Oban.Testing, repo: Pleroma.Repo - - import ExUnit.CaptureLog - import Pleroma.Factory - - @moduletag capture_log: true - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Signature - alias Pleroma.User - alias Pleroma.Web.ActivityPub.UserView - alias Pleroma.Web.Federator - alias Pleroma.Workers.SignatureRetryWorker - - defp signature_headers_for(%User{} = signer) do - [ - {"host", "local.test"}, - {"date", "Thu, 25 Jul 2024 13:33:31 GMT"}, - {"digest", "SHA-256=fake-digest"}, - {"content-type", "application/activity+json"}, - { - "signature", - "keyId=\"#{signer.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\"" - } - ] - end - - defp stub_actor_fetch(%User{} = signer) do - signer_json = UserView.render("user.json", %{user: signer}) |> Map.delete("featured") - - Tesla.Mock.mock(fn - %{url: url} when url == signer.ap_id -> - %Tesla.Env{ - status: 200, - body: Jason.encode!(signer_json), - headers: HttpRequestMock.activitypub_object_headers() - } - end) - end - - defp expect_signature_from(%User{} = signer) do - stub_actor_fetch(signer) - Mox.expect(Pleroma.StubbedHTTPSignaturesMock, :validate_conn, fn _conn -> true end) - end - - defp enqueue_failed_signature(params, signer) do - Federator.incoming_failed_signature_ap_doc(%{ - method: "POST", - req_headers: signature_headers_for(signer), - request_path: "/inbox", - params: params, - query_string: "" - }) - end - - defp failed_signature_job(params, req_headers, opts \\ []) do - %Oban.Job{ - args: %{ - "op" => "incoming_failed_signature_ap_doc", - "method" => Keyword.get(opts, :method, "POST"), - "req_headers" => req_headers, - "request_path" => Keyword.get(opts, :request_path, "/inbox"), - "params" => params, - "query_string" => Keyword.get(opts, :query_string, "") - } - } - end - - defp assert_mismatched_signature_cancelled(params, signer) do - assert {:ok, oban_job} = enqueue_failed_signature(params, signer) - - capture_log([level: :warning], fn -> - assert {:cancel, :actor_signature_mismatch} = SignatureRetryWorker.perform(oban_job) - end) - end - - test "Federator preserves request metadata for failed-signature retry jobs" do - params = insert(:note_activity).data - - req_headers = [ - {"host", "local.test"}, - {"signature", "keyId=\"https://one.com/users/alice#main-key\""} - ] - - assert {:ok, oban_job} = - Federator.incoming_failed_signature_ap_doc(%{ - method: "POST", - req_headers: req_headers, - request_path: "/inbox", - params: params, - query_string: "foo=bar" - }) - - assert oban_job.worker == "Pleroma.Workers.SignatureRetryWorker" - - assert %{ - "op" => "incoming_failed_signature_ap_doc", - "method" => "POST", - "req_headers" => ^req_headers, - "request_path" => "/inbox", - "params" => ^params, - "query_string" => "foo=bar" - } = oban_job.args - end - - test "cancels retry jobs without request metadata" do - params = insert(:note_activity).data - - log = - capture_log([level: :warning], fn -> - assert {:cancel, :missing_signature_retry_metadata} = - SignatureRetryWorker.perform(%Oban.Job{ - args: %{"op" => "incoming_failed_signature_ap_doc", "params" => params} - }) - end) - - assert log =~ "Failed-signature inbox retry rejected" - assert log =~ "reason=:missing_signature_retry_metadata" - assert log =~ "payload_actor=#{inspect(params["actor"])}" - assert log =~ "activity_id=#{inspect(params["id"])}" - assert log =~ "type=#{inspect(params["type"])}" - assert log =~ "request_path=nil" - end - - test "cancels retry jobs with malformed serialized request headers" do - params = insert(:note_activity).data - - log = - capture_log([level: :warning], fn -> - assert {:cancel, :invalid_signature_retry_metadata} = - SignatureRetryWorker.perform(failed_signature_job(params, [["signature"]])) - end) - - assert log =~ "Failed-signature inbox retry rejected" - assert log =~ "reason=:invalid_signature_retry_metadata" - assert log =~ "signature_actor=nil" - assert log =~ "request_path=\"/inbox\"" - end - - test "cancels retry jobs without a signature header" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - params = insert(:note_activity, user: alice).data - - log = - capture_log([level: :warning], fn -> - assert {:cancel, :invalid_signature} = - SignatureRetryWorker.perform( - failed_signature_job(params, [{"host", "local.test"}]) - ) - end) - - assert log =~ "Failed-signature inbox retry rejected" - assert log =~ "reason=:invalid_signature" - assert log =~ "payload_actor=#{inspect(params["actor"])}" - assert log =~ "signature_actor=nil" - assert log =~ "request_path=\"/inbox\"" - end - - test "cancels missing signature before fetching an unavailable payload actor" do - params = - insert(:note_activity).data - |> Map.put("actor", "https://unavailable.example/users/bob") - - assert {:cancel, :invalid_signature} = - SignatureRetryWorker.perform(failed_signature_job(params, [{"host", "local.test"}])) - end - - test "cancels signer mismatch before fetching an unavailable payload actor" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - - params = - insert(:note_activity).data - |> Map.put("actor", "https://unavailable.example/users/bob") - - assert {:cancel, :actor_signature_mismatch} = - SignatureRetryWorker.perform( - failed_signature_job(params, signature_headers_for(alice)) - ) - end - - test "cancels retry jobs with a signature header without keyId" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - params = insert(:note_activity, user: alice).data - - req_headers = [{"signature", "algorithm=\"rsa-sha256\",signature=\"fake-signature\""}] - - assert {:cancel, :invalid_signature} = - SignatureRetryWorker.perform(failed_signature_job(params, req_headers)) - end - - test "cancels retry jobs with an unparsable signature keyId" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - params = insert(:note_activity, user: alice).data - req_headers = [{"signature", "keyId=\"not an activitypub id\",signature=\"fake-signature\""}] - - assert {:cancel, :invalid_signature} = - SignatureRetryWorker.perform(failed_signature_job(params, req_headers)) - end - - test "cancels when the refetched key still cannot validate the signature" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - - create = %{ - "type" => "Create", - "actor" => alice.ap_id, - "id" => "https://one.com/activities/invalid-signature-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://one.com/objects/invalid-signature-note", - "actor" => alice.ap_id, - "attributedTo" => alice.ap_id, - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - stub_actor_fetch(alice) - - assert {:ok, oban_job} = enqueue_failed_signature(create, alice) - - log = - capture_log([level: :warning], fn -> - assert {:cancel, :invalid_signature} = SignatureRetryWorker.perform(oban_job) - end) - - assert log =~ "Failed-signature inbox retry rejected" - assert log =~ "reason=:invalid_signature" - assert log =~ "payload_actor=\"https://one.com/users/alice\"" - assert log =~ "signature_actor=\"https://one.com/users/alice\"" - assert log =~ "activity_id=\"https://one.com/activities/invalid-signature-create\"" - assert log =~ "type=\"Create\"" - assert log =~ "request_path=\"/inbox\"" - - refute Activity.get_by_ap_id(create["id"]) - end - - test "processes the activity after refetching a valid matching signature" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - - create = %{ - "type" => "Create", - "actor" => alice.ap_id, - "id" => "https://one.com/activities/valid-signature-create", - "context" => "https://one.com/contexts/valid-signature-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://one.com/objects/valid-signature-note", - "actor" => alice.ap_id, - "attributedTo" => alice.ap_id, - "context" => "https://one.com/contexts/valid-signature-create", - "content" => "valid post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - expect_signature_from(alice) - - assert {:ok, oban_job} = enqueue_failed_signature(create, alice) - assert {:ok, %Activity{}} = SignatureRetryWorker.perform(oban_job) - assert Activity.get_by_ap_id(create["id"]) - end - - test "processes the activity when a real signature validates with a query string" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - - create = %{ - "type" => "Create", - "actor" => alice.ap_id, - "id" => "https://one.com/activities/valid-query-signature-create", - "context" => "https://one.com/contexts/valid-query-signature-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://one.com/objects/valid-query-signature-note", - "actor" => alice.ap_id, - "attributedTo" => alice.ap_id, - "context" => "https://one.com/contexts/valid-query-signature-create", - "content" => "valid signed post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - stub_actor_fetch(alice) - - date = "Thu, 25 Jul 2024 13:33:31 GMT" - digest = "SHA-256=fake-digest" - - signature = - Signature.sign(alice, %{ - "(request-target)" => "post /inbox?foo=bar", - "content-type" => "application/activity+json", - date: date, - digest: digest, - host: "local.test" - }) - - req_headers = [ - ["host", "local.test"], - ["date", date], - ["digest", digest], - ["content-type", "application/activity+json"], - ["signature", signature] - ] - - assert {:ok, %Activity{}} = - SignatureRetryWorker.perform( - failed_signature_job(create, req_headers, query_string: "foo=bar") - ) - - assert Activity.get_by_ap_id(create["id"]) - end - - test "cancels when signature actor does not match payload actor" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - note = - insert(:note, - user: bob, - object_local: false, - data: %{"id" => "https://two.com/objects/malicious-update-note"} - ) - - update = %{ - "type" => "Update", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/malicious-update", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data - } - - assert_mismatched_signature_cancelled(update, alice) - end - - test "cancels signature actor mismatch through Federator-created jobs" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - note = - insert(:note, - user: bob, - object_local: false, - data: %{"id" => "https://two.com/objects/federator-malicious-note"} - ) - - update = %{ - "type" => "Update", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/federator-malicious-update", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data - } - - assert_mismatched_signature_cancelled(update, alice) - end - - test "cancels signature actor mismatch before processing a forged Create" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - create = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://two.com/objects/forged-note", - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert_mismatched_signature_cancelled(create, alice) - end - - test "cancels signature actor mismatch when payload actor is embedded" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - create = %{ - "type" => "Create", - "actor" => %{"id" => bob.ap_id}, - "id" => "https://two.com/activities/embedded-actor-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://two.com/objects/embedded-actor-forged-note", - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert_mismatched_signature_cancelled(create, alice) - end - - test "logs signature actor mismatch retry rejections" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - create = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/logged-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => "https://two.com/objects/logged-forged-note", - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - log = assert_mismatched_signature_cancelled(create, alice) - - assert log =~ "Failed-signature inbox retry rejected" - assert log =~ "reason=:actor_signature_mismatch" - assert log =~ "payload_actor=\"https://two.com/users/bob\"" - assert log =~ "signature_actor=\"https://one.com/users/alice\"" - assert log =~ "activity_id=\"https://two.com/activities/logged-forged-create\"" - assert log =~ "type=\"Create\"" - assert log =~ "request_path=\"/inbox\"" - end - - test "cancels signature actor mismatch before actually creating a forged post" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - object_id = "https://two.com/objects/actually-forged-note" - - create = %{ - "type" => "Create", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/actually-forged-create", - "context" => "https://two.com/contexts/actually-forged-create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => %{ - "type" => "Note", - "id" => object_id, - "actor" => bob.ap_id, - "attributedTo" => bob.ap_id, - "context" => "https://two.com/contexts/actually-forged-create", - "content" => "forged post", - "published" => "2024-07-25T13:33:31Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [] - } - } - - assert_mismatched_signature_cancelled(create, alice) - refute Object.get_by_ap_id(object_id) - end - - test "cancels signature actor mismatch before processing a forged Like" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - - like = %{ - "type" => "Like", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/forged-like", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data["id"] - } - - assert_mismatched_signature_cancelled(like, alice) - end - - test "cancels signature actor mismatch before actually creating a forged Like" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - - like = %{ - "type" => "Like", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/actually-forged-like", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data["id"] - } - - assert_mismatched_signature_cancelled(like, alice) - refute Activity.get_by_ap_id(like["id"]) - end - - test "cancels signature actor mismatch before processing a forged Announce" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - note = insert(:note) - - announce = %{ - "type" => "Announce", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/forged-announce", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => note.data["id"] - } - - assert_mismatched_signature_cancelled(announce, alice) - end - - test "cancels signature actor mismatch before processing a forged Follow" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - followed = insert(:user) - - follow = %{ - "type" => "Follow", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/forged-follow", - "to" => [followed.ap_id], - "cc" => [], - "object" => followed.ap_id - } - - assert_mismatched_signature_cancelled(follow, alice) - end - - test "cancels signature actor mismatch before processing a forged Undo" do - alice = insert(:user, local: false, ap_id: "https://one.com/users/alice") - bob = insert(:user, local: false, ap_id: "https://two.com/users/bob") - - undo = %{ - "type" => "Undo", - "actor" => bob.ap_id, - "id" => "https://two.com/activities/forged-undo", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "object" => "https://two.com/activities/existing-bob-activity" - } - - assert_mismatched_signature_cancelled(undo, alice) - end -end diff --git a/tools/check-changelog b/tools/check-changelog index d09a68895..5952aefcc 100644 --- a/tools/check-changelog +++ b/tools/check-changelog @@ -1,14 +1,14 @@ #!/bin/sh echo "adding ownership exception" -git config --global --add safe.directory "$(pwd)" +git config --global --add safe.directory $(pwd) echo "looking for change log" git remote add upstream https://git.pleroma.social/pleroma/pleroma.git -git fetch upstream ${CI_COMMIT_TARGET_BRANCH}:refs/remotes/upstream/${CI_COMMIT_TARGET_BRANCH} +git fetch upstream ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}:refs/remotes/upstream/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME -git diff --raw --no-renames upstream/${CI_COMMIT_TARGET_BRANCH} HEAD -- changelog.d | \ +git diff --raw --no-renames upstream/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME HEAD -- changelog.d | \ grep ' A\t' | grep '\.\(skip\|add\|remove\|fix\|security\|change\)$' ret=$?