From 55cf85376f7010b17b76a68726e2b6c3dc4de5f6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 22 Mar 2019 23:31:04 +0300 Subject: [PATCH 01/31] Add automatic doc build and deploy --- .gitlab-ci.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d5f2a762a..aecce1629 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,8 @@ stages: - lint - test - analysis + - docs_build + - docs_deploy before_script: - mix local.hex --force @@ -43,3 +45,37 @@ analysis: stage: analysis script: - mix credo --strict --only=warnings,todo,fixme,consistency,readability + +docs_build: + stage: docs_build + only: + - master@pleroma/pleroma + - develop@pleroma/pleroma + variables: + MIX_ENV: dev + before_script: + - mix local.hex --force + - mix local.rebar --force + - mix deps.get + - mix compile + script: + - mix docs + artifacts: + paths: + - priv/static/doc + +docs_deploy: + stage: docs_deploy + image: alpine:3.9 + only: + - master@pleroma/pleroma + - develop@pleroma/pleroma + before_script: + - apk update && apk add openssh-client rsync + script: + - echo ${CI_COMMIT_REF_NAME} + - mkdir -p ~/.ssh + - echo "${SSH_HOST_KEY}" > ~/.ssh/known_hosts + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + - rsync -hrvz --delete -e "ssh -p ${SSH_PORT}" priv/static/doc/ "${SSH_USER_HOST_LOCATION}/${CI_COMMIT_REF_NAME}" From 4bf327b6645b30b377fadc431daee0626a2c3d4b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 23 Mar 2019 01:01:01 +0300 Subject: [PATCH 02/31] Remove postgres from documentation related jobs --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aecce1629..9e070bbb1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,6 +48,7 @@ analysis: docs_build: stage: docs_build + services: only: - master@pleroma/pleroma - develop@pleroma/pleroma @@ -67,6 +68,7 @@ docs_build: docs_deploy: stage: docs_deploy image: alpine:3.9 + services: only: - master@pleroma/pleroma - develop@pleroma/pleroma From a5326bb78331361c79ffaa7a18e03c6f37e0eb46 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 23 Mar 2019 10:19:13 +0300 Subject: [PATCH 03/31] Remove useless echo --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9e070bbb1..dbdf59f65 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -75,7 +75,6 @@ docs_deploy: before_script: - apk update && apk add openssh-client rsync script: - - echo ${CI_COMMIT_REF_NAME} - mkdir -p ~/.ssh - echo "${SSH_HOST_KEY}" > ~/.ssh/known_hosts - eval $(ssh-agent -s) From 6f090f981b26274c87b9df88e1bcb2719f46814b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 25 Mar 2019 18:47:04 -0500 Subject: [PATCH 04/31] Attempt to fix incorrect federation of default instance avatars --- lib/pleroma/user.ex | 8 ++++++++ lib/pleroma/web/activity_pub/utils.ex | 15 +++++++++++++++ lib/pleroma/web/activity_pub/views/user_view.ex | 5 +---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 41289b4d0..ee5eb8efa 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -90,6 +90,14 @@ def avatar_url(user) do end end + # Do not return instance default avatar for federation + def avatar_url_ap(user) do + case user.avatar do + %{"url" => [%{"href" => href} | _]} -> href + _ -> nil + end + end + def banner_url(user) do case user.info.banner do %{"url" => [%{"href" => href} | _]} -> href diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2e9ffe41c..6d74738f0 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -230,6 +230,21 @@ def update_object_in_activities(%{data: %{"id" => id}} = object) do end) end + # Only federate user icon if not nil + # Prevents federating instance default avatars + def maybe_make_icon(user) do + if User.avatar_url_ap(user) do + %{ + "icon" => %{ + "type" => "Image", + "url" => User.avatar_url_ap(user) + } + } + else + [] + end + end + #### Like-related helpers @doc """ diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 3d00dcbf2..f5c86d360 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -87,16 +87,13 @@ def render("user.json", %{user: user}) do "publicKeyPem" => public_key }, "endpoints" => endpoints, - "icon" => %{ - "type" => "Image", - "url" => User.avatar_url(user) - }, "image" => %{ "type" => "Image", "url" => User.banner_url(user) }, "tag" => user.info.source_data["tag"] || [] } + |> Map.merge(Utils.maybe_make_icon(user)) |> Map.merge(Utils.make_json_ld_header()) end From c410296120152095e7b9f5324a798f8446cf3bb3 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 25 Mar 2019 19:00:35 -0500 Subject: [PATCH 05/31] Try sending an empty map --- lib/pleroma/web/activity_pub/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 6d74738f0..86b6e7029 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -241,7 +241,7 @@ def maybe_make_icon(user) do } } else - [] + %{} end end From 263ca3dea2620aa54d3b21b286e1bc1f8f3ed998 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 26 Mar 2019 15:09:06 +0300 Subject: [PATCH 06/31] Mastodon-based auth error messages. Defaulted User#auth_active?/1 to `true`. --- lib/pleroma/user.ex | 6 +----- lib/pleroma/web/oauth/oauth_controller.ex | 9 ++++++--- test/web/oauth/oauth_controller_test.exs | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 41289b4d0..09d20b432 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -60,14 +60,10 @@ defmodule Pleroma.User do timestamps() end - def auth_active?(%User{local: false}), do: true - - def auth_active?(%User{info: %User.Info{confirmation_pending: false}}), do: true - def auth_active?(%User{info: %User.Info{confirmation_pending: true}}), do: !Pleroma.Config.get([:instance, :account_activation_required]) - def auth_active?(_), do: false + def auth_active?(%User{}), do: true def visible_for?(user, for_user \\ nil) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index d151efe9e..be56f460a 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -83,14 +83,16 @@ def create_authorization(conn, %{ end else {scopes_issue, _} when scopes_issue in [:unsupported_scopes, :missing_scopes] -> + # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 conn - |> put_flash(:error, "Permissions not specified.") + |> put_flash(:error, "This action is outside the authorized scopes") |> put_status(:unauthorized) |> authorize(auth_params) {:auth_active, false} -> + # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn - |> put_flash(:error, "Account confirmation pending.") + |> put_flash(:error, "Your login is missing a confirmed e-mail address") |> put_status(:forbidden) |> authorize(auth_params) @@ -149,9 +151,10 @@ def token_exchange( json(conn, response) else {:auth_active, false} -> + # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn |> put_status(:forbidden) - |> json(%{error: "Account confirmation pending"}) + |> json(%{error: "Your login is missing a confirmed e-mail address"}) _error -> put_status(conn, 400) diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index ff1e56fe9..84ec7b4ee 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -87,7 +87,7 @@ test "returns 401 for missing scopes", %{conn: conn} do assert result =~ app.redirect_uris # Error message - assert result =~ "Permissions not specified" + assert result =~ "This action is outside the authorized scopes" end test "returns 401 for scopes beyond app scopes", %{conn: conn} do @@ -113,7 +113,7 @@ test "returns 401 for scopes beyond app scopes", %{conn: conn} do assert result =~ app.redirect_uris # Error message - assert result =~ "Permissions not specified" + assert result =~ "This action is outside the authorized scopes" end test "issues a token for an all-body request" do From b0759f821b13caa5ac2c4462748dcf6530a2d693 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 26 Mar 2019 15:24:29 +0300 Subject: [PATCH 07/31] Comments split. --- lib/pleroma/web/oauth/oauth_controller.ex | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index be56f460a..ebb3dd253 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -83,14 +83,16 @@ def create_authorization(conn, %{ end else {scopes_issue, _} when scopes_issue in [:unsupported_scopes, :missing_scopes] -> - # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 + # Per https://github.com/tootsuite/mastodon/blob/ + # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 conn |> put_flash(:error, "This action is outside the authorized scopes") |> put_status(:unauthorized) |> authorize(auth_params) {:auth_active, false} -> - # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 + # Per https://github.com/tootsuite/mastodon/blob/ + # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn |> put_flash(:error, "Your login is missing a confirmed e-mail address") |> put_status(:forbidden) @@ -151,7 +153,8 @@ def token_exchange( json(conn, response) else {:auth_active, false} -> - # Per https://github.com/tootsuite/mastodon/blob/51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 + # Per https://github.com/tootsuite/mastodon/blob/ + # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn |> put_status(:forbidden) |> json(%{error: "Your login is missing a confirmed e-mail address"}) From 568e34858893f2bab713a210ae82834e3f6c030e Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 25 Mar 2019 20:21:48 +0300 Subject: [PATCH 08/31] Increment replies_count on replies (MastoAPI) --- lib/pleroma/activity.ex | 46 +++++++++++++ lib/pleroma/object.ex | 46 +++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 26 +++++++ .../web/mastodon_api/views/status_view.ex | 2 +- ...190325215156_update_status_reply_count.exs | 48 +++++++++++++ test/web/activity_pub/activity_pub_test.exs | 68 +++++++++++++++++++ 6 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 priv/repo/migrations/20190325215156_update_status_reply_count.exs diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 3dfabe9f3..bc3f8caba 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -245,4 +245,50 @@ def all_by_actor_and_id(actor, status_ids) do |> where([s], s.actor == ^actor) |> Repo.all() end + + def increase_replies_count(id) do + Activity + |> where(id: ^id) + |> update([a], + set: [ + data: + fragment( + """ + jsonb_set(?, '{object, repliesCount}', + (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true) + """, + a.data, + a.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [activity]} -> activity + _ -> {:error, "Not found"} + end + end + + def decrease_replies_count(id) do + Activity + |> where(id: ^id) + |> update([a], + set: [ + data: + fragment( + """ + jsonb_set(?, '{object, repliesCount}', + (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true) + """, + a.data, + a.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [activity]} -> activity + _ -> {:error, "Not found"} + end + end end diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 193ae3fa8..8a670645d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -133,4 +133,50 @@ def update_and_set_cache(changeset) do e -> e end end + + def increase_replies_count(ap_id) do + Object + |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id))) + |> update([o], + set: [ + data: + fragment( + """ + jsonb_set(?, '{repliesCount}', + (coalesce((?->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true) + """, + o.data, + o.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [object]} -> set_cache(object) + _ -> {:error, "Not found"} + end + end + + def decrease_replies_count(ap_id) do + Object + |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id))) + |> update([o], + set: [ + data: + fragment( + """ + jsonb_set(?, '{repliesCount}', + (greatest(0, (?->>'repliesCount')::int - 1))::varchar::jsonb, true) + """, + o.data, + o.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [object]} -> set_cache(object) + _ -> {:error, "Not found"} + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 80c64ae04..0d9a89d0b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -89,6 +89,30 @@ def decrease_note_count_if_public(actor, object) do if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor} end + def increase_replies_count_if_reply(%{ + "object" => + %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object, + "type" => "Create" + }) do + if is_public?(object) do + Activity.increase_replies_count(reply_status_id) + Object.increase_replies_count(reply_ap_id) + end + end + + def increase_replies_count_if_reply(_create_data), do: :noop + + def decrease_replies_count_if_reply(%Object{ + data: %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object + }) do + if is_public?(object) do + Activity.decrease_replies_count(reply_status_id) + Object.decrease_replies_count(reply_ap_id) + end + end + + def decrease_replies_count_if_reply(_object), do: :noop + def insert(map, local \\ true) when is_map(map) do with nil <- Activity.normalize(map), map <- lazy_put_activity_defaults(map), @@ -178,6 +202,7 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d additional ), {:ok, activity} <- insert(create_data, local), + _ <- increase_replies_count_if_reply(create_data), # Changing note count prior to enqueuing federation task in order to avoid # race conditions on updating user.info {:ok, _actor} <- increase_note_count_if_public(actor, activity), @@ -329,6 +354,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru "deleted_activity_id" => activity && activity.id }, {:ok, activity} <- insert(data, local), + _ <- decrease_replies_count_if_reply(object), # Changing note count prior to enqueuing federation task in order to avoid # race conditions on updating user.info {:ok, _actor} <- decrease_note_count_if_public(user, object), diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 1ca8338cc..200bb453d 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -174,7 +174,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} content: content, created_at: created_at, reblogs_count: announcement_count, - replies_count: 0, + replies_count: object["repliesCount"] || 0, favourites_count: like_count, reblogged: present?(repeated), favourited: present?(favorited), diff --git a/priv/repo/migrations/20190325215156_update_status_reply_count.exs b/priv/repo/migrations/20190325215156_update_status_reply_count.exs new file mode 100644 index 000000000..50f1fe10b --- /dev/null +++ b/priv/repo/migrations/20190325215156_update_status_reply_count.exs @@ -0,0 +1,48 @@ +defmodule Pleroma.Repo.Migrations.UpdateStatusReplyCount do + use Ecto.Migration + + @public "https://www.w3.org/ns/activitystreams#Public" + + def up do + execute(""" + WITH reply_count AS ( + SELECT count(*) AS count, data->>'inReplyTo' AS ap_id + FROM objects + WHERE + data->>'inReplyTo' IS NOT NULL AND + data->>'type' = 'Note' AND ( + data->'cc' ? '#{@public}' OR + data->'to' ? '#{@public}') + GROUP BY data->>'inReplyTo' + ) + UPDATE objects AS o + SET "data" = jsonb_set(o.data, '{repliesCount}', reply_count.count::varchar::jsonb, true) + FROM reply_count + WHERE reply_count.ap_id = o.data->>'id'; + """) + + execute(""" + WITH reply_count AS (SELECT + count(*) as count, + data->'object'->>'inReplyTo' AS ap_id + FROM + activities + WHERE + data->'object'->>'inReplyTo' IS NOT NULL AND + data->'object'->>'type' = 'Note' AND ( + data->'object'->'cc' ? '#{@public}' OR + data->'object'->'to' ? '#{@public}') + GROUP BY + data->'object'->>'inReplyTo' + ) + UPDATE activities AS a + SET "data" = jsonb_set(a.data, '{object, repliesCount}', reply_count.count::varchar::jsonb, true) + FROM reply_count + WHERE reply_count.ap_id = a.data->'object'->>'id'; + """) + end + + def down do + :noop + end +end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 96ad64e62..40bcced33 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -232,6 +232,39 @@ test "increases user note count only for public activities" do user = Repo.get(User, user.id) assert user.info.note_count == 2 end + + test "increases replies count" do + user = insert(:user) + user2 = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) + ap_id = activity.data["id"] + reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} + + # public + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 1 + assert object.data["repliesCount"] == 1 + + # unlisted + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + # private + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + # direct + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + end end describe "fetch activities for recipients" do @@ -751,6 +784,40 @@ test "it creates a delete activity and checks that it is also sent to users ment assert user.ap_id in delete.data["to"] end + + test "decreases reply count" do + user = insert(:user) + user2 = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) + reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} + ap_id = activity.data["id"] + + {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public")) + {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted")) + {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private")) + {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct")) + + _ = CommonAPI.delete(direct_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + _ = CommonAPI.delete(private_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + _ = CommonAPI.delete(public_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 1 + assert object.data["repliesCount"] == 1 + + _ = CommonAPI.delete(unlisted_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 0 + assert object.data["repliesCount"] == 0 + end end describe "timeline post-processing" do @@ -789,6 +856,7 @@ test "it filters broken threads" do activities = ActivityPub.fetch_activities([user1.ap_id | user1.following]) + private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"]) assert [public_activity, private_activity_1, private_activity_3] == activities assert length(activities) == 3 From eef1042b167e657a80f831b6c3037cc4924d8147 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 26 Mar 2019 16:27:17 +0300 Subject: [PATCH 09/31] Mastodon 2.7.2 instance attributes (registrations, languages). --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 6be0f2baf..6b7c67012 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -161,6 +161,9 @@ def masto_instance(conn, _params) do }, stats: Stats.get_stats(), thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg", + languages: ["en"], + registrations: Pleroma.Config.get([:instance, :registrations_open]), + # Extra (not present in Mastodon): max_toot_chars: Keyword.get(instance, :limit) } From 406d19331fc80ce3be94e1342ad2d763e88569ce Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 26 Mar 2019 17:16:21 +0300 Subject: [PATCH 10/31] Remove ActivityRepresenter --- .../representers/activity_representer.ex | 15 -- .../activity_representer_test.exs | 170 ------------------ .../twitter_api_controller_test.exs | 55 ++++-- 3 files changed, 38 insertions(+), 202 deletions(-) delete mode 100644 lib/pleroma/web/twitter_api/representers/activity_representer.ex delete mode 100644 test/web/twitter_api/representers/activity_representer_test.exs diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex deleted file mode 100644 index 55c612ddd..000000000 --- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex +++ /dev/null @@ -1,15 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -# FIXME: Remove this module? -# THIS MODULE IS DEPRECATED! DON'T USE IT! -# USE THE Pleroma.Web.TwitterAPI.Views.ActivityView MODULE! -defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do - def to_map(activity, opts) do - Pleroma.Web.TwitterAPI.ActivityView.render( - "activity.json", - Map.put(opts, :activity, activity) - ) - end -end diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs deleted file mode 100644 index d154385a0..000000000 --- a/test/web/twitter_api/representers/activity_representer_test.exs +++ /dev/null @@ -1,170 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do - use Pleroma.DataCase - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter - alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter - alias Pleroma.Web.TwitterAPI.UserView - import Pleroma.Factory - - test "a like activity" do - user = insert(:user) - note_activity = insert(:note_activity) - object = Object.get_by_ap_id(note_activity.data["object"]["id"]) - - {:ok, like_activity, _object} = ActivityPub.like(user, object) - - status = - ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity}) - - assert status["id"] == like_activity.id - assert status["in_reply_to_status_id"] == note_activity.id - - note_activity = Activity.get_by_ap_id(note_activity.data["id"]) - activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"]) - liked_status = ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user}) - assert liked_status["favorited"] == true - assert status["activity_type"] == "like" - end - - test "an activity" do - user = insert(:user) - # {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"}) - mentioned_user = insert(:user, %{nickname: "shp"}) - - # {:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]}) - follower = insert(:user, %{following: [User.ap_followers(user)]}) - - object = %Object{ - data: %{ - "type" => "Image", - "url" => [ - %{ - "type" => "Link", - "mediaType" => "image/jpg", - "href" => "http://example.org/image.jpg" - } - ], - "uuid" => 1 - } - } - - content_html = - "Some :2hu: content mentioning @shp" - - content = HtmlSanitizeEx.strip_tags(content_html) - date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601() - - {:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert() - - to = [ - User.ap_followers(user), - "https://www.w3.org/ns/activitystreams#Public", - mentioned_user.ap_id - ] - - activity = %Activity{ - id: 1, - data: %{ - "type" => "Create", - "id" => "id", - "to" => to, - "actor" => User.ap_id(user), - "object" => %{ - "published" => date, - "type" => "Note", - "content" => content_html, - "summary" => "2hu :2hu:", - "inReplyToStatusId" => 213_123, - "attachment" => [ - object - ], - "external_url" => "some url", - "like_count" => 5, - "announcement_count" => 3, - "context" => "2hu", - "tag" => ["content", "mentioning", "nsfw"], - "emoji" => %{ - "2hu" => "corndog.png" - } - }, - "published" => date, - "context" => "2hu" - }, - local: false, - recipients: to - } - - corndog_emojo = ~s(2hu) - - expected_html = - ~s(

2hu ) <> - corndog_emojo <> - ~s(

alert\('YAY'\)Some ) <> - corndog_emojo <> - ~s( content mentioning
@shp) - - expected_status = %{ - "id" => activity.id, - "user" => UserView.render("show.json", %{user: user, for: follower}), - "is_local" => false, - "statusnet_html" => expected_html, - "text" => "2hu :2hu:" <> content, - "is_post_verb" => true, - "created_at" => "Tue May 24 13:26:08 +0000 2016", - "in_reply_to_status_id" => 213_123, - "in_reply_to_screen_name" => nil, - "in_reply_to_user_id" => nil, - "in_reply_to_profileurl" => nil, - "in_reply_to_ostatus_uri" => nil, - "statusnet_conversation_id" => convo_object.id, - "attachments" => [ - ObjectRepresenter.to_map(object) - ], - "attentions" => [ - UserView.render("show.json", %{user: mentioned_user, for: follower}) - ], - "fave_num" => 5, - "repeat_num" => 3, - "favorited" => false, - "repeated" => false, - "pinned" => false, - "external_url" => "some url", - "tags" => ["nsfw", "content", "mentioning"], - "activity_type" => "post", - "possibly_sensitive" => true, - "uri" => activity.data["object"]["id"], - "visibility" => "direct", - "card" => nil, - "muted" => false, - "summary" => "2hu :2hu:", - "summary_html" => - "2hu \"2hu\"" - } - - assert ActivityRepresenter.to_map(activity, %{ - user: user, - for: follower, - mentioned: [mentioned_user] - }) == expected_status - end - - test "a delete activity" do - object = insert(:note) - user = User.get_by_ap_id(object.data["actor"]) - - {:ok, delete} = ActivityPub.delete(object) - - map = ActivityRepresenter.to_map(delete, %{user: user}) - - assert map["is_post_verb"] == false - assert map["activity_type"] == "delete" - assert map["uri"] == object.data["id"] - end -end diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 1b810c9a0..ac481ca14 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -18,7 +18,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.TwitterAPI.Controller alias Pleroma.Web.TwitterAPI.NotificationView - alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter + alias Pleroma.Web.TwitterAPI.ActivityView alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.TwitterAPI.UserView @@ -116,7 +116,11 @@ test "with credentials", %{conn: conn, user: user} do |> post(request_path, %{status: "Nice meme.", visibility: "private"}) assert json_response(conn, 200) == - ActivityRepresenter.to_map(Repo.one(Activity), %{user: user, for: user}) + ActivityView.render("activity.json", %{ + activity: Repo.one(Activity), + user: user, + for: user + }) end end @@ -273,7 +277,7 @@ test "returns one status", %{conn: conn} do response = json_response(conn, 200) - assert response == ActivityRepresenter.to_map(activity, %{user: actor}) + assert response == ActivityView.render("activity.json", %{activity: activity, user: actor}) end end @@ -372,7 +376,8 @@ test "with credentials", %{conn: conn, user: current_user} do assert response == Enum.map(returned_activities, fn activity -> - ActivityRepresenter.to_map(activity, %{ + ActivityView.render("activity.json", %{ + activity: activity, user: User.get_cached_by_ap_id(activity.data["actor"]), for: current_user }) @@ -469,10 +474,10 @@ test "with credentials", %{conn: conn, user: current_user} do assert length(response) == 1 assert Enum.at(response, 0) == - ActivityRepresenter.to_map(activity, %{ + ActivityView.render("activity.json", %{ user: current_user, for: current_user, - mentioned: [current_user] + activity: activity }) end @@ -594,7 +599,9 @@ test "with user_id", %{conn: conn} do conn = get(conn, "/api/statuses/user_timeline.json", %{"user_id" => user.id}) response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) end test "with screen_name", %{conn: conn} do @@ -604,7 +611,9 @@ test "with screen_name", %{conn: conn} do conn = get(conn, "/api/statuses/user_timeline.json", %{"screen_name" => user.nickname}) response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) end test "with credentials", %{conn: conn, user: current_user} do @@ -620,7 +629,11 @@ test "with credentials", %{conn: conn, user: current_user} do assert length(response) == 1 assert Enum.at(response, 0) == - ActivityRepresenter.to_map(activity, %{user: current_user, for: current_user}) + ActivityView.render("activity.json", %{ + user: current_user, + for: current_user, + activity: activity + }) end test "with credentials with user_id", %{conn: conn, user: current_user} do @@ -635,7 +648,9 @@ test "with credentials with user_id", %{conn: conn, user: current_user} do response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) end test "with credentials screen_name", %{conn: conn, user: current_user} do @@ -650,7 +665,9 @@ test "with credentials screen_name", %{conn: conn, user: current_user} do response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) end test "with credentials with user_id, excluding RTs", %{conn: conn, user: current_user} do @@ -669,7 +686,9 @@ test "with credentials with user_id, excluding RTs", %{conn: conn, user: current response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) conn = conn @@ -678,7 +697,9 @@ test "with credentials with user_id, excluding RTs", %{conn: conn, user: current response = json_response(conn, 200) assert length(response) == 1 - assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + + assert Enum.at(response, 0) == + ActivityView.render("activity.json", %{user: user, activity: activity}) end end @@ -937,7 +958,7 @@ test "with credentials", %{conn: conn, user: current_user} do activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) assert json_response(response, 200) == - ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) + ActivityView.render("activity.json", %{user: activity_user, for: current_user, activity: activity}) end end @@ -971,7 +992,7 @@ test "with credentials", %{conn: conn, user: current_user} do activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) assert json_response(response, 200) == - ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) + ActivityView.render("activity.json", %{user: activity_user, for: current_user, activity: activity}) end end @@ -1955,7 +1976,7 @@ test "with credentials", %{conn: conn, user: user} do user = refresh_record(user) assert json_response(response, 200) == - ActivityRepresenter.to_map(activity, %{user: user, for: user}) + ActivityView.render("activity.json", %{user: user, for: user, activity: activity}) end end @@ -1985,7 +2006,7 @@ test "with credentials", %{conn: conn, user: user} do user = refresh_record(user) assert json_response(response, 200) == - ActivityRepresenter.to_map(activity, %{user: user, for: user}) + ActivityView.render("activity.json", %{user: user, for: user, activity: activity}) end end From 087662d4fb91e35497de90bb568a1d7cba441b34 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 26 Mar 2019 17:18:18 +0300 Subject: [PATCH 11/31] Fix formatting --- test/web/twitter_api/twitter_api_controller_test.exs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index ac481ca14..9e008b5a0 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -958,7 +958,11 @@ test "with credentials", %{conn: conn, user: current_user} do activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) assert json_response(response, 200) == - ActivityView.render("activity.json", %{user: activity_user, for: current_user, activity: activity}) + ActivityView.render("activity.json", %{ + user: activity_user, + for: current_user, + activity: activity + }) end end @@ -992,7 +996,11 @@ test "with credentials", %{conn: conn, user: current_user} do activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) assert json_response(response, 200) == - ActivityView.render("activity.json", %{user: activity_user, for: current_user, activity: activity}) + ActivityView.render("activity.json", %{ + user: activity_user, + for: current_user, + activity: activity + }) end end From aacdcac1be43aa31fb61407719ba7fb62cee4d79 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 26 Mar 2019 17:35:45 +0300 Subject: [PATCH 12/31] Credo is upset about me not remembering the alphabet --- test/web/twitter_api/twitter_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 9e008b5a0..083540017 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -16,9 +16,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.TwitterAPI.ActivityView alias Pleroma.Web.TwitterAPI.Controller alias Pleroma.Web.TwitterAPI.NotificationView - alias Pleroma.Web.TwitterAPI.ActivityView alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.TwitterAPI.UserView From caf0e9cf331dc70b8f055d741bb40bb8bf564f59 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 26 Mar 2019 18:13:24 +0300 Subject: [PATCH 13/31] Test for MastoAPI /api/v1/instance response structure. --- .../mastodon_api_controller_test.exs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b2302422b..aa9abe97d 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1808,6 +1808,27 @@ test "requires 'write' permission", %{conn: conn} do end test "get instance information", %{conn: conn} do + conn = get(conn, "/api/v1/instance") + assert result = json_response(conn, 200) + + # Note: not checking for "max_toot_chars" since it's optional + assert %{ + "uri" => _, + "title" => _, + "description" => _, + "version" => _, + "email" => _, + "urls" => %{ + "streaming_api" => _ + }, + "stats" => _, + "thumbnail" => _, + "languages" => _, + "registrations" => _ + } = result + end + + test "get instance stats", %{conn: conn} do user = insert(:user, %{local: true}) user2 = insert(:user, %{local: true}) From 47b49ab1a1453ac2068cca336ad6db9877c3e64b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 26 Mar 2019 18:18:36 +0300 Subject: [PATCH 14/31] Test for MastoAPI /api/v1/instance response structure (formatting fix). --- .../mastodon_api_controller_test.exs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index aa9abe97d..21e88eda9 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1813,19 +1813,19 @@ test "get instance information", %{conn: conn} do # Note: not checking for "max_toot_chars" since it's optional assert %{ - "uri" => _, - "title" => _, - "description" => _, - "version" => _, - "email" => _, - "urls" => %{ - "streaming_api" => _ - }, - "stats" => _, - "thumbnail" => _, - "languages" => _, - "registrations" => _ - } = result + "uri" => _, + "title" => _, + "description" => _, + "version" => _, + "email" => _, + "urls" => %{ + "streaming_api" => _ + }, + "stats" => _, + "thumbnail" => _, + "languages" => _, + "registrations" => _ + } = result end test "get instance stats", %{conn: conn} do From 10a7a4a868fbc5ff09516892b99e11100d5d3660 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 26 Mar 2019 16:40:09 +0100 Subject: [PATCH 15/31] AP UserView: Refactor banner / avatar display code, add test. --- lib/pleroma/user.ex | 16 ++++--------- lib/pleroma/web/activity_pub/utils.ex | 15 ------------ .../web/activity_pub/views/user_view.ex | 20 ++++++++++++---- .../web/activity_pub/views/user_view_test.exs | 23 +++++++++++++++++++ 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ee5eb8efa..efb4540b9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -83,25 +83,17 @@ def superuser?(%User{local: true, info: %User.Info{is_admin: true}}), do: true def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true def superuser?(_), do: false - def avatar_url(user) do + def avatar_url(user, options \\ []) do case user.avatar do %{"url" => [%{"href" => href} | _]} -> href - _ -> "#{Web.base_url()}/images/avi.png" + _ -> !options[:no_default] && "#{Web.base_url()}/images/avi.png" end end - # Do not return instance default avatar for federation - def avatar_url_ap(user) do - case user.avatar do - %{"url" => [%{"href" => href} | _]} -> href - _ -> nil - end - end - - def banner_url(user) do + def banner_url(user, options \\ []) do case user.info.banner do %{"url" => [%{"href" => href} | _]} -> href - _ -> "#{Web.base_url()}/images/banner.png" + _ -> !options[:no_default] && "#{Web.base_url()}/images/banner.png" end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 86b6e7029..2e9ffe41c 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -230,21 +230,6 @@ def update_object_in_activities(%{data: %{"id" => id}} = object) do end) end - # Only federate user icon if not nil - # Prevents federating instance default avatars - def maybe_make_icon(user) do - if User.avatar_url_ap(user) do - %{ - "icon" => %{ - "type" => "Image", - "url" => User.avatar_url_ap(user) - } - } - else - %{} - end - end - #### Like-related helpers @doc """ diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index f5c86d360..5926a3294 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -87,13 +87,10 @@ def render("user.json", %{user: user}) do "publicKeyPem" => public_key }, "endpoints" => endpoints, - "image" => %{ - "type" => "Image", - "url" => User.banner_url(user) - }, "tag" => user.info.source_data["tag"] || [] } - |> Map.merge(Utils.maybe_make_icon(user)) + |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) + |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) |> Map.merge(Utils.make_json_ld_header()) end @@ -291,4 +288,17 @@ def collection(collection, iri, page, show_items \\ true, total \\ nil) do map end end + + defp maybe_make_image(func, key, user) do + if image = func.(user, no_default: true) do + %{ + key => %{ + "type" => "Image", + "url" => image + } + } + else + %{} + end + end end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 0bc1d4728..9fb9455d2 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -16,6 +16,29 @@ test "Renders a user, including the public key" do assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY") end + test "Does not add an avatar image if the user hasn't set one" do + user = insert(:user) + {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + + result = UserView.render("user.json", %{user: user}) + refute result["icon"] + refute result["image"] + + user = + insert(:user, + avatar: %{"url" => [%{"href" => "https://someurl"}]}, + info: %{ + banner: %{"url" => [%{"href" => "https://somebanner"}]} + } + ) + + {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + + result = UserView.render("user.json", %{user: user}) + assert result["icon"]["url"] == "https://someurl" + assert result["image"]["url"] == "https://somebanner" + end + describe "endpoints" do test "local users have a usable endpoints structure" do user = insert(:user) From 691d1208b5abd5bfb6ff0c1c75a8f315ee0e4500 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Tue, 26 Mar 2019 21:42:03 +0300 Subject: [PATCH 16/31] Add GET /api/v1/apps/verify_credentials --- .../mastodon_api/mastodon_api_controller.ex | 9 +++++++ .../web/mastodon_api/views/app_view.ex | 27 +++++++++++++++++++ lib/pleroma/web/router.ex | 1 + .../mastodon_api_controller_test.exs | 20 ++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 lib/pleroma/web/mastodon_api/views/app_view.ex diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 6b7c67012..295c8bebe 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -18,6 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView + alias Pleroma.Web.MastodonAPI.AppView alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI @@ -132,6 +133,14 @@ def verify_credentials(%{assigns: %{user: user}} = conn, _) do json(conn, account) end + def verify_app_credentials(%{assigns: %{user: _user, token: token}} = conn, _) do + with %Token{app: %App{} = app} <- Repo.preload(token, :app) do + conn + |> put_view(AppView) + |> render("show.json", %{app: app}) + end + end + def user(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id), true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex new file mode 100644 index 000000000..1976d4dcb --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/app_view.ex @@ -0,0 +1,27 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AppView do + use Pleroma.Web, :view + + alias Pleroma.Web.OAuth.App + + def render("show.json", %{app: %App{website: webiste, client_name: name}}) do + result = %{ + name: name, + website: webiste + } + + vapid_key = Pleroma.Web.Push.vapid_config() |> Keyword.get(:public_key) + + result = + if vapid_key do + Map.put(result, "vapid_key", vapid_key) + else + result + end + + result + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index befd382ba..32e5f7644 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -328,6 +328,7 @@ defmodule Pleroma.Web.Router do get("/instance", MastodonAPIController, :masto_instance) get("/instance/peers", MastodonAPIController, :peers) post("/apps", MastodonAPIController, :create_app) + get("/apps/verify_credentials", MastodonAPIController, :verify_app_credentials) get("/custom_emojis", MastodonAPIController, :custom_emojis) get("/statuses/:id/card", MastodonAPIController, :status_card) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 21e88eda9..9c0fdf368 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -332,6 +332,26 @@ test "verify_credentials default scope unlisted", %{conn: conn} do assert id == to_string(user.id) end + test "apps/verify_credentials", %{conn: conn} do + token = insert(:oauth_token) + + conn = + conn + |> assign(:user, token.user) + |> assign(:token, token) + |> get("/api/v1/apps/verify_credentials") + + app = Repo.preload(token, :app).app + + expected = %{ + "name" => app.client_name, + "website" => app.website, + "vapid_key" => Pleroma.Web.Push.vapid_config() |> Keyword.get(:public_key) + } + + assert expected == json_response(conn, 200) + end + test "get a status", %{conn: conn} do activity = insert(:note_activity) From a4ab60ac54d7ef0e2983483868c0e6fd59213aa4 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Tue, 26 Mar 2019 23:21:31 +0300 Subject: [PATCH 17/31] Add vapid_key to the `POST /api/v1/apps` response --- .../mastodon_api/mastodon_api_controller.ex | 15 ++------ .../web/mastodon_api/views/app_view.ex | 38 +++++++++++++------ .../mastodon_api_controller_test.exs | 31 ++++++++++++++- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 295c8bebe..eee4e7678 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -52,16 +52,9 @@ def create_app(conn, params) do with cs <- App.register_changeset(%App{}, app_attrs), false <- cs.changes[:client_name] == @local_mastodon_name, {:ok, app} <- Repo.insert(cs) do - res = %{ - id: app.id |> to_string, - name: app.client_name, - client_id: app.client_id, - client_secret: app.client_secret, - redirect_uri: app.redirect_uris, - website: app.website - } - - json(conn, res) + conn + |> put_view(AppView) + |> render("show.json", %{app: app}) end end @@ -137,7 +130,7 @@ def verify_app_credentials(%{assigns: %{user: _user, token: token}} = conn, _) d with %Token{app: %App{} = app} <- Repo.preload(token, :app) do conn |> put_view(AppView) - |> render("show.json", %{app: app}) + |> render("short.json", %{app: app}) end end diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex index 1976d4dcb..f52b693a6 100644 --- a/lib/pleroma/web/mastodon_api/views/app_view.ex +++ b/lib/pleroma/web/mastodon_api/views/app_view.ex @@ -7,21 +7,35 @@ defmodule Pleroma.Web.MastodonAPI.AppView do alias Pleroma.Web.OAuth.App - def render("show.json", %{app: %App{website: webiste, client_name: name}}) do - result = %{ + @vapid_key :web_push_encryption + |> Application.get_env(:vapid_details, []) + |> Keyword.get(:public_key) + + def render("show.json", %{app: %App{} = app}) do + %{ + id: app.id |> to_string, + name: app.client_name, + client_id: app.client_id, + client_secret: app.client_secret, + redirect_uri: app.redirect_uris, + website: app.website + } + |> with_vapid_key() + end + + def render("short.json", %{app: %App{website: webiste, client_name: name}}) do + %{ name: name, website: webiste } + |> with_vapid_key() + end - vapid_key = Pleroma.Web.Push.vapid_config() |> Keyword.get(:public_key) - - result = - if vapid_key do - Map.put(result, "vapid_key", vapid_key) - else - result - end - - result + defp with_vapid_key(data) do + if @vapid_key do + Map.put(data, "vapid_key", @vapid_key) + else + data + end end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 9c0fdf368..d9bcbf5a9 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -14,7 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.FilterView + alias Pleroma.Web.OAuth.App alias Pleroma.Web.OStatus + alias Pleroma.Web.Push alias Pleroma.Web.TwitterAPI.TwitterAPI import Pleroma.Factory import ExUnit.CaptureLog @@ -346,7 +348,34 @@ test "apps/verify_credentials", %{conn: conn} do expected = %{ "name" => app.client_name, "website" => app.website, - "vapid_key" => Pleroma.Web.Push.vapid_config() |> Keyword.get(:public_key) + "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) + } + + assert expected == json_response(conn, 200) + end + + test "creates an oauth app", %{conn: conn} do + user = insert(:user) + app_attrs = build(:oauth_app) + + conn = + conn + |> assign(:user, user) + |> post("/api/v1/apps", %{ + client_name: app_attrs.client_name, + redirect_uris: app_attrs.redirect_uris + }) + + [app] = Repo.all(App) + + expected = %{ + "name" => app.client_name, + "website" => app.website, + "client_id" => app.client_id, + "client_secret" => app.client_secret, + "id" => app.id |> to_string(), + "redirect_uri" => app.redirect_uris, + "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) } assert expected == json_response(conn, 200) From 3cf7539bca56ce1118bbedaba547d371f3f20eed Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 27 Mar 2019 03:51:59 +0500 Subject: [PATCH 18/31] Add more user filters + move search to its own module --- docs/Admin-API.md | 23 +++-- lib/pleroma/user.ex | 84 ++++++++---------- .../web/admin_api/admin_api_controller.ex | 36 +++++--- lib/pleroma/web/admin_api/search.ex | 54 ++++++++++++ test/user_test.exs | 18 +--- .../admin_api/admin_api_controller_test.exs | 40 +++++++-- test/web/admin_api/search_test.exs | 88 +++++++++++++++++++ 7 files changed, 256 insertions(+), 87 deletions(-) create mode 100644 lib/pleroma/web/admin_api/search.ex create mode 100644 test/web/admin_api/search_test.exs diff --git a/docs/Admin-API.md b/docs/Admin-API.md index 2edb31f3c..84adca6ff 100644 --- a/docs/Admin-API.md +++ b/docs/Admin-API.md @@ -8,10 +8,15 @@ Authentication is required and the user must be an admin. - Method `GET` - Query Params: - - `query`: **string** *optional* search term - - `local_only`: **bool** *optional* whether to return only local users - - `page`: **integer** *optional* page number - - `page_size`: **integer** *optional* number of users per page (default is `50`) + - *optional* `query`: **string** search term + - *optional* `filters`: **string** comma-separated string of filters: + - `local`: only local users + - `external`: only external users + - `active`: only active users + - `deactivated`: only deactivated users + - *optional* `page`: **integer** page number + - *optional* `page_size`: **integer** number of users per page (default is `50`) +- Example: `https://mypleroma.org/api/pleroma/admin/users?query=john&filters=local,active&page=1&page_size=10` - Response: ```JSON @@ -22,7 +27,13 @@ Authentication is required and the user must be an admin. { "deactivated": bool, "id": integer, - "nickname": string + "nickname": string, + "roles": { + "admin": bool, + "moderator": bool + }, + "local": bool, + "tags": array }, ... ] @@ -99,7 +110,7 @@ Authentication is required and the user must be an admin. Note: Available `:permission_group` is currently moderator and admin. 404 is returned when the permission group doesn’t exist. -### Get user user permission groups membership +### Get user user permission groups membership per permission group - Method: `GET` - Params: none diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 41289b4d0..495f9bdf5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -772,52 +772,6 @@ def get_recipients_from_activity(%Activity{recipients: to}) do Repo.all(query) end - @spec search_for_admin(%{ - local: boolean(), - page: number(), - page_size: number() - }) :: {:ok, [Pleroma.User.t()], number()} - def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do - query = - from(u in User, order_by: u.nickname) - |> maybe_local_user_query(local) - - paginated_query = - query - |> paginate(page, page_size) - - count = - query - |> Repo.aggregate(:count, :id) - - {:ok, Repo.all(paginated_query), count} - end - - @spec search_for_admin(%{ - query: binary(), - local: boolean(), - page: number(), - page_size: number() - }) :: {:ok, [Pleroma.User.t()], number()} - def search_for_admin(%{ - query: term, - local: local, - page: page, - page_size: page_size - }) do - maybe_local_query = User |> maybe_local_user_query(local) - - search_query = from(u in maybe_local_query, where: ilike(u.nickname, ^"%#{term}%")) - count = search_query |> Repo.aggregate(:count, :id) - - results = - search_query - |> paginate(page, page_size) - |> Repo.all() - - {:ok, results, count} - end - def search(query, resolve \\ false, for_user \\ nil) do # Strip the beginning @ off if there is a query query = String.trim_leading(query, "@") @@ -856,7 +810,7 @@ defp boost_search_rank_query(query, for_user) do search_rank: fragment( """ - CASE WHEN (?) THEN (?) * 1.3 + CASE WHEN (?) THEN (?) * 1.3 WHEN (?) THEN (?) * 1.2 WHEN (?) THEN (?) * 1.1 ELSE (?) END @@ -1071,6 +1025,42 @@ def local_user_query(query \\ User) do ) end + def maybe_external_user_query(query, external) do + if external, do: external_user_query(query), else: query + end + + def external_user_query(query \\ User) do + from( + u in query, + where: u.local == false, + where: not is_nil(u.nickname) + ) + end + + def maybe_active_user_query(query, active) do + if active, do: active_user_query(query), else: query + end + + def active_user_query(query \\ User) do + from( + u in query, + where: fragment("not (?->'deactivated' @> 'true')", u.info), + where: not is_nil(u.nickname) + ) + end + + def maybe_deactivated_user_query(query, deactivated) do + if deactivated, do: deactivated_user_query(query), else: query + end + + def deactivated_user_query(query \\ User) do + from( + u in query, + where: fragment("(?->'deactivated' @> 'true')", u.info), + where: not is_nil(u.nickname) + ) + end + def active_local_user_query do from( u in local_user_query(), diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 6d9bf2895..3fa9c6909 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -3,17 +3,18 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.AdminAPIController do - @users_page_size 50 - use Pleroma.Web, :controller alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.AdminAPI.AccountView + alias Pleroma.Web.AdminAPI.Search import Pleroma.Web.ControllerHelper, only: [json_response: 3] require Logger + @users_page_size 50 + action_fallback(:errors) def user_delete(conn, %{"nickname" => nickname}) do @@ -63,17 +64,17 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do do: json_response(conn, :no_content, "") end - def list_users(%{assigns: %{user: admin}} = conn, params) do + def list_users(conn, params) do {page, page_size} = page_params(params) + filters = maybe_parse_filters(params["filters"]) - with {:ok, users, count} <- - User.search_for_admin(%{ - query: params["query"], - admin: admin, - local: params["local_only"] == "true", - page: page, - page_size: page_size - }), + search_params = %{ + query: params["query"], + page: page, + page_size: page_size + } + + with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)), do: conn |> json( @@ -85,6 +86,19 @@ def list_users(%{assigns: %{user: admin}} = conn, params) do ) end + @filters ~w(local external active deactivated) + + defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{} + + @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{} + defp maybe_parse_filters(filters) do + filters + |> String.split(",") + |> Enum.filter(&Enum.member?(@filters, &1)) + |> Enum.map(&String.to_atom(&1)) + |> Enum.into(%{}, &{&1, true}) + end + def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname}) when permission_group in ["moderator", "admin"] do user = User.get_by_nickname(nickname) diff --git a/lib/pleroma/web/admin_api/search.ex b/lib/pleroma/web/admin_api/search.ex new file mode 100644 index 000000000..9a8e41c2a --- /dev/null +++ b/lib/pleroma/web/admin_api/search.ex @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.Search do + import Ecto.Query + + alias Pleroma.Repo + alias Pleroma.User + + @page_size 50 + + def user(%{query: term} = params) when is_nil(term) or term == "" do + query = maybe_filtered_query(params) + + paginated_query = + maybe_filtered_query(params) + |> paginate(params[:page] || 1, params[:page_size] || @page_size) + + count = query |> Repo.aggregate(:count, :id) + + results = Repo.all(paginated_query) + + {:ok, results, count} + end + + def user(%{query: term} = params) when is_binary(term) do + search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%")) + + count = search_query |> Repo.aggregate(:count, :id) + + results = + search_query + |> paginate(params[:page] || 1, params[:page_size] || @page_size) + |> Repo.all() + + {:ok, results, count} + end + + defp maybe_filtered_query(params) do + from(u in User, order_by: u.nickname) + |> User.maybe_local_user_query(params[:local]) + |> User.maybe_external_user_query(params[:external]) + |> User.maybe_active_user_query(params[:active]) + |> User.maybe_deactivated_user_query(params[:deactivated]) + end + + defp paginate(query, page, page_size) do + from(u in query, + limit: ^page_size, + offset: ^((page - 1) * page_size) + ) + end +end diff --git a/test/user_test.exs b/test/user_test.exs index 442599910..8cf2ba6ab 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.UserTest do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI + use Pleroma.DataCase import Pleroma.Factory @@ -1107,21 +1108,4 @@ test "bookmarks" do assert {:ok, user_state3} = User.bookmark(user, id2) assert user_state3.bookmarks == [id2] end - - describe "search for admin" do - test "it ignores case" do - insert(:user, nickname: "papercoach") - insert(:user, nickname: "CanadaPaperCoach") - - {:ok, _results, count} = - User.search_for_admin(%{ - query: "paper", - local: false, - page: 1, - page_size: 50 - }) - - assert count == 2 - end - end end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 0aab7f262..7da237eca 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -408,13 +408,13 @@ test "regular search" do test "regular search with page size" do admin = insert(:user, info: %{is_admin: true}) - user = insert(:user, nickname: "bob") - user2 = insert(:user, nickname: "bo") + user = insert(:user, nickname: "aalice") + user2 = insert(:user, nickname: "alice") conn = build_conn() |> assign(:user, admin) - |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=1") + |> get("/api/pleroma/admin/users?query=a&page_size=1&page=1") assert json_response(conn, 200) == %{ "count" => 2, @@ -434,7 +434,7 @@ test "regular search with page size" do conn = build_conn() |> assign(:user, admin) - |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=2") + |> get("/api/pleroma/admin/users?query=a&page_size=1&page=2") assert json_response(conn, 200) == %{ "count" => 2, @@ -461,7 +461,7 @@ test "only local users" do conn = build_conn() |> assign(:user, admin) - |> get("/api/pleroma/admin/users?query=bo&local_only=true") + |> get("/api/pleroma/admin/users?query=bo&filters=local") assert json_response(conn, 200) == %{ "count" => 1, @@ -488,7 +488,7 @@ test "only local users with no query" do conn = build_conn() |> assign(:user, admin) - |> get("/api/pleroma/admin/users?local_only=true") + |> get("/api/pleroma/admin/users?filters=local") assert json_response(conn, 200) == %{ "count" => 2, @@ -513,6 +513,34 @@ test "only local users with no query" do ] } end + + test "it works with multiple filters" do + admin = insert(:user, nickname: "john", info: %{is_admin: true}) + user = insert(:user, nickname: "bob", local: false, info: %{deactivated: true}) + + insert(:user, nickname: "ken", local: true, info: %{deactivated: true}) + insert(:user, nickname: "bobb", local: false, info: %{deactivated: false}) + + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/users?filters=deactivated,external") + + assert json_response(conn, 200) == %{ + "count" => 1, + "page_size" => 50, + "users" => [ + %{ + "deactivated" => user.info.deactivated, + "id" => user.id, + "nickname" => user.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => user.local, + "tags" => [] + } + ] + } + end end test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs new file mode 100644 index 000000000..3950996ed --- /dev/null +++ b/test/web/admin_api/search_test.exs @@ -0,0 +1,88 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.SearchTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Web.AdminAPI.Search + + import Pleroma.Factory + + describe "search for admin" do + test "it ignores case" do + insert(:user, nickname: "papercoach") + insert(:user, nickname: "CanadaPaperCoach") + + {:ok, _results, count} = + Search.user(%{ + query: "paper", + local: false, + page: 1, + page_size: 50 + }) + + assert count == 2 + end + + test "it returns local/external users" do + insert(:user, local: true) + insert(:user, local: false) + insert(:user, local: false) + + {:ok, _results, local_count} = + Search.user(%{ + query: "", + local: true + }) + + {:ok, _results, external_count} = + Search.user(%{ + query: "", + external: true + }) + + assert local_count == 1 + assert external_count == 2 + end + + test "it returns active/deactivated users" do + insert(:user, info: %{deactivated: true}) + insert(:user, info: %{deactivated: true}) + insert(:user, info: %{deactivated: false}) + + {:ok, _results, active_count} = + Search.user(%{ + query: "", + active: true + }) + + {:ok, _results, deactivated_count} = + Search.user(%{ + query: "", + deactivated: true + }) + + assert active_count == 1 + assert deactivated_count == 2 + end + + test "it returns specific user" do + insert(:user) + insert(:user) + insert(:user, nickname: "bob", local: true, info: %{deactivated: false}) + + {:ok, _results, total_count} = Search.user(%{query: ""}) + + {:ok, _results, count} = + Search.user(%{ + query: "Bo", + active: true, + local: true + }) + + assert total_count == 3 + assert count == 1 + end + end +end From ce6d64bbd8570c0c8bc46efe8a5a338876687df8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 27 Mar 2019 12:28:53 +0300 Subject: [PATCH 19/31] Fix missing announces in MastoAPI home timeline Closes #762 --- lib/pleroma/web/activity_pub/activity_pub.ex | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 0d9a89d0b..6e1ed7ec9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -737,8 +737,13 @@ defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do from( activity in query, - where: fragment("not ?->>'type' = 'Announce'", activity.data), - where: fragment("not ? = ANY(?)", activity.actor, ^muted_reblogs) + where: + fragment( + "not ( ?->>'type' = 'Announce' and ? = ANY(?))", + activity.data, + activity.actor, + ^muted_reblogs + ) ) end From 776bb5137f6d35b349b9c0e346bfe3426306ccb8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 27 Mar 2019 13:43:43 +0300 Subject: [PATCH 20/31] Fix muting reblogs tests --- test/web/activity_pub/activity_pub_test.exs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 40bcced33..ac5fbe0a9 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -494,7 +494,21 @@ test "doesn't return reblogs for users for whom reblogs have been muted" do activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) - refute Enum.member?(activities, activity) + refute Enum.any?(activities, fn %{id: id} -> id == activity.id end) + end + + test "returns reblogs for users for whom reblogs have not been muted" do + activity = insert(:note_activity) + user = insert(:user) + booster = insert(:user) + {:ok, user} = CommonAPI.hide_reblogs(user, booster) + {:ok, user} = CommonAPI.show_reblogs(user, booster) + + {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) + + activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + + assert Enum.any?(activities, fn %{id: id} -> id == activity.id end) end end From 10c81fc902c639633bddff64a3e7450a6796d180 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Wed, 27 Mar 2019 21:19:00 +0300 Subject: [PATCH 21/31] Add user show endpoint for Pleroma admin API --- docs/Admin-API.md | 11 ++++++ .../web/admin_api/admin_api_controller.ex | 15 ++++++++ lib/pleroma/web/router.ex | 1 + .../admin_api/admin_api_controller_test.exs | 35 +++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/docs/Admin-API.md b/docs/Admin-API.md index 84adca6ff..53b68ffd4 100644 --- a/docs/Admin-API.md +++ b/docs/Admin-API.md @@ -149,6 +149,17 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - `nickname` - `status` BOOLEAN field, false value means deactivation. +## `/api/pleroma/admin/users/:nickname` + +### Retrive the details of a user + +- Method: `GET` +- Params: + - `nickname` +- Response: + - On failure: `Not found` + - On success: JSON of the user + ## `/api/pleroma/admin/relay` ### Follow a Relay diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 3fa9c6909..b3a09e49e 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -45,6 +45,15 @@ def user_create( |> json(user.nickname) end + def user_show(conn, %{"nickname" => nickname}) do + with %User{} = user <- User.get_by_nickname(nickname) do + conn + |> json(AccountView.render("show.json", %{user: user})) + else + _ -> {:error, :not_found} + end + end + def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_by_nickname(nickname) @@ -231,6 +240,12 @@ def get_password_reset(conn, %{"nickname" => nickname}) do |> json(token.token) end + def errors(conn, {:error, :not_found}) do + conn + |> put_status(404) + |> json("Not found") + end + def errors(conn, {:param_cast, _}) do conn |> put_status(400) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 32e5f7644..9ccb4e535 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,6 +140,7 @@ defmodule Pleroma.Web.Router do pipe_through([:admin_api, :oauth_write]) get("/users", AdminAPIController, :list_users) + get("/users/:nickname", AdminAPIController, :user_show) delete("/user", AdminAPIController, :user_delete) patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) post("/user", AdminAPIController, :user_create) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 7da237eca..2f53416a3 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -40,6 +40,41 @@ test "Create" do end end + describe "/api/pleroma/admin/users/:nickname" do + test "Show", %{conn: conn} do + admin = insert(:user, info: %{is_admin: true}) + user = insert(:user) + + conn = + conn + |> assign(:user, admin) + |> get("/api/pleroma/admin/users/#{user.nickname}") + + expected = %{ + "deactivated" => false, + "id" => to_string(user.id), + "local" => true, + "nickname" => user.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "tags" => [] + } + + assert expected == json_response(conn, 200) + end + + test "when the user doesn't exist", %{conn: conn} do + admin = insert(:user, info: %{is_admin: true}) + user = build(:user) + + conn = + conn + |> assign(:user, admin) + |> get("/api/pleroma/admin/users/#{user.nickname}") + + assert "Not found" == json_response(conn, 404) + end + end + describe "PUT /api/pleroma/admin/users/tag" do setup do admin = insert(:user, info: %{is_admin: true}) From dfae0050af385786c5799ee886de315f69d36a78 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 19:46:30 +0300 Subject: [PATCH 22/31] Move out of Gitlab Wiki I understand that this change is quite unreadable and hard to review, sorry for forgetting to do atomic commits. This patch does not change too much content wise, it just * Gets everything from gitlab wiki * Removes some specific gitlab hacks * Formats all documentation file names to be in snake case so they look the same way as our code does --- README.md | 2 +- docs/.Clients.md.swp | Bin 0 -> 16384 bytes docs/admin/admin_tasks.md | 44 +++ docs/admin/backup.md | 15 + docs/admin/updating.md | 9 + docs/{Admin-API.md => api/admin_api.md} | 1 + .../differences_in_mastoapi_responses.md} | 0 docs/{Pleroma-API.md => api/pleroma_api.md} | 5 +- docs/{Clients.md => clients.md} | 0 ...General-tips-for-customizing-Pleroma-FE.md | 17 ++ .../custom_emoji.md} | 2 +- docs/config/hardening.md | 103 +++++++ docs/config/howto_change_ip_and_port.md | 7 + docs/config/howto_mediaproxy.md | 32 ++ docs/config/howto_proxy.md | 12 + docs/config/howto_user_recomendation.md | 31 ++ docs/config/i2p.md | 197 +++++++++++++ .../mrf.md} | 6 +- docs/config/onion_federation.md | 159 ++++++++++ docs/config/small_customizations.md | 35 +++ docs/{ => config}/static_dir.md | 0 docs/fuckgitlablol.sh | 12 + docs/installation/alpine_linux_en.md | 215 ++++++++++++++ docs/installation/arch_linux_en.md | 214 ++++++++++++++ docs/installation/centos7_en.md | 277 ++++++++++++++++++ docs/installation/debian_based_en.md | 202 +++++++++++++ docs/installation/debian_based_jp.md | 191 ++++++++++++ docs/installation/netbsd_en.md | 198 +++++++++++++ docs/installation/openbsd_en.md | 222 ++++++++++++++ docs/installation/openbsd_fi.md | 110 +++++++ docs/introduction.md | 55 ++++ mix.exs | 16 +- 32 files changed, 2373 insertions(+), 16 deletions(-) create mode 100644 docs/.Clients.md.swp create mode 100644 docs/admin/admin_tasks.md create mode 100644 docs/admin/backup.md create mode 100644 docs/admin/updating.md rename docs/{Admin-API.md => api/admin_api.md} (99%) rename docs/{Differences-in-MastodonAPI-Responses.md => api/differences_in_mastoapi_responses.md} (100%) rename docs/{Pleroma-API.md => api/pleroma_api.md} (96%) rename docs/{Clients.md => clients.md} (100%) create mode 100644 docs/config/General-tips-for-customizing-Pleroma-FE.md rename docs/{Custom-Emoji.md => config/custom_emoji.md} (97%) create mode 100644 docs/config/hardening.md create mode 100644 docs/config/howto_change_ip_and_port.md create mode 100644 docs/config/howto_mediaproxy.md create mode 100644 docs/config/howto_proxy.md create mode 100644 docs/config/howto_user_recomendation.md create mode 100644 docs/config/i2p.md rename docs/{Message-Rewrite-Facility-configuration.md => config/mrf.md} (98%) create mode 100644 docs/config/onion_federation.md create mode 100644 docs/config/small_customizations.md rename docs/{ => config}/static_dir.md (100%) create mode 100755 docs/fuckgitlablol.sh create mode 100644 docs/installation/alpine_linux_en.md create mode 100644 docs/installation/arch_linux_en.md create mode 100644 docs/installation/centos7_en.md create mode 100644 docs/installation/debian_based_en.md create mode 100644 docs/installation/debian_based_jp.md create mode 100644 docs/installation/netbsd_en.md create mode 100644 docs/installation/openbsd_en.md create mode 100644 docs/installation/openbsd_fi.md create mode 100644 docs/introduction.md diff --git a/README.md b/README.md index 4f22445d0..47d2abf6d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ While we don’t provide docker files, other people have written very good ones. * Run `mix deps.get` to install elixir dependencies. * Run `mix pleroma.instance gen`. This will ask you questions about your instance and generate a configuration file in `config/generated_config.exs`. Check that and copy it to either `config/dev.secret.exs` or `config/prod.secret.exs`. It will also create a `config/setup_db.psql`, which you should run as the PostgreSQL superuser (i.e., `sudo -u postgres psql -f config/setup_db.psql`). It will create the database, user, and password you gave `mix pleroma.gen.instance` earlier, as well as set up the necessary extensions in the database. PostgreSQL superuser privileges are only needed for this step. -* For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. Documentation for the config can be found at [`docs/config.md`](docs/config.md) +* For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. Documentation for the config can be found at [`docs/config.md`](docs/config.md) in the repository, or at the "Configuration" page on * Run `mix ecto.migrate` to run the database migrations. You will have to do this again after certain updates. * You can check if your instance is configured correctly by running it with `mix phx.server` and checking the instance info endpoint at `/api/v1/instance`. If it shows your uri, name and email correctly, you are configured correctly. If it shows something like `localhost:4000`, your configuration is probably wrong, unless you are running a local development setup. * The common and convenient way for adding HTTPS is by using Nginx as a reverse proxy. You can look at example Nginx configuration in `installation/pleroma.nginx`. If you need TLS/SSL certificates for HTTPS, you can look get some for free with letsencrypt: . The simplest way to obtain and install a certificate is to use [Certbot.](https://certbot.eff.org) Depending on your specific setup, certbot may be able to get a certificate and configure your web server automatically. diff --git a/docs/.Clients.md.swp b/docs/.Clients.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..1f5aa277616ff6979a1bbcf0538237ad9a5ae847 GIT binary patch literal 16384 zcmeHN&2J<}6)(a^_}U~&P$b||!53S2x@~WiO{`@-_Abr_VaHl;vILVvHQhBmweIQa zR8{XVAi@Do;XqDV0ScFJAe<8Aun;2H1?cm_NJo`L^C1{eMaUb#b>Jo7XTTQl&r^ha2>cFs75Ei!4LAe*wsfxmo?kQad;0?z`^08apO!0VsIJizn7 zkAUZZ1>k<*gF6Yi3H%0l1^5LZfwRD0KSRi$ft$b$;5FbUz$xJGpGF^W6Sx8V8h8=d z0=@*i_bEc&2HpZ*1q$Fn;H$t_fV+S{;U&sXfgX?m-vv$s|HjLgSAYTV4Dd9t3w#-{ ze);_jFIigjyvz)X%qrb$Yn~N>2M^t zKw5NH7Wk$E^TvFYo~;EFVR}U;h-5$97LiPu#)GwCnW?1Dk-51!x@$Ecm}HYPQz))i z>9(Z1Msd~`S%QvjX)x_h^(hF|MV?D#sL+&A%_Et`ObuxwS&Fd@({hn9d~3qTmKh%P zGMUO`c!+i5PG?~)Ka+u&mSrg$Xqknz;5q1XQTBPxk|r&6w<9{NXxMSuPBJl~fnMS) z9!?tAV`(&$S-Wyr5NSO~0;!U*ann7{GADSnVVN|nQ)LD$-O!^oY{Zru8+H*tJ+3O%Y%t+wR@IWI$fI_W3KR7X zEP#n-M`0;2lX_RX{ivhZkgKqx3d2&Yu_Gb_LxYH^NNN^j+=RK3S9xTx*ksoXnBwCZ zT-0pTGh!*x_0({cF(a;VdWCoBV;SzdEaLiD8g^1{_;S?T=AXCh|t}(+(W{1i-%^4Bcz}aOg?lynd&*ggochEH``41 zBk?%hnzrw?5y9E;LJ{qc6Ul5TawIrYoR~uI50Qw&%l6_ZTiu|*#lMiXp|;}|%{<`e zy|$6kAU@lDZQ?Arnva)f-Qwck4Lo4k+S=MdFJTjLPBCJ0j)lcwlAYB|Lx9z=LVOUZh6_X)3Z&UQOa8hVN_&8Eao_(CBoogy`6f zliPRD9F1{d#`k3=3hSMwt$UlT3pR6Lm&zs5x>SuFR-tWTBFpZhQYI;X+w@Y`Y0=mwY4pXCArL>`)4gi9e)xN?BDrl_SeCjG@Ubj7=U3+)b)Jwf8oH zW-6oawRxeK7F>1Y@K!Z%h#sqdUHo0*Mnw2>_gk`;h3iPu^0~?I8C8tJ6dBjnyD2Xt zpwQO+Av_787Ivvtohw2SFRv^=xV-$(%Foz78*8aY~KLXN|&UR}t?Re4;Go{6A(a5zA*#XCa9t(fb5Bl9D8 z8jZ7?u?vVRwX8MTmdx`jOUsY6mX=#94=>o7+E9jHnk(L7Y2HKeY*3ieAvX|cgi2{U zoqu%u@vU!K^&1r&>KKuAP{m$t40Us9+=hMR zM)k;Ww>+9u-mb3yV-L@lX09EpNgcpb8^j5|nNIg^_<9a++5?YG_Y|Q_FH}CZ0b5^^ zP0mx=Rh&~JX;hulXrb+0hf@~EJhs=ShvQEww0VG3r=#^a7Dk{_VJVHO@8oHp4Xw~X zs(l=!Xs0lc!YT< zzhT?_k7vL$;2H1?cm_NJo&nE*XTUSy8So5v20R1*T?P(&C3LyRY0R(jROWrWp0oc^ YjS8i3iFX1b!@DBRlzly5-xCGoV;ss;z5oCK literal 0 HcmV?d00001 diff --git a/docs/admin/admin_tasks.md b/docs/admin/admin_tasks.md new file mode 100644 index 000000000..883095cdb --- /dev/null +++ b/docs/admin/admin_tasks.md @@ -0,0 +1,44 @@ +# Admin tasks +## Important + +If your instance is running in prod mode (most likely it is) make sure to prefix every command with `MIX_ENV=prod`. + +## User management + +It is possible to obtain a list of all available tasks with their options by executing `mix help pleroma.user` + +### Adding users + +Use `mix pleroma.user invite` to generate an invite link for a new user. + +Also, `mix pleroma.user new NICKNAME EMAIL [OPTION...]` can be used to register an account. + +### Making a user a moderator/admin/locked + +Run `mix pleroma.user set username --[no-]moderator` to make user a moderator or remove the moderator status. + +To make the user admin or locked use `mix pleroma.user set NICKNAME --[no-]admin` and `mix pleroma.user set NICKNAME --[no-]locked` respectively + +### Resetting a password + +Run `mix pleroma.user reset_password NICKNAME` to generate a password reset link that you can then send to the user. + +### Banning users + +Run `mix pleroma.user rm NICKNAME` to remove a local account. + +To deactivate(block from the server completely)/reactivate local and remote user accounts run: + +`mix pleroma.user toggle_activated NICKNAME@instancename` + +## Relay managment + +It is possible to obtain a list of all available tasks with their options by executing `mix help pleroma.relay` + +### Following a relay + +Run `mix pleroma.relay follow RELAY_URL` + +### Unfollowing a relay + +Run `mix pleroma.relay unfollow RELAY_URL` diff --git a/docs/admin/backup.md b/docs/admin/backup.md new file mode 100644 index 000000000..b373996f5 --- /dev/null +++ b/docs/admin/backup.md @@ -0,0 +1,15 @@ +# Backup your instance + +1. Stop the Pleroma service. +2. Go to the working directory of Pleroma (default is `/opt/pleroma`) +3. Run `sudo -Hu postgres pg_dump -d --format=custom -f ` +4. Copy `pleroma.pgdump`, `config/prod.secret.exs` and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. +5. Restart the Pleroma service. + +## Restore your instance + +1. Stop the Pleroma service. +2. Go to the working directory of Pleroma (default is `/opt/pleroma`) +3. Copy the above mentioned files back to their original position. +4. Run `sudo -Hu postgres pg_restore -d -v -1 ` +5. Restart the Pleroma service. diff --git a/docs/admin/updating.md b/docs/admin/updating.md new file mode 100644 index 000000000..33ce1ab4f --- /dev/null +++ b/docs/admin/updating.md @@ -0,0 +1,9 @@ +# Updating your instance +1. Stop the Pleroma service. +2. Go to the working directory of Pleroma (default is `/opt/pleroma`) +3. Run `git pull`. This pulls the latest changes from upstream. +4. Run `mix deps.get`. This pulls in any new dependencies. +5. Run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. +6. Restart the Pleroma service. + +[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. diff --git a/docs/Admin-API.md b/docs/api/admin_api.md similarity index 99% rename from docs/Admin-API.md rename to docs/api/admin_api.md index 84adca6ff..ea9b9308c 100644 --- a/docs/Admin-API.md +++ b/docs/api/admin_api.md @@ -1,4 +1,5 @@ # Admin API +# Admin API Authentication is required and the user must be an admin. diff --git a/docs/Differences-in-MastodonAPI-Responses.md b/docs/api/differences_in_mastoapi_responses.md similarity index 100% rename from docs/Differences-in-MastodonAPI-Responses.md rename to docs/api/differences_in_mastoapi_responses.md diff --git a/docs/Pleroma-API.md b/docs/api/pleroma_api.md similarity index 96% rename from docs/Pleroma-API.md rename to docs/api/pleroma_api.md index 478c9d874..bd3fcaa5d 100644 --- a/docs/Pleroma-API.md +++ b/docs/api/pleroma_api.md @@ -61,7 +61,10 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi "cover_photo": "https://pleroma.soykaf.com/images/banner.png", "created_at": "Tue Dec 18 16:55:56 +0000 2018", "default_scope": "public", - "description": "blushy-crushy fediverse idol + pleroma dev\nlet's be friends \nぷれろまの生徒会長。謎の外人。日本語OK. \n公主病.", + "description": "blushy-crushy fediverse idol + pleroma dev +let's be friends +ぷれろまの生徒会長。謎の外人。日本語OK. +公主病.", "description_html": "blushy-crushy fediverse idol + pleroma dev.
let's be friends
ぷれろまの生徒会長。謎の外人。日本語OK.
公主病.", "favourites_count": 0, "fields": [], diff --git a/docs/Clients.md b/docs/clients.md similarity index 100% rename from docs/Clients.md rename to docs/clients.md diff --git a/docs/config/General-tips-for-customizing-Pleroma-FE.md b/docs/config/General-tips-for-customizing-Pleroma-FE.md new file mode 100644 index 000000000..15c4882dd --- /dev/null +++ b/docs/config/General-tips-for-customizing-Pleroma-FE.md @@ -0,0 +1,17 @@ +# General tips for customizing Pleroma FE +There are some configuration scripts for Pleroma BE and FE: + +1. `config/prod.secret.exs` +1. `config/config.exs` +1. `priv/static/static/config.json` + +The `prod.secret.exs` affects first. `config.exs` is for fallback or default. `config.json` is for GNU-social-BE-Pleroma-FE instances. + +Usually all you have to do is: + +1. Copy the section in the `config/config.exs` which you want to activate. +1. Paste into `config/prod.secret.exs`. +1. Edit `config/prod.secret.exs`. +1. Restart the Pleroma daemon. + +`prod.secret.exs` is for the `MIX_ENV=prod` environment. `dev.secret.exs` is for the `MIX_ENV=dev` environment respectively. diff --git a/docs/Custom-Emoji.md b/docs/config/custom_emoji.md similarity index 97% rename from docs/Custom-Emoji.md rename to docs/config/custom_emoji.md index 9d90e5822..e833d2080 100644 --- a/docs/Custom-Emoji.md +++ b/docs/config/custom_emoji.md @@ -1,4 +1,4 @@ -# Custom emoji +# Custom Emoji To add custom emoji: * Add the image file(s) to `priv/static/emoji/custom` diff --git a/docs/config/hardening.md b/docs/config/hardening.md new file mode 100644 index 000000000..b54c28850 --- /dev/null +++ b/docs/config/hardening.md @@ -0,0 +1,103 @@ +# Hardening your instance +Here are some suggestions which improve the security of parts of your Pleroma instance. + +## Configuration file + +These changes should go into `prod.secret.exs` or `dev.secret.exs`, depending on your `MIX_ENV` value. + +### `http` + +> Recommended value: `[ip: {127, 0, 0, 1}]` + +This sets the Pleroma application server to only listen to the localhost interface. This way, you can only reach your server over the Internet by going through the reverse proxy. By default, Pleroma listens on all interfaces. + +### `secure_cookie_flag` + +> Recommended value: `true` + +This sets the `secure` flag on Pleroma’s session cookie. This makes sure, that the cookie is only accepted over encrypted HTTPs connections. This implicitly renames the cookie from `pleroma_key` to `__Host-pleroma-key` which enforces some restrictions. (see [cookie prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Cookie_prefixes)) + +### `:http_security` + +> Recommended value: `true` + +This will send additional HTTP security headers to the clients, including: + +* `X-XSS-Protection: "1; mode=block"` +* `X-Permitted-Cross-Domain-Policies: "none"` +* `X-Frame-Options: "DENY"` +* `X-Content-Type-Options: "nosniff"` +* `X-Download-Options: "noopen"` + +A content security policy (CSP) will also be set: + +```csp +content-security-policy: + default-src 'none'; + base-uri 'self'; + frame-ancestors 'none'; + img-src 'self' data: https:; + media-src 'self' https:; + style-src 'self' 'unsafe-inline'; + font-src 'self'; + script-src 'self'; + connect-src 'self' wss://example.tld; + manifest-src 'self'; + upgrade-insecure-requests; +``` + +#### `sts` + +> Recommended value: `true` + +An additional “Strict transport security” header will be sent with the configured `sts_max_age` parameter. This tells the browser, that the domain should only be accessed over a secure HTTPs connection. + +#### `ct_max_age` + +An additional “Expect-CT” header will be sent with the configured `ct_max_age` parameter. This enforces the use of TLS certificates that are published in the certificate transparency log. (see [Expect-CT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT)) + +#### `referrer_policy` + +> Recommended value: `same-origin` + +If you click on a link, your browser’s request to the other site will include from where it is coming from. The “Referrer policy” header tells the browser how and if it should send this information. (see [Referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)) + +## systemd + +A systemd unit example is provided at `installation/pleroma.service`. + +### PrivateTmp + +> Recommended value: `true` + +Use private `/tmp` and `/var/tmp` folders inside a new file system namespace, which are discarded after the process stops. + +### ProtectHome + +> Recommended value: `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`. + +### ProtectSystem + +> Recommended value: `full` + +Mount `/usr`, `/boot`, and `/etc` as read-only for processes invoked by this service. + +### PrivateDevices + +> Recommended value: `true` + +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. This may not work on devices like the Raspberry Pi, where you need to set this to `false`. + +### NoNewPrivileges + +> Recommended value: `true` + +Ensures that the service process and all its children can never gain new privileges through `execve()`. + +### CapabilityBoundingSet + +> Recommended value: `~CAP_SYS_ADMIN` + +Drops the sysadmin capability from the daemon. diff --git a/docs/config/howto_change_ip_and_port.md b/docs/config/howto_change_ip_and_port.md new file mode 100644 index 000000000..decddd35c --- /dev/null +++ b/docs/config/howto_change_ip_and_port.md @@ -0,0 +1,7 @@ +# How to change the port or IP Pleroma listens to +To change the port or IP Pleroma listens to, head over to your generated config inside the Pleroma folder at config/prod.secret.exs and edit the following according to your needs. +``` +config :pleroma, Pleroma.Web.Endpoint, + [...] + http: [ip: {127, 0, 0, 1}, port: 4000] +``` diff --git a/docs/config/howto_mediaproxy.md b/docs/config/howto_mediaproxy.md new file mode 100644 index 000000000..fb731112b --- /dev/null +++ b/docs/config/howto_mediaproxy.md @@ -0,0 +1,32 @@ +# How to activate mediaproxy +## Explanation + +Without the `mediaproxy` function, Pleroma don't store any remote content like pictures, video etc. locally. So every time you open Pleroma, the content is loaded from the source server, from where the post is coming. This can result in slowly loading content or/and increased bandwidth usage on the source server. +With the `mediaproxy` function you can use the cache ability of nginx, to cache these content, so user can access it faster, cause it's loaded from your server. + +## Activate it + +* Edit your nginx config and add the following location: +``` +location /proxy { + proxy_cache pleroma_media_cache; + proxy_cache_lock on; + proxy_pass http://localhost:4000; +} +``` +Also add the following on top of the configuration, outside of the `server` block: +``` +proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off; +``` +If you came here from one of the installation guides, take a look at the example configuration `/installation/pleroma.nginx`, where this part is already included. + +* Append the following to your `prod.secret.exs` or `dev.secret.exs` (depends on which mode your instance is running): +``` +config :pleroma, :media_proxy, + enabled: true, + redirect_on_failure: true + #base_url: "https://cache.pleroma.social" +``` +If you want to use a subdomain to serve the files, uncomment `base_url`, change the url and add a comma after `true` in the previous line. + +* Restart nginx and Pleroma diff --git a/docs/config/howto_proxy.md b/docs/config/howto_proxy.md new file mode 100644 index 000000000..10a635266 --- /dev/null +++ b/docs/config/howto_proxy.md @@ -0,0 +1,12 @@ +# How to configure upstream proxy for federation +If you want to proxify all http requests (e.g. for TOR) that pleroma makes to an upstream proxy server, edit you config file (`dev.secret.exs` or `prod.secret.exs`) and add the following: + +``` +config :pleroma, :http, + proxy_url: "127.0.0.1:8123" +``` + +The other way to do it, for example, with Tor you would most likely add something like this: +``` +config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050} +``` diff --git a/docs/config/howto_user_recomendation.md b/docs/config/howto_user_recomendation.md new file mode 100644 index 000000000..27c0760dd --- /dev/null +++ b/docs/config/howto_user_recomendation.md @@ -0,0 +1,31 @@ +# How to activate user recommendation (Who to follow panel) +![who-to-follow-panel-small](/uploads/9de1b1300436c32461d272945f1bc23e/who-to-follow-panel-small.png) + +To show the *who to follow* panel, edit `config/prod.secret.exs` in the Pleroma backend. Following code activates the *who to follow* panel: + +```elixir +config :pleroma, :suggestions, + enabled: true, + third_party_engine: + "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}", + timeout: 300_000, + limit: 23, + web: "https://vinayaka.distsn.org/?{{host}}+{{user}}" + +``` + +`config/config.exs` already includes this code, but `enabled:` is `false`. + +`/api/v1/suggestions` is also provided when *who to follow* panel is enabled. + +For advanced customization, following code shows the newcomers of the fediverse at the *who to follow* panel: + +```elixir +config :pleroma, :suggestions, + enabled: true, + third_party_engine: + "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-new-suggestions-api.cgi?{{host}}+{{user}}", + timeout: 60_000, + limit: 23, + web: "https://vinayaka.distsn.org/user-new.html" +``` diff --git a/docs/config/i2p.md b/docs/config/i2p.md new file mode 100644 index 000000000..c477eb6e4 --- /dev/null +++ b/docs/config/i2p.md @@ -0,0 +1,197 @@ +# I2P Federation +# I2P Federation and Accessability + +This guide is going to focus on the Pleroma federation aspect. The actual installation is neatly explained in the official documentation, and more likely to remain up-to-date. +It might be added to this guide if there will be a need for that. + +We're going to use I2PD for its lightweightness over the official client. +Follow the documentation according to your distro: https://i2pd.readthedocs.io/en/latest/user-guide/install/#installing + +How to run it: https://i2pd.readthedocs.io/en/latest/user-guide/run/ + +## I2P Federation + +There are 2 ways to go about this. +One using the config, and one using external software (fedproxy). The external software works better so far. + +### Using the Config + +**Warning:** So far, everytime I followed this way of federating using I2P, the rest of my federation stopped working. I'm leaving this here in case it will help with making it work. + +Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`: +``` +config :pleroma, :http, proxy_url: {:socks5, :localhost, 4447} +``` +And then run the following: +``` +su pleroma +MIX_ENV=prod mix deps.get +MIX_ENV=prod mix ecto.migrate +exit +``` +You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P. +``` +systemctl stop i2pd.service --no-block +systemctl start i2pd.service +``` +*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes). + +You can change the socks proxy port in `/etc/i2pd/i2pd.conf`. + +### Using Fedproxy + +Fedproxy passes through clearnet requests direct to where they are going. It doesn't force anything over Tor. + +To use [fedproxy](https://github.com/majestrate/fedproxy) you'll need to install Golang. +``` +apt install golang +``` +Use a different user than pleroma or root. Run the following to add the Gopath to your ~/.bashrc. +``` +echo "export GOPATH=/home/ren/.go" >> ~/.bashrc +``` +Restart that bash session (you can exit and log back in). +Run the following to get fedproxy. +``` +go get -u github.com/majestrate/fedproxy$ +cp $(GOPATH)/bin/fedproxy /usr/local/bin/fedproxy +``` +And then the following to start it for I2P only. +``` +fedproxy 127.0.0.1:2000 127.0.0.1:4447 +``` +If you want to also use it for Tor, add `127.0.0.1:9050` to that command. +You'll also need to modify your Pleroma config. + +Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`: +``` +config :pleroma, :http, proxy_url: {:socks5, :localhost, 2000} +``` +And then run the following: +``` +su pleroma +MIX_ENV=prod mix deps.get +MIX_ENV=prod mix ecto.migrate +exit +``` +You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P. + +``` +systemctl stop i2pd.service --no-block +systemctl start i2pd.service +``` +*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes). + +You can change the socks proxy port in `/etc/i2pd/i2pd.conf`. + +## I2P Instance Access + +Make your instance accessible using I2P. + +Add the following to your I2PD config `/etc/i2pd/tunnels.conf`: +``` +[pleroma] +type = http +host = 127.0.0.1 +port = 14447 +keys = pleroma.dat +``` +Restart I2PD: +``` +systemctl stop i2pd.service --no-block +systemctl start i2pd.service +``` +*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes). + +Now you'll have to find your address. +To do that you can download and use I2PD tools.[^1] +Or you'll need to access your web-console on localhost:7070. +If you don't have a GUI, you'll have to SSH tunnel into it like this: +`ssh -L 7070:127.0.0.1:7070 user@ip -p port`. +Now you can access it at localhost:7070. +Go to I2P tunnels page. Look for Server tunnels and you will see an address that ends with `.b32.i2p` next to "pleroma". +This is your site's address. + +### I2P-only Instance + +If creating an I2P-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following: +``` + url: [host: "i2paddress", scheme: "http", port: 80], +``` +In addition to that, replace the existing nginx config's contents with the example below. + +### Existing Instance (Clearnet Instance) + +If not an I2P-only instance, add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`. + +And for both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet). +Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/): +``` +config :pleroma, :http_security, + enabled: false +``` + +Use this as the Nginx config: +``` +proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off; +# The above already exists in a clearnet instance's config. +# If not, add it. + +server { + listen 127.0.0.1:14447; + server_name youri2paddress; + + # Comment to enable logs + access_log /dev/null; + error_log /dev/null; + + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml; + + client_max_body_size 16m; + + location / { + + add_header X-XSS-Protection "1; mode=block"; + add_header X-Permitted-Cross-Domain-Policies none; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Referrer-Policy same-origin; + add_header X-Download-Options noopen; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + + proxy_pass http://localhost:4000; + + client_max_body_size 16m; + } + + location /proxy { + proxy_cache pleroma_media_cache; + proxy_cache_lock on; + proxy_ignore_client_abort on; + proxy_pass http://localhost:4000; + } +} +``` +reload Nginx: +``` +systemctl stop i2pd.service --no-block +systemctl start i2pd.service +``` +*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes). + +You should now be able to both access your instance using I2P and federate with other I2P instances! + +[^1]: [I2PD tools](https://github.com/purplei2p/i2pd-tools) to print information about a router info file or an I2P private key, generate an I2P private key, and generate vanity addresses. + +### Possible Issues + +Will be added when encountered. diff --git a/docs/Message-Rewrite-Facility-configuration.md b/docs/config/mrf.md similarity index 98% rename from docs/Message-Rewrite-Facility-configuration.md rename to docs/config/mrf.md index 35ce52ea9..2cc16cef0 100644 --- a/docs/Message-Rewrite-Facility-configuration.md +++ b/docs/config/mrf.md @@ -1,4 +1,4 @@ -# Message Rewrite Facility configuration +# Message Rewrite Facility The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages. Possible uses include: @@ -70,7 +70,7 @@ As discussed above, the MRF system is a modular system that supports pluggable p For example, here is a sample policy module which rewrites all messages to "new message content": -```!elixir +```elixir # This is a sample MRF policy which rewrites all Notes to have "new message # content." defmodule Site.RewritePolicy do @@ -116,4 +116,4 @@ config :pleroma, :instance, ] ``` -Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request. \ No newline at end of file +Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request. diff --git a/docs/config/onion_federation.md b/docs/config/onion_federation.md new file mode 100644 index 000000000..99f104995 --- /dev/null +++ b/docs/config/onion_federation.md @@ -0,0 +1,159 @@ +# Easy Onion Federation (Tor) +Tor can free people from the necessity of a domain, in addition to helping protect their privacy. As Pleroma's goal is to empower the people and let as many as possible host an instance with as little resources as possible, the ability to host an instance with a small, cheap computer like a RaspberryPi along with Tor, would be a great way to achieve that. +In addition, federating with such instances will also help furthering that goal. + +This is a guide to show you how it can be easily done. + +This guide assumes you already got Pleroma working, and that it's running on the default port 4000. +Currently only has an Nginx example. + +To install Tor on Debian / Ubuntu: +``` +apt -yq install tor +``` +If using an old server version (older than Debian Stretch or Ubuntu 18.04), install from backports or PPA. +I recommend using a newer server version instead. + +To have the newest, V3 onion addresses (which I recommend) in Debian, install Tor from backports. +If you do not have backports, uncomment the stretch-backports links at the end of `/etc/apt/sources.list`. +Then install: +``` +apt update +apt -t stretch-backports -yq install tor +``` +**WARNING:** Onion instances not using a Tor version supporting V3 addresses will not be able to federate with you. + +Create the hidden service for your Pleroma instance in `/etc/tor/torrc`: +``` +HiddenServiceDir /var/lib/tor/pleroma_hidden_service/ +HiddenServicePort 80 127.0.0.1:8099 +HiddenServiceVersion 3 # Remove if Tor version is below 0.3 ( tor --version ) +``` +Restart Tor to generate an adress: +``` +systemctl restart tor@default.service +``` +Get the address: +``` +cat /var/lib/tor/pleroma_hidden_service/hostname +``` + +# Federation + +Next, edit your Pleroma config. +If running in prod, cd to your Pleroma directory, edit `config/prod.secret.exs` +and append this line: +``` +config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050} +``` +In your Pleroma directory, assuming you're running prod, +run the following: +``` +su pleroma +MIX_ENV=prod mix deps.get +MIX_ENV=prod mix ecto.migrate +exit +``` +restart Pleroma (if using systemd): +``` +systemctl restart pleroma +``` + +# Tor Instance Access + +Make your instance accessible using Tor. + +## Tor-only Instance +If creating a Tor-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following: +``` + url: [host: "onionaddress", scheme: "http", port: 80], +``` +In addition to that, replace the existing nginx config's contents with the example below. + +## Existing Instance (Clearnet Instance) +If not a Tor-only instance, +add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`. + +--- +For both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet). +Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/): +``` +config :pleroma, :http_security, + enabled: false +``` + +Use this as the Nginx config: +``` +proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off; +# The above already exists in a clearnet instance's config. +# If not, add it. + +server { + listen 127.0.0.1:8099; + server_name youronionaddress; + + # Comment to enable logs + access_log /dev/null; + error_log /dev/null; + + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml; + + client_max_body_size 16m; + + location / { + + add_header X-XSS-Protection "1; mode=block"; + add_header X-Permitted-Cross-Domain-Policies none; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Referrer-Policy same-origin; + add_header X-Download-Options noopen; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + + proxy_pass http://localhost:4000; + + client_max_body_size 16m; + } + + location /proxy { + proxy_cache pleroma_media_cache; + proxy_cache_lock on; + proxy_ignore_client_abort on; + proxy_pass http://localhost:4000; + } +} +``` +reload Nginx: +``` +systemctl reload nginx +``` + +You should now be able to both access your instance using Tor and federate with other Tor instances! + +--- + +### Possible Issues + +* In Debian, make sure your hidden service folder `/var/lib/tor/pleroma_hidden_service/` and its contents, has debian-tor as both owner and group by using +``` +ls -la /var/lib/tor/ +``` +If it's not, run: +``` +chown -R debian-tor:debian-tor /var/lib/tor/pleroma_hidden_service/ +``` +* Make sure *only* the owner has *only* read and write permissions. +If not, run: +``` +chmod -R 600 /var/lib/tor/pleroma_hidden_service/ +``` +* If you have trouble logging in to the Mastodon Frontend when using Tor, use the Tor Browser Bundle. diff --git a/docs/config/small_customizations.md b/docs/config/small_customizations.md new file mode 100644 index 000000000..09e8d6041 --- /dev/null +++ b/docs/config/small_customizations.md @@ -0,0 +1,35 @@ +# Small customizations +Replace `dev.secret.exs` with `prod.secret.exs` according to your setup. + +# Thumbnail + +Replace `priv/static/instance/thumbnail.jpeg` with your selfie or other neat picture. It will appear in [Pleroma Instances](http://distsn.org/pleroma-instances.html). + +# Instance-specific panel + +![instance-specific panel demo](/uploads/296b19ec806b130e0b49b16bfe29ce8a/image.png) + +To show the instance specific panel, set `show_instance_panel` to `true` in `config/dev.secret.exs`. You can modify its content by editing `priv/static/instance/panel.html`. + +# Background + +You can change the background of your Pleroma instance by uploading it to `priv/static/static`, and then changing `"background"` in `config/dev.secret.exs` accordingly. + +# Logo + +![logo modification demo](/uploads/c70b14de60fa74245e7f0dcfa695ebff/image.png) + +If you want to give a brand to your instance, look no further. You can change the logo of your instance by uploading it to `priv/static/static`, and then changing `logo` in `config/dev.secret.exs` accordingly. + +# Theme + +All users of your instance will be able to change the theme they use by going to the settings (the cog in the top-right hand corner). However, if you wish to change the default theme, you can do so by editing `theme` in `config/dev.secret.exs` accordingly. + +# Terms of Service + +Terms of Service will be shown to all users on the registration page. It's the best place where to write down the rules for your instance. You can modify the rules by changing `priv/static/static/terms-of-service.html`. + +# Message Visibility + +To enable message visibility options when posting like in the Mastodon frontend, set +`scope_options_enabled` to `true` in `config/dev.secret.exs`. diff --git a/docs/static_dir.md b/docs/config/static_dir.md similarity index 100% rename from docs/static_dir.md rename to docs/config/static_dir.md diff --git a/docs/fuckgitlablol.sh b/docs/fuckgitlablol.sh new file mode 100755 index 000000000..32e7b8998 --- /dev/null +++ b/docs/fuckgitlablol.sh @@ -0,0 +1,12 @@ +#!/bin/sh +lstr=`ls -A1 *.md` +readarray -t lsarr <<<"$lstr" +for i in "${lsarr[@]}" +do + : + echo $i + title=`echo $i | sed 's/-/\ /g' | sed 's/\.md//g'` + echo $title + echo -e "# $title\n$(cat $i)" > $i +done + diff --git a/docs/installation/alpine_linux_en.md b/docs/installation/alpine_linux_en.md new file mode 100644 index 000000000..c493816d6 --- /dev/null +++ b/docs/installation/alpine_linux_en.md @@ -0,0 +1,215 @@ +# Installing on Alpine Linux +## Installation + +This guide is a step-by-step installation guide for Alpine Linux. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l -s $SHELL -c 'command'` instead. + +### Required packages + +* `postgresql` +* `elixir` +* `erlang` +* `erlang-parsetools` +* `erlang-xmerl` +* `git` +* Development Tools + +#### Optional packages used in this guide + +* `nginx` (preferred, example configs for other reverse proxies can be found in the repo) +* `certbot` (or any other ACME client for Let’s Encrypt certificates) + +### Prepare the system + +* First make sure to have the community repository enabled: + +```shell +echo "https://nl.alpinelinux.org/alpine/latest-stable/community" | sudo tee -a /etc/apk/repository +``` + +* Then update the system, if not already done: + +```shell +sudo apk update +sudo apk upgrade +``` + +* Install some tools, which are needed later: + +```shell +sudo apk add git build-base +``` + +### Install Elixir and Erlang + +* Install Erlang and Elixir: + +```shell +sudo apk add erlang erlang-runtime-tools erlang-xmerl elixir +``` + +* Install `erlang-eldap` if you want to enable ldap authenticator + +```shell +sudo apk add erlang-eldap +``` +### Install PostgreSQL + +* Install Postgresql server: + +```shell +sudo apk add postgresql postgresql-contrib +``` + +* Initialize database: + +```shell +sudo /etc/init.d/postgresql start +``` + +* Enable and start postgresql server: + +```shell +sudo rc-update add postgresql +``` + +### Install PleromaBE + +* Add a new system user for the Pleroma service: + +```shell +sudo adduser -S -s /bin/false -h /opt/pleroma -H pleroma +``` + +**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell. + +* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory: + +```shell +sudo mkdir -p /opt/pleroma +sudo chown -R pleroma:pleroma /opt/pleroma +sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma +``` + +* Change to the new directory: + +```shell +cd /opt/pleroma +``` + +* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`: + +```shell +sudo -Hu pleroma mix deps.get +``` + +* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen` + * Answer with `yes` if it asks you to install `rebar3`. + * This may take some time, because parts of pleroma get compiled first. + * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`. + +* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances): + +```shell +mv config/{generated_config.exs,prod.secret.exs} +``` + +* The previous command creates also the file `config/setup_db.psql`, with which you can create the database: + +```shell +sudo -Hu postgres psql -f config/setup_db.psql +``` + +* Now run the database migration: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate +``` + +* Now you can start Pleroma already + +```shell +sudo -Hu pleroma MIX_ENV=prod mix phx.server +``` + +### Finalize installation + +If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create an OpenRC service file for Pleroma. + +#### Nginx + +* Install nginx, if not already done: + +```shell +sudo apk add nginx +``` + +* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it: + +```shell +sudo apk add certbot +``` + +and then set it up: + +```shell +sudo mkdir -p /var/lib/letsencrypt/ +sudo certbot certonly --email -d --standalone +``` + +If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again). + +* Copy the example nginx configuration to the nginx folder + +```shell +sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf +``` + +* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths) +* Enable and start nginx: + +```shell +sudo rc-update add nginx +sudo service nginx start +``` + +If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run: + +```shell +sudo certbot certonly --email -d --webroot -w /var/lib/letsencrypt/ +``` + +#### OpenRC service + +* Copy example service file: + +```shell +sudo cp /opt/pleroma/installation/init.d/pleroma /etc/init.d/pleroma +``` + +* Make sure to start it during the boot + +```shell +sudo rc-update add pleroma +``` + +#### Create your first user + +If your instance is up and running, you can create your first user with administrative rights with the following task: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new --admin +``` + +#### Further reading + +* [Admin tasks](Admin tasks) +* [Backup your instance](Backup-your-instance) +* [Configuration tips](General tips for customizing pleroma fe) +* [Hardening your instance](Hardening-your-instance) +* [How to activate mediaproxy](How-to-activate-mediaproxy) +* [Small Pleroma-FE customizations](Small customizations) +* [Updating your instance](Updating-your-instance) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. diff --git a/docs/installation/arch_linux_en.md b/docs/installation/arch_linux_en.md new file mode 100644 index 000000000..4b3bbbbb0 --- /dev/null +++ b/docs/installation/arch_linux_en.md @@ -0,0 +1,214 @@ +# Installing on Arch Linux +## Installation + +This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -s $SHELL -c 'command'` instead. + +### Required packages + +* `postgresql` +* `elixir` +* `erlang-unixodbc` +* `git` +* `base-devel` + +#### Optional packages used in this guide + +* `nginx` (preferred, example configs for other reverse proxies can be found in the repo) +* `certbot` (or any other ACME client for Let’s Encrypt certificates) + +### Prepare the system + +* First update the system, if not already done: + +```shell +sudo pacman -Syu +``` + +* Install some of the above mentioned programs: + +```shell +sudo pacman -S git base-devel elixir erlang-unixodbc +``` + +### Install PostgreSQL + +[Arch Wiki article](https://wiki.archlinux.org/index.php/PostgreSQL) + +* Install the `postgresql` package: + +```shell +sudo pacman -S postgresql +``` + +* Initialize the database cluster: + +```shell +sudo -iu postgres initdb -D /var/lib/postgres/data +``` + +* Start and enable the `postgresql.service` + +```shell +sudo systemctl enable --now postgresql.service +``` + +### Install PleromaBE + +* Add a new system user for the Pleroma service: + +```shell +sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma +``` + +**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell. + +* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory: + +```shell +sudo mkdir -p /opt/pleroma +sudo chown -R pleroma:pleroma /opt/pleroma +sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma +``` + +* Change to the new directory: + +```shell +cd /opt/pleroma +``` + +* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`: + +```shell +sudo -Hu pleroma mix deps.get +``` + +* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen` + * Answer with `yes` if it asks you to install `rebar3`. + * This may take some time, because parts of pleroma get compiled first. + * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`. + +* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances): + +```shell +mv config/{generated_config.exs,prod.secret.exs} +``` + +* The previous command creates also the file `config/setup_db.psql`, with which you can create the database: + +```shell +sudo -Hu postgres psql -f config/setup_db.psql +``` + +* Now run the database migration: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate +``` + +* Now you can start Pleroma already + +```shell +sudo -Hu pleroma MIX_ENV=prod mix phx.server +``` + +### Finalize installation + +If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma. + +#### Nginx + +* Install nginx, if not already done: + +```shell +sudo pacman -S nginx +``` + +* Create directories for available and enabled sites: + +```shell +sudo mkdir -p /etc/nginx/sites-{available,enabled} +``` + +* Append the following line at the end of the `http` block in `/etc/nginx/nginx.conf`: + +```Nginx +include sites-enabled/*; +``` + +* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it: + +```shell +sudo pacman -S certbot certbot-nginx +``` + +and then set it up: + +```shell +sudo mkdir -p /var/lib/letsencrypt/ +sudo certbot certonly --email -d --standalone +``` + +If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again). + +--- + +* Copy the example nginx configuration and activate it: + +```shell +sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx +sudo ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +``` + +* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths) +* Enable and start nginx: + +```shell +sudo systemctl enable --now nginx.service +``` + +If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run: + +```shell +sudo certbot certonly --email -d --webroot -w /var/lib/letsencrypt/ +``` + +#### Other webserver/proxies + +You can find example configurations for them in `/opt/pleroma/installation/`. + +#### Systemd service + +* Copy example service file + +```shell +sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service +``` + +* Edit the service file and make sure that all paths fit your installation +* Enable and start `pleroma.service`: + +```shell +sudo systemctl enable --now pleroma.service +``` + +#### Create your first user + +If your instance is up and running, you can create your first user with administrative rights with the following task: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new --admin +``` + +#### Further reading + +* [Admin tasks](Admin tasks) +* [Backup your instance](Backup-your-instance) +* [Configuration tips](General tips for customizing pleroma fe) +* [Hardening your instance](Hardening-your-instance) +* [How to activate mediaproxy](How-to-activate-mediaproxy) +* [Small Pleroma-FE customizations](Small customizations) +* [Updating your instance](Updating-your-instance) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. diff --git a/docs/installation/centos7_en.md b/docs/installation/centos7_en.md new file mode 100644 index 000000000..76de21ed8 --- /dev/null +++ b/docs/installation/centos7_en.md @@ -0,0 +1,277 @@ +# Installing on CentOS 7 +## Installation + +This guide is a step-by-step installation guide for CentOS 7. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-create-a-sudo-user-on-centos-quickstart). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -s $SHELL -c 'command'` instead. + +### Required packages + +* `postgresql` (9,6+, CentOS 7 comes with 9.2, we will install version 11 in this guide) +* `elixir` (1.5+) +* `erlang` +* `erlang-parsetools` +* `erlang-xmerl` +* `git` +* Development Tools + +#### Optional packages used in this guide + +* `nginx` (preferred, example configs for other reverse proxies can be found in the repo) +* `certbot` (or any other ACME client for Let’s Encrypt certificates) + +### Prepare the system + +* First update the system, if not already done: + +```shell +sudo yum update +``` + +* Install some of the above mentioned programs: + +```shell +sudo yum install wget git unzip +``` + +* Install development tools: + +```shell +sudo yum group install "Development Tools" +``` + +### Install Elixir and Erlang + +* Add the EPEL repo: + +```shell +sudo yum install epel-release +sudo yum -y update +``` + +* Install Erlang repository: + +```shell +wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm +sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm +``` + +* Install Erlang: + +```shell +sudo yum install erlang erlang-parsetools erlang-xmerl +``` + +* Download [latest Elixir release from Github](https://github.com/elixir-lang/elixir/releases/tag/v1.8.1) (Example for the newest version at the time when this manual was written) + +```shell +wget -P /tmp/ https://github.com/elixir-lang/elixir/releases/download/v1.8.1/Precompiled.zip +``` + +* Create folder where you want to install Elixir, we’ll use: + +```shell +sudo mkdir -p /opt/elixir +``` + +* Unzip downloaded file there: + +```shell +sudo unzip /tmp/Precompiled.zip -d /opt/elixir +``` + +* Create symlinks for the pre-compiled binaries: + +```shell +for e in elixir elixirc iex mix; do sudo ln -s /opt/elixir/bin/${e} /usr/local/bin/${e}; done +``` + +### Install PostgreSQL + +* Add the Postgresql repository: + +```shell +sudo yum install https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-2.noarch.rpm +``` + +* Install the Postgresql server: + +```shell +sudo yum install postgresql11-server postgresql11-contrib +``` + +* Initialize database: + +```shell +sudo /usr/pgsql-11/bin/postgresql-11-setup initdb +``` + +* Open configuration file `/var/lib/pgsql/11/data/pg_hba.conf` and change the following lines from: + +```plain +# IPv4 local connections: +host all all 127.0.0.1/32 ident +# IPv6 local connections: +host all all ::1/128 ident +``` + +to + +```plain +# IPv4 local connections: +host all all 127.0.0.1/32 md5 +# IPv6 local connections: +host all all ::1/128 md5 +``` + +* Enable and start postgresql server: + +```shell +sudo systemctl enable --now postgresql-11.service +``` + +### Install PleromaBE + +* Add a new system user for the Pleroma service: + +```shell +sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma +``` + +**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell. + +* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory: + +```shell +sudo mkdir -p /opt/pleroma +sudo chown -R pleroma:pleroma /opt/pleroma +sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma +``` + +* Change to the new directory: + +```shell +cd /opt/pleroma +``` + +* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`: + +```shell +sudo -Hu pleroma mix deps.get +``` + +* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen` + * Answer with `yes` if it asks you to install `rebar3`. + * This may take some time, because parts of pleroma get compiled first. + * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`. + +* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances): + +```shell +mv config/{generated_config.exs,prod.secret.exs} +``` + +* The previous command creates also the file `config/setup_db.psql`, with which you can create the database: + +```shell +sudo -Hu postgres psql -f config/setup_db.psql +``` + +* Now run the database migration: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate +``` + +* Now you can start Pleroma already + +```shell +sudo -Hu pleroma MIX_ENV=prod mix phx.server +``` + +### Finalize installation + +If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma. + +#### Nginx + +* Install nginx, if not already done: + +```shell +sudo yum install nginx +``` + +* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it: + +```shell +sudo yum install certbot-nginx +``` + +and then set it up: + +```shell +sudo mkdir -p /var/lib/letsencrypt/ +sudo certbot certonly --email -d --standalone +``` + +If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again). + +--- + +* Copy the example nginx configuration to the nginx folder + +```shell +sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf +``` + +* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths) +* Enable and start nginx: + +```shell +sudo systemctl enable --now nginx +``` + +If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run: + +```shell +sudo certbot certonly --email -d --webroot -w /var/lib/letsencrypt/ +``` + +#### Other webserver/proxies + +You can find example configurations for them in `/opt/pleroma/installation/`. + +#### Systemd service + +* Copy example service file + +```shell +sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service +``` + +* Edit the service file and make sure that all paths fit your installation +* Enable and start `pleroma.service`: + +```shell +sudo systemctl enable --now pleroma.service +``` + +#### Create your first user + +If your instance is up and running, you can create your first user with administrative rights with the following task: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new --admin +``` + +#### Further reading + +* [Admin tasks](Admin tasks) +* [Backup your instance](Backup-your-instance) +* [Configuration tips](General tips for customizing pleroma fe) +* [Hardening your instance](Hardening-your-instance) +* [How to activate mediaproxy](How-to-activate-mediaproxy) +* [Small Pleroma-FE customizations](Small customizations) +* [Updating your instance](Updating-your-instance) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md new file mode 100644 index 000000000..9613a329b --- /dev/null +++ b/docs/installation/debian_based_en.md @@ -0,0 +1,202 @@ +# Installing on Debian Based Distributions +## Installation + +This guide will assume you are on Debian Stretch. This guide should also work with Ubuntu 16.04 and 18.04. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -s $SHELL -c 'command'` instead. + +### Required packages + +* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/)) +* `postgresql-contrib` (9.6+, same situtation as above) +* `elixir` (1.5+, [install from here, Debian and Ubuntu ship older versions](https://elixir-lang.org/install.html#unix-and-unix-like) or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user) +* `erlang-dev` +* `erlang-tools` +* `erlang-parsetools` +* `erlang-eldap`, if you want to enable ldap authenticator +* `erlang-xmerl` +* `git` +* `build-essential` + +#### Optional packages used in this guide + +* `nginx` (preferred, example configs for other reverse proxies can be found in the repo) +* `certbot` (or any other ACME client for Let’s Encrypt certificates) + +### Prepare the system + +* First update the system, if not already done: + +```shell +sudo apt update +sudo apt full-upgrade +``` + +* Install some of the above mentioned programs: + +```shell +sudo apt install git build-essential postgresql postgresql-contrib +``` + +### Install Elixir and Erlang + +* Download and add the Erlang repository: + +```shell +wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb +sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb +``` + +* Install Elixir and Erlang: + +```shell +sudo apt update +sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools +``` + +### Install PleromaBE + +* Add a new system user for the Pleroma service: + +```shell +sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma +``` + +**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell. + +* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory: + +```shell +sudo mkdir -p /opt/pleroma +sudo chown -R pleroma:pleroma /opt/pleroma +sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma +``` + +* Change to the new directory: + +```shell +cd /opt/pleroma +``` + +* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`: + +```shell +sudo -Hu pleroma mix deps.get +``` + +* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen` + * Answer with `yes` if it asks you to install `rebar3`. + * This may take some time, because parts of pleroma get compiled first. + * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`. + +* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances): + +```shell +mv config/{generated_config.exs,prod.secret.exs} +``` + +* The previous command creates also the file `config/setup_db.psql`, with which you can create the database: + +```shell +sudo -Hu postgres psql -f config/setup_db.psql +``` + +* Now run the database migration: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate +``` + +* Now you can start Pleroma already + +```shell +sudo -Hu pleroma MIX_ENV=prod mix phx.server +``` + +### Finalize installation + +If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma. + +#### Nginx + +* Install nginx, if not already done: + +```shell +sudo apt install nginx +``` + +* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it: + +```shell +sudo apt install certbot +``` + +and then set it up: + +```shell +sudo mkdir -p /var/lib/letsencrypt/ +sudo certbot certonly --email -d --standalone +``` + +If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again). + +--- + +* Copy the example nginx configuration and activate it: + +```shell +sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx +sudo ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +``` + +* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths) +* Enable and start nginx: + +```shell +sudo systemctl enable --now nginx.service +``` + +If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run: + +```shell +sudo certbot certonly --email -d --webroot -w /var/lib/letsencrypt/ +``` + +#### Other webserver/proxies + +You can find example configurations for them in `/opt/pleroma/installation/`. + +#### Systemd service + +* Copy example service file + +```shell +sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service +``` + +* Edit the service file and make sure that all paths fit your installation +* Enable and start `pleroma.service`: + +```shell +sudo systemctl enable --now pleroma.service +``` + +#### Create your first user + +If your instance is up and running, you can create your first user with administrative rights with the following task: + +```shell +sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new --admin +``` + +#### Further reading + +* [Admin tasks](Admin tasks) +* [Backup your instance](Backup-your-instance) +* [Configuration tips](General tips for customizing pleroma fe) +* [Hardening your instance](Hardening-your-instance) +* [How to activate mediaproxy](How-to-activate-mediaproxy) +* [Small Pleroma-FE customizations](Small customizations) +* [Updating your instance](Updating-your-instance) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md new file mode 100644 index 000000000..ac5dcaaee --- /dev/null +++ b/docs/installation/debian_based_jp.md @@ -0,0 +1,191 @@ +# Pleromaの入れ方 +## 日本語訳について + +この記事は [Installing on Debian based distributions](Installing on Debian based distributions) の日本語訳です。何かがおかしいと思ったら、原文を見てください。 + +## インストール + +このガイドはDebian Stretchを仮定しています。Ubuntu 16.04でも可能です。 + +### 必要なソフトウェア + +- PostgreSQL 9.6+ (postgresql-contrib-9.6 または他のバージョンの PSQL をインストールしてください) +- Elixir 1.5 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like))。または [asdf](https://github.com/asdf-vm/asdf) を pleroma ユーザーでインストール。 +- erlang-dev +- erlang-tools +- erlang-parsetools +- erlang-xmerl (Jessieではバックポートからインストールすること!) +- git +- build-essential +- openssh +- openssl +- nginx prefered (Apacheも動くかもしれませんが、誰もテストしていません!) +- certbot (または何らかのACME Let's encryptクライアント) + +### システムを準備する + +* まずシステムをアップデートしてください。 +``` +apt update && apt dist-upgrade +``` + +* 複数のツールとpostgresqlをインストールします。あとで必要になるので。 +``` +apt install git build-essential openssl ssh sudo postgresql-9.6 postgresql-contrib-9.6 +``` +(postgresqlのバージョンは、あなたのディストロにあわせて変えてください。または、バージョン番号がいらないかもしれません。) + +### ElixirとErlangをインストールします + +* Erlangのリポジトリをダウンロードおよびインストールします。 +``` +wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb +``` + +* ElixirとErlangをインストールします、 +``` +apt update && apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools +``` + +### Pleroma BE (バックエンド) をインストールします + +* 新しいユーザーを作ります。 +``` +adduser pleroma +``` +(Give it any password you want, make it STRONG) + +* 新しいユーザーをsudoグループに入れます。 +``` +usermod -aG sudo pleroma +``` + +* 新しいユーザーに変身し、ホームディレクトリに移動します。 +``` +su pleroma +cd ~ +``` + +* Gitリポジトリをクローンします。 +``` +git clone https://git.pleroma.social/pleroma/pleroma +``` + +* 新しいディレクトリに移動します。 +``` +cd pleroma/ +``` + +* Pleromaが依存するパッケージをインストールします。Hexをインストールしてもよいか聞かれたら、yesを入力してください。 +``` +mix deps.get +``` + +* コンフィギュレーションを生成します。 +``` +mix pleroma.instance gen +``` + * rebar3をインストールしてもよいか聞かれたら、yesを入力してください。 + * この処理には時間がかかります。私もよく分かりませんが、何らかのコンパイルが行われているようです。 + * あなたのインスタンスについて、いくつかの質問があります。その回答は `config/generated_config.exs` というコンフィギュレーションファイルに保存されます。 + +**注意**: メディアプロクシを有効にすると回答して、なおかつ、キャッシュのURLは空欄のままにしている場合は、`generated_config.exs` を編集して、`base_url` で始まる行をコメントアウトまたは削除してください。そして、上にある行の `true` の後にあるコンマを消してください。 + +* コンフィギュレーションを確認して、もし問題なければ、ファイル名を変更してください。 +``` +mv config/{generated_config.exs,prod.secret.exs} +``` + +* これまでのコマンドで、すでに `config/setup_db.psql` というファイルが作られています。このファイルをもとに、データベースを作成します。 +``` +sudo su postgres -c 'psql -f config/setup_db.psql' +``` + +* そして、データベースのミグレーションを実行します。 +``` +MIX_ENV=prod mix ecto.migrate +``` + +* Pleromaを起動できるようになりました。 +``` +MIX_ENV=prod mix phx.server +``` + +### インストールを終わらせる + +あなたの新しいインスタンスを世界に向けて公開するには、nginxまたは何らかのウェブサーバー (プロクシ) を使用する必要があります。また、Pleroma のためにシステムサービスファイルを作成する必要があります。 + +#### Nginx + +* まだインストールしていないなら、nginxをインストールします。 +``` +apt install nginx +``` + +* SSLをセットアップします。他の方法でもよいですが、ここではcertbotを説明します。 +certbotを使うならば、まずそれをインストールします。 +``` +apt install certbot +``` +そしてセットアップします。 +``` +mkdir -p /var/lib/letsencrypt/.well-known +% certbot certonly --email your@emailaddress --webroot -w /var/lib/letsencrypt/ -d yourdomain +``` +もしうまくいかないときは、先にnginxを設定してください。ssl "on" を "off" に変えてから再試行してください。 + +--- + +* nginxコンフィギュレーションの例をnginxフォルダーにコピーします。 +``` +cp /home/pleroma/pleroma/installation/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx +``` + +* nginxを起動する前に、コンフィギュレーションを編集してください。例えば、サーバー名、証明書のパスなどを変更する必要があります。 +* nginxを再起動します。 +``` +systemctl reload nginx.service +``` + +#### Systemd サービス + +* サービスファイルの例をコピーします。 +``` +cp /home/pleroma/pleroma/installation/pleroma.service /usr/lib/systemd/system/pleroma.service +``` + +* サービスファイルを変更します。すべてのパスが正しいことを確認してください。また、`[Service]` セクションに以下の行があることを確認してください。 +``` +Environment="MIX_ENV=prod" +``` + +* `pleroma.service` を enable および start してください。 +``` +systemctl enable --now pleroma.service +``` + +#### モデレーターを作る + +新たにユーザーを作ったら、モデレーター権限を与えたいかもしれません。以下のタスクで可能です。 +``` +mix set_moderator username [true|false] +``` + +モデレーターはすべてのポストを消すことができます。将来的には他のことも可能になるかもしれません。 + +#### メディアプロクシを有効にする + +`generate_config` でメディアプロクシを有効にしているなら、すでにメディアプロクシが動作しています。あとから設定を変更したいなら、[How to activate mediaproxy](How-to-activate-mediaproxy) を見てください。 + +#### コンフィギュレーションとカスタマイズ + +* [Configuration tips](General tips for customizing pleroma fe) +* [Small Pleroma-FE customizations](Small customizations) +* [Admin tasks](Admin tasks) + +## 質問ある? + +インストールについて質問がある、もしくは、うまくいかないときは、以下のところで質問できます。 + +* [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) +* **Freenode** の **#pleroma** IRCチャンネル diff --git a/docs/installation/netbsd_en.md b/docs/installation/netbsd_en.md new file mode 100644 index 000000000..e0ac98359 --- /dev/null +++ b/docs/installation/netbsd_en.md @@ -0,0 +1,198 @@ +# Installing on NetBSD + +## Required software + +pkgin should have been installed by the NetBSD installer if you selected +the right options. If it isn't installed, install it using pkg_add. + +Note that `postgresql11-contrib` is needed for the Postgres extensions +Pleroma uses. + +The `mksh` shell is needed to run the Elixir `mix` script. + +`# pkgin install acmesh elixir git-base git-docs mksh nginx postgresql11-server postgresql11-client postgresql11-contrib sudo` + +You can also build these packages using pkgsrc: +``` +databases/postgresql11-contrib +databases/postgresql11-client +databases/postgresql11-server +devel/git-base +devel/git-docs +lang/elixir +security/acmesh +security/sudo +shells/mksh +www/nginx +``` + +Copy the rc.d scripts to the right directory: + +``` +# cp /usr/pkg/share/examples/rc.d/nginx /usr/pkg/share/examples/rc.d/pgsql /etc/rc.d +``` + +Add nginx and Postgres to `/etc/rc.conf`: + +``` +nginx=YES +pgsql=YES +``` + +## Configuring postgres + +First, run `# /etc/rc.d/pgsql start`. Then, `$ sudo -Hu pgsql -g pgsql createdb`. + +## Configuring Pleroma + +Create a user for Pleroma: + +``` +# groupadd pleroma +# useradd -d /home/pleroma -m -g pleroma -s /usr/pkg/bin/mksh pleroma +# echo 'export LC_ALL="en_GB.UTF-8"' >> /home/pleroma/.profile +# su -l pleroma -c $SHELL +``` + +Clone the repository: + +``` +$ cd /home/pleroma +$ git clone https://git.pleroma.social/pleroma/pleroma.git +``` + +Configure Pleroma. Note that you need a domain name at this point: + +``` +$ cd /home/pleroma/pleroma +$ mix deps.get +$ mix pleroma.instance gen # You will be asked a few questions here. +``` + +Since Postgres is configured, we can now initialize the database. There should +now be a file in `config/setup_db.psql` that makes this easier. Edit it, and +*change the password* to a password of your choice. Make sure it is secure, since +it'll be protecting your database. Now initialize the database: + +``` +$ sudo -Hu pgsql -g pgsql psql -f config/setup_db.psql +``` + +Postgres allows connections from all users without a password by default. To +fix this, edit `/usr/pkg/pgsql/data/pg_hba.conf`. Change every `trust` to +`password`. + +Once this is done, restart Postgres with `# /etc/rc.d/pgsql restart`. + +Run the database migrations. +You will need to do this whenever you update with `git pull`: + +``` +$ MIX_ENV=prod mix ecto.migrate +``` + +## Configuring nginx + +Install the example configuration file +`/home/pleroma/pleroma/installation/pleroma.nginx` to +`/usr/pkg/etc/nginx.conf`. + +Note that it will need to be wrapped in a `http {}` block. You should add +settings for the nginx daemon outside of the http block, for example: + +``` +user nginx nginx; +error_log /var/log/nginx/error.log; +worker_processes 4; + +events { +} +``` + +Edit the defaults: + +* Change `ssl_certificate` and `ssl_trusted_certificate` to +`/etc/nginx/tls/fullchain`. +* Change `ssl_certificate_key` to `/etc/nginx/tls/key`. +* Change `example.tld` to your instance's domain name. + +## Configuring acme.sh + +We'll be using acme.sh in Stateless Mode for TLS certificate renewal. + +First, get your account fingerprint: + +``` +$ sudo -Hu nginx -g nginx acme.sh --register-account +``` + +You need to add the following to your nginx configuration for the server +running on port 80: + +``` + location ~ ^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$ { + default_type text/plain; + return 200 "$1.6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd"; + } +``` + +Replace the string after after `$1.` with your fingerprint. + +Start nginx: + +``` +# /etc/rc.d/nginx start +``` + +It should now be possible to issue a cert (replace `example.com` +with your domain name): + +``` +$ sudo -Hu nginx -g nginx acme.sh --issue -d example.com --stateless +``` + +Let's add auto-renewal to `/etc/daily.local` +(replace `example.com` with your domain): + +``` +/usr/pkg/bin/sudo -Hu nginx -g nginx \ + /usr/pkg/sbin/acme.sh -r \ + -d example.com \ + --cert-file /etc/nginx/tls/cert \ + --key-file /etc/nginx/tls/key \ + --ca-file /etc/nginx/tls/ca \ + --fullchain-file /etc/nginx/tls/fullchain \ + --stateless +``` + +## Creating a startup script for Pleroma + +Copy the startup script to the correct location and make sure it's executable: + +``` +# cp /home/pleroma/pleroma/installation/netbsd/rc.d/pleroma /etc/rc.d/pleroma +# chmod +x /etc/rc.d/pleroma +``` + +Add the following to `/etc/rc.conf`: + +``` +pleroma=YES +pleroma_home="/home/pleroma" +pleroma_user="pleroma" +``` + +Run `# /etc/rc.d/pleroma start` to start Pleroma. + +## Conclusion + +Restart nginx with `# /etc/rc.d/nginx restart` and you should be up and running. + +If you need further help, contact niaa on freenode. + +Make sure your time is in sync, or other instances will receive your posts with +incorrect timestamps. You should have ntpd running. + +## Instances running NetBSD + +* diff --git a/docs/installation/openbsd_en.md b/docs/installation/openbsd_en.md new file mode 100644 index 000000000..633b08e6c --- /dev/null +++ b/docs/installation/openbsd_en.md @@ -0,0 +1,222 @@ +# Installing on OpenBSD +This guide describes the installation and configuration of pleroma (and the required software to run it) on a single OpenBSD 6.4 server. +For any additional information regarding commands and configuration files mentioned here, check the man pages [online](https://man.openbsd.org/) or directly on your server with the man command. + +#### Required software +The following packages need to be installed: + * elixir + * gmake + * ImageMagick + * git + * postgresql-server + * postgresql-contrib + +To install them, run the following command (with doas or as root): +`pkg_add elixir gmake ImageMagick git postgresql-server postgresql-contrib` + +Pleroma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd). Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt. + +#### Creating the pleroma user +Pleroma will be run by a dedicated user, \_pleroma. Before creating it, insert the following lines in login.conf: +``` +pleroma:\ + :datasize-max=1536M:\ + :datasize-cur=1536M:\ + :openfiles-max=4096 +``` +This creates a "pleroma" login class and sets higher values than default for datasize and openfiles (see [login.conf(5)](https://man.openbsd.org/login.conf)), this is required to avoid having pleroma crash some time after starting. + +Create the \_pleroma user, assign it the pleroma login class and create its home directory (/home/\_pleroma/): `useradd -m -L pleroma _pleroma` + +#### Clone pleroma's directory +Enter a shell as the \_pleroma user. As root, run `su _pleroma -;cd`. Then clone the repository with `git clone https://git.pleroma.social/pleroma/pleroma.git`. Pleroma is now installed in /home/\_pleroma/pleroma/, it will be configured and started at the end of this guide. + +#### Postgresql +Start a shell as the \_postgresql user (as root run `su _postgresql -` then run the `initdb` command to initialize postgresql: +If you wish to not use the default location for postgresql's data (/var/postgresql/data), add the following switch at the end of the command: `-D ` and modify the `datadir` variable in the /etc/rc.d/postgresql script. + +When this is done, enable postgresql so that it starts on boot and start it. As root, run: +``` +rcctl enable postgresql +rcctl start postgresql +``` +To check that it started properly and didn't fail right after starting, you can run `ps aux | grep postgres`, there should be multiple lines of output. + +#### httpd +httpd will have three fuctions: + * redirect requests trying to reach the instance over http to the https URL + * serve a robots.txt file + * get Let's Encrypt certificates, with acme-client + +Insert the following config in httpd.conf: +``` +# $OpenBSD: httpd.conf,v 1.17 2017/04/16 08:50:49 ajacoutot Exp $ + +ext_inet="" +ext_inet6="" + +server "default" { + listen on $ext_inet port 80 # Comment to disable listening on IPv4 + listen on $ext_inet6 port 80 # Comment to disable listening on IPv6 + listen on 127.0.0.1 port 80 # Do NOT comment this line + + log syslog + directory no index + + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + + location "/robots.txt" { root "/htdocs/local/" } + location "/*" { block return 302 "https://$HTTP_HOST$REQUEST_URI" } +} + +types { + include "/usr/share/misc/mime.types" +} +``` +Do not forget to change *\* to your server's address(es). If httpd should only listen on one protocol family, comment one of the two first *listen* options. + +Create the /var/www/htdocs/local/ folder and write the content of your robots.txt in /var/www/htdocs/local/robots.txt. +Check the configuration with `httpd -n`, if it is OK enable and start httpd (as root): +``` +rcctl enable httpd +rcctl start httpd +``` + +#### acme-client +acme-client is used to get SSL/TLS certificates from Let's Encrypt. +Insert the following configuration in /etc/acme-client.conf: +``` +# +# $OpenBSD: acme-client.conf,v 1.4 2017/03/22 11:14:14 benno Exp $ +# + +authority letsencrypt- { + #agreement url "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + api url "https://acme-v01.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-privkey-.pem" +} + +domain { + domain key "/etc/ssl/private/.key" + domain certificate "/etc/ssl/.crt" + domain full chain certificate "/etc/ssl/.fullchain.pem" + sign with letsencrypt- + challengedir "/var/www/acme/" +} +``` +Replace *\* by the domain name you'll use for your instance. As root, run `acme-client -n` to check the config, then `acme-client -ADv ` to create account and domain keys, and request a certificate for the first time. +Make acme-client run everyday by adding it in /etc/daily.local. As root, run the following command: `echo "acme-client " >> /etc/daily.local`. + +Relayd will look for certificates and keys based on the address it listens on (see next part), the easiest way to make them available to relayd is to create a link, as root run: +``` +ln -s /etc/ssl/.fullchain.pem /etc/ssl/.crt +ln -s /etc/ssl/private/.key /etc/ssl/private/.key +``` +This will have to be done for each IPv4 and IPv6 address relayd listens on. + +#### relayd +relayd will be used as the reverse proxy sitting in front of pleroma. +Insert the following configuration in /etc/relayd.conf: +``` +# $OpenBSD: relayd.conf,v 1.4 2018/03/23 09:55:06 claudio Exp $ + +ext_inet="" +ext_inet6="" + +table { 127.0.0.1 } +table { 127.0.0.1 } + +http protocol plerup { # Protocol for upstream pleroma server + #tcp { nodelay, sack, socket buffer 65536, backlog 128 } # Uncomment and adjust as you see fit + tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305" + tls ecdhe secp384r1 + + # Forward some paths to the local server (as pleroma won't respond to them as you might want) + pass request quick path "/robots.txt" forward to + + # Append a bunch of headers + match request header append "X-Forwarded-For" value "$REMOTE_ADDR" # This two header and the next one are not strictly required by pleroma but adding them won't hurt + match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT" + + match response header append "X-XSS-Protection" value "1; mode=block" + match response header append "X-Permitted-Cross-Domain-Policies" value "none" + match response header append "X-Frame-Options" value "DENY" + match response header append "X-Content-Type-Options" value "nosniff" + match response header append "Referrer-Policy" value "same-origin" + match response header append "X-Download-Options" value "noopen" + match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'self'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here + match request header append "Connection" value "upgrade" + #match response header append "Strict-Transport-Security" value "max-age=31536000; includeSubDomains" # Uncomment this only after you get HTTPS working. + + # If you do not want remote frontends to be able to access your Pleroma backend server, comment these lines + match response header append "Access-Control-Allow-Origin" value "*" + match response header append "Access-Control-Allow-Methods" value "POST, PUT, DELETE, GET, PATCH, OPTIONS" + match response header append "Access-Control-Allow-Headers" value "Authorization, Content-Type, Idempotency-Key" + match response header append "Access-Control-Expose-Headers" value "Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id" + # Stop commenting lines here +} + +relay wwwtls { + listen on $ext_inet port https tls # Comment to disable listening on IPv4 + listen on $ext_inet6 port https tls # Comment to disable listening on IPv6 + + protocol plerup + + forward to port 4000 check http "/" code 200 + forward to port 80 check http "/robots.txt" code 200 +} +``` +Again, change *\* to your server's address(es) and comment one of the two *listen* options if needed. Also change *wss://CHANGEME.tld* to *wss://\*. +Check the configuration with `relayd -n`, if it is OK enable and start relayd (as root): +``` +rcctl enable relayd +rcctl start relayd +``` + +#### pf +Enabling and configuring pf is highly recommended. +In /etc/pf.conf, insert the following configuration: +``` +# Macros +if="" +authorized_ssh_clients="any" + +# Skip traffic on loopback interface +set skip on lo + +# Default behavior +set block-policy drop +block in log all +pass out quick + +# Security features +match in all scrub (no-df random-id) +block in log from urpf-failed + +# Rules +pass in quick on $if inet proto icmp to ($if) icmp-type { echoreq unreach paramprob trace } # ICMP +pass in quick on $if inet6 proto icmp6 to ($if) icmp6-type { echoreq unreach paramprob timex toobig } # ICMPv6 +pass in quick on $if proto tcp to ($if) port { http https } # relayd/httpd +pass in quick on $if proto tcp from $authorized_ssh_clients to ($if) port ssh +``` +Replace *\* by your server's network interface name (which you can get with ifconfig). Consider replacing the content of the authorized\_ssh\_clients macro by, for exemple, your home IP address, to avoid SSH connection attempts from bots. + +Check pf's configuration by running `pfctl -nf /etc/pf.conf`, load it with `pfctl -f /etc/pf.conf` and enable pf at boot with `rcctl enable pf`. + +#### Configure and start pleroma +Enter a shell as \_pleroma (as root `su _pleroma -`) and enter pleroma's installation directory (`cd ~/pleroma/`). +Then follow the main installation guide: + * run `mix deps.get` + * run `mix pleroma.instance gen` and enter your instance's information when asked + * copy config/generated\_config.exs to config/prod.secret.exs. The default values should be sufficient but you should edit it and check that everything seems OK. + * exit your current shell back to a root one and run `psql -U postgres -f /home/_pleroma/config/setup_db.psql` to setup the database. + * return to a \_pleroma shell into pleroma's installation directory (`su _pleroma -;cd ~/pleroma`) and run `MIX_ENV=prod mix ecto.migrate` + +As \_pleroma in /home/\_pleroma/pleroma, you can now run `LC_ALL=en_US.UTF-8 MIX_ENV=prod mix phx.server` to start your instance. +In another SSH session/tmux window, check that it is working properly by running `ftp -MVo - http://127.0.0.1:4000/api/v1/instance`, you should get json output. Double-check that *uri*'s value is your instance's domain name. + +##### Starting pleroma at boot +An rc script to automatically start pleroma at boot hasn't been written yet, it can be run in a tmux session (tmux is in base). diff --git a/docs/installation/openbsd_fi.md b/docs/installation/openbsd_fi.md new file mode 100644 index 000000000..fa6faa62d --- /dev/null +++ b/docs/installation/openbsd_fi.md @@ -0,0 +1,110 @@ +# Pleroman asennus OpenBSD:llä + +Tarvitset: +* Oman domainin +* OpenBSD 6.3 -serverin +* Auttavan ymmärryksen unix-järjestelmistä + +Komennot, joiden edessä on '#', tulee ajaa käyttäjänä `root`. Tämä on +suositeltavaa tehdä komennon `doas` avulla, katso `doas (1)` ja `doas.conf (5)`. +Tästä eteenpäin oletuksena on, että domain "esimerkki.com" osoittaa +serverin IP-osoitteeseen. + +Jos asennuksen kanssa on ongelmia, IRC-kanava #pleroma Freenodessa tai +Matrix-kanava #freenode_#pleroma:matrix.org ovat hyviä paikkoja löytää apua +(englanniksi), `/msg eal kukkuu` jos haluat välttämättä puhua härmää. + +Asenna tarvittava ohjelmisto: + +`# pkg_add git elixir gmake postgresql-server-10.3 postgresql-contrib-10.3` + +Luo postgresql-tietokanta: + +`# su - _postgresql` + +`$ mkdir /var/postgresql/data` + +`$ initdb -D /var/postgresql/data -E UTF8` + +`$ createdb` + +Käynnistä tietokanta ja aseta se käynnistymään automaattisesti. + +`# rcctl start postgresql` + +`# rcctl enable postgresql` + +Luo käyttäjä pleromaa varten (kysyy muutaman kysymyksen): + +`# adduser pleroma` + +Vaihda pleroma-käyttäjään ja mene kotihakemistoosi: + +`# su - pleroma` + +Lataa pleroman lähdekoodi: + +`$ git clone https://git.pleroma.social/pleroma/pleroma.git` + +`$ cd pleroma` + +Asenna tarvittavat elixir-kirjastot: + +`$ mix deps.get` + +`$ mix deps.compile` + +Luo tarvittava konfiguraatio: + +`$ mix generate_config` + +`$ cp config/generated_config.exs config/prod.secret.exs` + +Aja luodut tietokantakomennot: + +`# su _postgres -c 'psql -f config/setup_db.psql'` + +`$ MIX_ENV=prod mix ecto.migrate` + +Käynnistä pleroma-prosessi: + +`$ MIX_ENV=prod mix compile` + +`$ MIX_ENV=prod mix phx.server` + +Tässä vaiheessa on hyvä tarkistaa että asetukset ovat oikein. Avaa selaimella, +curlilla tai vastaavalla työkalulla `esimerkki.com:4000/api/v1/instance` ja katso +että kohta "uri" on "https://esimerkki.com". + +Huom! Muista varmistaa että muuttuja MIX_ENV on "prod" mix-komentoja ajaessasi. +Mix lukee oikean konfiguraatiotiedoston sen mukaisesti. + +Ohessa enimmäkseen toimivaksi todettu rc.d-skripti pleroman käynnistämiseen. +Kirjoita se tiedostoon /etc/rc.d/pleroma. Tämän jälkeen aja +`# chmod +x /etc/rc.d/pleroma`, ja voit käynnistää pleroman komennolla +`# /etc/rc.d/pleroma start`. + +``` +#!/bin/ksh +#/etc/rc.d/pleroma + +daemon="cd /home/pleroma/pleroma;MIX_ENV=prod /usr/local/bin/elixir" +daemon_flags="--detached /usr/local/bin/mix phx.server" +daemon_user="pleroma" +rc_reload="NO" +rc_bg="YES" + +pexp="beam" + +. /etc/rc.d/rc.subr + +rc_cmd $1 +``` + +Tämän jälkeen tarvitset enää HTTP-serverin välittämään kutsut pleroma-prosessille. +Tiedostosta `install/pleroma.nginx` löytyy esimerkkikonfiguraatio, ja TLS-sertifikaatit +saat ilmaiseksi esimerkiksi [letsencryptiltä](https://certbot.eff.org/lets-encrypt/opbsd-nginx.html). +Nginx asentuu yksinkertaisesti komennolla `# pkg_add nginx`. + +Kun olet valmis, avaa https://esimerkki.com selaimessasi. Luo käyttäjä ja seuraa kiinnostavia +tyyppejä muilla palvelimilla! diff --git a/docs/introduction.md b/docs/introduction.md new file mode 100644 index 000000000..096a23277 --- /dev/null +++ b/docs/introduction.md @@ -0,0 +1,55 @@ +# Introduction to Pleroma +**What is Pleroma?** +Pleroma is a federated social networking platform, compatible with GNU social, Mastodon and other OStatus and ActivityPub implementations. It is free software licensed under the AGPLv3. +It actually consists of two components: a backend, named simply Pleroma, and a user-facing frontend, named Pleroma-FE. It also includes the Mastodon frontend, if that's your thing. +It's part of what we call the fediverse, a federated network of instances which speak common protocols and can communicate with each other. +One account on a instance is enough to talk to the entire fediverse! + +**How can I use it?** + +Pleroma instances are already widely deployed, a list can be found here: +http://distsn.org/pleroma-instances.html + +If you don't feel like joining an existing instance, but instead prefer to deploy your own instance, that's easy too! +Installation instructions can be found here: +[main Pleroma wiki](/) + +**I got an account, now what?** +Great! Now you can explore the fediverse! +- Open the login page for your Pleroma instance (for ex. https://pleroma.soykaf.com) and login with your username and password. +(If you don't have one yet, click on Register) :slightly_smiling_face: + +At this point you will have two columns in front of you. + +***left column*** +- first block: here you can see your avatar, your nickname a bio, and statistics (Statuses, Following, Followers). +Under that you have a text form which allows you to post new statuses. The icon on the left is for uploading media files and attach them to your post. The number under the text form is a character counter, every instance can have a different character limit (the default is 5000). +If you want to mention someone, type @ + name of the person. A drop-down menu will help you in finding the right person. :slight_smile: +To post your status, simply press Submit. + +- second block: Here you can switch between the different timelines: + - Timeline: all the people that you follow + - Mentions: all the statutes where you are mentioned + - Public Timeline: all the statutes from the local instance + - The Whole Known Network: everything, local and remote! + +- third block: this is the Chat block, where you communicate with people on the same instance in realtime. It is local-only, for now, but we're planning to make it extendable to the entire fediverse! :sweat_smile: + +- fourth block: This is the Notifications block, here you will get notified whenever somebody mentions you, follows you, repeats or favorites one of your statuses. + +***right column*** +This is where the interesting stuff happens! :slight_smile: +Depending on the timeline you will see different statuses, but each status has a standard structure: +- Icon + name + link to profile. An optional left-arrow if it's a reply to another status (hovering will reveal the replied-to status). +- A + button on the right allows you to Expand/Collapse an entire discussion thread. It also updates in realtime! +- A binocular icon allows you to open the status on the instance where it's originating from. +- The text of the status, including mentions. If you click on a mention, it will automatically open the profile page of that person. +- Four buttons (left to right): Reply, Repeat, Favorite, Delete. + +**Mastodon interface** +If the Pleroma 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! :smile: +Just add a "/web" after your instance url (for ex. https://pleroma.soycaf.com/web) and you'll end on the Mastodon web interface, but with a Pleroma backend! MAGIC! :fireworks: +For more information on the Mastodon interface, please look here: +https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md + +Remember, what you see is only the frontend part of Mastodon, the backend is still Pleroma. diff --git a/mix.exs b/mix.exs index 99a262089..661430464 100644 --- a/mix.exs +++ b/mix.exs @@ -22,16 +22,12 @@ def project do homepage_url: "https://pleroma.social/", docs: [ logo: "priv/static/static/logo.png", - extras: [ - "README.md", - "docs/Admin-API.md", - "docs/Clients.md", - "docs/config.md", - "docs/Custom-Emoji.md", - "docs/Differences-in-MastodonAPI-Responses.md", - "docs/Message-Rewrite-Facility-configuration.md", - "docs/Pleroma-API.md", - "docs/static_dir.md" + extras: ["README.md" | Path.wildcard("docs/**/*.md")], + groups_for_extras: [ + "Installation manuals": Path.wildcard("docs/installation/*.md"), + Configuration: Path.wildcard("docs/config/*.md"), + Administration: Path.wildcard("docs/admin/*.md"), + "Pleroma's APIs and Mastodon API extensions": Path.wildcard("docs/api/*.md") ], main: "readme", output: "priv/static/doc" From d0026761b73ef1c806affcdfb7b645d2b4bddda2 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 20:13:22 +0300 Subject: [PATCH 23/31] cringe --- docs/.Clients.md.swp | Bin 16384 -> 0 bytes docs/fuckgitlablol.sh | 12 ------------ 2 files changed, 12 deletions(-) delete mode 100644 docs/.Clients.md.swp delete mode 100755 docs/fuckgitlablol.sh diff --git a/docs/.Clients.md.swp b/docs/.Clients.md.swp deleted file mode 100644 index 1f5aa277616ff6979a1bbcf0538237ad9a5ae847..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHN&2J<}6)(a^_}U~&P$b||!53S2x@~WiO{`@-_Abr_VaHl;vILVvHQhBmweIQa zR8{XVAi@Do;XqDV0ScFJAe<8Aun;2H1?cm_NJo`L^C1{eMaUb#b>Jo7XTTQl&r^ha2>cFs75Ei!4LAe*wsfxmo?kQad;0?z`^08apO!0VsIJizn7 zkAUZZ1>k<*gF6Yi3H%0l1^5LZfwRD0KSRi$ft$b$;5FbUz$xJGpGF^W6Sx8V8h8=d z0=@*i_bEc&2HpZ*1q$Fn;H$t_fV+S{;U&sXfgX?m-vv$s|HjLgSAYTV4Dd9t3w#-{ ze);_jFIigjyvz)X%qrb$Yn~N>2M^t zKw5NH7Wk$E^TvFYo~;EFVR}U;h-5$97LiPu#)GwCnW?1Dk-51!x@$Ecm}HYPQz))i z>9(Z1Msd~`S%QvjX)x_h^(hF|MV?D#sL+&A%_Et`ObuxwS&Fd@({hn9d~3qTmKh%P zGMUO`c!+i5PG?~)Ka+u&mSrg$Xqknz;5q1XQTBPxk|r&6w<9{NXxMSuPBJl~fnMS) z9!?tAV`(&$S-Wyr5NSO~0;!U*ann7{GADSnVVN|nQ)LD$-O!^oY{Zru8+H*tJ+3O%Y%t+wR@IWI$fI_W3KR7X zEP#n-M`0;2lX_RX{ivhZkgKqx3d2&Yu_Gb_LxYH^NNN^j+=RK3S9xTx*ksoXnBwCZ zT-0pTGh!*x_0({cF(a;VdWCoBV;SzdEaLiD8g^1{_;S?T=AXCh|t}(+(W{1i-%^4Bcz}aOg?lynd&*ggochEH``41 zBk?%hnzrw?5y9E;LJ{qc6Ul5TawIrYoR~uI50Qw&%l6_ZTiu|*#lMiXp|;}|%{<`e zy|$6kAU@lDZQ?Arnva)f-Qwck4Lo4k+S=MdFJTjLPBCJ0j)lcwlAYB|Lx9z=LVOUZh6_X)3Z&UQOa8hVN_&8Eao_(CBoogy`6f zliPRD9F1{d#`k3=3hSMwt$UlT3pR6Lm&zs5x>SuFR-tWTBFpZhQYI;X+w@Y`Y0=mwY4pXCArL>`)4gi9e)xN?BDrl_SeCjG@Ubj7=U3+)b)Jwf8oH zW-6oawRxeK7F>1Y@K!Z%h#sqdUHo0*Mnw2>_gk`;h3iPu^0~?I8C8tJ6dBjnyD2Xt zpwQO+Av_787Ivvtohw2SFRv^=xV-$(%Foz78*8aY~KLXN|&UR}t?Re4;Go{6A(a5zA*#XCa9t(fb5Bl9D8 z8jZ7?u?vVRwX8MTmdx`jOUsY6mX=#94=>o7+E9jHnk(L7Y2HKeY*3ieAvX|cgi2{U zoqu%u@vU!K^&1r&>KKuAP{m$t40Us9+=hMR zM)k;Ww>+9u-mb3yV-L@lX09EpNgcpb8^j5|nNIg^_<9a++5?YG_Y|Q_FH}CZ0b5^^ zP0mx=Rh&~JX;hulXrb+0hf@~EJhs=ShvQEww0VG3r=#^a7Dk{_VJVHO@8oHp4Xw~X zs(l=!Xs0lc!YT< zzhT?_k7vL$;2H1?cm_NJo&nE*XTUSy8So5v20R1*T?P(&C3LyRY0R(jROWrWp0oc^ YjS8i3iFX1b!@DBRlzly5-xCGoV;ss;z5oCK diff --git a/docs/fuckgitlablol.sh b/docs/fuckgitlablol.sh deleted file mode 100755 index 32e7b8998..000000000 --- a/docs/fuckgitlablol.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -lstr=`ls -A1 *.md` -readarray -t lsarr <<<"$lstr" -for i in "${lsarr[@]}" -do - : - echo $i - title=`echo $i | sed 's/-/\ /g' | sed 's/\.md//g'` - echo $title - echo -e "# $title\n$(cat $i)" > $i -done - From e4601b2c1d5f7c2d5d8acf947b9f8dc8beee1747 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 20:16:14 +0300 Subject: [PATCH 24/31] remove admin tasks as they have their page in mix tasks category already --- docs/admin/admin_tasks.md | 44 --------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 docs/admin/admin_tasks.md diff --git a/docs/admin/admin_tasks.md b/docs/admin/admin_tasks.md deleted file mode 100644 index 883095cdb..000000000 --- a/docs/admin/admin_tasks.md +++ /dev/null @@ -1,44 +0,0 @@ -# Admin tasks -## Important - -If your instance is running in prod mode (most likely it is) make sure to prefix every command with `MIX_ENV=prod`. - -## User management - -It is possible to obtain a list of all available tasks with their options by executing `mix help pleroma.user` - -### Adding users - -Use `mix pleroma.user invite` to generate an invite link for a new user. - -Also, `mix pleroma.user new NICKNAME EMAIL [OPTION...]` can be used to register an account. - -### Making a user a moderator/admin/locked - -Run `mix pleroma.user set username --[no-]moderator` to make user a moderator or remove the moderator status. - -To make the user admin or locked use `mix pleroma.user set NICKNAME --[no-]admin` and `mix pleroma.user set NICKNAME --[no-]locked` respectively - -### Resetting a password - -Run `mix pleroma.user reset_password NICKNAME` to generate a password reset link that you can then send to the user. - -### Banning users - -Run `mix pleroma.user rm NICKNAME` to remove a local account. - -To deactivate(block from the server completely)/reactivate local and remote user accounts run: - -`mix pleroma.user toggle_activated NICKNAME@instancename` - -## Relay managment - -It is possible to obtain a list of all available tasks with their options by executing `mix help pleroma.relay` - -### Following a relay - -Run `mix pleroma.relay follow RELAY_URL` - -### Unfollowing a relay - -Run `mix pleroma.relay unfollow RELAY_URL` From d16e2a2e0435b2ff1ef5190279b35121180d14ca Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 20:16:59 +0300 Subject: [PATCH 25/31] Remove duplicated header from admin_api.md --- docs/api/admin_api.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index ea9b9308c..84adca6ff 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -1,5 +1,4 @@ # Admin API -# Admin API Authentication is required and the user must be an admin. From 9bd80e60448e5ab1d3634d83589e8605f24d37d8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 20:27:01 +0300 Subject: [PATCH 26/31] did it really take me 4 commits to fix this? --- docs/api/pleroma_api.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index bd3fcaa5d..478c9d874 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -61,10 +61,7 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi "cover_photo": "https://pleroma.soykaf.com/images/banner.png", "created_at": "Tue Dec 18 16:55:56 +0000 2018", "default_scope": "public", - "description": "blushy-crushy fediverse idol + pleroma dev -let's be friends -ぷれろまの生徒会長。謎の外人。日本語OK. -公主病.", + "description": "blushy-crushy fediverse idol + pleroma dev\nlet's be friends \nぷれろまの生徒会長。謎の外人。日本語OK. \n公主病.", "description_html": "blushy-crushy fediverse idol + pleroma dev.
let's be friends
ぷれろまの生徒会長。謎の外人。日本語OK.
公主病.", "favourites_count": 0, "fields": [], From 634e09e1a8d0c26ad9a89875e3f713a0bf07ea3e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 28 Mar 2019 20:29:46 +0300 Subject: [PATCH 27/31] Remove duplicated header from i2p.md --- docs/config/i2p.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/config/i2p.md b/docs/config/i2p.md index c477eb6e4..62ced8b7a 100644 --- a/docs/config/i2p.md +++ b/docs/config/i2p.md @@ -1,4 +1,3 @@ -# I2P Federation # I2P Federation and Accessability This guide is going to focus on the Pleroma federation aspect. The actual installation is neatly explained in the official documentation, and more likely to remain up-to-date. From b2f3a40e5386d66daae214cc798b6943590f4003 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 29 Mar 2019 01:57:02 +0100 Subject: [PATCH 28/31] Revert awfully long migration from 568e34858 --- ...190325215156_update_status_reply_count.exs | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 priv/repo/migrations/20190325215156_update_status_reply_count.exs diff --git a/priv/repo/migrations/20190325215156_update_status_reply_count.exs b/priv/repo/migrations/20190325215156_update_status_reply_count.exs deleted file mode 100644 index 50f1fe10b..000000000 --- a/priv/repo/migrations/20190325215156_update_status_reply_count.exs +++ /dev/null @@ -1,48 +0,0 @@ -defmodule Pleroma.Repo.Migrations.UpdateStatusReplyCount do - use Ecto.Migration - - @public "https://www.w3.org/ns/activitystreams#Public" - - def up do - execute(""" - WITH reply_count AS ( - SELECT count(*) AS count, data->>'inReplyTo' AS ap_id - FROM objects - WHERE - data->>'inReplyTo' IS NOT NULL AND - data->>'type' = 'Note' AND ( - data->'cc' ? '#{@public}' OR - data->'to' ? '#{@public}') - GROUP BY data->>'inReplyTo' - ) - UPDATE objects AS o - SET "data" = jsonb_set(o.data, '{repliesCount}', reply_count.count::varchar::jsonb, true) - FROM reply_count - WHERE reply_count.ap_id = o.data->>'id'; - """) - - execute(""" - WITH reply_count AS (SELECT - count(*) as count, - data->'object'->>'inReplyTo' AS ap_id - FROM - activities - WHERE - data->'object'->>'inReplyTo' IS NOT NULL AND - data->'object'->>'type' = 'Note' AND ( - data->'object'->'cc' ? '#{@public}' OR - data->'object'->'to' ? '#{@public}') - GROUP BY - data->'object'->>'inReplyTo' - ) - UPDATE activities AS a - SET "data" = jsonb_set(a.data, '{object, repliesCount}', reply_count.count::varchar::jsonb, true) - FROM reply_count - WHERE reply_count.ap_id = a.data->'object'->>'id'; - """) - end - - def down do - :noop - end -end From 9a39d1d84613bb11542a0628e8b762970bd18bd0 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 29 Mar 2019 12:46:05 +0000 Subject: [PATCH 29/31] Replace Pleroma.Jobs with `pleroma_job_queue` --- config/config.exs | 8 +- config/test.exs | 2 +- docs/config.md | 17 +-- lib/pleroma/application.ex | 1 - lib/pleroma/emails/mailer.ex | 2 +- lib/pleroma/jobs.ex | 152 ------------------------- lib/pleroma/web/federator/federator.ex | 19 ++-- mix.exs | 3 +- mix.lock | 1 + test/jobs_test.exs | 83 -------------- test/support/jobs_worker_mock.ex | 19 ---- 11 files changed, 24 insertions(+), 283 deletions(-) delete mode 100644 lib/pleroma/jobs.ex delete mode 100644 test/jobs_test.exs delete mode 100644 test/support/jobs_worker_mock.ex diff --git a/config/config.exs b/config/config.exs index bd8922b77..0df38d75a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -348,10 +348,10 @@ initial_timeout: 30, max_retries: 5 -config :pleroma, Pleroma.Jobs, - federator_incoming: [max_jobs: 50], - federator_outgoing: [max_jobs: 50], - mailer: [max_jobs: 10] +config :pleroma_job_queue, :queues, + federator_incoming: 50, + federator_outgoing: 50, + mailer: 10 config :pleroma, :fetch_initial_posts, enabled: false, diff --git a/config/test.exs b/config/test.exs index 3691e5bd1..6a7b9067e 100644 --- a/config/test.exs +++ b/config/test.exs @@ -48,7 +48,7 @@ config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock -config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2] +config :pleroma_job_queue, disabled: true try do import_config "test.secret.exs" diff --git a/docs/config.md b/docs/config.md index c1246ee25..c206358ab 100644 --- a/docs/config.md +++ b/docs/config.md @@ -253,25 +253,20 @@ You can then do curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken" ``` -## Pleroma.Jobs +## :pleroma_job_queue -A list of job queues and their settings. - -Job queue settings: - -* `max_jobs`: The maximum amount of parallel jobs running at the same time. +[Pleroma Job Queue][https://git.pleroma.social/pleroma/pleroma_job_queue] configuration: a list of queues with maximum concurrent jobs. Example: -```exs -config :pleroma, Pleroma.Jobs, - federator_incoming: [max_jobs: 50], - federator_outgoing: [max_jobs: 50] +```elixir +config :pleroma_job_queue, :queues, + federator_incoming: 50, + federator_outgoing: 50 ``` This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`. - ## Pleroma.Web.Federator.RetryQueue * `enabled`: If set to `true`, failed federation jobs will be retried diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index cc81e1805..782d1d589 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -110,7 +110,6 @@ def start(_type, _args) do worker(Pleroma.Web.Federator.RetryQueue, []), worker(Pleroma.Stats, []), worker(Pleroma.Web.Push, []), - worker(Pleroma.Jobs, []), worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary) ] ++ streamer_child() ++ diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index f7e3aa78b..b384e6fec 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Mailer do use Swoosh.Mailer, otp_app: :pleroma def deliver_async(email, config \\ []) do - Pleroma.Jobs.enqueue(:mailer, __MODULE__, [:deliver_async, email, config]) + PleromaJobQueue.enqueue(:mailer, __MODULE__, [:deliver_async, email, config]) end def perform(:deliver_async, email, config), do: deliver(email, config) diff --git a/lib/pleroma/jobs.ex b/lib/pleroma/jobs.ex deleted file mode 100644 index 24b7e5e46..000000000 --- a/lib/pleroma/jobs.ex +++ /dev/null @@ -1,152 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Jobs do - @moduledoc """ - A basic job queue - """ - use GenServer - - require Logger - - def init(args) do - {:ok, args} - end - - def start_link do - queues = - Pleroma.Config.get(Pleroma.Jobs) - |> Enum.map(fn {name, _} -> create_queue(name) end) - |> Enum.into(%{}) - - state = %{ - queues: queues, - refs: %{} - } - - GenServer.start_link(__MODULE__, state, name: __MODULE__) - end - - def create_queue(name) do - {name, {:sets.new(), []}} - end - - @doc """ - Enqueues a job. - - Returns `:ok`. - - ## Arguments - - - `queue_name` - a queue name(must be specified in the config). - - `mod` - a worker module (must have `perform` function). - - `args` - a list of arguments for the `perform` function of the worker module. - - `priority` - a job priority (`0` by default). - - ## Examples - - Enqueue `Module.perform/0` with `priority=1`: - - iex> Pleroma.Jobs.enqueue(:example_queue, Module, []) - :ok - - Enqueue `Module.perform(:job_name)` with `priority=5`: - - iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:job_name], 5) - :ok - - Enqueue `Module.perform(:another_job, data)` with `priority=1`: - - iex> data = "foobar" - iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:another_job, data]) - :ok - - Enqueue `Module.perform(:foobar_job, :foo, :bar, 42)` with `priority=1`: - - iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:foobar_job, :foo, :bar, 42]) - :ok - - """ - - def enqueue(queue_name, mod, args, priority \\ 1) - - if Mix.env() == :test do - def enqueue(_queue_name, mod, args, _priority) do - apply(mod, :perform, args) - end - else - @spec enqueue(atom(), atom(), [any()], integer()) :: :ok - def enqueue(queue_name, mod, args, priority) do - GenServer.cast(__MODULE__, {:enqueue, queue_name, mod, args, priority}) - end - end - - def handle_cast({:enqueue, queue_name, mod, args, priority}, state) do - {running_jobs, queue} = state[:queues][queue_name] - - queue = enqueue_sorted(queue, {mod, args}, priority) - - state = - state - |> update_queue(queue_name, {running_jobs, queue}) - |> maybe_start_job(queue_name, running_jobs, queue) - - {:noreply, state} - end - - def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do - queue_name = state.refs[ref] - - {running_jobs, queue} = state[:queues][queue_name] - - running_jobs = :sets.del_element(ref, running_jobs) - - state = - state - |> remove_ref(ref) - |> update_queue(queue_name, {running_jobs, queue}) - |> maybe_start_job(queue_name, running_jobs, queue) - - {:noreply, state} - end - - def maybe_start_job(state, queue_name, running_jobs, queue) do - if :sets.size(running_jobs) < Pleroma.Config.get([__MODULE__, queue_name, :max_jobs]) && - queue != [] do - {{mod, args}, queue} = queue_pop(queue) - {:ok, pid} = Task.start(fn -> apply(mod, :perform, args) end) - mref = Process.monitor(pid) - - state - |> add_ref(queue_name, mref) - |> update_queue(queue_name, {:sets.add_element(mref, running_jobs), queue}) - else - state - end - end - - def enqueue_sorted(queue, element, priority) do - [%{item: element, priority: priority} | queue] - |> Enum.sort_by(fn %{priority: priority} -> priority end) - end - - def queue_pop([%{item: element} | queue]) do - {element, queue} - end - - defp add_ref(state, queue_name, ref) do - refs = Map.put(state[:refs], ref, queue_name) - Map.put(state, :refs, refs) - end - - defp remove_ref(state, ref) do - refs = Map.delete(state[:refs], ref) - Map.put(state, :refs, refs) - end - - defp update_queue(state, queue_name, data) do - queues = Map.put(state[:queues], queue_name, data) - Map.put(state, :queues, queues) - end -end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 5e690ddb8..c47328e13 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -4,7 +4,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Activity - alias Pleroma.Jobs alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay @@ -31,39 +30,39 @@ def init do # Client API def incoming_doc(doc) do - Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc]) + PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc]) end def incoming_ap_doc(params) do - Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params]) + PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params]) end def publish(activity, priority \\ 1) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority) end def publish_single_ap(params) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params]) end def publish_single_websub(websub) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub]) end def verify_websub(websub) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub]) end def request_subscription(sub) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub]) end def refresh_subscriptions do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions]) end def publish_single_salmon(params) do - Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params]) + PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params]) end # Job Worker Callbacks diff --git a/mix.exs b/mix.exs index 661430464..333f21a91 100644 --- a/mix.exs +++ b/mix.exs @@ -93,7 +93,8 @@ defp deps do {:timex, "~> 3.5"}, {:auto_linker, git: "https://git.pleroma.social/pleroma/auto_linker.git", - ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"} + ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}, + {:pleroma_job_queue, "~> 0.2.0"} ] end diff --git a/mix.lock b/mix.lock index 05eaa1d69..f401258e9 100644 --- a/mix.lock +++ b/mix.lock @@ -50,6 +50,7 @@ "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"}, + "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, diff --git a/test/jobs_test.exs b/test/jobs_test.exs deleted file mode 100644 index d55c86ccc..000000000 --- a/test/jobs_test.exs +++ /dev/null @@ -1,83 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.JobsTest do - use ExUnit.Case, async: true - - alias Jobs.WorkerMock - alias Pleroma.Jobs - - setup do - state = %{ - queues: Enum.into([Jobs.create_queue(:testing)], %{}), - refs: %{} - } - - [state: state] - end - - test "creates queue" do - queue = Jobs.create_queue(:foobar) - - assert {:foobar, set} = queue - assert :set == elem(set, 0) |> elem(0) - end - - test "enqueues an element according to priority" do - queue = [%{item: 1, priority: 2}] - - new_queue = Jobs.enqueue_sorted(queue, 2, 1) - assert new_queue == [%{item: 2, priority: 1}, %{item: 1, priority: 2}] - - new_queue = Jobs.enqueue_sorted(queue, 2, 3) - assert new_queue == [%{item: 1, priority: 2}, %{item: 2, priority: 3}] - end - - test "pop first item" do - queue = [%{item: 2, priority: 1}, %{item: 1, priority: 2}] - - assert {2, [%{item: 1, priority: 2}]} = Jobs.queue_pop(queue) - end - - test "enqueue a job", %{state: state} do - assert {:noreply, new_state} = - Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) - - assert %{queues: %{testing: {running_jobs, []}}, refs: _} = new_state - assert :sets.size(running_jobs) == 1 - assert [ref] = :sets.to_list(running_jobs) - assert %{refs: %{^ref => :testing}} = new_state - end - - test "max jobs setting", %{state: state} do - max_jobs = Pleroma.Config.get([Jobs, :testing, :max_jobs]) - - {:noreply, state} = - Enum.reduce(1..(max_jobs + 1), {:noreply, state}, fn _, {:noreply, state} -> - Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) - end) - - assert %{ - queues: %{ - testing: - {running_jobs, [%{item: {WorkerMock, [:test_job, :foo, :bar]}, priority: 3}]} - } - } = state - - assert :sets.size(running_jobs) == max_jobs - end - - test "remove job after it finished", %{state: state} do - {:noreply, new_state} = - Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state) - - %{queues: %{testing: {running_jobs, []}}} = new_state - [ref] = :sets.to_list(running_jobs) - - assert {:noreply, %{queues: %{testing: {running_jobs, []}}, refs: %{}}} = - Jobs.handle_info({:DOWN, ref, :process, nil, nil}, new_state) - - assert :sets.size(running_jobs) == 0 - end -end diff --git a/test/support/jobs_worker_mock.ex b/test/support/jobs_worker_mock.ex deleted file mode 100644 index 0fb976d05..000000000 --- a/test/support/jobs_worker_mock.ex +++ /dev/null @@ -1,19 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Jobs.WorkerMock do - require Logger - - def perform(:test_job, arg, arg2) do - Logger.debug({:perform, :test_job, arg, arg2}) - end - - def perform(:test_job, payload) do - Logger.debug({:perform, :test_job, payload}) - end - - def test_job(payload) do - Pleroma.Jobs.enqueue(:testing, __MODULE__, [:test_job, payload]) - end -end From 11584488d1301f6bd8a06d45b6bca0ff12f82889 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 29 Mar 2019 16:11:22 +0300 Subject: [PATCH 30/31] Improve PleromaJobQeue config documentation --- docs/config.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index c206358ab..b4e1ad275 100644 --- a/docs/config.md +++ b/docs/config.md @@ -255,7 +255,12 @@ curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerando ## :pleroma_job_queue -[Pleroma Job Queue][https://git.pleroma.social/pleroma/pleroma_job_queue] configuration: a list of queues with maximum concurrent jobs. +[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs. + +Pleroma has the following qeues: +* `federator_outgoing` - Outgoing federation +* `federator_incoming` - Incoming federation +* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer) Example: From afbc905a1caf62705a7c5332d7fd847509701e54 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 29 Mar 2019 16:38:18 +0300 Subject: [PATCH 31/31] qs --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index b4e1ad275..3624e295b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -257,7 +257,7 @@ curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerando [Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs. -Pleroma has the following qeues: +Pleroma has the following queues: * `federator_outgoing` - Outgoing federation * `federator_incoming` - Incoming federation * `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)