diff --git a/.gitignore b/.gitignore index f9de4ed49..14373fb8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # App artifacts docs/site +*.zip *.sw* secret /_build diff --git a/CHANGELOG.md b/CHANGELOG.md index 15472eda6..ac6695c36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,13 @@ 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/). -## Unreleased +## 2022.11 ## Added - Officially supported docker release - Ability to remove followers unilaterally without a block - Scraping of nodeinfo from remote instances to display instance info +- `requested_by` in relationships when the user has requested to follow you ## Changes - Follows no longer override domain blocks, a domain block is final @@ -19,6 +20,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Fixed - Registrations via ldap are now compatible with the latest OTP24 +## Update notes +- If you use LDAP and run from source, please update your elixir/erlang + to the latest. The changes in OTP24.3 are breaking. +- You can now remove the leading `*.` from domain blocks, but you do not have to. + ## 2022.10 ### Added diff --git a/README.md b/README.md index 74b8919e4..8d35212aa 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is a fork of Pleroma, which is a microblogging server software that can federate (= exchange messages with) other servers that support ActivityPub. What that means is that you can host a server for yourself or your friends and stay in control of your online identity, but still exchange messages with people on larger servers. Akkoma will federate with all servers that implement ActivityPub, like Friendica, GNU Social, Hubzilla, Mastodon, Misskey, Peertube, and Pixelfed. -Akkoma is written in Elixir and uses PostgresSQL for data storage. +Akkoma is written in Elixir and uses PostgreSQL for data storage. For clients it supports the [Mastodon client API](https://docs.joinmastodon.org/api/guidelines/) with Pleroma extensions (see the API section on ). @@ -46,15 +46,13 @@ If your platform is not supported, or you just want to be able to edit the sourc - [Alpine Linux](https://docs.akkoma.dev/stable/installation/alpine_linux_en/) - [Arch Linux](https://docs.akkoma.dev/stable/installation/arch_linux_en/) - [Debian-based](https://docs.akkoma.dev/stable/installation/debian_based_en/) -- [Debian-based (jp)](https://docs.akkoma.dev/stable/installation/debian_based_jp/) - [FreeBSD](https://docs.akkoma.dev/stable/installation/freebsd_en/) - [Gentoo Linux](https://docs.akkoma.dev/stable/installation/gentoo_en/) - [NetBSD](https://docs.akkoma.dev/stable/installation/netbsd_en/) - [OpenBSD](https://docs.akkoma.dev/stable/installation/openbsd_en/) -- [OpenBSD (fi)](https://docs.akkoma.dev/stable/installation/openbsd_fi/) ### Docker -While we don’t provide docker files, other people have written very good ones. Take a look at or . +Docker installation is supported via [this setup](https://docs.akkoma.dev/stable/installation/docker_en/) ### Compilation Troubleshooting If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things: @@ -66,3 +64,4 @@ If you ever encounter compilation issues during the updating of Akkoma, you can ## Documentation - https://docs.akkoma.dev/stable +- https://docs.akkoma.dev/develop diff --git a/config/config.exs b/config/config.exs index 644155aeb..ba77d8b02 100644 --- a/config/config.exs +++ b/config/config.exs @@ -317,7 +317,7 @@ config :pleroma, :frontend_configurations, nsfwCensorImage: "", postContentType: "text/plain", redirectRootLogin: "/main/friends", - redirectRootNoLogin: "/main/all", + redirectRootNoLogin: "/main/public", scopeCopy: true, sidebarRight: false, showFeaturesPanel: true, @@ -584,6 +584,27 @@ config :pleroma, :workers, federator_incoming: 5, federator_outgoing: 5, search_indexing: 2 + ], + timeout: [ + activity_expiration: :timer.seconds(5), + token_expiration: :timer.seconds(5), + filter_expiration: :timer.seconds(5), + backup: :timer.seconds(900), + federator_incoming: :timer.seconds(10), + federator_outgoing: :timer.seconds(10), + ingestion_queue: :timer.seconds(5), + web_push: :timer.seconds(5), + mailer: :timer.seconds(5), + transmogrifier: :timer.seconds(5), + scheduled_activities: :timer.seconds(5), + poll_notifications: :timer.seconds(5), + background: :timer.seconds(5), + remote_fetcher: :timer.seconds(10), + attachments_cleanup: :timer.seconds(900), + new_users_digest: :timer.seconds(10), + mute_expire: :timer.seconds(5), + search_indexing: :timer.seconds(5), + nodeinfo_fetcher: :timer.seconds(10) ] config :pleroma, Pleroma.Formatter, diff --git a/config/description.exs b/config/description.exs index 4843c0aae..287abb747 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1979,6 +1979,32 @@ config :pleroma, :config_description, [ federator_incoming: 5, federator_outgoing: 5 ] + }, + %{ + key: :timeout, + type: {:keyword, :integer}, + description: "Timeout for jobs, per `Oban` queue, in ms", + suggestions: [ + activity_expiration: :timer.seconds(5), + token_expiration: :timer.seconds(5), + filter_expiration: :timer.seconds(5), + backup: :timer.seconds(900), + federator_incoming: :timer.seconds(10), + federator_outgoing: :timer.seconds(10), + ingestion_queue: :timer.seconds(5), + web_push: :timer.seconds(5), + mailer: :timer.seconds(5), + transmogrifier: :timer.seconds(5), + scheduled_activities: :timer.seconds(5), + poll_notifications: :timer.seconds(5), + background: :timer.seconds(5), + remote_fetcher: :timer.seconds(10), + attachments_cleanup: :timer.seconds(900), + new_users_digest: :timer.seconds(10), + mute_expire: :timer.seconds(5), + search_indexing: :timer.seconds(5), + nodeinfo_fetcher: :timer.seconds(10) + ] } ] }, diff --git a/docs/Makefile b/docs/Makefile index 022459cf0..85b6dee65 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,9 +1,14 @@ all: install pipenv run mkdocs build +branch := $(shell git rev-parse --abbrev-ref HEAD) install: pipenv install clean: rm -rf site serve: pipenv run python3 -m http.server -d site +zip: + zip -r docs.zip site/* +deploy: + cd site && rclone copy . scaleway:akkoma-docs/$(branch) diff --git a/docs/Pipfile.lock b/docs/Pipfile.lock index ae39a2776..c7b8f50db 100644 --- a/docs/Pipfile.lock +++ b/docs/Pipfile.lock @@ -14,6 +14,22 @@ ] }, "default": { + "certifi": { + "hashes": [ + "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", + "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" + ], + "markers": "python_version >= '3.6'", + "version": "==2022.9.24" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", + "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.1" + }, "click": { "hashes": [ "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", @@ -29,13 +45,13 @@ ], "version": "==2.1.0" }, - "importlib-metadata": { + "idna": { "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], - "markers": "python_version >= '3.7'", - "version": "==4.12.0" + "markers": "python_version >= '3.5'", + "version": "==3.4" }, "jinja2": { "hashes": [ @@ -55,10 +71,10 @@ }, "markdown-include": { "hashes": [ - "sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2" + "sha256:a06183b7c7225e73112737acdc6fe0ac0686c39457234eeb5ede23881fed001d" ], "index": "pypi", - "version": "==0.6.0" + "version": "==0.7.0" }, "markupsafe": { "hashes": [ @@ -116,27 +132,27 @@ }, "mkdocs": { "hashes": [ - "sha256:26bd2b03d739ac57a3e6eed0b7bcc86168703b719c27b99ad6ca91dc439aacde", - "sha256:b504405b04da38795fec9b2e5e28f6aa3a73bb0960cb6d5d27ead28952bd35ea" + "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5", + "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c" ], - "markers": "python_version >= '3.6'", - "version": "==1.3.0" + "markers": "python_version >= '3.7'", + "version": "==1.4.2" }, "mkdocs-material": { "hashes": [ - "sha256:263f2721f3abe533b61f7c8bed435a0462620912742c919821ac2d698b4bfe67", - "sha256:dc82b667d2a83f0de581b46a6d0949732ab77e7638b87ea35b770b33bc02e75a" + "sha256:143ea55843b3747b640e1110824d91e8a4c670352380e166e64959f9abe98862", + "sha256:45eeabb23d2caba8fa3b85c91d9ec8e8b22add716e9bba8faf16d56af8aa5622" ], "index": "pypi", - "version": "==8.3.9" + "version": "==8.5.9" }, "mkdocs-material-extensions": { "hashes": [ - "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44", - "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2" + "sha256:96ca979dae66d65c2099eefe189b49d5ac62f76afb59c38e069ffc7cf3c131ec", + "sha256:bcc2e5fc70c0ec50e59703ee6e639d87c7e664c0c441c014ea84461a90f1e902" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.3" + "markers": "python_version >= '3.7'", + "version": "==1.1" }, "packaging": { "hashes": [ @@ -148,19 +164,19 @@ }, "pygments": { "hashes": [ - "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", - "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" + "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", + "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" ], "markers": "python_version >= '3.6'", - "version": "==2.12.0" + "version": "==2.13.0" }, "pymdown-extensions": { "hashes": [ - "sha256:3ef2d998c0d5fa7eb09291926d90d69391283561cf6306f85cd588a5eb5befa0", - "sha256:ec141c0f4983755349f0c8710416348d1a13753976c028186ed14f190c8061c4" + "sha256:1bd4a173095ef8c433b831af1f3cb13c10883be0c100ae613560668e594651f7", + "sha256:8e62688a8b1128acd42fa823f3d429d22f4284b5e6dd4d3cd56721559a5a211b" ], "markers": "python_version >= '3.7'", - "version": "==9.5" + "version": "==9.8" }, "pyparsing": { "hashes": [ @@ -180,6 +196,7 @@ }, "pyyaml": { "hashes": [ + "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", @@ -191,26 +208,32 @@ "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" ], @@ -225,6 +248,14 @@ "markers": "python_version >= '3.6'", "version": "==0.1" }, + "requests": { + "hashes": [ + "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", + "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + ], + "markers": "python_version >= '3.7' and python_version < '4'", + "version": "==2.28.1" + }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -233,6 +264,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "urllib3": { + "hashes": [ + "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", + "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", + "version": "==1.26.12" + }, "watchdog": { "hashes": [ "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", @@ -263,14 +302,6 @@ ], "markers": "python_version >= '3.6'", "version": "==2.1.9" - }, - "zipp": { - "hashes": [ - "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", - "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.0" } }, "develop": {} diff --git a/docs/docs/development/API/differences_in_mastoapi_responses.md b/docs/docs/development/API/differences_in_mastoapi_responses.md index 752be1762..b41561c45 100644 --- a/docs/docs/development/API/differences_in_mastoapi_responses.md +++ b/docs/docs/development/API/differences_in_mastoapi_responses.md @@ -195,7 +195,7 @@ Additional parameters can be added to the JSON body/Form data: - `preview`: boolean, if set to `true` the post won't be actually posted, but the status entity would still be rendered back. This could be useful for previewing rich text/custom emoji, for example. - `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint. -- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply. +- `to`: A list of nicknames (like `admin@otp.akkoma.dev` or `admin` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply. - `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted`, `local` or `public`) it can be used to address a List by setting it to `list:LIST_ID`. - `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour. - `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`. diff --git a/docs/docs/development/API/prometheus.md b/docs/docs/development/API/prometheus.md index 0c23a404d..39ecc5d38 100644 --- a/docs/docs/development/API/prometheus.md +++ b/docs/docs/development/API/prometheus.md @@ -40,5 +40,5 @@ The following is a config example to use with [Grafana](https://grafana.com) metrics_path: /api/pleroma/app_metrics scheme: https static_configs: - - targets: ['pleroma.soykaf.com'] + - targets: ['otp.akkoma.dev'] ``` diff --git a/docs/docs/index.md b/docs/docs/index.md index 1018e9c2b..f5b00b457 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -29,14 +29,14 @@ If you don't feel like joining an existing instance, but instead prefer to deplo Installation instructions can be found in the installation section of these docs. ## I got an account, now what? -Great! Now you can explore the fediverse! Open the login page for your Akkoma instance (e.g. ) and login with your username and password. (If you don't have an account yet, click on Register) +Great! Now you can explore the fediverse! Open the login page for your Akkoma instance (e.g. ) and login with your username and password. (If you don't have an account yet, click on Register) ### Pleroma-FE The default front-end used by Akkoma is Pleroma-FE. You can find more information on what it is and how to use it in the [Introduction to Pleroma-FE](https://docs-fe.akkoma.dev/stable/). ### Mastodon interface If the Pleroma-FE interface isn't your thing, or you're just trying something new but you want to keep using the familiar Mastodon interface, we got that too! -Just add a "/web" after your instance url (e.g. ) and you'll end on the Mastodon web interface, but with a Akkoma backend! MAGIC! +Just add a "/web" after your instance url (e.g. ) and you'll end on the Mastodon web interface, but with a Akkoma backend! MAGIC! The Mastodon interface is from the Glitch-soc fork. For more information on the Mastodon interface you can check the [Mastodon](https://docs.joinmastodon.org/) and [Glitch-soc](https://glitch-soc.github.io/docs/) documentation. Remember, what you see is only the frontend part of Mastodon, the backend is still Akkoma. diff --git a/docs/requirements.txt b/docs/requirements.txt index 70fbd9dc4..d67bbf65f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,22 +1,26 @@ +certifi==2022.9.24 +charset-normalizer==2.1.1 click==8.1.3 ghp-import==2.1.0 +idna==3.4 importlib-metadata==4.12.0 Jinja2==3.1.2 Markdown==3.3.7 -markdown-include==0.6.0 +markdown-include==0.7.0 MarkupSafe==2.1.1 mergedeep==1.3.4 -mkdocs==1.3.0 -mkdocs-bootswatch==1.1 -mkdocs-material==8.1.8 -mkdocs-material-extensions==1.0.3 +mkdocs==1.4.2 +mkdocs-material==8.5.9 +mkdocs-material-extensions==1.1 packaging==21.3 -Pygments==2.11.2 -pymdown-extensions==9.1 +Pygments==2.13.0 +pymdown-extensions==9.8 pyparsing==3.0.9 python-dateutil==2.8.2 PyYAML==6.0 pyyaml_env_tag==0.1 +requests==2.28.1 six==1.16.0 +urllib3==1.26.12 watchdog==2.1.9 zipp==3.8.0 diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index 770044de2..3a00424c6 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -48,7 +48,9 @@ defmodule Pleroma.Web.Federator do @impl true def publish(%{data: %{"object" => object}} = activity) when is_binary(object) do - PublisherWorker.enqueue("publish", %{"activity_id" => activity.id, "object_data" => nil}) + PublisherWorker.enqueue("publish", %{"activity_id" => activity.id, "object_data" => nil}, + priority: publish_priority(activity) + ) end @impl true @@ -63,7 +65,7 @@ defmodule Pleroma.Web.Federator do ) end - defp publish_priority(%{type: "Delete"}), do: 3 + defp publish_priority(%{data: %{"type" => "Delete"}}), do: 3 defp publish_priority(_), do: 0 # Job Worker Callbacks diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index cbb57aee6..a04ffaaf3 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -94,12 +94,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do followed_by = if following_relationships do - case FollowingRelationship.find(following_relationships, target, reading_user) do - %{state: :follow_accept} -> true - _ -> false - end + target_to_user_following_relation = + FollowingRelationship.find(following_relationships, target, reading_user) + + User.get_follow_state(target, reading_user, target_to_user_following_relation) else - User.following?(target, reading_user) + User.get_follow_state(target, reading_user) end subscribing = @@ -115,7 +115,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do %{ id: to_string(target.id), following: follow_state == :follow_accept, - followed_by: followed_by, + followed_by: followed_by == :follow_accept, blocking: UserRelationship.exists?( user_relationships, @@ -151,6 +151,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do subscribing: subscribing, notifying: subscribing, requested: follow_state == :follow_pending, + requested_by: followed_by == :follow_pending, domain_blocking: User.blocks_domain?(reading_user, target), showing_reblogs: not UserRelationship.exists?( diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 3e8e931d1..fc2f7b268 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -104,13 +104,12 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do {[img_src, " https:"], [media_src, " https:"]} end - connect_src = ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] - connect_src = - if Config.get(:env) == :dev do - [connect_src, " http://localhost:3035/"] + if Config.get([:media_proxy, :enabled]) do + sources = build_csp_multimedia_source_list() + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url, ?\s, sources] else - connect_src + ["connect-src 'self' blob: ", static_url, ?\s, websocket_url] end script_src = diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex index 7b87d8f17..72f20e8de 100644 --- a/lib/pleroma/web/plugs/uploaded_media.ex +++ b/lib/pleroma/web/plugs/uploaded_media.ex @@ -35,7 +35,7 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do conn = case fetch_query_params(conn) do %{query_params: %{"name" => name}} = conn -> - name = String.replace(name, "\"", "\\\"") + name = escape_header_value(name) put_resp_header(conn, "content-disposition", "filename=\"#{name}\"") @@ -98,4 +98,11 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do |> send_resp(:internal_server_error, dgettext("errors", "Internal Error")) |> halt() end + + defp escape_header_value(value) do + value + |> String.replace("\"", "\\\"") + |> String.replace("\\r", "") + |> String.replace("\\n", "") + end end diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex index 66c5c3591..cf78f1cb9 100644 --- a/lib/pleroma/workers/backup_worker.ex +++ b/lib/pleroma/workers/backup_worker.ex @@ -14,6 +14,11 @@ defmodule Pleroma.Workers.BackupWorker do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :backup], :timer.minutes(1)) + end + def schedule_deletion(backup) do days = Pleroma.Config.get([Backup, :purge_after_days]) time = 60 * 60 * 24 * days @@ -30,6 +35,7 @@ defmodule Pleroma.Workers.BackupWorker do |> Oban.insert() end + @impl true def perform(%Job{ args: %{"op" => "process", "backup_id" => backup_id, "admin_user_id" => admin_user_id} }) do diff --git a/lib/pleroma/workers/purge_expired_activity.ex b/lib/pleroma/workers/purge_expired_activity.ex index 027171c1e..652e1d6b1 100644 --- a/lib/pleroma/workers/purge_expired_activity.ex +++ b/lib/pleroma/workers/purge_expired_activity.ex @@ -27,6 +27,11 @@ defmodule Pleroma.Workers.PurgeExpiredActivity do end end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :activity_expiration], :timer.minutes(1)) + end + @impl true def perform(%Oban.Job{args: %{"activity_id" => id}}) do with %Activity{} = activity <- find_activity(id), diff --git a/lib/pleroma/workers/purge_expired_filter.ex b/lib/pleroma/workers/purge_expired_filter.ex index 4740d52e9..593380d13 100644 --- a/lib/pleroma/workers/purge_expired_filter.ex +++ b/lib/pleroma/workers/purge_expired_filter.ex @@ -24,6 +24,11 @@ defmodule Pleroma.Workers.PurgeExpiredFilter do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :filter_expiration], :timer.minutes(1)) + end + @impl true def perform(%Job{args: %{"filter_id" => id}}) do Pleroma.Filter diff --git a/lib/pleroma/workers/purge_expired_token.ex b/lib/pleroma/workers/purge_expired_token.ex index cfdf5c6dc..b4db84f4e 100644 --- a/lib/pleroma/workers/purge_expired_token.ex +++ b/lib/pleroma/workers/purge_expired_token.ex @@ -19,6 +19,11 @@ defmodule Pleroma.Workers.PurgeExpiredToken do |> Oban.insert() end + @impl Oban.Worker + def timeout(_job) do + Pleroma.Config.get([:workers, :timeout, :token_expiration], :timer.minutes(1)) + end + @impl true def perform(%Oban.Job{args: %{"token_id" => id, "mod" => module}}) do module diff --git a/lib/pleroma/workers/worker_helper.ex b/lib/pleroma/workers/worker_helper.ex index 4befbeb3b..4c0a55774 100644 --- a/lib/pleroma/workers/worker_helper.ex +++ b/lib/pleroma/workers/worker_helper.ex @@ -43,6 +43,12 @@ defmodule Pleroma.Workers.WorkerHelper do |> apply(:new, [params, worker_args]) |> Oban.insert() end + + @impl Oban.Worker + def timeout(_job) do + queue_atom = String.to_atom(unquote(queue)) + Config.get([:workers, :timeout, queue_atom], :timer.minutes(1)) + end end end end diff --git a/mix.exs b/mix.exs index d95cc1778..201299aa5 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("3.3.1"), + version: version("3.4.0"), elixir: "~> 1.12", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), diff --git a/priv/gettext/es/LC_MESSAGES/errors.po b/priv/gettext/es/LC_MESSAGES/errors.po index 0a6fceaad..166e2fb98 100644 --- a/priv/gettext/es/LC_MESSAGES/errors.po +++ b/priv/gettext/es/LC_MESSAGES/errors.po @@ -3,16 +3,16 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-09-09 09:49+0000\n" -"PO-Revision-Date: 2020-09-11 21:26+0000\n" -"Last-Translator: tarteka \n" -"Language-Team: Spanish \n" +"PO-Revision-Date: 2022-08-19 09:25+0000\n" +"Last-Translator: mint \n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.0.4\n" +"X-Generator: Weblate 4.13.1\n" ## This file is a PO Template file. ## @@ -66,8 +66,8 @@ msgstr[1] "debe tener %{count} caracteres" msgid "should have %{count} item(s)" msgid_plural "should have %{count} item(s)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "debería tener %{count} item" +msgstr[1] "debería tener %{count} items" msgid "should be at least %{count} character(s)" msgid_plural "should be at least %{count} character(s)" diff --git a/priv/gettext/nl/LC_MESSAGES/posix_errors.po b/priv/gettext/nl/LC_MESSAGES/posix_errors.po new file mode 100644 index 000000000..d94b0c8e2 --- /dev/null +++ b/priv/gettext/nl/LC_MESSAGES/posix_errors.po @@ -0,0 +1,163 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-08-16 10:49+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 3.7.1\n" + +## This file is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here as no +## effect: edit them in PO (`.po`) files instead. +msgid "eperm" +msgstr "" + +msgid "eacces" +msgstr "" + +msgid "eagain" +msgstr "" + +msgid "ebadf" +msgstr "" + +msgid "ebadmsg" +msgstr "" + +msgid "ebusy" +msgstr "" + +msgid "edeadlk" +msgstr "" + +msgid "edeadlock" +msgstr "" + +msgid "edquot" +msgstr "" + +msgid "eexist" +msgstr "" + +msgid "efault" +msgstr "" + +msgid "efbig" +msgstr "" + +msgid "eftype" +msgstr "" + +msgid "eintr" +msgstr "" + +msgid "einval" +msgstr "" + +msgid "eio" +msgstr "" + +msgid "eisdir" +msgstr "" + +msgid "eloop" +msgstr "" + +msgid "emfile" +msgstr "" + +msgid "emlink" +msgstr "" + +msgid "emultihop" +msgstr "" + +msgid "enametoolong" +msgstr "" + +msgid "enfile" +msgstr "" + +msgid "enobufs" +msgstr "" + +msgid "enodev" +msgstr "" + +msgid "enolck" +msgstr "" + +msgid "enolink" +msgstr "" + +msgid "enoent" +msgstr "" + +msgid "enomem" +msgstr "" + +msgid "enospc" +msgstr "" + +msgid "enosr" +msgstr "" + +msgid "enostr" +msgstr "" + +msgid "enosys" +msgstr "" + +msgid "enotblk" +msgstr "" + +msgid "enotdir" +msgstr "" + +msgid "enotsup" +msgstr "" + +msgid "enxio" +msgstr "" + +msgid "eopnotsupp" +msgstr "" + +msgid "eoverflow" +msgstr "" + +msgid "epipe" +msgstr "" + +msgid "erange" +msgstr "" + +msgid "erofs" +msgstr "" + +msgid "espipe" +msgstr "" + +msgid "esrch" +msgstr "" + +msgid "estale" +msgstr "" + +msgid "etxtbsy" +msgstr "" + +msgid "exdev" +msgstr "" 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 d1903af80..f4a5f4d50 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -347,6 +347,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do subscribing: false, notifying: false, requested: false, + requested_by: false, domain_blocking: false, showing_reblogs: true, endorsed: false, @@ -432,6 +433,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do end end + test "represent a relationship for a user with an inbound pending follow request" do + follower = insert(:user) + followed = insert(:user, is_locked: true) + + {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + + follower = User.get_cached_by_id(follower.id) + followed = User.get_cached_by_id(followed.id) + + expected = + Map.merge( + @blank_response, + %{requested_by: true, followed_by: false, id: to_string(follower.id)} + ) + + test_relationship_rendering(followed, follower, expected) + end + test "returns the settings store if the requesting user is the represented user and it's requested specifically" do user = insert(:user, pleroma_settings_store: %{fe: "test"}) diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index eb94cd665..7f85f4a11 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -100,12 +100,14 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do url = "https://example.com" clear_config([:media_proxy, :base_url], url) assert_media_img_src(conn, url) + assert_connect_src(conn, url) end test "upload with base url", %{conn: conn} do url = "https://example2.com" clear_config([Pleroma.Upload, :base_url], url) assert_media_img_src(conn, url) + assert_connect_src(conn, url) end test "with S3 public endpoint", %{conn: conn} do @@ -138,6 +140,12 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do assert csp =~ "img-src 'self' data: blob: #{url};" end + defp assert_connect_src(conn, url) do + conn = get(conn, "/api/v1/instance") + [csp] = Conn.get_resp_header(conn, "content-security-policy") + assert csp =~ ~r/connect-src 'self' blob: [^;]+ #{url}/ + end + test "it does not send CSP headers when disabled", %{conn: conn} do clear_config([:http_security, :enabled], false) diff --git a/test/pleroma/web/plugs/uploaded_media_plug_test.exs b/test/pleroma/web/plugs/uploaded_media_plug_test.exs index 75f313282..c71a7e789 100644 --- a/test/pleroma/web/plugs/uploaded_media_plug_test.exs +++ b/test/pleroma/web/plugs/uploaded_media_plug_test.exs @@ -40,4 +40,15 @@ defmodule Pleroma.Web.Plugs.UploadedMediaPlugTest do &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""}) ) end + + test "removes control characters from the Content-Disposition header", %{ + attachment_url: attachment_url + } do + conn = get(build_conn(), attachment_url <> "?name=\"cofe\".gif\\r\\n") + + assert Enum.any?( + conn.resp_headers, + &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""}) + ) + end end diff --git a/test/pleroma/workers/publisher_worker_test.exs b/test/pleroma/workers/publisher_worker_test.exs new file mode 100644 index 000000000..cf0ac0ccb --- /dev/null +++ b/test/pleroma/workers/publisher_worker_test.exs @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.PublisherWorkerTest do + use Pleroma.DataCase, async: true + use Oban.Testing, repo: Pleroma.Repo + + import Pleroma.Factory + + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Federator + + describe "Oban job priority:" do + setup do + user = insert(:user) + + {:ok, post} = CommonAPI.post(user, %{status: "Regrettable post"}) + object = Object.normalize(post, fetch: false) + {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) + {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) + + %{ + post: post, + delete: delete + } + end + + test "Deletions are lower priority", %{delete: delete} do + assert {:ok, %Oban.Job{priority: 3}} = Federator.publish(delete) + end + + test "Creates are normal priority", %{post: post} do + assert {:ok, %Oban.Job{priority: 0}} = Federator.publish(post) + end + end + + describe "Oban job timeout" do + test "should have a timeout" do + clear_config([:workers, :timeout, :federator_outgoing], :timer.minutes(2)) + assert Pleroma.Workers.PublisherWorker.timeout(nil) == :timer.minutes(2) + end + + test "should use a default timeout if none specified" do + clear_config([:workers, :timeout, :federator_outgoing]) + assert Pleroma.Workers.PublisherWorker.timeout(nil) == :timer.seconds(10) + end + end +end diff --git a/test/pleroma/workers/purge_expired_activity_test.exs b/test/pleroma/workers/purge_expired_activity_test.exs index 98f30f61f..6285dca3e 100644 --- a/test/pleroma/workers/purge_expired_activity_test.exs +++ b/test/pleroma/workers/purge_expired_activity_test.exs @@ -56,4 +56,9 @@ defmodule Pleroma.Workers.PurgeExpiredActivityTest do assert {:error, :activity_not_found} = perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: "some_if"}) end + + test "has a timeout" do + clear_config([:workers, :timeout, :activity_expiration], 50) + assert Pleroma.Workers.PurgeExpiredActivity.timeout(%Oban.Job{}) == 50 + end end diff --git a/test/pleroma/workers/scheduled_activity_worker_test.exs b/test/pleroma/workers/scheduled_activity_worker_test.exs index 5558d5b5f..9f5f1b687 100644 --- a/test/pleroma/workers/scheduled_activity_worker_test.exs +++ b/test/pleroma/workers/scheduled_activity_worker_test.exs @@ -49,4 +49,9 @@ defmodule Pleroma.Workers.ScheduledActivityWorkerTest do ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => 42}}) end) =~ "Couldn't find scheduled activity: 42" end + + test "has a timeout" do + clear_config([:workers, :timeout, :scheduled_activities], :timer.minutes(5)) + assert ScheduledActivityWorker.timeout(nil) == :timer.minutes(5) + end end