From 63ab61ed3f4988bfaf9080bcdc4fc8d5046fa57e Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 11 Mar 2019 20:37:26 +0300 Subject: Sign in via Twitter (WIP). --- lib/pleroma/web/endpoint.ex | 10 ++++++---- lib/pleroma/web/oauth/oauth_controller.ex | 11 +++++++++++ lib/pleroma/web/oauth/oauth_view.ex | 1 + lib/pleroma/web/router.ex | 12 ++++++++++++ lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 7 +++++++ 5 files changed, 37 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 3eed047ca..d906db67d 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -50,23 +50,25 @@ defmodule Pleroma.Web.Endpoint do plug(Plug.MethodOverride) plug(Plug.Head) + secure_cookies = Pleroma.Config.get([__MODULE__, :secure_cookie_flag]) + cookie_name = - if Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag), + if secure_cookies, do: "__Host-pleroma_key", else: "pleroma_key" # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. # Set :encryption_salt if you would also like to encrypt it. + # Note: "SameSite=Strict" would cause issues with Twitter OAuth plug( Plug.Session, store: :cookie, key: cookie_name, signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]}, http_only: true, - secure: - Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag), - extra: "SameSite=Strict" + secure: secure_cookies, + extra: "SameSite=Lax" ) plug(Pleroma.Web.Router) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 36318d69b..7b052cb36 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -15,11 +15,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] + plug(Ueberauth) plug(:fetch_session) plug(:fetch_flash) action_fallback(Pleroma.Web.OAuth.FallbackController) + def callback(%{assigns: %{ueberauth_failure: _failure}} = conn, _params) do + conn + |> put_flash(:error, "Failed to authenticate.") + |> redirect(to: "/") + end + + def callback(%{assigns: %{ueberauth_auth: _auth}} = _conn, _params) do + raise "Authenticated successfully. Sign up via OAuth is not yet implemented." + end + def authorize(conn, params) do app = Repo.get_by(App, client_id: params["client_id"]) available_scopes = (app && app.scopes) || [] diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex index 9b37a91c5..1450b5a8d 100644 --- a/lib/pleroma/web/oauth/oauth_view.ex +++ b/lib/pleroma/web/oauth/oauth_view.ex @@ -5,4 +5,5 @@ defmodule Pleroma.Web.OAuth.OAuthView do use Pleroma.Web, :view import Phoenix.HTML.Form + import Phoenix.HTML.Link end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 65a90e31e..7cf7794b3 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -5,6 +5,11 @@ defmodule Pleroma.Web.Router do use Pleroma.Web, :router + pipeline :browser do + plug(:accepts, ["html"]) + plug(:fetch_session) + end + pipeline :api do plug(:accepts, ["json"]) plug(:fetch_session) @@ -197,6 +202,13 @@ defmodule Pleroma.Web.Router do post("/authorize", OAuthController, :create_authorization) post("/token", OAuthController, :token_exchange) post("/revoke", OAuthController, :token_revoke) + + scope [] do + pipe_through(:browser) + + get("/:provider", OAuthController, :request) + get("/:provider/callback", OAuthController, :callback) + end end scope "/api/v1", Pleroma.Web.MastodonAPI do diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 161333847..d465f06b1 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -4,7 +4,9 @@ <%= if get_flash(@conn, :error) do %> <% end %> +

OAuth Authorization

+ <%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
<%= label f, :name, "Name or email" %> @@ -33,3 +35,8 @@ <%= hidden_input f, :state, value: @state%> <%= submit "Authorize" %> <% end %> + +
+<%= link to: "/oauth/twitter", class: "alert alert-info" do %> + Sign in with Twitter +<% end %> \ No newline at end of file -- cgit v1.2.3 From d013b58e84f2c8213a5d26b1c3daf36e2f4807e5 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 12 Mar 2019 22:04:08 +0700 Subject: add `mix pleroma.user delete_activities NICKNAME` task --- lib/mix/tasks/pleroma/user.ex | 12 ++++++++++++ lib/pleroma/user.ex | 8 ++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 037e44716..e232df14f 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -304,6 +304,18 @@ defmodule Mix.Tasks.Pleroma.User do end end + def run(["delete_activities", nickname]) do + Common.start_pleroma() + + with %User{local: true} = user <- User.get_by_nickname(nickname) do + User.delete_user_activities(user) + Mix.shell().info("User #{nickname} deleted.") + else + _ -> + Mix.shell().error("No local user #{nickname}") + end + end + defp set_moderator(user, value) do info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value}) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 50e7e7ccd..2d0a8cde4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1083,6 +1083,12 @@ defmodule Pleroma.User do friends |> Enum.each(fn followed -> User.unfollow(user, followed) end) + delete_user_activities(user) + + {:ok, user} + end + + def delete_user_activities(user) do query = from(a in Activity, where: a.actor == ^user.ap_id) Repo.all(query) @@ -1096,8 +1102,6 @@ defmodule Pleroma.User do "Doing nothing" end end) - - {:ok, user} end def html_filter_policy(%User{info: %{no_rich_text: true}}) do -- cgit v1.2.3 From 16e598ec11cb9178b9fc53a1ec4b649d97c5f3b8 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 12 Mar 2019 22:12:05 +0700 Subject: fix wording --- lib/mix/tasks/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index e232df14f..ec06d908a 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -309,7 +309,7 @@ defmodule Mix.Tasks.Pleroma.User do with %User{local: true} = user <- User.get_by_nickname(nickname) do User.delete_user_activities(user) - Mix.shell().info("User #{nickname} deleted.") + Mix.shell().info("User #{nickname} statuses deleted..") else _ -> Mix.shell().error("No local user #{nickname}") -- cgit v1.2.3 From aacbf0f57053786533df045125dee93ace0daa93 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 15 Mar 2019 17:08:03 +0300 Subject: [#923] OAuth: prototype of sign in / sign up with Twitter. --- lib/pleroma/user.ex | 46 ++++++++++-- lib/pleroma/web/auth/authenticator.ex | 9 ++- lib/pleroma/web/auth/pleroma_authenticator.ex | 56 ++++++++++++++- lib/pleroma/web/endpoint.ex | 11 ++- lib/pleroma/web/oauth/oauth_controller.ex | 83 ++++++++++++++++------ lib/pleroma/web/oauth/oauth_view.ex | 1 - .../web/templates/o_auth/o_auth/consumer.html.eex | 14 ++++ .../web/templates/o_auth/o_auth/show.html.eex | 8 +-- 8 files changed, 192 insertions(+), 36 deletions(-) create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f49ede149..e17df8e34 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -40,6 +40,8 @@ defmodule Pleroma.User do field(:email, :string) field(:name, :string) field(:nickname, :string) + field(:auth_provider, :string) + field(:auth_provider_uid, :string) field(:password_hash, :string) field(:password, :string, virtual: true) field(:password_confirmation, :string, virtual: true) @@ -206,6 +208,36 @@ defmodule Pleroma.User do update_and_set_cache(password_update_changeset(user, data)) end + # TODO: FIXME (WIP): + def oauth_register_changeset(struct, params \\ %{}) do + info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed) + + changeset = + struct + |> cast(params, [:email, :nickname, :name, :bio, :auth_provider, :auth_provider_uid]) + |> validate_required([:auth_provider, :auth_provider_uid]) + |> unique_constraint(:email) + |> unique_constraint(:nickname) + |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames])) + |> validate_format(:email, @email_regex) + |> validate_length(:bio, max: 1000) + |> put_change(:info, info_change) + + if changeset.valid? do + nickname = changeset.changes[:nickname] + ap_id = (nickname && User.ap_id(%User{nickname: nickname})) || nil + followers = User.ap_followers(%User{nickname: ap_id}) + + changeset + |> put_change(:ap_id, ap_id) + |> unique_constraint(:ap_id) + |> put_change(:following, [followers]) + |> put_change(:follower_address, followers) + else + changeset + end + end + def register_changeset(struct, params \\ %{}, opts \\ []) do confirmation_status = if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do @@ -504,13 +536,19 @@ defmodule Pleroma.User do end end + def get_by_email(email), do: Repo.get_by(User, email: email) + def get_by_nickname_or_email(nickname_or_email) do - case user = Repo.get_by(User, nickname: nickname_or_email) do - %User{} -> user - nil -> Repo.get_by(User, email: nickname_or_email) - end + get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email) end + def get_by_auth_provider_uid(auth_provider, auth_provider_uid), + do: + Repo.get_by(User, + auth_provider: to_string(auth_provider), + auth_provider_uid: to_string(auth_provider_uid) + ) + def get_cached_user_info(user) do key = "user_info:#{user.id}" Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end) diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index 82267c595..fa439d562 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -12,8 +12,13 @@ defmodule Pleroma.Web.Auth.Authenticator do ) end - @callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()} - def get_user(plug), do: implementation().get_user(plug) + @callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()} + def get_user(plug, params), do: implementation().get_user(plug, params) + + @callback get_or_create_user_by_oauth(Plug.Conn.t(), Map.t()) :: + {:ok, User.t()} | {:error, any()} + def get_or_create_user_by_oauth(plug, params), + do: implementation().get_or_create_user_by_oauth(plug, params) @callback handle_error(Plug.Conn.t(), any()) :: any() def handle_error(plug, error), do: implementation().handle_error(plug, error) diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 3cc19af01..fb04ef8da 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -8,9 +8,9 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do @behaviour Pleroma.Web.Auth.Authenticator - def get_user(%Plug.Conn{} = conn) do - %{"authorization" => %{"name" => name, "password" => password}} = conn.params - + def get_user(%Plug.Conn{} = _conn, %{ + "authorization" => %{"name" => name, "password" => password} + }) do with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)}, {_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do {:ok, user} @@ -20,6 +20,56 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do end end + def get_user(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials} + + def get_or_create_user_by_oauth( + %Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}}, + _params + ) do + user = User.get_by_auth_provider_uid(provider, uid) + + if user do + {:ok, user} + else + info = auth.info + email = info.email + nickname = info.nickname + + # TODO: FIXME: connect to existing (non-oauth) account (need a UI flow for that) / generate a random nickname? + email = + if email && User.get_by_email(email) do + nil + else + email + end + + nickname = + if nickname && User.get_by_nickname(nickname) do + nil + else + nickname + end + + new_user = + User.oauth_register_changeset( + %User{}, + %{ + auth_provider: to_string(provider), + auth_provider_uid: to_string(uid), + name: info.name, + bio: info.description, + email: email, + nickname: nickname + } + ) + + Pleroma.Repo.insert(new_user) + end + end + + def get_or_create_user_by_oauth(%Plug.Conn{} = _conn, _params), + do: {:error, :missing_credentials} + def handle_error(%Plug.Conn{} = _conn, error) do error end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index d906db67d..31ffdecc0 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -57,10 +57,17 @@ defmodule Pleroma.Web.Endpoint do do: "__Host-pleroma_key", else: "pleroma_key" + same_site = + if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do + # Note: "SameSite=Strict" prevents sign in with external OAuth provider (no cookies during callback request) + "SameSite=Lax" + else + "SameSite=Strict" + end + # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. # Set :encryption_salt if you would also like to encrypt it. - # Note: "SameSite=Strict" would cause issues with Twitter OAuth plug( Plug.Session, store: :cookie, @@ -68,7 +75,7 @@ defmodule Pleroma.Web.Endpoint do signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]}, http_only: true, secure: secure_cookies, - extra: "SameSite=Lax" + extra: same_site ) plug(Pleroma.Web.Router) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 7b052cb36..366085a57 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -15,20 +15,57 @@ defmodule Pleroma.Web.OAuth.OAuthController do import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] - plug(Ueberauth) + if Pleroma.Config.get([:auth, :oauth_consumer_enabled]), do: plug(Ueberauth) + plug(:fetch_session) plug(:fetch_flash) action_fallback(Pleroma.Web.OAuth.FallbackController) - def callback(%{assigns: %{ueberauth_failure: _failure}} = conn, _params) do + def request(conn, params) do + message = + if params["provider"] do + "Unsupported OAuth provider: #{params["provider"]}." + else + "Bad OAuth request." + end + conn - |> put_flash(:error, "Failed to authenticate.") + |> put_flash(:error, message) |> redirect(to: "/") end - def callback(%{assigns: %{ueberauth_auth: _auth}} = _conn, _params) do - raise "Authenticated successfully. Sign up via OAuth is not yet implemented." + def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do + messages = for e <- Map.get(failure, :errors, []), do: e.message + message = Enum.join(messages, "; ") + + conn + |> put_flash(:error, "Failed to authenticate: #{message}.") + |> redirect(external: redirect_uri(conn, redirect_uri)) + end + + def callback( + conn, + %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params + ) do + with {:ok, user} <- Authenticator.get_or_create_user_by_oauth(conn, params) do + do_create_authorization( + conn, + %{ + "authorization" => %{ + "client_id" => client_id, + "redirect_uri" => redirect_uri, + "scope" => oauth_scopes(params, nil) + } + }, + user + ) + else + _ -> + conn + |> put_flash(:error, "Failed to set up user account.") + |> redirect(external: redirect_uri(conn, redirect_uri)) + end end def authorize(conn, params) do @@ -47,14 +84,21 @@ defmodule Pleroma.Web.OAuth.OAuthController do }) end - def create_authorization(conn, %{ - "authorization" => - %{ - "client_id" => client_id, - "redirect_uri" => redirect_uri - } = auth_params - }) do - with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)}, + def create_authorization(conn, params), do: do_create_authorization(conn, params, nil) + + defp do_create_authorization( + conn, + %{ + "authorization" => + %{ + "client_id" => client_id, + "redirect_uri" => redirect_uri + } = auth_params + } = params, + user + ) do + with {_, {:ok, %User{} = user}} <- + {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)}, %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), scopes <- oauth_scopes(auth_params, []), @@ -63,13 +107,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do {:missing_scopes, false} <- {:missing_scopes, scopes == []}, {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do - redirect_uri = - if redirect_uri == "." do - # Special case: Local MastodonFE - mastodon_api_url(conn, :login) - else - redirect_uri - end + redirect_uri = redirect_uri(conn, redirect_uri) cond do redirect_uri == "urn:ietf:wg:oauth:2.0:oob" -> @@ -225,4 +263,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do nil end end + + # Special case: Local MastodonFE + defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login) + + defp redirect_uri(_conn, redirect_uri), do: redirect_uri end diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex index 1450b5a8d..9b37a91c5 100644 --- a/lib/pleroma/web/oauth/oauth_view.ex +++ b/lib/pleroma/web/oauth/oauth_view.ex @@ -5,5 +5,4 @@ defmodule Pleroma.Web.OAuth.OAuthView do use Pleroma.Web, :view import Phoenix.HTML.Form - import Phoenix.HTML.Link end diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex new file mode 100644 index 000000000..e7251bce8 --- /dev/null +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -0,0 +1,14 @@ +

External OAuth Authorization

+<%= form_for @conn, o_auth_path(@conn, :request, :twitter), [method: "get"], fn f -> %> +
+ <%= label f, :scope, "Permissions" %> +
+ <%= text_input f, :scope, value: Enum.join(@available_scopes, " ") %> +
+
+ + <%= hidden_input f, :client_id, value: @client_id %> + <%= hidden_input f, :redirect_uri, value: @redirect_uri %> + <%= hidden_input f, :state, value: @state%> + <%= submit "Sign in with Twitter" %> +<% end %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index d465f06b1..2fa7837fc 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -36,7 +36,7 @@ <%= submit "Authorize" %> <% end %> -
-<%= link to: "/oauth/twitter", class: "alert alert-info" do %> - Sign in with Twitter -<% end %> \ No newline at end of file +<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %> +
+ <%= render @view_module, "consumer.html", assigns %> +<% end %> -- cgit v1.2.3 From 26b63540953f6a65bb52531b434fd6ab85aaedfe Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 18 Mar 2019 17:23:38 +0300 Subject: [#923] Support for multiple (external) registrations per user via Registration. --- lib/pleroma/registration.ex | 36 +++++++++++++++++++ lib/pleroma/user.ex | 16 +++------ lib/pleroma/web/auth/authenticator.ex | 6 ++-- lib/pleroma/web/auth/ldap_authenticator.ex | 2 +- lib/pleroma/web/auth/pleroma_authenticator.ex | 51 ++++++++++++++++----------- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- 6 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 lib/pleroma/registration.ex (limited to 'lib') diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex new file mode 100644 index 000000000..1bd91a316 --- /dev/null +++ b/lib/pleroma/registration.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Registration do + use Ecto.Schema + + import Ecto.Changeset + + alias Pleroma.Registration + alias Pleroma.Repo + alias Pleroma.User + + schema "registrations" do + belongs_to(:user, User, type: Pleroma.FlakeId) + field(:provider, :string) + field(:uid, :string) + field(:info, :map, default: %{}) + + timestamps() + end + + def changeset(registration, params \\ %{}) do + registration + |> cast(params, [:user_id, :provider, :uid, :info]) + |> foreign_key_constraint(:user_id) + |> unique_constraint(:uid, name: :registrations_provider_uid_index) + end + + def get_by_provider_uid(provider, uid) do + Repo.get_by(Registration, + provider: to_string(provider), + uid: to_string(uid) + ) + end +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7f8b282e0..bd742b2fd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -13,6 +13,7 @@ defmodule Pleroma.User do alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object + alias Pleroma.Registration alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web @@ -41,8 +42,6 @@ defmodule Pleroma.User do field(:email, :string) field(:name, :string) field(:nickname, :string) - field(:auth_provider, :string) - field(:auth_provider_uid, :string) field(:password_hash, :string) field(:password, :string, virtual: true) field(:password_confirmation, :string, virtual: true) @@ -56,6 +55,7 @@ defmodule Pleroma.User do field(:bookmarks, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime) has_many(:notifications, Notification) + has_many(:registrations, Registration) embeds_one(:info, Pleroma.User.Info) timestamps() @@ -210,13 +210,12 @@ defmodule Pleroma.User do end # TODO: FIXME (WIP): - def oauth_register_changeset(struct, params \\ %{}) do + def external_registration_changeset(struct, params \\ %{}) do info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed) changeset = struct - |> cast(params, [:email, :nickname, :name, :bio, :auth_provider, :auth_provider_uid]) - |> validate_required([:auth_provider, :auth_provider_uid]) + |> cast(params, [:email, :nickname, :name, :bio]) |> unique_constraint(:email) |> unique_constraint(:nickname) |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames])) @@ -544,13 +543,6 @@ defmodule Pleroma.User do get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email) end - def get_by_auth_provider_uid(auth_provider, auth_provider_uid), - do: - Repo.get_by(User, - auth_provider: to_string(auth_provider), - auth_provider_uid: to_string(auth_provider_uid) - ) - def get_cached_user_info(user) do key = "user_info:#{user.id}" Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end) diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index fa439d562..11f45eec3 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -15,10 +15,10 @@ defmodule Pleroma.Web.Auth.Authenticator do @callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()} def get_user(plug, params), do: implementation().get_user(plug, params) - @callback get_or_create_user_by_oauth(Plug.Conn.t(), Map.t()) :: + @callback get_by_external_registration(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()} - def get_or_create_user_by_oauth(plug, params), - do: implementation().get_or_create_user_by_oauth(plug, params) + def get_by_external_registration(plug, params), + do: implementation().get_by_external_registration(plug, params) @callback handle_error(Plug.Conn.t(), any()) :: any() def handle_error(plug, error), do: implementation().handle_error(plug, error) diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index 6c65cff27..51a0f0fa2 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -40,7 +40,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do end end - def get_or_create_user_by_oauth(conn, params), do: get_user(conn, params) + def get_by_external_registration(conn, params), do: get_user(conn, params) def handle_error(%Plug.Conn{} = _conn, error) do error diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 2e2bcfb70..2d4399490 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do alias Comeonin.Pbkdf2 alias Pleroma.User + alias Pleroma.Registration + alias Pleroma.Repo @behaviour Pleroma.Web.Auth.Authenticator @@ -27,20 +29,21 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do end end - def get_or_create_user_by_oauth( + def get_by_external_registration( %Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}}, _params ) do - user = User.get_by_auth_provider_uid(provider, uid) + registration = Registration.get_by_provider_uid(provider, uid) - if user do + if registration do + user = Repo.preload(registration, :user).user {:ok, user} else info = auth.info email = info.email nickname = info.nickname - # TODO: FIXME: connect to existing (non-oauth) account (need a UI flow for that) / generate a random nickname? + # Note: nullifying email in case this email is already taken email = if email && User.get_by_email(email) do nil @@ -48,31 +51,39 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do email end + # Note: generating a random numeric suffix to nickname in case this nickname is already taken nickname = if nickname && User.get_by_nickname(nickname) do - nil + "#{nickname}_#{:os.system_time()}" else nickname end - new_user = - User.oauth_register_changeset( - %User{}, - %{ - auth_provider: to_string(provider), - auth_provider_uid: to_string(uid), - name: info.name, - bio: info.description, - email: email, - nickname: nickname - } - ) - - Pleroma.Repo.insert(new_user) + with {:ok, new_user} <- + User.external_registration_changeset( + %User{}, + %{ + name: info.name, + bio: info.description, + email: email, + nickname: nickname + } + ) + |> Repo.insert(), + {:ok, _} <- + Registration.changeset(%Registration{}, %{ + user_id: new_user.id, + provider: to_string(provider), + uid: to_string(uid), + info: %{nickname: info.nickname, email: info.email} + }) + |> Repo.insert() do + {:ok, new_user} + end end end - def get_or_create_user_by_oauth(%Plug.Conn{} = _conn, _params), + def get_by_external_registration(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials} def handle_error(%Plug.Conn{} = _conn, error) do diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 588933d31..8c864cb1d 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do conn, %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params ) do - with {:ok, user} <- Authenticator.get_or_create_user_by_oauth(conn, params) do + with {:ok, user} <- Authenticator.get_by_external_registration(conn, params) do do_create_authorization( conn, %{ -- cgit v1.2.3 From 8d21859717a75e01128f50b0b51efdd0a4748670 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 18 Mar 2019 18:09:53 +0300 Subject: [#923] External User registration refactoring, password randomization. --- lib/pleroma/user.ex | 38 ++++++--------------------- lib/pleroma/web/auth/pleroma_authenticator.ex | 14 +++++++--- 2 files changed, 18 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index bd742b2fd..558216894 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -209,35 +209,6 @@ defmodule Pleroma.User do update_and_set_cache(password_update_changeset(user, data)) end - # TODO: FIXME (WIP): - def external_registration_changeset(struct, params \\ %{}) do - info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed) - - changeset = - struct - |> cast(params, [:email, :nickname, :name, :bio]) - |> unique_constraint(:email) - |> unique_constraint(:nickname) - |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames])) - |> validate_format(:email, @email_regex) - |> validate_length(:bio, max: 1000) - |> put_change(:info, info_change) - - if changeset.valid? do - nickname = changeset.changes[:nickname] - ap_id = (nickname && User.ap_id(%User{nickname: nickname})) || nil - followers = User.ap_followers(%User{nickname: ap_id}) - - changeset - |> put_change(:ap_id, ap_id) - |> unique_constraint(:ap_id) - |> put_change(:following, [followers]) - |> put_change(:follower_address, followers) - else - changeset - end - end - def register_changeset(struct, params \\ %{}, opts \\ []) do confirmation_status = if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do @@ -251,7 +222,7 @@ defmodule Pleroma.User do changeset = struct |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation]) - |> validate_required([:email, :name, :nickname, :password, :password_confirmation]) + |> validate_required([:name, :nickname, :password, :password_confirmation]) |> validate_confirmation(:password) |> unique_constraint(:email) |> unique_constraint(:nickname) @@ -262,6 +233,13 @@ defmodule Pleroma.User do |> validate_length(:name, min: 1, max: 100) |> put_change(:info, info_change) + changeset = + if opts[:external] do + changeset + else + validate_required(changeset, [:email]) + end + if changeset.valid? do hashed = Pbkdf2.hashpwsalt(changeset.changes[:password]) ap_id = User.ap_id(%User{nickname: changeset.changes[:nickname]}) diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 2d4399490..36ecd0560 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -54,20 +54,26 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do # Note: generating a random numeric suffix to nickname in case this nickname is already taken nickname = if nickname && User.get_by_nickname(nickname) do - "#{nickname}_#{:os.system_time()}" + "#{nickname}#{:os.system_time()}" else nickname end + random_password = :crypto.strong_rand_bytes(64) |> Base.encode64() + with {:ok, new_user} <- - User.external_registration_changeset( + User.register_changeset( %User{}, %{ name: info.name, bio: info.description, email: email, - nickname: nickname - } + nickname: nickname, + password: random_password, + password_confirmation: random_password + }, + external: true, + confirmed: true ) |> Repo.insert(), {:ok, _} <- -- cgit v1.2.3 From 40e9a04c31a9965dee92cb8f07ed6db28f8ccd75 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 18 Mar 2019 20:31:24 +0300 Subject: [#923] Registration validations & unique index on [:user_id, :provider]. --- lib/pleroma/registration.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex index 1bd91a316..773e25fa6 100644 --- a/lib/pleroma/registration.ex +++ b/lib/pleroma/registration.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Registration do def changeset(registration, params \\ %{}) do registration |> cast(params, [:user_id, :provider, :uid, :info]) + |> validate_required([:provider, :uid]) |> foreign_key_constraint(:user_id) |> unique_constraint(:uid, name: :registrations_provider_uid_index) end -- cgit v1.2.3 From e17a9a1f6680bfc464a1433fcff37b6d61cc5340 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 20 Mar 2019 10:35:31 +0300 Subject: [#923] Nickname & email selection for external registrations, option to connect to existing account. --- lib/pleroma/registration.ex | 20 ++ lib/pleroma/web/auth/authenticator.ex | 12 +- lib/pleroma/web/auth/ldap_authenticator.ex | 11 +- lib/pleroma/web/auth/pleroma_authenticator.ex | 89 ++++---- lib/pleroma/web/oauth/oauth_controller.ex | 245 +++++++++++++++------ lib/pleroma/web/router.ex | 2 + .../web/templates/o_auth/o_auth/register.html.eex | 48 ++++ 7 files changed, 304 insertions(+), 123 deletions(-) create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/register.html.eex (limited to 'lib') diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex index 773e25fa6..21fd1fc3f 100644 --- a/lib/pleroma/registration.ex +++ b/lib/pleroma/registration.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Registration do alias Pleroma.Repo alias Pleroma.User + @primary_key {:id, Pleroma.FlakeId, autogenerate: true} + schema "registrations" do belongs_to(:user, User, type: Pleroma.FlakeId) field(:provider, :string) @@ -20,6 +22,18 @@ defmodule Pleroma.Registration do timestamps() end + def nickname(registration, default \\ nil), + do: Map.get(registration.info, "nickname", default) + + def email(registration, default \\ nil), + do: Map.get(registration.info, "email", default) + + def name(registration, default \\ nil), + do: Map.get(registration.info, "name", default) + + def description(registration, default \\ nil), + do: Map.get(registration.info, "description", default) + def changeset(registration, params \\ %{}) do registration |> cast(params, [:user_id, :provider, :uid, :info]) @@ -28,6 +42,12 @@ defmodule Pleroma.Registration do |> unique_constraint(:uid, name: :registrations_provider_uid_index) end + def bind_to_user(registration, user) do + registration + |> changeset(%{user_id: (user && user.id) || nil}) + |> Repo.update() + end + def get_by_provider_uid(provider, uid) do Repo.get_by(Registration, provider: to_string(provider), diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index 11f45eec3..1f614668c 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Auth.Authenticator do alias Pleroma.User + alias Pleroma.Registration def implementation do Pleroma.Config.get( @@ -15,10 +16,15 @@ defmodule Pleroma.Web.Auth.Authenticator do @callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()} def get_user(plug, params), do: implementation().get_user(plug, params) - @callback get_by_external_registration(Plug.Conn.t(), Map.t()) :: + @callback create_from_registration(Plug.Conn.t(), Map.t(), Registration.t()) :: {:ok, User.t()} | {:error, any()} - def get_by_external_registration(plug, params), - do: implementation().get_by_external_registration(plug, params) + def create_from_registration(plug, params, registration), + do: implementation().create_from_registration(plug, params, registration) + + @callback get_registration(Plug.Conn.t(), Map.t()) :: + {:ok, Registration.t()} | {:error, any()} + def get_registration(plug, params), + do: implementation().get_registration(plug, params) @callback handle_error(Plug.Conn.t(), any()) :: any() def handle_error(plug, error), do: implementation().handle_error(plug, error) diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index 51a0f0fa2..65abd7f38 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -8,10 +8,15 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do require Logger @behaviour Pleroma.Web.Auth.Authenticator + @base Pleroma.Web.Auth.PleromaAuthenticator @connection_timeout 10_000 @search_timeout 10_000 + defdelegate get_registration(conn, params), to: @base + + defdelegate create_from_registration(conn, params, registration), to: @base + def get_user(%Plug.Conn{} = conn, params) do if Pleroma.Config.get([:ldap, :enabled]) do {name, password} = @@ -29,19 +34,17 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do {:error, {:ldap_connection_error, _}} -> # When LDAP is unavailable, try default authenticator - Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn, params) + @base.get_user(conn, params) error -> error end else # Fall back to default authenticator - Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn, params) + @base.get_user(conn, params) end end - def get_by_external_registration(conn, params), do: get_user(conn, params) - def handle_error(%Plug.Conn{} = _conn, error) do error end diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 36ecd0560..60847ce6a 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -29,68 +29,63 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do end end - def get_by_external_registration( + def get_registration( %Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}}, _params ) do registration = Registration.get_by_provider_uid(provider, uid) if registration do - user = Repo.preload(registration, :user).user - {:ok, user} + {:ok, registration} else info = auth.info - email = info.email - nickname = info.nickname - # Note: nullifying email in case this email is already taken - email = - if email && User.get_by_email(email) do - nil - else - email - end + Registration.changeset(%Registration{}, %{ + provider: to_string(provider), + uid: to_string(uid), + info: %{ + "nickname" => info.nickname, + "email" => info.email, + "name" => info.name, + "description" => info.description + } + }) + |> Repo.insert() + end + end - # Note: generating a random numeric suffix to nickname in case this nickname is already taken - nickname = - if nickname && User.get_by_nickname(nickname) do - "#{nickname}#{:os.system_time()}" - else - nickname - end + def get_registration(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials} - random_password = :crypto.strong_rand_bytes(64) |> Base.encode64() + def create_from_registration(_conn, params, registration) do + nickname = value([params["nickname"], Registration.nickname(registration)]) + email = value([params["email"], Registration.email(registration)]) + name = value([params["name"], Registration.name(registration)]) || nickname + bio = value([params["bio"], Registration.description(registration)]) - with {:ok, new_user} <- - User.register_changeset( - %User{}, - %{ - name: info.name, - bio: info.description, - email: email, - nickname: nickname, - password: random_password, - password_confirmation: random_password - }, - external: true, - confirmed: true - ) - |> Repo.insert(), - {:ok, _} <- - Registration.changeset(%Registration{}, %{ - user_id: new_user.id, - provider: to_string(provider), - uid: to_string(uid), - info: %{nickname: info.nickname, email: info.email} - }) - |> Repo.insert() do - {:ok, new_user} - end + random_password = :crypto.strong_rand_bytes(64) |> Base.encode64() + + with {:ok, new_user} <- + User.register_changeset( + %User{}, + %{ + email: email, + nickname: nickname, + name: name, + bio: bio, + password: random_password, + password_confirmation: random_password + }, + external: true, + confirmed: true + ) + |> Repo.insert(), + {:ok, _} <- + Registration.changeset(registration, %{user_id: new_user.id}) |> Repo.update() do + {:ok, new_user} end end - def get_by_external_registration(%Plug.Conn{} = _conn, _params), - do: {:error, :missing_credentials} + defp value(list), do: Enum.find(list, &(to_string(&1) != "")) def handle_error(%Plug.Conn{} = _conn, error) do error diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 8c864cb1d..a2c62ae68 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Registration alias Pleroma.Web.Auth.Authenticator alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization @@ -21,52 +22,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do action_fallback(Pleroma.Web.OAuth.FallbackController) - def request(conn, params) do - message = - if params["provider"] do - "Unsupported OAuth provider: #{params["provider"]}." - else - "Bad OAuth request." - end - - conn - |> put_flash(:error, message) - |> redirect(to: "/") - end - - def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do - messages = for e <- Map.get(failure, :errors, []), do: e.message - message = Enum.join(messages, "; ") - - conn - |> put_flash(:error, "Failed to authenticate: #{message}.") - |> redirect(external: redirect_uri(conn, redirect_uri)) - end - - def callback( - conn, - %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params - ) do - with {:ok, user} <- Authenticator.get_by_external_registration(conn, params) do - do_create_authorization( - conn, - %{ - "authorization" => %{ - "client_id" => client_id, - "redirect_uri" => redirect_uri, - "scope" => oauth_scopes(params, nil) - } - }, - user - ) - else - _ -> - conn - |> put_flash(:error, "Failed to set up user account.") - |> redirect(external: redirect_uri(conn, redirect_uri)) - end - end - def authorize(conn, params) do app = Repo.get_by(App, client_id: params["client_id"]) available_scopes = (app && app.scopes) || [] @@ -83,29 +38,16 @@ defmodule Pleroma.Web.OAuth.OAuthController do }) end - def create_authorization(conn, params), do: do_create_authorization(conn, params, nil) - - defp do_create_authorization( - conn, - %{ - "authorization" => - %{ - "client_id" => client_id, - "redirect_uri" => redirect_uri - } = auth_params - } = params, - user - ) do - with {_, {:ok, %User{} = user}} <- - {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)}, - %App{} = app <- Repo.get_by(App, client_id: client_id), - true <- redirect_uri in String.split(app.redirect_uris), - scopes <- oauth_scopes(auth_params, []), - {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes}, - # Note: `scope` param is intentionally not optional in this context - {:missing_scopes, false} <- {:missing_scopes, scopes == []}, - {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, - {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do + def create_authorization( + conn, + %{ + "authorization" => %{"redirect_uri" => redirect_uri} = auth_params + } = params, + opts \\ [] + ) do + with {:ok, auth} <- + (opts[:auth] && {:ok, opts[:auth]}) || + do_create_authorization(conn, params, opts[:user]) do redirect_uri = redirect_uri(conn, redirect_uri) cond do @@ -232,6 +174,166 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + def request(conn, params) do + message = + if params["provider"] do + "Unsupported OAuth provider: #{params["provider"]}." + else + "Bad OAuth request." + end + + conn + |> put_flash(:error, message) + |> redirect(to: "/") + end + + def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do + messages = for e <- Map.get(failure, :errors, []), do: e.message + message = Enum.join(messages, "; ") + + conn + |> put_flash(:error, "Failed to authenticate: #{message}.") + |> redirect(external: redirect_uri(conn, redirect_uri)) + end + + def callback( + conn, + %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params + ) do + with {:ok, registration} <- Authenticator.get_registration(conn, params) do + user = Repo.preload(registration, :user).user + + auth_params = %{ + "client_id" => client_id, + "redirect_uri" => redirect_uri, + "scopes" => oauth_scopes(params, nil) + } + + if user do + create_authorization( + conn, + %{"authorization" => auth_params}, + user: user + ) + else + registration_params = + Map.merge(auth_params, %{ + "nickname" => Registration.nickname(registration), + "email" => Registration.email(registration) + }) + + conn + |> put_session(:registration_id, registration.id) + |> redirect(to: o_auth_path(conn, :registration_details, registration_params)) + end + else + _ -> + conn + |> put_flash(:error, "Failed to set up user account.") + |> redirect(external: redirect_uri(conn, redirect_uri)) + end + end + + def registration_details(conn, params) do + render(conn, "register.html", %{ + client_id: params["client_id"], + redirect_uri: params["redirect_uri"], + scopes: oauth_scopes(params, []), + nickname: params["nickname"], + email: params["email"] + }) + end + + def register(conn, %{"op" => "connect"} = params) do + create_authorization_params = %{ + "authorization" => Map.merge(params, %{"name" => params["auth_name"]}) + } + + with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), + %Registration{} = registration <- Repo.get(Registration, registration_id), + {:ok, auth} <- do_create_authorization(conn, create_authorization_params), + %User{} = user <- Repo.preload(auth, :user).user, + {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do + conn + |> put_session_registration_id(nil) + |> create_authorization( + create_authorization_params, + auth: auth + ) + else + _ -> + conn + |> put_flash(:error, "Unknown error, please try again.") + |> redirect(to: o_auth_path(conn, :registration_details, params)) + end + end + + def register(conn, params) do + with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), + %Registration{} = registration <- Repo.get(Registration, registration_id), + {:ok, user} <- Authenticator.create_from_registration(conn, params, registration) do + conn + |> put_session_registration_id(nil) + |> create_authorization( + %{ + "authorization" => %{ + "client_id" => params["client_id"], + "redirect_uri" => params["redirect_uri"], + "scopes" => oauth_scopes(params, nil) + } + }, + user: user + ) + else + {:error, changeset} -> + message = + Enum.map(changeset.errors, fn {field, {error, _}} -> + "#{field} #{error}" + end) + |> Enum.join("; ") + + message = + String.replace( + message, + "ap_id has already been taken", + "nickname has already been taken" + ) + + conn + |> put_flash(:error, "Error: #{message}.") + |> redirect(to: o_auth_path(conn, :registration_details, params)) + + _ -> + conn + |> put_flash(:error, "Unknown error, please try again.") + |> redirect(to: o_auth_path(conn, :registration_details, params)) + end + end + + defp do_create_authorization( + conn, + %{ + "authorization" => + %{ + "client_id" => client_id, + "redirect_uri" => redirect_uri + } = auth_params + } = params, + user \\ nil + ) do + with {_, {:ok, %User{} = user}} <- + {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)}, + %App{} = app <- Repo.get_by(App, client_id: client_id), + true <- redirect_uri in String.split(app.redirect_uris), + scopes <- oauth_scopes(auth_params, []), + {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes}, + # Note: `scope` param is intentionally not optional in this context + {:missing_scopes, false} <- {:missing_scopes, scopes == []}, + {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do + Authorization.create_authorization(app, user, scopes) + end + end + # XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be # decoding it. Investigate sometime. defp fix_padding(token) do @@ -269,4 +371,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login) defp redirect_uri(_conn, redirect_uri), do: redirect_uri + + defp get_session_registration_id(conn), do: get_session(conn, :registration_id) + + defp put_session_registration_id(conn, registration_id), + do: put_session(conn, :registration_id, registration_id) end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9b6784120..f2cec574b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -208,12 +208,14 @@ defmodule Pleroma.Web.Router do post("/authorize", OAuthController, :create_authorization) post("/token", OAuthController, :token_exchange) post("/revoke", OAuthController, :token_revoke) + get("/registration_details", OAuthController, :registration_details) scope [] do pipe_through(:browser) get("/:provider", OAuthController, :request) get("/:provider/callback", OAuthController, :callback) + post("/register", OAuthController, :register) end end diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex new file mode 100644 index 000000000..f4547170c --- /dev/null +++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex @@ -0,0 +1,48 @@ +<%= if get_flash(@conn, :info) do %> + +<% end %> +<%= if get_flash(@conn, :error) do %> + +<% end %> + +

Registration Details

+ +

If you'd like to register a new account, +
+please provide the details below.

+
+ +<%= form_for @conn, o_auth_path(@conn, :register), [], fn f -> %> + +
+ <%= label f, :nickname, "Nickname" %> + <%= text_input f, :nickname, value: @nickname %> +
+
+ <%= label f, :email, "Email" %> + <%= text_input f, :email, value: @email %> +
+ +<%= submit "Proceed as new user", name: "op", value: "register" %> + +
+
+
+

Alternatively, sign in to connect to existing account.

+ +
+ <%= label f, :auth_name, "Name or email" %> + <%= text_input f, :auth_name %> +
+
+ <%= label f, :password, "Password" %> + <%= password_input f, :password %> +
+ +<%= submit "Proceed as existing user", name: "op", value: "connect" %> + +<%= hidden_input f, :client_id, value: @client_id %> +<%= hidden_input f, :redirect_uri, value: @redirect_uri %> +<%= hidden_input f, :scope, value: Enum.join(@scopes, " ") %> + +<% end %> -- cgit v1.2.3 From af68a42ef7841013476831e92d3841088fa875df Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 20 Mar 2019 20:25:48 +0300 Subject: [#923] Support for multiple OAuth consumer strategies. --- lib/pleroma/web/oauth/oauth_controller.ex | 29 +++++++++++++++------- .../web/templates/o_auth/o_auth/consumer.html.eex | 20 ++++++--------- .../web/templates/o_auth/o_auth/show.html.eex | 1 - 3 files changed, 28 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index a2c62ae68..b300c96df 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -187,25 +187,25 @@ defmodule Pleroma.Web.OAuth.OAuthController do |> redirect(to: "/") end - def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do + def callback(%{assigns: %{ueberauth_failure: failure}} = conn, params) do + params = callback_params(params) messages = for e <- Map.get(failure, :errors, []), do: e.message message = Enum.join(messages, "; ") conn |> put_flash(:error, "Failed to authenticate: #{message}.") - |> redirect(external: redirect_uri(conn, redirect_uri)) + |> redirect(external: redirect_uri(conn, params["redirect_uri"])) end - def callback( - conn, - %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params - ) do + def callback(conn, params) do + params = callback_params(params) + with {:ok, registration} <- Authenticator.get_registration(conn, params) do user = Repo.preload(registration, :user).user auth_params = %{ - "client_id" => client_id, - "redirect_uri" => redirect_uri, + "client_id" => params["client_id"], + "redirect_uri" => params["redirect_uri"], "scopes" => oauth_scopes(params, nil) } @@ -230,10 +230,21 @@ defmodule Pleroma.Web.OAuth.OAuthController do _ -> conn |> put_flash(:error, "Failed to set up user account.") - |> redirect(external: redirect_uri(conn, redirect_uri)) + |> redirect(external: redirect_uri(conn, params["redirect_uri"])) end end + defp callback_params(%{"state" => state} = params) do + [client_id, redirect_uri, scope, state] = String.split(state, "|") + + Map.merge(params, %{ + "client_id" => client_id, + "redirect_uri" => redirect_uri, + "scope" => scope, + "state" => state + }) + end + def registration_details(conn, params) do render(conn, "register.html", %{ client_id: params["client_id"], diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index e7251bce8..a64859a49 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -1,14 +1,10 @@ -

External OAuth Authorization

-<%= form_for @conn, o_auth_path(@conn, :request, :twitter), [method: "get"], fn f -> %> -
- <%= label f, :scope, "Permissions" %> -
- <%= text_input f, :scope, value: Enum.join(@available_scopes, " ") %> -
-
+
+
+

Sign in with external provider

- <%= hidden_input f, :client_id, value: @client_id %> - <%= hidden_input f, :redirect_uri, value: @redirect_uri %> - <%= hidden_input f, :state, value: @state%> - <%= submit "Sign in with Twitter" %> +<%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %> + <%= form_for @conn, o_auth_path(@conn, :request, strategy), [method: "get"], fn f -> %> + <%= hidden_input f, :state, value: Enum.join([@client_id, @redirect_uri, Enum.join(@available_scopes, " "), @state], "|") %> + <%= submit "Sign in with #{String.capitalize(strategy)}" %> + <% end %> <% end %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 2fa7837fc..b2381869a 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -37,6 +37,5 @@ <% end %> <%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %> -
<%= render @view_module, "consumer.html", assigns %> <% end %> -- cgit v1.2.3 From 2a95014b9d7142aa2549e70f428293af78fae8eb Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 27 Mar 2019 15:39:35 +0300 Subject: [#923] OAuth consumer improvements, fixes, refactoring. --- lib/pleroma/web/auth/authenticator.ex | 6 +++++ lib/pleroma/web/auth/ldap_authenticator.ex | 2 ++ lib/pleroma/web/auth/pleroma_authenticator.ex | 2 ++ lib/pleroma/web/oauth/oauth_controller.ex | 28 +++++++++++++++------- lib/pleroma/web/router.ex | 1 + .../web/templates/o_auth/o_auth/_scopes.html.eex | 13 ++++++++++ .../web/templates/o_auth/o_auth/consumer.html.eex | 15 ++++++++---- .../web/templates/o_auth/o_auth/show.html.eex | 16 +++---------- 8 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index 1f614668c..bb87b323c 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -33,4 +33,10 @@ defmodule Pleroma.Web.Auth.Authenticator do def auth_template do implementation().auth_template() || Pleroma.Config.get(:auth_template, "show.html") end + + @callback oauth_consumer_template() :: String.t() | nil + def oauth_consumer_template do + implementation().oauth_consumer_template() || + Pleroma.Config.get(:oauth_consumer_template, "consumer.html") + end end diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index 65abd7f38..8b6d5a77f 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -51,6 +51,8 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do def auth_template, do: nil + def oauth_consumer_template, do: nil + defp ldap_user(name, password) do ldap = Pleroma.Config.get(:ldap, []) host = Keyword.get(ldap, :host, "localhost") diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 60847ce6a..8b190f97f 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -92,4 +92,6 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do end def auth_template, do: nil + + def oauth_consumer_template, do: nil end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index b300c96df..078839d5c 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -174,6 +174,25 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + def prepare_request(conn, %{"provider" => provider} = params) do + scope = + oauth_scopes(params, []) + |> Enum.join(" ") + + state = + params + |> Map.delete("scopes") + |> Map.put("scope", scope) + |> Poison.encode!() + + params = + params + |> Map.drop(~w(scope scopes client_id redirect_uri)) + |> Map.put("state", state) + + redirect(conn, to: o_auth_path(conn, :request, provider, params)) + end + def request(conn, params) do message = if params["provider"] do @@ -235,14 +254,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do end defp callback_params(%{"state" => state} = params) do - [client_id, redirect_uri, scope, state] = String.split(state, "|") - - Map.merge(params, %{ - "client_id" => client_id, - "redirect_uri" => redirect_uri, - "scope" => scope, - "state" => state - }) + Map.merge(params, Poison.decode!(state)) end def registration_details(conn, params) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f2cec574b..4d0e04d9f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -213,6 +213,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:browser) + get("/prepare_request", OAuthController, :prepare_request) get("/:provider", OAuthController, :request) get("/:provider/callback", OAuthController, :callback) post("/register", OAuthController, :register) diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex new file mode 100644 index 000000000..4b8fb5dae --- /dev/null +++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex @@ -0,0 +1,13 @@ +
+ <%= label @form, :scope, "Permissions" %> + +
+ <%= for scope <- @available_scopes do %> + <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> +
+ <%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: assigns[:scope_param] || "scope[]" %> + <%= label @form, :"scope_#{scope}", String.capitalize(scope) %> +
+ <% end %> +
+
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index a64859a49..002f014e6 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -2,9 +2,14 @@

Sign in with external provider

-<%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %> - <%= form_for @conn, o_auth_path(@conn, :request, strategy), [method: "get"], fn f -> %> - <%= hidden_input f, :state, value: Enum.join([@client_id, @redirect_uri, Enum.join(@available_scopes, " "), @state], "|") %> - <%= submit "Sign in with #{String.capitalize(strategy)}" %> - <% end %> +<%= form_for @conn, o_auth_path(@conn, :prepare_request), [method: "get"], fn f -> %> + <%= render @view_module, "_scopes.html", Map.put(assigns, :form, f) %> + + <%= hidden_input f, :client_id, value: @client_id %> + <%= hidden_input f, :redirect_uri, value: @redirect_uri %> + <%= hidden_input f, :state, value: @state %> + + <%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %> + <%= submit "Sign in with #{String.capitalize(strategy)}", name: "provider", value: strategy %> + <% end %> <% end %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index b2381869a..e6cf1db45 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -16,18 +16,8 @@ <%= label f, :password, "Password" %> <%= password_input f, :password %>
-
-<%= label f, :scope, "Permissions" %> -
- <%= for scope <- @available_scopes do %> - <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %> -
- <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %> - <%= label f, :"scope_#{scope}", String.capitalize(scope) %> -
- <% end %> -
-
+ +<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f, scope_param: "authorization[scope][]"}) %> <%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :response_type, value: @response_type %> @@ -37,5 +27,5 @@ <% end %> <%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %> - <%= render @view_module, "consumer.html", assigns %> + <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %> <% end %> -- cgit v1.2.3 From 1bb4d5d65be725f374e06da88a5e8e826660596b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 29 Mar 2019 21:59:04 +0300 Subject: Implement fake status submit --- lib/pleroma/web/activity_pub/activity_pub.ex | 31 +++++++++++++++++++++------- lib/pleroma/web/common_api/common_api.ex | 17 ++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6e1ed7ec9..b459fd882 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -113,15 +113,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def decrease_replies_count_if_reply(_object), do: :noop - def insert(map, local \\ true) when is_map(map) do + def insert(map, local \\ true, fake \\ false) when is_map(map) do with nil <- Activity.normalize(map), map <- lazy_put_activity_defaults(map), :ok <- check_actor_is_active(map["actor"]), {_, true} <- {:remote_limit_error, check_remote_limit(map)}, {:ok, map} <- MRF.filter(map), + {recipients, _, _} = get_recipients(map), + {:fake, false, map, recipients} <- {:fake, fake, map, recipients}, {:ok, object} <- insert_full_object(map) do - {recipients, _, _} = get_recipients(map) - {:ok, activity} = Repo.insert(%Activity{ data: map, @@ -146,8 +146,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do stream_out(activity) {:ok, activity} else - %Activity{} = activity -> {:ok, activity} - error -> {:error, error} + %Activity{} = activity -> + {:ok, activity} + + {:fake, true, map, recipients} -> + {:ok, + %Activity{ + data: map, + local: local, + actor: map["actor"], + recipients: recipients, + id: "pleroma:fakeid" + }} + + error -> + {:error, error} end end @@ -190,7 +203,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def create(%{to: to, actor: actor, context: context, object: object} = params) do + def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do additional = params[:additional] || %{} # only accept false as false value local = !(params[:local] == false) @@ -201,13 +214,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do %{to: to, actor: actor, published: published, context: context, object: object}, additional ), - {:ok, activity} <- insert(create_data, local), + {:ok, activity} <- insert(create_data, local, fake), + {:fake, false, activity} <- {:fake, fake, activity}, _ <- 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), :ok <- maybe_federate(activity) do {:ok, activity} + else + {:fake, true, activity} -> + {:ok, activity} end end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 25b990677..8e2937ac5 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -172,13 +172,16 @@ defmodule Pleroma.Web.CommonAPI do end) ) do res = - ActivityPub.create(%{ - to: to, - actor: user, - context: context, - object: object, - additional: %{"cc" => cc, "directMessage" => visibility == "direct"} - }) + ActivityPub.create( + %{ + to: to, + actor: user, + context: context, + object: object, + additional: %{"cc" => cc, "directMessage" => visibility == "direct"} + }, + data["fake"] || false + ) res end -- cgit v1.2.3 From cd387f8693c57b925576ab92f8202ef28007cfc0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 30 Mar 2019 13:57:54 +0300 Subject: Add a fake option to lazy_put_actvity_defaults --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 34 +++++++++++++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index b459fd882..a94040d01 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def insert(map, local \\ true, fake \\ false) when is_map(map) do with nil <- Activity.normalize(map), - map <- lazy_put_activity_defaults(map), + map <- lazy_put_activity_defaults(map, fake), :ok <- check_actor_is_active(map["actor"]), {_, true} <- {:remote_limit_error, check_remote_limit(map)}, {:ok, map} <- MRF.filter(map), diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2e9ffe41c..3959e9bd9 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -175,21 +175,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do Adds an id and a published data if they aren't there, also adds it to an included object """ - def lazy_put_activity_defaults(map) do - %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) - - map = - map - |> Map.put_new_lazy("id", &generate_activity_id/0) - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("context", context) - |> Map.put_new("context_id", context_id) - - if is_map(map["object"]) do - object = lazy_put_object_defaults(map["object"], map) - %{map | "object" => object} + def lazy_put_activity_defaults(map, fake \\ false) do + unless fake do + %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + + map = + map + |> Map.put_new_lazy("id", &generate_activity_id/0) + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", context) + |> Map.put_new("context_id", context_id) + + if is_map(map["object"]) do + object = lazy_put_object_defaults(map["object"], map) + %{map | "object" => object} + else + map + end else map + |> Map.put_new("id", "pleroma:fakeid") + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", "pleroma:fakecontext") + |> Map.put_new("context_id", -1) end end -- cgit v1.2.3 From eadafc88b898879eb50545b700ea13c8596e908b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 1 Apr 2019 09:28:56 +0300 Subject: [#923] Deps config adjustment (no `override` for `httpoison`), code analysis issues fixes. --- lib/pleroma/web/auth/pleroma_authenticator.ex | 2 +- lib/pleroma/web/endpoint.ex | 3 ++- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 8b190f97f..c826adb4c 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -4,9 +4,9 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do alias Comeonin.Pbkdf2 - alias Pleroma.User alias Pleroma.Registration alias Pleroma.Repo + alias Pleroma.User @behaviour Pleroma.Web.Auth.Authenticator diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index f92724d8b..b85b95bf9 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -60,7 +60,8 @@ defmodule Pleroma.Web.Endpoint do same_site = if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do - # Note: "SameSite=Strict" prevents sign in with external OAuth provider (no cookies during callback request) + # Note: "SameSite=Strict" prevents sign in with external OAuth provider + # (there would be no cookies during callback request from OAuth provider) "SameSite=Lax" else "SameSite=Strict" diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index e54e196aa..54e0a35ba 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -5,9 +5,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do use Pleroma.Web, :controller + alias Pleroma.Registration alias Pleroma.Repo alias Pleroma.User - alias Pleroma.Registration alias Pleroma.Web.Auth.Authenticator alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization -- cgit v1.2.3 From 804173fc924ec591558b8ed7671e35b506be9345 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 1 Apr 2019 09:45:44 +0300 Subject: [#923] Minor code readability fix. --- lib/pleroma/web/auth/authenticator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index bb87b323c..4eeef5034 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -3,8 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Auth.Authenticator do - alias Pleroma.User alias Pleroma.Registration + alias Pleroma.User def implementation do Pleroma.Config.get( -- cgit v1.2.3 From 45ba10bf47baf350fd4d538cbe32cec447d496e6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 1 Apr 2019 11:55:59 +0300 Subject: Fix the issue with HTML scrubber --- lib/pleroma/html.ex | 17 +++++++++++++++-- lib/pleroma/object.ex | 5 +++++ lib/pleroma/web/activity_pub/activity_pub.ex | 22 ++++++++++++++-------- 3 files changed, 34 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 5b152d926..f19b42b42 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -28,9 +28,13 @@ defmodule Pleroma.HTML do def filter_tags(html), do: filter_tags(html, nil) def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags) + # TODO: rename object to activity because that's what it is really working with def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}" - Cachex.fetch!(:scrubber_cache, key, fn _key -> ensure_scrubbed_html(content, scrubbers) end) + + Cachex.fetch!(:scrubber_cache, key, fn _key -> + ensure_scrubbed_html(content, scrubbers, object.data["object"]["fake"] || false) + end) end def get_cached_stripped_html_for_object(content, object, module) do @@ -44,11 +48,20 @@ defmodule Pleroma.HTML do def ensure_scrubbed_html( content, - scrubbers + scrubbers, + _fake = false ) do {:commit, filter_tags(content, scrubbers)} end + def ensure_scrubbed_html( + content, + scrubbers, + _fake = true + ) do + {:ignore, filter_tags(content, scrubbers)} + end + defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do generate_scrubber_signature([scrubber]) end diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 8a670645d..013d62157 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -44,6 +44,11 @@ defmodule Pleroma.Object do # Use this whenever possible, especially when walking graphs in an O(N) loop! def normalize(%Activity{object: %Object{} = object}), do: object + # A hack for fake activities + def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}) do + %Object{id: "pleroma:fake_object_id", data: data} + end + # Catch and log Object.normalize() calls where the Activity's child object is not # preloaded. def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a94040d01..716a40419 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -150,14 +150,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, activity} {:fake, true, map, recipients} -> - {:ok, - %Activity{ - data: map, - local: local, - actor: map["actor"], - recipients: recipients, - id: "pleroma:fakeid" - }} + map = + map + |> put_in(["object", "fake"], true) + + activity = %Activity{ + data: map, + local: local, + actor: map["actor"], + recipients: recipients, + id: "pleroma:fakeid" + } + + # Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) + {:ok, activity} error -> {:error, error} -- cgit v1.2.3 From d866b59eeaed25a1ad19581bd6c942f9f2d2711e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 1 Apr 2019 11:58:08 +0300 Subject: oof --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 716a40419..9cb4a0542 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -162,7 +162,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do id: "pleroma:fakeid" } - # Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) + Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) {:ok, activity} error -> -- cgit v1.2.3 From 975482f091f2f957c138d1b4f2d37e6b5d2b82a8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 1 Apr 2019 12:16:51 +0300 Subject: insert object defaults for fake activities and make credo happy --- lib/pleroma/html.ex | 4 ++-- lib/pleroma/web/activity_pub/utils.ex | 34 ++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index f19b42b42..1e48749a8 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -49,7 +49,7 @@ defmodule Pleroma.HTML do def ensure_scrubbed_html( content, scrubbers, - _fake = false + false = _fake ) do {:commit, filter_tags(content, scrubbers)} end @@ -57,7 +57,7 @@ defmodule Pleroma.HTML do def ensure_scrubbed_html( content, scrubbers, - _fake = true + true = _fake ) do {:ignore, filter_tags(content, scrubbers)} end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 3959e9bd9..feb73518e 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -176,35 +176,45 @@ defmodule Pleroma.Web.ActivityPub.Utils do also adds it to an included object """ def lazy_put_activity_defaults(map, fake \\ false) do - unless fake do - %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + map = + unless fake do + %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) - map = map |> Map.put_new_lazy("id", &generate_activity_id/0) |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("context", context) |> Map.put_new("context_id", context_id) - - if is_map(map["object"]) do - object = lazy_put_object_defaults(map["object"], map) - %{map | "object" => object} else map + |> Map.put_new("id", "pleroma:fakeid") + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", "pleroma:fakecontext") + |> Map.put_new("context_id", -1) end + + if is_map(map["object"]) do + object = lazy_put_object_defaults(map["object"], map, fake) + %{map | "object" => object} else map - |> Map.put_new("id", "pleroma:fakeid") - |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("context", "pleroma:fakecontext") - |> Map.put_new("context_id", -1) end end @doc """ Adds an id and published date if they aren't there. """ - def lazy_put_object_defaults(map, activity \\ %{}) do + def lazy_put_object_defaults(map, activity \\ %{}, fake) + + def lazy_put_object_defaults(map, activity, true = _fake) do + map + |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("id", "pleroma:fakeid") + |> Map.put_new("context", activity["context"]) + |> Map.put_new("context_id", activity["context_id"]) + end + + def lazy_put_object_defaults(map, activity, _fake) do map |> Map.put_new_lazy("id", &generate_object_id/0) |> Map.put_new_lazy("published", &make_date/0) -- cgit v1.2.3 From fe5145eeaab81573614a3475463a24229a6a58a3 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 1 Apr 2019 12:25:53 +0300 Subject: Move putting fake attribute to lib/pleroma/web/activity_pub/utils.ex --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ---- lib/pleroma/web/activity_pub/utils.ex | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 9cb4a0542..f217e7bac 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -150,10 +150,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, activity} {:fake, true, map, recipients} -> - map = - map - |> put_in(["object", "fake"], true) - activity = %Activity{ data: map, local: local, diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index feb73518e..d22da6f40 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -209,8 +209,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do def lazy_put_object_defaults(map, activity, true = _fake) do map |> Map.put_new_lazy("published", &make_date/0) - |> Map.put_new("id", "pleroma:fakeid") + |> Map.put_new("id", "pleroma:fake_object_id") |> Map.put_new("context", activity["context"]) + |> Map.put_new("fake", true) |> Map.put_new("context_id", activity["context_id"]) end -- cgit v1.2.3 From 3601f03147bd104f6acff64e7c8d5d4d3e1f53a2 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Apr 2019 17:17:57 +0700 Subject: Adding tag to emoji ets table changes in apis --- lib/pleroma/emoji.ex | 53 +++++++++++++++++++--- lib/pleroma/formatter.ex | 8 ++-- lib/pleroma/web/common_api/common_api.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 2 +- .../web/mastodon_api/mastodon_api_controller.ex | 5 +- .../web/twitter_api/controllers/util_controller.ex | 8 +++- 6 files changed, 63 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index f3f08cd9d..c35aed6ee 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Emoji do * the built-in Finmojis (if enabled in configuration), * the files: `config/emoji.txt` and `config/custom_emoji.txt` - * glob paths + * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. """ @@ -152,8 +152,10 @@ defmodule Pleroma.Emoji do "woollysocks" ] defp load_finmoji(true) do + tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) + Enum.map(@finmoji, fn finmoji -> - {finmoji, "/finmoji/128px/#{finmoji}-128.png"} + {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} end) end @@ -168,31 +170,70 @@ defmodule Pleroma.Emoji do end defp load_from_file_stream(stream) do + default_tag = + stream.path + |> Path.basename(".txt") + |> get_default_tag() + stream |> Stream.map(&String.trim/1) |> Stream.map(fn line -> case String.split(line, ~r/,\s*/) do - [name, file] -> {name, file} - _ -> nil + [name, file, tags] -> + {name, file, tags} + + [name, file] -> + {name, file, default_tag} + + _ -> + nil end end) |> Enum.to_list() end + @spec get_default_tag(String.t()) :: String.t() + defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do + Keyword.get( + Application.get_env(:pleroma, :emoji), + String.to_existing_atom(file_name <> "_tag") + ) + end + + defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") paths = Enum.map(globs, fn glob -> + static_part = + Path.dirname(glob) + |> String.replace_trailing("**", "") + Path.join(static_path, glob) |> Path.wildcard() + |> Enum.map(fn path -> + custom_folder = + path + |> Path.relative_to(Path.join(static_path, static_part)) + |> Path.dirname() + + [path, custom_folder] + end) end) |> Enum.concat() - Enum.map(paths, fn path -> + Enum.map(paths, fn [path, custom_folder] -> + tag = + case custom_folder do + "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + tag -> tag + end + shortcode = Path.basename(path, Path.extname(path)) external_path = Path.join("/", Path.relative_to(path, static_path)) - {shortcode, external_path} + {shortcode, external_path, tag} end) end end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index e3625383b..8ea9dbd38 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -77,9 +77,9 @@ defmodule Pleroma.Formatter do def emojify(text, nil), do: text def emojify(text, emoji, strip \\ false) do - Enum.reduce(emoji, text, fn {emoji, file}, text -> - emoji = HTML.strip_tags(emoji) - file = HTML.strip_tags(file) + Enum.reduce(emoji, text, fn emoji_data, text -> + emoji = HTML.strip_tags(elem(emoji_data, 0)) + file = HTML.strip_tags(elem(emoji_data, 1)) html = if not strip do @@ -101,7 +101,7 @@ defmodule Pleroma.Formatter do def demojify(text, nil), do: text def get_emoji(text) when is_binary(text) do - Enum.filter(Emoji.get_all(), fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end) + Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end) end def get_emoji(_), do: [] diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 25b990677..f910eb1f9 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -167,7 +167,7 @@ defmodule Pleroma.Web.CommonAPI do object, "emoji", (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"])) - |> Enum.reduce(%{}, fn {name, file}, acc -> + |> Enum.reduce(%{}, fn {name, file, _}, acc -> Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") end) ) do diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index f596f703b..49f0170cc 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -285,7 +285,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do def emoji_from_profile(%{info: _info} = user) do (Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name)) - |> Enum.map(fn {shortcode, url} -> + |> Enum.map(fn {shortcode, url, _} -> %{ "type" => "Emoji", "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"}, diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index eee4e7678..583e4007c 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -178,14 +178,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do defp mastodonized_emoji do Pleroma.Emoji.get_all() - |> Enum.map(fn {shortcode, relative_url} -> + |> Enum.map(fn {shortcode, relative_url, tags} -> url = to_string(URI.merge(Web.base_url(), relative_url)) %{ "shortcode" => shortcode, "static_url" => url, "visible_in_picker" => true, - "url" => url + "url" => url, + "tags" => String.split(tags, ",") } end) end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index faa733fec..e58d9e4cd 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -266,7 +266,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def emoji(conn, _params) do - json(conn, Enum.into(Emoji.get_all(), %{})) + emoji = + Emoji.get_all() + |> Enum.map(fn {short_code, path, tags} -> + %{short_code => %{image_url: path, tags: String.split(tags, ",")}} + end) + + json(conn, emoji) end def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do -- cgit v1.2.3 From 17d3d05a7196140b62dd791af8d7ced8b0ad9fa1 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Apr 2019 17:54:30 +0700 Subject: code style little fix --- lib/pleroma/emoji.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index c35aed6ee..ad3170f9a 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -152,7 +152,7 @@ defmodule Pleroma.Emoji do "woollysocks" ] defp load_finmoji(true) do - tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag) + tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag] Enum.map(@finmoji, fn finmoji -> {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} @@ -193,14 +193,14 @@ defmodule Pleroma.Emoji do end @spec get_default_tag(String.t()) :: String.t() - defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do + defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do Keyword.get( Application.get_env(:pleroma, :emoji), String.to_existing_atom(file_name <> "_tag") ) end - defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) + defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag] defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") -- cgit v1.2.3 From cbe09d94d1e71b2ee5fdce51d3ac014bf69a6b88 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 1 Apr 2019 14:46:50 +0300 Subject: Added `force_login` authentication option (previously applied by default). --- lib/pleroma/web/controller_helper.ex | 5 +++++ lib/pleroma/web/oauth/oauth_controller.ex | 37 ++++++++++++++++++++++++------- lib/pleroma/web/router.ex | 15 ++++++++----- 3 files changed, 44 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 4d6192db0..6fc5a3cb6 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -5,6 +5,11 @@ defmodule Pleroma.Web.ControllerHelper do use Pleroma.Web, :controller + # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html + @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"] + def truthy_param?(nil), do: nil + def truthy_param?(value), do: value not in @falsy_param_values + def oauth_scopes(params, default) do # Note: `scopes` is used by Mastodon — supporting it but sticking to # OAuth's standard `scope` wherever we control it diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index ebb3dd253..0221b4c6f 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.Auth.Authenticator + alias Pleroma.Web.ControllerHelper alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Token @@ -19,7 +20,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do action_fallback(Pleroma.Web.OAuth.FallbackController) - def authorize(conn, params) do + def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do + if ControllerHelper.truthy_param?(params["force_login"]) do + do_authorize(conn, params) + else + redirect_uri = + if is_binary(params["redirect_uri"]) do + params["redirect_uri"] + else + app = Repo.preload(token, :app).app + + app.redirect_uris + |> String.split() + |> Enum.at(0) + end + + redirect(conn, external: redirect_uri(conn, redirect_uri)) + end + end + + def authorize(conn, params), do: do_authorize(conn, params) + + defp do_authorize(conn, params) do app = Repo.get_by(App, client_id: params["client_id"]) available_scopes = (app && app.scopes) || [] scopes = oauth_scopes(params, nil) || available_scopes @@ -51,13 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do {:missing_scopes, false} <- {:missing_scopes, scopes == []}, {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do - redirect_uri = - if redirect_uri == "." do - # Special case: Local MastodonFE - mastodon_api_url(conn, :login) - else - redirect_uri - end + redirect_uri = redirect_uri(conn, redirect_uri) cond do redirect_uri == "urn:ietf:wg:oauth:2.0:oob" -> @@ -221,4 +237,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do nil end end + + # Special case: Local MastodonFE + defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :index, []) + + defp redirect_uri(_conn, redirect_uri), do: redirect_uri end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9ccb4e535..8acab304a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -5,6 +5,11 @@ defmodule Pleroma.Web.Router do use Pleroma.Web, :router + pipeline :oauth do + plug(:fetch_session) + plug(Pleroma.Plugs.OAuthPlug) + end + pipeline :api do plug(:accepts, ["json"]) plug(:fetch_session) @@ -105,10 +110,6 @@ defmodule Pleroma.Web.Router do plug(:accepts, ["json", "xml"]) end - pipeline :oauth do - plug(:accepts, ["html", "json"]) - end - pipeline :pleroma_api do plug(:accepts, ["html", "json"]) end @@ -200,7 +201,11 @@ defmodule Pleroma.Web.Router do end scope "/oauth", Pleroma.Web.OAuth do - get("/authorize", OAuthController, :authorize) + scope [] do + pipe_through(:oauth) + get("/authorize", OAuthController, :authorize) + end + post("/authorize", OAuthController, :create_authorization) post("/token", OAuthController, :token_exchange) post("/revoke", OAuthController, :token_revoke) -- cgit v1.2.3 From 6910fb371b221a130bebf97c712fdccc26b50c27 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 1 Apr 2019 17:25:25 +0300 Subject: Fixed local MastoFE authentication / `force_login` option. --- lib/pleroma/web/controller_helper.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 14 +++++++++++--- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 6fc5a3cb6..181483664 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.ControllerHelper do # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"] - def truthy_param?(nil), do: nil + def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil def truthy_param?(value), do: value not in @falsy_param_values def oauth_scopes(params, default) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index eee4e7678..457020fe7 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1249,16 +1249,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do "glitch" end - def login(conn, %{"code" => code}) do + def login(%{assigns: %{user: %User{}}} = conn, _params) do + redirect(conn, to: local_mastodon_root_path(conn)) + end + + @doc "Local Mastodon FE login init action" + def login(conn, %{"code" => auth_token}) do with {:ok, app} <- get_or_make_app(), - %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id), + %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id), {:ok, token} <- Token.exchange_token(app, auth) do conn |> put_session(:oauth_token, token.token) - |> redirect(to: "/web/getting-started") + |> redirect(to: local_mastodon_root_path(conn)) end end + @doc "Local Mastodon FE callback action" def login(conn, _) do with {:ok, app} <- get_or_make_app() do path = @@ -1276,6 +1282,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"]) + defp get_or_make_app do find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."} scopes = ["read", "write", "follow", "push"] diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 0221b4c6f..e16d08196 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -239,7 +239,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do end # Special case: Local MastodonFE - defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :index, []) + defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login) defp redirect_uri(_conn, redirect_uri), do: redirect_uri end -- cgit v1.2.3 From 1d01e8e656c364b97b9ee36a6173a830d3f5f4fc Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Mon, 1 Apr 2019 22:12:02 +0545 Subject: [OStatus] adds status to pleroma instance if the url given is a status --- .../web/twitter_api/controllers/util_controller.ex | 48 ++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index faa733fec..7f301a518 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do require Logger alias Comeonin.Pbkdf2 + alias Pleroma.Activity alias Pleroma.Emoji alias Pleroma.Notification alias Pleroma.PasswordResetToken @@ -73,26 +74,39 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do - {err, followee} = OStatus.find_or_make_user(acct) - avatar = User.avatar_url(followee) - name = followee.nickname - id = followee.id - - if !!user do - conn - |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id}) - else - conn - |> render("follow_login.html", %{ - error: false, - acct: acct, - avatar: avatar, - name: name, - id: id - }) + case is_status?(acct) do + true -> + {:ok, object} = ActivityPub.fetch_object_from_id(acct) + %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) + redirect(conn, to: "/notice/#{activity_id}") + + false -> + {err, followee} = OStatus.find_or_make_user(acct) + avatar = User.avatar_url(followee) + name = followee.nickname + id = followee.id + + if !!user do + conn + |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id}) + else + conn + |> render("follow_login.html", %{ + error: false, + acct: acct, + avatar: avatar, + name: name, + id: id + }) + end end end + defp is_status?(acct) do + %URI{path: path} = URI.parse(acct) + Regex.match?(~r/\/users\/[^\/]+\/statuses\/([0-9]+)$/, path) + end + def do_remote_follow(conn, %{ "authorization" => %{"name" => username, "password" => password, "id" => id} }) do -- cgit v1.2.3 From b6f9f7b8aa659c10049b8c43326e58a4b1b18664 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Mon, 1 Apr 2019 22:40:48 +0200 Subject: Handle dates in the Unix timestamp format (Fixes #763) --- lib/pleroma/web/common_api/utils.ex | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index f596f703b..3f5348d66 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -240,8 +240,23 @@ defmodule Pleroma.Web.CommonAPI.Utils do Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y") end + def date_to_asctime(date) when is_float(date) do + date + |> trunc() + |> date_to_asctime() + end + + def date_to_asctime(date) when is_integer(date) do + with {:ok, date} <- DateTime.from_unix(date) do + format_asctime(date) + else + _e -> + "" + end + end + def date_to_asctime(date) do - with {:ok, date, _offset} <- date |> DateTime.from_iso8601() do + with {:ok, date, _offset} <- DateTime.from_iso8601(date) do format_asctime(date) else _e -> -- cgit v1.2.3 From 6386c1c9c1ff971c784744922a479ae38e5fdbad Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Tue, 2 Apr 2019 10:26:09 +0545 Subject: fetch url for OStatus to know if it is a/c or status --- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 7f301a518..2a1c73111 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -103,8 +103,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end defp is_status?(acct) do - %URI{path: path} = URI.parse(acct) - Regex.match?(~r/\/users\/[^\/]+\/statuses\/([0-9]+)$/, path) + case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do + {:ok, %{"type" => "Note"}} -> true + _ -> false + end end def do_remote_follow(conn, %{ -- cgit v1.2.3 From f20e8d28de97e154ec43120cb4fc07e2792e955a Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Tue, 2 Apr 2019 12:15:41 +0545 Subject: add support for all status type (ostatus) and replase case with if --- .../web/twitter_api/controllers/util_controller.ex | 55 +++++++++++----------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 2a1c73111..b661c4363 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -74,38 +74,39 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do - case is_status?(acct) do - true -> - {:ok, object} = ActivityPub.fetch_object_from_id(acct) - %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) - redirect(conn, to: "/notice/#{activity_id}") - - false -> - {err, followee} = OStatus.find_or_make_user(acct) - avatar = User.avatar_url(followee) - name = followee.nickname - id = followee.id - - if !!user do - conn - |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id}) - else - conn - |> render("follow_login.html", %{ - error: false, - acct: acct, - avatar: avatar, - name: name, - id: id - }) - end + if is_status?(acct) do + {:ok, object} = ActivityPub.fetch_object_from_id(acct) + %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) + redirect(conn, to: "/notice/#{activity_id}") + else + {err, followee} = OStatus.find_or_make_user(acct) + avatar = User.avatar_url(followee) + name = followee.nickname + id = followee.id + + if !!user do + conn + |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id}) + else + conn + |> render("follow_login.html", %{ + error: false, + acct: acct, + avatar: avatar, + name: name, + id: id + }) + end end end defp is_status?(acct) do case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do - {:ok, %{"type" => "Note"}} -> true - _ -> false + {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] -> + true + + _ -> + false end end -- cgit v1.2.3 From 9b2188da7cab43a162d441294db7d3155e2eeab3 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 15:44:56 +0700 Subject: refactoring of emoji tags config to use groups --- lib/pleroma/emoji.ex | 92 ++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 43 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index ad3170f9a..b60d19e89 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -13,8 +13,14 @@ defmodule Pleroma.Emoji do This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. """ use GenServer + + @type pattern :: Regex.t() | module() | String.t() + @type patterns :: pattern | [pattern] + @type group_patterns :: keyword(patterns) + @ets __MODULE__.Ets @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] + @groups Application.get_env(:pleroma, :emoji)[:groups] @doc false def start_link do @@ -73,13 +79,14 @@ defmodule Pleroma.Emoji do end defp load do + finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled) + shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) + emojis = - (load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++ + (load_finmoji(finmoji_enabled) ++ load_from_file("config/emoji.txt") ++ load_from_file("config/custom_emoji.txt") ++ - load_from_globs( - Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) - )) + load_from_globs(shortcode_globs)) |> Enum.reject(fn value -> value == nil end) true = :ets.insert(@ets, emojis) @@ -151,11 +158,12 @@ defmodule Pleroma.Emoji do "white_nights", "woollysocks" ] - defp load_finmoji(true) do - tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag] + defp load_finmoji(true) do Enum.map(@finmoji, fn finmoji -> - {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag} + file_name = "/finmoji/128px/#{finmoji}-128.png" + group = match_extra(@groups, file_name) + {finmoji, file_name, to_string(group)} end) end @@ -170,11 +178,6 @@ defmodule Pleroma.Emoji do end defp load_from_file_stream(stream) do - default_tag = - stream.path - |> Path.basename(".txt") - |> get_default_tag() - stream |> Stream.map(&String.trim/1) |> Stream.map(fn line -> @@ -183,7 +186,7 @@ defmodule Pleroma.Emoji do {name, file, tags} [name, file] -> - {name, file, default_tag} + {name, file, to_string(match_extra(@groups, file))} _ -> nil @@ -192,48 +195,51 @@ defmodule Pleroma.Emoji do |> Enum.to_list() end - @spec get_default_tag(String.t()) :: String.t() - defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do - Keyword.get( - Application.get_env(:pleroma, :emoji), - String.to_existing_atom(file_name <> "_tag") - ) - end - - defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag] - defp load_from_globs(globs) do static_path = Path.join(:code.priv_dir(:pleroma), "static") paths = Enum.map(globs, fn glob -> - static_part = - Path.dirname(glob) - |> String.replace_trailing("**", "") - Path.join(static_path, glob) |> Path.wildcard() - |> Enum.map(fn path -> - custom_folder = - path - |> Path.relative_to(Path.join(static_path, static_part)) - |> Path.dirname() - - [path, custom_folder] - end) end) |> Enum.concat() - Enum.map(paths, fn [path, custom_folder] -> - tag = - case custom_folder do - "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag) - tag -> tag - end - + Enum.map(paths, fn path -> + tag = match_extra(@groups, Path.join("/", Path.relative_to(path, static_path))) shortcode = Path.basename(path, Path.extname(path)) external_path = Path.join("/", Path.relative_to(path, static_path)) - {shortcode, external_path, tag} + {shortcode, external_path, to_string(tag)} + end) + end + + @doc """ + Finds a matching group for the given extra filename + """ + @spec match_extra(group_patterns(), String.t()) :: atom() | nil + def match_extra(group_patterns, filename) do + match_group_patterns(group_patterns, fn pattern -> + case pattern do + %Regex{} = regex -> Regex.match?(regex, filename) + string when is_binary(string) -> filename == string + end + end) + end + + defp match_group_patterns(group_patterns, matcher) do + Enum.find_value(group_patterns, fn {group, patterns} -> + patterns = + patterns + |> List.wrap() + |> Enum.map(fn pattern -> + if String.contains?(pattern, "*") do + ~r(#{String.replace(pattern, "*", ".*")}) + else + pattern + end + end) + + Enum.any?(patterns, matcher) && group end) end end -- cgit v1.2.3 From 08d64b977f74abb7cb42bf985116eba91d9a6166 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 16:13:34 +0700 Subject: little changes and typos --- lib/pleroma/emoji.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index b60d19e89..7a60f3961 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -15,8 +15,8 @@ defmodule Pleroma.Emoji do use GenServer @type pattern :: Regex.t() | module() | String.t() - @type patterns :: pattern | [pattern] - @type group_patterns :: keyword(patterns) + @type patterns :: pattern() | [pattern()] + @type group_patterns :: keyword(patterns()) @ets __MODULE__.Ets @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] @@ -80,7 +80,7 @@ defmodule Pleroma.Emoji do defp load do finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled) - shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) + shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || [] emojis = (load_finmoji(finmoji_enabled) ++ -- cgit v1.2.3 From a14742f495fac78f4dfd7ab02f4c3ae5c7c37c3b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 2 Apr 2019 16:30:11 +0700 Subject: add `user delete_activities` mix task --- lib/mix/tasks/pleroma/user.ex | 8 ++++++-- lib/pleroma/user.ex | 33 +++++++++++++++++---------------- 2 files changed, 23 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 680422c19..62c9fceda 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -23,7 +23,7 @@ defmodule Mix.Tasks.Pleroma.User do - `--password PASSWORD` - the user's password - `--moderator`/`--no-moderator` - whether the user is a moderator - `--admin`/`--no-admin` - whether the user is an admin - - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions + - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions ## Generate an invite link. @@ -33,6 +33,10 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user rm NICKNAME + ## Delete the user's activities. + + mix pleroma.user delete_activities NICKNAME + ## Deactivate or activate the user's account. mix pleroma.user toggle_activated NICKNAME @@ -309,7 +313,7 @@ defmodule Mix.Tasks.Pleroma.User do with %User{local: true} = user <- User.get_by_nickname(nickname) do User.delete_user_activities(user) - Mix.shell().info("User #{nickname} statuses deleted..") + Mix.shell().info("User #{nickname} statuses deleted.") else _ -> Mix.shell().error("No local user #{nickname}") diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 18cf374dd..a180c1a8b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1088,29 +1088,30 @@ defmodule Pleroma.User do # Remove all relationships {:ok, followers} = User.get_followers(user) - followers - |> Enum.each(fn follower -> User.unfollow(follower, user) end) + Enum.each(followers, fn follower -> User.unfollow(follower, user) end) {:ok, friends} = User.get_friends(user) - friends - |> Enum.each(fn followed -> User.unfollow(user, followed) end) + Enum.each(friends, fn followed -> User.unfollow(user, followed) end) - query = - from(a in Activity, where: a.actor == ^user.ap_id) - |> Activity.with_preloaded_object() + delete_user_activities(user) + end - Repo.all(query) - |> Enum.each(fn activity -> - case activity.data["type"] do - "Create" -> - ActivityPub.delete(Object.normalize(activity)) + def delete_user_activities(%User{ap_id: ap_id} = user) do + Activity + |> where(actor: ^ap_id) + |> Activity.with_preloaded_object() + |> Repo.all() + |> Enum.each(fn + %{data: %{"type" => "Create"}} = activity -> + activity |> Object.normalize() |> ActivityPub.delete() - # TODO: Do something with likes, follows, repeats. - _ -> - "Doing nothing" - end + # TODO: Do something with likes, follows, repeats. + _ -> + "Doing nothing" end) + + {:ok, user} end def html_filter_policy(%User{info: %{no_rich_text: true}}) do -- cgit v1.2.3 From 3db923515057b7da23e4bb58a1696cd14df7ed52 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Tue, 2 Apr 2019 11:25:51 +0200 Subject: Ignore dates in wrong formats --- lib/pleroma/web/common_api/utils.ex | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 3f5348d66..0bf4de2f6 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -15,6 +15,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do alias Pleroma.Web.Endpoint alias Pleroma.Web.MediaProxy + require Logger + # This is a hack for twidere. def get_by_id_or_ap_id(id) do activity = @@ -240,28 +242,19 @@ defmodule Pleroma.Web.CommonAPI.Utils do Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y") end - def date_to_asctime(date) when is_float(date) do - date - |> trunc() - |> date_to_asctime() - end - - def date_to_asctime(date) when is_integer(date) do - with {:ok, date} <- DateTime.from_unix(date) do + def date_to_asctime(date) when is_binary(date) do + with {:ok, date, _offset} <- DateTime.from_iso8601(date) do format_asctime(date) else _e -> + Logger.warn("Date #{date} in wrong format, must be ISO 8601") "" end end def date_to_asctime(date) do - with {:ok, date, _offset} <- DateTime.from_iso8601(date) do - format_asctime(date) - else - _e -> - "" - end + Logger.warn("Date #{date} in wrong format, must be ISO 8601") + "" end def to_masto_date(%NaiveDateTime{} = date) do -- cgit v1.2.3 From 4212527928020de5b67424f090c67fc20d0844af Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 2 Apr 2019 16:50:31 +0700 Subject: change `Repo.get(Activity, id)` => `Activity.get_by_id(id)` --- lib/pleroma/gopher/server.ex | 3 +-- lib/pleroma/web/activity_pub/utils.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 14 +++++++------- lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 ++-- 6 files changed, 13 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index 3b9629d77..6a56a6f67 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -38,7 +38,6 @@ end defmodule Pleroma.Gopher.Server.ProtocolHandler do alias Pleroma.Activity alias Pleroma.HTML - alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility @@ -111,7 +110,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do end def response("/notices/" <> id) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.is_public?(activity) do activities = ActivityPub.fetch_activities_for_context(activity.data["context"]) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2e9ffe41c..77841278a 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -354,7 +354,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do [state, actor, object] ) - activity = Repo.get(Activity, activity.id) + activity = Activity.get_by_id(activity.id) {:ok, activity} rescue e -> diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index f596f703b..4c338de12 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do def get_replied_to_activity(""), do: nil def get_replied_to_activity(id) when not is_nil(id) do - Repo.get(Activity, id) + Activity.get_by_id(id) end def get_replied_to_activity(_), do: nil diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index eee4e7678..18e4ddb88 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -319,7 +319,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(StatusView) @@ -328,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), activities <- ActivityPub.fetch_activities_for_context(activity.data["context"], %{ "blocking_user" => user, @@ -460,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do @@ -471,7 +471,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do @@ -593,7 +593,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def favourited_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^likes) users = Repo.all(q) @@ -606,7 +606,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def reblogged_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^announces) users = Repo.all(q) @@ -1454,7 +1454,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do - with %Activity{} = activity <- Repo.get(Activity, status_id), + with %Activity{} = activity <- Activity.get_by_id(status_id), true <- Visibility.visible_for_user?(activity, user) do data = StatusView.render( diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 9978c7f64..d0e58e71b 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def delete(%User{} = user, id) do - with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id), + with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id), {:ok, activity} <- CommonAPI.delete(id, user) do {:ok, activity} end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 62cce18dc..eebd4dcd3 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -270,7 +270,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(ActivityView) @@ -342,7 +342,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end def get_by_id_or_ap_id(id) do - activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id) + activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id) if activity.data["type"] == "Create" do activity -- cgit v1.2.3 From 1b3d92192194baf6b431cd9f0ce58062d1b703d5 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 2 Apr 2019 17:01:26 +0700 Subject: change `Repo.get(User, id)` => `User.get_by_id(id)` --- lib/mix/tasks/pleroma/user.ex | 7 +++-- lib/pleroma/PasswordResetToken.ex | 2 +- lib/pleroma/list.ex | 2 +- lib/pleroma/user.ex | 8 +++--- lib/pleroma/web/channels/user_socket.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 2 +- .../web/mastodon_api/mastodon_api_controller.ex | 30 +++++++++++----------- lib/pleroma/web/mastodon_api/websocket_handler.ex | 2 +- lib/pleroma/web/oauth/oauth_controller.ex | 2 +- lib/pleroma/web/oauth/token.ex | 2 +- lib/pleroma/web/streamer.ex | 3 +-- .../web/twitter_api/controllers/util_controller.ex | 8 +++--- .../web/twitter_api/twitter_api_controller.ex | 6 ++--- 13 files changed, 37 insertions(+), 39 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index f6cca0d06..2487b4ab5 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -6,7 +6,6 @@ defmodule Mix.Tasks.Pleroma.User do use Mix.Task import Ecto.Changeset alias Mix.Tasks.Pleroma.Common - alias Pleroma.Repo alias Pleroma.User @shortdoc "Manages Pleroma users" @@ -23,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.User do - `--password PASSWORD` - the user's password - `--moderator`/`--no-moderator` - whether the user is a moderator - `--admin`/`--no-admin` - whether the user is an admin - - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions + - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions ## Generate an invite link. @@ -202,7 +201,7 @@ defmodule Mix.Tasks.Pleroma.User do {:ok, friends} = User.get_friends(user) Enum.each(friends, fn friend -> - user = Repo.get(User, user.id) + user = User.get_by_id(user.id) Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}") User.unfollow(user, friend) @@ -210,7 +209,7 @@ defmodule Mix.Tasks.Pleroma.User do :timer.sleep(500) - user = Repo.get(User, user.id) + user = User.get_by_id(user.id) if Enum.empty?(user.following) do Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}") diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex index 772c239a1..7afbc8751 100644 --- a/lib/pleroma/PasswordResetToken.ex +++ b/lib/pleroma/PasswordResetToken.ex @@ -39,7 +39,7 @@ defmodule Pleroma.PasswordResetToken do def reset_password(token, data) do with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), - %User{} = user <- Repo.get(User, token.user_id), + %User{} = user <- User.get_by_id(token.user_id), {:ok, _user} <- User.reset_password(user, data), {:ok, token} <- Repo.update(used_changeset(token)) do {:ok, token} diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex index 55c4cf6df..110be8355 100644 --- a/lib/pleroma/list.ex +++ b/lib/pleroma/list.ex @@ -80,7 +80,7 @@ defmodule Pleroma.List do # Get lists to which the account belongs. def get_lists_account_belongs(%User{} = owner, account_id) do - user = Repo.get(User, account_id) + user = User.get_by_id(account_id) query = from( diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 728b00a56..eb305dd95 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1231,8 +1231,8 @@ defmodule Pleroma.User do # this is because we have synchronous follow APIs and need to simulate them # with an async handshake def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do - with %User{} = a <- Repo.get(User, a.id), - %User{} = b <- Repo.get(User, b.id) do + with %User{} = a <- User.get_by_id(a.id), + %User{} = b <- User.get_by_id(b.id) do {:ok, a, b} else _e -> @@ -1242,8 +1242,8 @@ defmodule Pleroma.User do def wait_and_refresh(timeout, %User{} = a, %User{} = b) do with :ok <- :timer.sleep(timeout), - %User{} = a <- Repo.get(User, a.id), - %User{} = b <- Repo.get(User, b.id) do + %User{} = a <- User.get_by_id(a.id), + %User{} = b <- User.get_by_id(b.id) do {:ok, a, b} else _e -> diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex index 3a700fa3b..6503979a1 100644 --- a/lib/pleroma/web/channels/user_socket.ex +++ b/lib/pleroma/web/channels/user_socket.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Web.UserSocket do def connect(%{"token" => token}, socket) do with true <- Pleroma.Config.get([:chat, :enabled]), {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600), - %User{} = user <- Pleroma.Repo.get(User, user_id) do + %User{} = user <- Pleroma.User.get_by_id(user_id) do {:ok, assign(socket, :user_name, user.nickname)} else _e -> :error diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 4c338de12..40cea3090 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -275,7 +275,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do end def confirm_current_password(user, password) do - with %User{local: true} = db_user <- Repo.get(User, user.id), + with %User{local: true} = db_user <- User.get_by_id(user.id), true <- Pbkdf2.checkpw(password, db_user.password_hash) do {:ok, db_user} else diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 18e4ddb88..da96d1674 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -285,7 +285,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do - with %User{} = user <- Repo.get(User, params["id"]) do + with %User{} = user <- User.get_by_id(params["id"]) do activities = ActivityPub.fetch_user_activities(user, reading_user, params) conn @@ -657,7 +657,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do - with %User{} = user <- Repo.get(User, id), + with %User{} = user <- User.get_by_id(id), followers <- MastodonAPI.get_followers(user, params) do followers = cond do @@ -674,7 +674,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do - with %User{} = user <- Repo.get(User, id), + with %User{} = user <- User.get_by_id(id), followers <- MastodonAPI.get_friends(user, params) do followers = cond do @@ -699,7 +699,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do - with %User{} = follower <- Repo.get(User, id), + with %User{} = follower <- User.get_by_id(id), {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do conn |> put_view(AccountView) @@ -713,7 +713,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do - with %User{} = follower <- Repo.get(User, id), + with %User{} = follower <- User.get_by_id(id), {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do conn |> put_view(AccountView) @@ -727,7 +727,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with %User{} = followed <- Repo.get(User, id), + with %User{} = followed <- User.get_by_id(id), false <- User.following?(follower, followed), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn @@ -769,7 +769,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with %User{} = followed <- Repo.get(User, id), + with %User{} = followed <- User.get_by_id(id), {:ok, follower} <- CommonAPI.unfollow(follower, followed) do conn |> put_view(AccountView) @@ -778,7 +778,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do - with %User{} = muted <- Repo.get(User, id), + with %User{} = muted <- User.get_by_id(id), {:ok, muter} <- User.mute(muter, muted) do conn |> put_view(AccountView) @@ -792,7 +792,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do - with %User{} = muted <- Repo.get(User, id), + with %User{} = muted <- User.get_by_id(id), {:ok, muter} <- User.unmute(muter, muted) do conn |> put_view(AccountView) @@ -813,7 +813,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do - with %User{} = blocked <- Repo.get(User, id), + with %User{} = blocked <- User.get_by_id(id), {:ok, blocker} <- User.block(blocker, blocked), {:ok, _activity} <- ActivityPub.block(blocker, blocked) do conn @@ -828,7 +828,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do - with %User{} = blocked <- Repo.get(User, id), + with %User{} = blocked <- User.get_by_id(id), {:ok, blocker} <- User.unblock(blocker, blocked), {:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do conn @@ -966,7 +966,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def bookmarks(%{assigns: %{user: user}} = conn, _) do - user = Repo.get(User, user.id) + user = User.get_by_id(user.id) activities = user.bookmarks @@ -1023,7 +1023,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do accounts |> Enum.each(fn account_id -> with %Pleroma.List{} = list <- Pleroma.List.get(id, user), - %User{} = followed <- Repo.get(User, account_id) do + %User{} = followed <- User.get_by_id(account_id) do Pleroma.List.follow(list, followed) end end) @@ -1035,7 +1035,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do accounts |> Enum.each(fn account_id -> with %Pleroma.List{} = list <- Pleroma.List.get(id, user), - %User{} = followed <- Repo.get(Pleroma.User, account_id) do + %User{} = followed <- Pleroma.User.get_by_id(account_id) do Pleroma.List.unfollow(list, followed) end end) @@ -1312,7 +1312,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do Logger.debug("Unimplemented, returning unmodified relationship") - with %User{} = target <- Repo.get(User, id) do + with %User{} = target <- User.get_by_id(id) do conn |> put_view(AccountView) |> render("relationship.json", %{user: user, target: target}) diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index 9b262f461..1b3721e2b 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do # Authenticated streams. defp allow_request(stream, {"access_token", access_token}) when stream in @streams do with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token), - user = %User{} <- Repo.get(User, user_id) do + user = %User{} <- User.get_by_id(user_id) do {:ok, user} else _ -> {:error, 403} diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index ebb3dd253..75506e168 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -108,7 +108,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do fixed_token = fix_padding(params["code"]), %Authorization{} = auth <- Repo.get_by(Authorization, token: fixed_token, app_id: app.id), - %User{} = user <- Repo.get(User, auth.user_id), + %User{} = user <- User.get_by_id(auth.user_id), {:ok, token} <- Token.exchange_token(app, auth), {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do response = %{ diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index a8b06db36..2b5ad9b94 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do def exchange_token(app, auth) do with {:ok, auth} <- Authorization.use_token(auth), true <- auth.app_id == app.id do - create_token(app, Repo.get(User, auth.user_id), auth.scopes) + create_token(app, User.get_by_id(auth.user_id), auth.scopes) end end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 592749b42..a82109f92 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.Streamer do alias Pleroma.Activity alias Pleroma.Notification alias Pleroma.Object - alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility @@ -82,7 +81,7 @@ defmodule Pleroma.Web.Streamer do _ -> Pleroma.List.get_lists_from_activity(item) |> Enum.filter(fn list -> - owner = Repo.get(User, list.user_id) + owner = User.get_by_id(list.user_id) Visibility.visible_for_user?(item, owner) end) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index faa733fec..e817f0d79 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def show_password_reset(conn, %{"token" => token}) do with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), - %User{} = user <- Repo.get(User, token.user_id) do + %User{} = user <- User.get_by_id(token.user_id) do render(conn, "password_reset.html", %{ token: token, user: user @@ -96,13 +96,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def do_remote_follow(conn, %{ "authorization" => %{"name" => username, "password" => password, "id" => id} }) do - followee = Repo.get(User, id) + followee = User.get_by_id(id) avatar = User.avatar_url(followee) name = followee.nickname with %User{} = user <- User.get_cached_by_nickname(username), true <- Pbkdf2.checkpw(password, user.password_hash), - %User{} = _followed <- Repo.get(User, id), + %User{} = _followed <- User.get_by_id(id), {:ok, follower} <- User.follow(user, followee), {:ok, _activity} <- ActivityPub.follow(follower, followee) do conn @@ -124,7 +124,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do - with %User{} = followee <- Repo.get(User, id), + with %User{} = followee <- User.get_by_id(id), {:ok, follower} <- User.follow(user, followee), {:ok, _activity} <- ActivityPub.follow(follower, followee) do conn diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index eebd4dcd3..a7ec9949c 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -434,7 +434,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end def confirm_email(conn, %{"user_id" => uid, "token" => token}) do - with %User{} = user <- Repo.get(User, uid), + with %User{} = user <- User.get_by_id(uid), true <- user.local, true <- user.info.confirmation_pending, true <- user.info.confirmation_token == token, @@ -587,7 +587,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do def approve_friend_request(conn, %{"user_id" => uid} = _params) do with followed <- conn.assigns[:user], - %User{} = follower <- Repo.get(User, uid), + %User{} = follower <- User.get_by_id(uid), {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do conn |> put_view(UserView) @@ -599,7 +599,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do def deny_friend_request(conn, %{"user_id" => uid} = _params) do with followed <- conn.assigns[:user], - %User{} = follower <- Repo.get(User, uid), + %User{} = follower <- User.get_by_id(uid), {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do conn |> put_view(UserView) -- cgit v1.2.3 From 88d3cb44c3adc234ee828a8b50bc0c3857eb85a9 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 2 Apr 2019 17:47:02 +0700 Subject: replace `Repo.get_by(User, nickname: nickname)` with `User.get_by_nickname(nickname)` --- lib/pleroma/plugs/user_fetcher_plug.ex | 22 ++-------------------- .../web/mastodon_api/mastodon_api_controller.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api.ex | 9 +++------ 3 files changed, 6 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_fetcher_plug.ex b/lib/pleroma/plugs/user_fetcher_plug.ex index 5a77f6833..4089aa958 100644 --- a/lib/pleroma/plugs/user_fetcher_plug.ex +++ b/lib/pleroma/plugs/user_fetcher_plug.ex @@ -3,9 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.UserFetcherPlug do - alias Pleroma.Repo alias Pleroma.User - import Plug.Conn def init(options) do @@ -14,26 +12,10 @@ defmodule Pleroma.Plugs.UserFetcherPlug do def call(conn, _options) do with %{auth_credentials: %{username: username}} <- conn.assigns, - {:ok, %User{} = user} <- user_fetcher(username) do - conn - |> assign(:auth_user, user) + %User{} = user <- User.get_by_nickname_or_email(username) do + assign(conn, :auth_user, user) else _ -> conn end end - - defp user_fetcher(username_or_email) do - { - :ok, - cond do - # First, try logging in as if it was a name - user = Repo.get_by(User, %{nickname: username_or_email}) -> - user - - # If we get nil, we try using it as an email - user = Repo.get_by(User, %{email: username_or_email}) -> - user - end - } - end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index da96d1674..ffd544644 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -755,7 +755,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do - with %User{} = followed <- Repo.get_by(User, nickname: uri), + with %User{} = followed <- User.get_by_nickname(uri), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn |> put_view(AccountView) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index d0e58e71b..9b081a316 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -227,12 +227,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end %{"screen_name" => nickname} -> - case target = Repo.get_by(User, nickname: nickname) do - nil -> - {:error, "No user with such screen_name"} - - _ -> - {:ok, target} + case User.get_by_nickname(nickname) do + nil -> {:error, "No user with such screen_name"} + target -> {:ok, target} end _ -> -- cgit v1.2.3 From 95c92c49c928340a479717aa171dcb83585f3275 Mon Sep 17 00:00:00 2001 From: cascode Date: Tue, 2 Apr 2019 10:51:33 +0000 Subject: Fix account lookup for nicknames beginning with numbers --- lib/pleroma/flake_id.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex index 4259d5718..58ab3650d 100644 --- a/lib/pleroma/flake_id.ex +++ b/lib/pleroma/flake_id.ex @@ -46,7 +46,7 @@ defmodule Pleroma.FlakeId do def from_string(string) when is_binary(string) and byte_size(string) < 18 do case Integer.parse(string) do - {id, _} -> <<0::integer-size(64), id::integer-size(64)>> + {id, ""} -> <<0::integer-size(64), id::integer-size(64)>> _ -> nil end end -- cgit v1.2.3 From fdb4357e9ba7a34a603997d50d85593ca2bf6395 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 2 Apr 2019 14:31:18 +0300 Subject: Rename fake param to preview and make the tests check that the object was not inserted to the db --- lib/pleroma/web/common_api/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 8e2937ac5..2f82a32f3 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -180,7 +180,7 @@ defmodule Pleroma.Web.CommonAPI do object: object, additional: %{"cc" => cc, "directMessage" => visibility == "direct"} }, - data["fake"] || false + data["preview"] || false ) res -- cgit v1.2.3 From d140738edf75467420b35c500716cf89de66548d Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Apr 2019 20:35:41 +0700 Subject: second level of headertext change in doc --- lib/pleroma/emoji.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 7a60f3961..87c7f2cec 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -214,7 +214,7 @@ defmodule Pleroma.Emoji do end @doc """ - Finds a matching group for the given extra filename + Finds a matching group for the given emoji filename """ @spec match_extra(group_patterns(), String.t()) :: atom() | nil def match_extra(group_patterns, filename) do -- cgit v1.2.3 From fd07745d1b18e2a1eeb88a99eaa9d5e728d1aa71 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 2 Apr 2019 16:04:18 +0200 Subject: ActivityPub Utils: Greatly speed up the follow / block activity fetching. --- lib/pleroma/web/activity_pub/utils.ex | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2e9ffe41c..a4b1518de 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -404,13 +404,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do activity.data ), where: activity.actor == ^follower_id, + # this is to use the index where: fragment( - "? @> ?", + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", + activity.data, activity.data, - ^%{object: followed_id} + ^followed_id ), - order_by: [desc: :id], + order_by: [fragment("? desc nulls last", activity.id)], limit: 1 ) @@ -567,13 +569,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do activity.data ), where: activity.actor == ^blocker_id, + # this is to use the index where: fragment( - "? @> ?", + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", + activity.data, activity.data, - ^%{object: blocked_id} + ^blocked_id ), - order_by: [desc: :id], + order_by: [fragment("? desc nulls last", activity.id)], limit: 1 ) -- cgit v1.2.3 From 79cb34a4b0dd1c0ffe45e796f5ac6790e3b31025 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 2 Apr 2019 23:07:16 +0300 Subject: Fix preview not being usable in form data --- lib/pleroma/web/common_api/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2f82a32f3..745d1839b 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -180,7 +180,7 @@ defmodule Pleroma.Web.CommonAPI do object: object, additional: %{"cc" => cc, "directMessage" => visibility == "direct"} }, - data["preview"] || false + Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false ) res -- cgit v1.2.3 From cd41584ac4a90a666f33786d967d37a619c67762 Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Wed, 3 Apr 2019 00:54:16 +0545 Subject: Generate permissive or restrictive robots.txt in the config generator --- lib/mix/tasks/pleroma/instance.ex | 34 ++++++++++++++++++++++++++++++++++ lib/mix/tasks/pleroma/robots_txt.eex | 2 ++ 2 files changed, 36 insertions(+) create mode 100644 lib/mix/tasks/pleroma/robots_txt.eex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 1ba452275..8f8d86a11 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -81,6 +81,14 @@ defmodule Mix.Tasks.Pleroma.Instance do email = Common.get_option(options, :admin_email, "What is your admin email address?") + indexable = + Common.get_option( + options, + :indexable, + "Do you want search engines to index your site? (y/n)", + "y" + ) === "y" + dbhost = Common.get_option(options, :dbhost, "What is the hostname of your database?", "localhost") @@ -142,6 +150,8 @@ defmodule Mix.Tasks.Pleroma.Instance do Mix.shell().info("Writing #{psql_path}.") File.write(psql_path, result_psql) + write_robots_txt(indexable) + Mix.shell().info( "\n" <> """ @@ -163,4 +173,28 @@ defmodule Mix.Tasks.Pleroma.Instance do ) end end + + defp write_robots_txt(indexable) do + robots_txt = + EEx.eval_file( + Path.expand("robots_txt.eex", __DIR__), + indexable: indexable + ) + + static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") + + unless File.exists?(static_dir) do + File.mkdir_p!(static_dir) + end + + robots_txt_path = Path.join(static_dir, "robots.txt") + + if File.exists?(robots_txt_path) do + File.cp!(robots_txt_path, "#{robots_txt_path}.bak") + Mix.shell().info("Backing up existing robots.txt to #{robots_txt_path}.bak") + end + + File.write(robots_txt_path, robots_txt) + Mix.shell().info("Writing #{robots_txt_path}.") + end end diff --git a/lib/mix/tasks/pleroma/robots_txt.eex b/lib/mix/tasks/pleroma/robots_txt.eex new file mode 100644 index 000000000..1af3c47ee --- /dev/null +++ b/lib/mix/tasks/pleroma/robots_txt.eex @@ -0,0 +1,2 @@ +User-Agent: * +Disallow: <%= if indexable, do: "", else: "/" %> -- cgit v1.2.3 From af0065a71feb470bd69bec36999bc40a662e3e83 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Thu, 4 Apr 2019 09:07:25 +0200 Subject: mastodon_api_controller.ex: Add pleroma-tan to initial_state --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0de2cca4e..89fd7629a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1121,7 +1121,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do auto_play_gif: false, display_sensitive_media: false, reduce_motion: false, - max_toot_chars: limit + max_toot_chars: limit, + mascot: "/images/pleroma-fox-tan-smol.png" }, rights: %{ delete_others_notice: present?(user.info.is_moderator), -- cgit v1.2.3 From cfa6e7289f5cfdb1fce17eb89bc0513ff624480d Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 4 Apr 2019 16:10:43 +0700 Subject: Improve Transmogrifier.upgrade_user_from_ap_id/2 --- lib/pleroma/web/activity_pub/transmogrifier.ex | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index f733ae7e1..593ae3188 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -954,7 +954,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do defp strip_internal_tags(object), do: object - defp user_upgrade_task(user) do + def perform(:user_upgrade, user) do # we pass a fake user so that the followers collection is stripped away old_follower_address = User.ap_followers(%User{nickname: user.nickname}) @@ -999,28 +999,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do Repo.update_all(q, []) end - def upgrade_user_from_ap_id(ap_id, async \\ true) do + def upgrade_user_from_ap_id(ap_id) do with %User{local: false} = user <- User.get_by_ap_id(ap_id), - {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do - already_ap = User.ap_enabled?(user) - - {:ok, user} = - User.upgrade_changeset(user, data) - |> Repo.update() - - if !already_ap do - # This could potentially take a long time, do it in the background - if async do - Task.start(fn -> - user_upgrade_task(user) - end) - else - user_upgrade_task(user) - end + {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id), + already_ap <- User.ap_enabled?(user), + {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do + unless already_ap do + PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user]) end {:ok, user} else + %User{} = user -> {:ok, user} e -> e end end -- cgit v1.2.3 From bc3618a38d2e37254e27f723d3dd61679eca9be5 Mon Sep 17 00:00:00 2001 From: href Date: Wed, 30 Jan 2019 16:32:30 +0100 Subject: Set up telemetry and prometheus --- lib/pleroma/application.ex | 8 ++++++++ lib/pleroma/repo.ex | 4 ++++ lib/pleroma/web/endpoint.ex | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 782d1d589..03dcbab1a 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -25,6 +25,7 @@ defmodule Pleroma.Application do import Cachex.Spec Pleroma.Config.DeprecationWarnings.warn() + setup_instrumenters() # Define workers and child supervisors to be supervised children = @@ -140,6 +141,13 @@ defmodule Pleroma.Application do end end + defp setup_instrumenters() do + Pleroma.Web.Endpoint.MetricsExporter.setup() + Pleroma.Web.Endpoint.PipelineInstrumenter.setup() + Pleroma.Web.Endpoint.Instrumenter.setup() + Pleroma.Repo.Instrumenter.setup() + end + if Mix.env() == :test do defp streamer_child, do: [] defp chat_child, do: [] diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex index 4af1bde56..aa5d427ae 100644 --- a/lib/pleroma/repo.ex +++ b/lib/pleroma/repo.ex @@ -8,6 +8,10 @@ defmodule Pleroma.Repo do adapter: Ecto.Adapters.Postgres, migration_timestamps: [type: :naive_datetime_usec] + defmodule Instrumenter do + use Prometheus.EctoInstrumenter + end + @doc """ Dynamically loads the repository url from the DATABASE_URL environment variable. diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index fa2d1cbe7..6d9528c86 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -70,6 +70,26 @@ defmodule Pleroma.Web.Endpoint do extra: "SameSite=Strict" ) + # Note: the plug and its configuration is compile-time this can't be upstreamed yet + if proxies = Pleroma.Config.get([__MODULE__, :reverse_proxies]) do + plug(RemoteIp, proxies: proxies) + end + + defmodule Instrumenter do + use Prometheus.PhoenixInstrumenter + end + + defmodule PipelineInstrumenter do + use Prometheus.PlugPipelineInstrumenter + end + + defmodule MetricsExporter do + use Prometheus.PlugExporter + end + + plug(PipelineInstrumenter) + plug(MetricsExporter) + plug(Pleroma.Web.Router) @doc """ -- cgit v1.2.3 From 0b5c818cb78b8c23fb2ba7ef372d0688ea9f36b7 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 25 Mar 2019 15:29:04 +0700 Subject: [#1] fix telemetry --- lib/pleroma/application.ex | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 03dcbab1a..c3f3126c6 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -127,6 +127,24 @@ defmodule Pleroma.Application do Supervisor.start_link(children, opts) end + defp setup_instrumenters() do + require Prometheus.Registry + + :ok = + :telemetry.attach( + "prometheus-ecto", + [:pleroma, :repo, :query], + &Pleroma.Repo.Instrumenter.handle_event/4, + %{} + ) + + Prometheus.Registry.register_collector(:prometheus_process_collector) + Pleroma.Web.Endpoint.MetricsExporter.setup() + Pleroma.Web.Endpoint.PipelineInstrumenter.setup() + Pleroma.Web.Endpoint.Instrumenter.setup() + Pleroma.Repo.Instrumenter.setup() + end + def enabled_hackney_pools do [:media] ++ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do @@ -141,13 +159,6 @@ defmodule Pleroma.Application do end end - defp setup_instrumenters() do - Pleroma.Web.Endpoint.MetricsExporter.setup() - Pleroma.Web.Endpoint.PipelineInstrumenter.setup() - Pleroma.Web.Endpoint.Instrumenter.setup() - Pleroma.Repo.Instrumenter.setup() - end - if Mix.env() == :test do defp streamer_child, do: [] defp chat_child, do: [] -- cgit v1.2.3 From 69038887b2930072356aa00841b889c59518e264 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 4 Apr 2019 12:36:57 -0500 Subject: Code readability tweak --- lib/pleroma/application.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index c3f3126c6..1fc3fb728 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -127,7 +127,7 @@ defmodule Pleroma.Application do Supervisor.start_link(children, opts) end - defp setup_instrumenters() do + defp setup_instrumenters do require Prometheus.Registry :ok = -- cgit v1.2.3 From f7cd9131d4aa0da3c4c0174acc56ce1bbdbd284c Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Thu, 4 Apr 2019 22:41:03 +0300 Subject: [#923] OAuth consumer controller tests. Misc. improvements. --- lib/pleroma/web/oauth/oauth_controller.ex | 4 ++++ lib/pleroma/web/templates/o_auth/o_auth/register.html.eex | 1 + lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 1b467e983..2dcaaabc1 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -253,6 +253,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do auth_params = %{ "client_id" => params["client_id"], "redirect_uri" => params["redirect_uri"], + "state" => params["state"], "scopes" => oauth_scopes(params, nil) } @@ -289,6 +290,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do render(conn, "register.html", %{ client_id: params["client_id"], redirect_uri: params["redirect_uri"], + state: params["state"], scopes: oauth_scopes(params, []), nickname: params["nickname"], email: params["email"] @@ -313,6 +315,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do ) else _ -> + params = Map.delete(params, "password") + conn |> put_flash(:error, "Unknown error, please try again.") |> redirect(to: o_auth_path(conn, :registration_details, params)) diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex index f4547170c..2e806e5fb 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex @@ -44,5 +44,6 @@ please provide the details below.

<%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> <%= hidden_input f, :scope, value: Enum.join(@scopes, " ") %> +<%= hidden_input f, :state, value: @state %> <% end %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index e6cf1db45..0144675ab 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -22,7 +22,7 @@ <%= hidden_input f, :client_id, value: @client_id %> <%= hidden_input f, :response_type, value: @response_type %> <%= hidden_input f, :redirect_uri, value: @redirect_uri %> -<%= hidden_input f, :state, value: @state%> +<%= hidden_input f, :state, value: @state %> <%= submit "Authorize" %> <% end %> -- cgit v1.2.3 From 3e7f2bfc2f4769af3cedea3126fa0b3cab3f2b7b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 5 Apr 2019 09:19:17 +0300 Subject: [#923] OAuthController#callback adjustments (with tests). --- lib/pleroma/web/oauth/oauth_controller.ex | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 2dcaaabc1..404728899 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -249,13 +249,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do with {:ok, registration} <- Authenticator.get_registration(conn, params) do user = Repo.preload(registration, :user).user - - auth_params = %{ - "client_id" => params["client_id"], - "redirect_uri" => params["redirect_uri"], - "state" => params["state"], - "scopes" => oauth_scopes(params, nil) - } + auth_params = Map.take(params, ~w(client_id redirect_uri scope scopes state)) if user do create_authorization( -- cgit v1.2.3 From 47a236f7537ad4366d07361d184c84f3912648f1 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 5 Apr 2019 15:12:02 +0300 Subject: [#923] OAuth consumer mode refactoring, new tests, tests adjustments, readme. --- lib/pleroma/config.ex | 4 + lib/pleroma/web/endpoint.ex | 2 +- lib/pleroma/web/oauth/fallback_controller.ex | 17 ++- lib/pleroma/web/oauth/oauth_controller.ex | 130 +++++++++++---------- .../web/templates/o_auth/o_auth/consumer.html.eex | 2 +- .../web/templates/o_auth/o_auth/show.html.eex | 2 +- 6 files changed, 88 insertions(+), 69 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index 21507cd38..189faa15f 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -57,4 +57,8 @@ defmodule Pleroma.Config do def delete(key) do Application.delete_env(:pleroma, key) end + + def oauth_consumer_strategies, do: get([:auth, :oauth_consumer_strategies], []) + + def oauth_consumer_enabled?, do: oauth_consumer_strategies() != [] end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index b85b95bf9..085f23159 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -59,7 +59,7 @@ defmodule Pleroma.Web.Endpoint do else: "pleroma_key" same_site = - if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do + if Pleroma.Config.oauth_consumer_enabled?() do # Note: "SameSite=Strict" prevents sign in with external OAuth provider # (there would be no cookies during callback request from OAuth provider) "SameSite=Lax" diff --git a/lib/pleroma/web/oauth/fallback_controller.ex b/lib/pleroma/web/oauth/fallback_controller.ex index f0fe3b578..afaa00242 100644 --- a/lib/pleroma/web/oauth/fallback_controller.ex +++ b/lib/pleroma/web/oauth/fallback_controller.ex @@ -6,8 +6,21 @@ defmodule Pleroma.Web.OAuth.FallbackController do use Pleroma.Web, :controller alias Pleroma.Web.OAuth.OAuthController - # No user/password - def call(conn, _) do + def call(conn, {:register, :generic_error}) do + conn + |> put_status(:internal_server_error) + |> put_flash(:error, "Unknown error, please check the details and try again.") + |> OAuthController.registration_details(conn.params) + end + + def call(conn, {:register, _error}) do + conn + |> put_status(:unauthorized) + |> put_flash(:error, "Invalid Username/Password") + |> OAuthController.registration_details(conn.params) + end + + def call(conn, _error) do conn |> put_status(:unauthorized) |> put_flash(:error, "Invalid Username/Password") diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 404728899..108303eb2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] - if Pleroma.Config.get([:auth, :oauth_consumer_enabled]), do: plug(Ueberauth) + if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) plug(:fetch_session) plug(:fetch_flash) @@ -62,60 +62,65 @@ defmodule Pleroma.Web.OAuth.OAuthController do def create_authorization( conn, - %{ - "authorization" => %{"redirect_uri" => redirect_uri} = auth_params - } = params, + %{"authorization" => auth_params} = params, opts \\ [] ) do - with {:ok, auth} <- - (opts[:auth] && {:ok, opts[:auth]}) || - do_create_authorization(conn, params, opts[:user]) do - redirect_uri = redirect_uri(conn, redirect_uri) - - cond do - redirect_uri == "urn:ietf:wg:oauth:2.0:oob" -> - render(conn, "results.html", %{ - auth: auth - }) - - true -> - connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" - url = "#{redirect_uri}#{connector}" - url_params = %{:code => auth.token} - - url_params = - if auth_params["state"] do - Map.put(url_params, :state, auth_params["state"]) - else - url_params - end + with {:ok, auth} <- do_create_authorization(conn, params, opts[:user]) do + after_create_authorization(conn, auth, auth_params) + else + error -> + handle_create_authorization_error(conn, error, auth_params) + end + end - url = "#{url}#{Plug.Conn.Query.encode(url_params)}" + def after_create_authorization(conn, auth, %{"redirect_uri" => redirect_uri} = auth_params) do + redirect_uri = redirect_uri(conn, redirect_uri) - redirect(conn, external: url) - end + if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do + render(conn, "results.html", %{ + auth: auth + }) 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, "This action is outside the authorized scopes") - |> put_status(:unauthorized) - |> authorize(auth_params) + connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" + url = "#{redirect_uri}#{connector}" + url_params = %{:code => auth.token} - {:auth_active, false} -> - # 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) - |> authorize(auth_params) + url_params = + if auth_params["state"] do + Map.put(url_params, :state, auth_params["state"]) + else + url_params + end - error -> - Authenticator.handle_error(conn, error) + url = "#{url}#{Plug.Conn.Query.encode(url_params)}" + + redirect(conn, external: url) end end + defp handle_create_authorization_error(conn, {scopes_issue, _}, auth_params) + when scopes_issue in [:unsupported_scopes, :missing_scopes] do + # 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) + end + + defp handle_create_authorization_error(conn, {:auth_active, false}, auth_params) do + # 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) + |> authorize(auth_params) + end + + defp handle_create_authorization_error(conn, error, _auth_params) do + Authenticator.handle_error(conn, error) + end + def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do with %App{} = app <- get_app_from_request(conn, params), fixed_token = fix_padding(params["code"]), @@ -202,6 +207,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + @doc "Prepares OAuth request to provider for Ueberauth" def prepare_request(conn, %{"provider" => provider} = params) do scope = oauth_scopes(params, []) @@ -218,6 +224,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do |> Map.drop(~w(scope scopes client_id redirect_uri)) |> Map.put("state", state) + # Handing the request to Ueberauth redirect(conn, to: o_auth_path(conn, :request, provider, params)) end @@ -266,7 +273,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do conn |> put_session(:registration_id, registration.id) - |> redirect(to: o_auth_path(conn, :registration_details, registration_params)) + |> registration_details(registration_params) end else _ -> @@ -292,32 +299,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do end def register(conn, %{"op" => "connect"} = params) do - create_authorization_params = %{ - "authorization" => Map.merge(params, %{"name" => params["auth_name"]}) - } + authorization_params = Map.put(params, "name", params["auth_name"]) + create_authorization_params = %{"authorization" => authorization_params} with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), %Registration{} = registration <- Repo.get(Registration, registration_id), - {:ok, auth} <- do_create_authorization(conn, create_authorization_params), + {_, {:ok, auth}} <- + {:create_authorization, do_create_authorization(conn, create_authorization_params)}, %User{} = user <- Repo.preload(auth, :user).user, {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do conn |> put_session_registration_id(nil) - |> create_authorization( - create_authorization_params, - auth: auth - ) + |> after_create_authorization(auth, authorization_params) else - _ -> - params = Map.delete(params, "password") + {:create_authorization, error} -> + {:register, handle_create_authorization_error(conn, error, create_authorization_params)} - conn - |> put_flash(:error, "Unknown error, please try again.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + _ -> + {:register, :generic_error} end end - def register(conn, params) do + def register(conn, %{"op" => "register"} = params) do with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), %Registration{} = registration <- Repo.get(Registration, registration_id), {:ok, user} <- Authenticator.create_from_registration(conn, params, registration) do @@ -349,13 +352,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do ) conn + |> put_status(:forbidden) |> put_flash(:error, "Error: #{message}.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + |> registration_details(params) _ -> - conn - |> put_flash(:error, "Unknown error, please try again.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + {:register, :generic_error} end end diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 002f014e6..9365c7c44 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -9,7 +9,7 @@ <%= hidden_input f, :redirect_uri, value: @redirect_uri %> <%= hidden_input f, :state, value: @state %> - <%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %> + <%= for strategy <- Pleroma.Config.oauth_consumer_strategies() do %> <%= submit "Sign in with #{String.capitalize(strategy)}", name: "provider", value: strategy %> <% end %> <% end %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 0144675ab..87278e636 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -26,6 +26,6 @@ <%= submit "Authorize" %> <% end %> -<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %> +<%= if Pleroma.Config.oauth_consumer_enabled?() do %> <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %> <% end %> -- cgit v1.2.3 From f0f30019e1c9992cb420ba54457840cddaeb6a3a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 5 Apr 2019 15:19:44 +0300 Subject: Refactor html caching functions to have a key instead of a module, use more correct terminology and fix summaries in mastoapi --- lib/pleroma/html.ex | 15 +++++++-------- lib/pleroma/web/mastodon_api/views/status_view.ex | 14 +++++++++++--- lib/pleroma/web/metadata/utils.ex | 2 +- lib/pleroma/web/twitter_api/views/activity_view.ex | 6 +++--- 4 files changed, 22 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 1e48749a8..7f1dbe28c 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -28,21 +28,20 @@ defmodule Pleroma.HTML do def filter_tags(html), do: filter_tags(html, nil) def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags) - # TODO: rename object to activity because that's what it is really working with - def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do - key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}" + def get_cached_scrubbed_html_for_activity(content, scrubbers, activity, key \\ "") do + key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" Cachex.fetch!(:scrubber_cache, key, fn _key -> - ensure_scrubbed_html(content, scrubbers, object.data["object"]["fake"] || false) + ensure_scrubbed_html(content, scrubbers, activity.data["object"]["fake"] || false) end) end - def get_cached_stripped_html_for_object(content, object, module) do - get_cached_scrubbed_html_for_object( + def get_cached_stripped_html_for_activity(content, activity, key) do + get_cached_scrubbed_html_for_activity( content, HtmlSanitizeEx.Scrubber.StripTags, - object, - module + activity, + key ) end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 200bb453d..4c0b53bdd 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -147,10 +147,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do content = object |> render_content() - |> HTML.get_cached_scrubbed_html_for_object( + |> HTML.get_cached_scrubbed_html_for_activity( User.html_filter_policy(opts[:for]), activity, - __MODULE__ + "mastoapi:content" + ) + + summary = + (object["summary"] || "") + |> HTML.get_cached_scrubbed_html_for_activity( + User.html_filter_policy(opts[:for]), + activity, + "mastoapi:summary" ) card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)) @@ -182,7 +190,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user), pinned: pinned?(activity, user), sensitive: sensitive, - spoiler_text: object["summary"] || "", + spoiler_text: summary, visibility: get_visibility(object), media_attachments: attachments, mentions: mentions, diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 23bbde1a6..58385a3d1 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.Metadata.Utils do # html content comes from DB already encoded, decode first and scrub after |> HtmlEntities.decode() |> String.replace(~r//, " ") - |> HTML.get_cached_stripped_html_for_object(object, __MODULE__) + |> HTML.get_cached_stripped_html_for_activity(object, "metadata") |> Formatter.demojify() |> Formatter.truncate() end diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index aa1d41fa2..433322eb8 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -254,10 +254,10 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do html = content - |> HTML.get_cached_scrubbed_html_for_object( + |> HTML.get_cached_scrubbed_html_for_activity( User.html_filter_policy(opts[:for]), activity, - __MODULE__ + "twitterapi:content" ) |> Formatter.emojify(object["emoji"]) @@ -265,7 +265,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do if content do content |> String.replace(~r//, "\n") - |> HTML.get_cached_stripped_html_for_object(activity, __MODULE__) + |> HTML.get_cached_stripped_html_for_activity(activity, "twitterapi:content") else "" end -- cgit v1.2.3 From f1712cd2f1ec6061f70d259f8f5e2b7e9f408d8c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 5 Apr 2019 19:38:44 +0700 Subject: Use PleromaJobQueue in Pleroma.Web.Push --- lib/pleroma/application.ex | 4 ++-- lib/pleroma/web/push/impl.ex | 6 +++--- lib/pleroma/web/push/push.ex | 48 +++++++++----------------------------------- 3 files changed, 15 insertions(+), 43 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 782d1d589..8f8d26814 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -109,8 +109,8 @@ defmodule Pleroma.Application do [ worker(Pleroma.Web.Federator.RetryQueue, []), worker(Pleroma.Stats, []), - worker(Pleroma.Web.Push, []), - worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary) + worker(Task, [&Pleroma.Web.Push.init/0], restart: :temporary, id: :web_push_init), + worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary, id: :federator_init) ] ++ streamer_child() ++ chat_child() ++ diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 863573185..2233480c5 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -19,8 +19,8 @@ defmodule Pleroma.Web.Push.Impl do @types ["Create", "Follow", "Announce", "Like"] @doc "Performs sending notifications for user subscriptions" - @spec perform_send(Notification.t()) :: list(any) - def perform_send( + @spec perform(Notification.t()) :: list(any) | :error + def perform( %{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} = notif ) @@ -50,7 +50,7 @@ defmodule Pleroma.Web.Push.Impl do end end - def perform_send(_) do + def perform(_) do Logger.warn("Unknown notification type") :error end diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex index 5259e8e33..cdd50005d 100644 --- a/lib/pleroma/web/push/push.ex +++ b/lib/pleroma/web/push/push.ex @@ -3,18 +3,20 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Push do - use GenServer - alias Pleroma.Web.Push.Impl require Logger - ############## - # Client API # - ############## + def init() do + unless enabled() do + Logger.warn(""" + VAPID key pair is not found. If you wish to enabled web push, please run + + mix web_push.gen.keypair - def start_link do - GenServer.start_link(__MODULE__, :ok, name: __MODULE__) + and add the resulting output to your configuration file. + """) + end end def vapid_config do @@ -30,35 +32,5 @@ defmodule Pleroma.Web.Push do end def send(notification), - do: GenServer.cast(__MODULE__, {:send, notification}) - - #################### - # Server Callbacks # - #################### - - @impl true - def init(:ok) do - if enabled() do - {:ok, nil} - else - Logger.warn(""" - VAPID key pair is not found. If you wish to enabled web push, please run - - mix web_push.gen.keypair - - and add the resulting output to your configuration file. - """) - - :ignore - end - end - - @impl true - def handle_cast({:send, notification}, state) do - if enabled() do - Impl.perform_send(notification) - end - - {:noreply, state} - end + do: PleromaJobQueue.enqueue(:web_push, Impl, [notification]) end -- cgit v1.2.3 From 1c2e4f88d1a707791818014f8bcdedd986c2fa75 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 5 Apr 2019 19:46:28 +0700 Subject: fix credo --- lib/pleroma/web/push/push.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex index cdd50005d..729dad02a 100644 --- a/lib/pleroma/web/push/push.ex +++ b/lib/pleroma/web/push/push.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.Push do require Logger - def init() do + def init do unless enabled() do Logger.warn(""" VAPID key pair is not found. If you wish to enabled web push, please run -- cgit v1.2.3 From 7895ee37fae82de26b3c06e69a96788d8c88d139 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 16 Dec 2018 16:41:56 +0100 Subject: Add user following / unfollowing to the admin api. --- lib/pleroma/web/admin_api/admin_api_controller.ex | 20 ++++++++++++++++++++ lib/pleroma/web/router.ex | 4 ++++ 2 files changed, 24 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index b3a09e49e..84d0aabaf 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -25,6 +25,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> json(nickname) end + def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do + with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}), + %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do + User.follow(follower, followed) + end + + conn + |> json("ok") + end + + def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do + with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}), + %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do + User.unfollow(follower, followed) + end + + conn + |> json("ok") + end + def user_create( conn, %{"nickname" => nickname, "email" => email, "password" => password} diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 605a327fc..1c752e44c 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,8 +140,12 @@ defmodule Pleroma.Web.Router do scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through([:admin_api, :oauth_write]) + post("/user/follow", AdminAPIController, :user_follow) + post("/user/unfollow", AdminAPIController, :user_unfollow) + 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) -- cgit v1.2.3 From b5a2d384f71de9f7ff33d99c95c5db4674141d9a Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 5 Apr 2019 11:41:41 -0500 Subject: Redundant Repo.get_by usage was recently removed from the codebase --- lib/pleroma/web/admin_api/admin_api_controller.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 84d0aabaf..78bf31893 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -26,8 +26,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do - with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}), - %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do + with %User{} = follower <- User.get_by_nickname(follower_nick), + %User{} = followed <- User.get_by_nickname(followed_nick) do User.follow(follower, followed) end @@ -36,8 +36,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do - with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}), - %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do + with %User{} = follower <- User.get_by_nickname(follower_nick), + %User{} = followed <- User.get_by_nickname(followed_nick) do User.unfollow(follower, followed) end -- cgit v1.2.3 From 325a2680173f714a5875ed726f9171e7984f7f7a Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Fri, 5 Apr 2019 23:36:42 +0000 Subject: Redirect to the referer url after mastofe authorization --- .../web/mastodon_api/mastodon_api_controller.ex | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 89fd7629a..bcc79b08a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1091,9 +1091,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def index(%{assigns: %{user: user}} = conn, _params) do - token = - conn - |> get_session(:oauth_token) + token = get_session(conn, :oauth_token) if user && token do mastodon_emoji = mastodonized_emoji() @@ -1194,6 +1192,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> render("index.html", %{initial_state: initial_state, flavour: flavour}) else conn + |> put_session(:return_to, conn.request_path) |> redirect(to: "/web/login") end end @@ -1278,12 +1277,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do scope: Enum.join(app.scopes, " ") ) - conn - |> redirect(to: path) + redirect(conn, to: path) end end - defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"]) + defp local_mastodon_root_path(conn) do + case get_session(conn, :return_to) do + nil -> + mastodon_api_path(conn, :index, ["getting-started"]) + + return_to -> + delete_session(conn, :return_to) + return_to + end + end defp get_or_make_app do find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."} -- cgit v1.2.3 From 7aa53d52bd982b5ab233a65048f5fb1823127d4a Mon Sep 17 00:00:00 2001 From: eugenijm Date: Sat, 6 Apr 2019 00:22:42 +0300 Subject: Return 403 on oauth token exchange for a deactivated user --- lib/pleroma/web/oauth/oauth_controller.ex | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 26d53df1a..aac8f97fc 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -152,6 +152,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)}, %App{} = app <- get_app_from_request(conn, params), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, + {:user_active, true} <- {:user_active, !user.info.deactivated}, scopes <- oauth_scopes(params, app.scopes), [] <- scopes -- app.scopes, true <- Enum.any?(scopes), @@ -175,6 +176,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do |> put_status(:forbidden) |> json(%{error: "Your login is missing a confirmed e-mail address"}) + {:user_active, false} -> + conn + |> put_status(:forbidden) + |> json(%{error: "Your account is currently disabled"}) + _error -> put_status(conn, 400) |> json(%{error: "Invalid credentials"}) -- cgit v1.2.3 From 7bf622ce736af12db9b4865d8d3c2db5792d6f03 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Thu, 28 Mar 2019 12:39:10 +0300 Subject: Add scheduled activities --- lib/pleroma/scheduled_activity.ex | 74 ++++++++++++++++++++++ lib/pleroma/web/mastodon_api/mastodon_api.ex | 7 ++ .../web/mastodon_api/mastodon_api_controller.ex | 47 ++++++++++++++ .../mastodon_api/views/scheduled_activity_view.ex | 23 +++++++ lib/pleroma/web/router.ex | 6 ++ 5 files changed, 157 insertions(+) create mode 100644 lib/pleroma/scheduled_activity.ex create mode 100644 lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex (limited to 'lib') diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex new file mode 100644 index 000000000..0c1b26a33 --- /dev/null +++ b/lib/pleroma/scheduled_activity.ex @@ -0,0 +1,74 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ScheduledActivity do + use Ecto.Schema + + alias Pleroma.Repo + alias Pleroma.ScheduledActivity + alias Pleroma.User + + import Ecto.Query + import Ecto.Changeset + + schema "scheduled_activities" do + belongs_to(:user, User, type: Pleroma.FlakeId) + field(:scheduled_at, :naive_datetime) + field(:params, :map) + + timestamps() + end + + def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do + scheduled_activity + |> cast(attrs, [:scheduled_at, :params]) + end + + def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do + scheduled_activity + |> cast(attrs, [:scheduled_at]) + end + + def new(%User{} = user, attrs) do + %ScheduledActivity{user_id: user.id} + |> changeset(attrs) + end + + def create(%User{} = user, attrs) do + user + |> new(attrs) + |> Repo.insert() + end + + def get(%User{} = user, scheduled_activity_id) do + ScheduledActivity + |> where(user_id: ^user.id) + |> where(id: ^scheduled_activity_id) + |> Repo.one() + end + + def update(%User{} = user, scheduled_activity_id, attrs) do + with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do + scheduled_activity + |> update_changeset(attrs) + |> Repo.update() + else + nil -> {:error, :not_found} + end + end + + def delete(%User{} = user, scheduled_activity_id) do + with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do + scheduled_activity + |> Repo.delete() + else + nil -> {:error, :not_found} + end + end + + def for_user_query(%User{} = user) do + ScheduledActivity + |> where(user_id: ^user.id) + end +end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 08ea5f967..382f07e6b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do alias Pleroma.Activity alias Pleroma.Notification alias Pleroma.Pagination + alias Pleroma.ScheduledActivity alias Pleroma.User def get_followers(user, params \\ %{}) do @@ -28,6 +29,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do |> Pagination.fetch_paginated(params) end + def get_scheduled_activities(user, params \\ %{}) do + user + |> ScheduledActivity.for_user_query() + |> Pagination.fetch_paginated(params) + end + defp cast_params(params) do param_types = %{ exclude_types: {:array, :string} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index bcc79b08a..0916d84dc 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ScheduledActivity alias Pleroma.Stats alias Pleroma.User alias Pleroma.Web @@ -25,6 +26,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.MastodonView alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.ReportView + alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App @@ -364,6 +366,45 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do + with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do + conn + |> add_link_headers(:scheduled_statuses, scheduled_activities) + |> put_view(ScheduledActivityView) + |> render("index.json", %{scheduled_activities: scheduled_activities}) + end + end + + def show_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do + with %ScheduledActivity{} = scheduled_activity <- + ScheduledActivity.get(user, scheduled_activity_id) do + conn + |> put_view(ScheduledActivityView) + |> render("show.json", %{scheduled_activity: scheduled_activity}) + else + _ -> {:error, :not_found} + end + end + + def update_scheduled_status( + %{assigns: %{user: user}} = conn, + %{"id" => scheduled_activity_id} = params + ) do + with {:ok, scheduled_activity} <- + ScheduledActivity.update(user, scheduled_activity_id, params) do + conn + |> put_view(ScheduledActivityView) + |> render("show.json", %{scheduled_activity: scheduled_activity}) + end + end + + def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do + with {:ok, %ScheduledActivity{}} <- ScheduledActivity.delete(user, scheduled_activity_id) do + conn + |> json(%{}) + end + end + def post_status(conn, %{"status" => "", "media_ids" => media_ids} = params) when length(media_ids) > 0 do params = @@ -1406,6 +1447,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do # fallback action # + def errors(conn, {:error, :not_found}) do + conn + |> put_status(404) + |> json(%{error: "Record not found"}) + end + def errors(conn, _) do conn |> put_status(500) diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex new file mode 100644 index 000000000..87aa3729e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex @@ -0,0 +1,23 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do + use Pleroma.Web, :view + + alias Pleroma.ScheduledActivity + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.ScheduledActivityView + + def render("index.json", %{scheduled_activities: scheduled_activities}) do + render_many(scheduled_activities, ScheduledActivityView, "show.json") + end + + def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do + %{ + id: scheduled_activity.id |> to_string, + scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(), + params: scheduled_activity.params + } + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1c752e44c..3b5ac6fdd 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -244,6 +244,9 @@ defmodule Pleroma.Web.Router do get("/notifications", MastodonAPIController, :notifications) get("/notifications/:id", MastodonAPIController, :get_notification) + get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) + get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status) + get("/lists", MastodonAPIController, :get_lists) get("/lists/:id", MastodonAPIController, :get_list) get("/lists/:id/accounts", MastodonAPIController, :list_accounts) @@ -278,6 +281,9 @@ defmodule Pleroma.Web.Router do post("/statuses/:id/mute", MastodonAPIController, :mute_conversation) post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation) + put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status) + delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status) + post("/media", MastodonAPIController, :upload) put("/media/:id", MastodonAPIController, :update_media) -- cgit v1.2.3 From b3870df51fb2f35c3e51bea435134fe3fb692ef8 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Sat, 30 Mar 2019 12:58:40 +0300 Subject: Handle `scheduled_at` on status creation. --- lib/pleroma/activity.ex | 2 +- lib/pleroma/scheduled_activity.ex | 16 +++++++++++++ .../web/mastodon_api/mastodon_api_controller.ex | 27 ++++++++++++++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index bc3f8caba..ab8861b27 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Activity do field(:data, :map) field(:local, :boolean, default: true) field(:actor, :string) - field(:recipients, {:array, :string}) + field(:recipients, {:array, :string}, default: []) has_many(:notifications, Notification, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex index 0c1b26a33..9fdc13990 100644 --- a/lib/pleroma/scheduled_activity.ex +++ b/lib/pleroma/scheduled_activity.ex @@ -12,6 +12,8 @@ defmodule Pleroma.ScheduledActivity do import Ecto.Query import Ecto.Changeset + @min_offset :timer.minutes(5) + schema "scheduled_activities" do belongs_to(:user, User, type: Pleroma.FlakeId) field(:scheduled_at, :naive_datetime) @@ -30,6 +32,20 @@ defmodule Pleroma.ScheduledActivity do |> cast(attrs, [:scheduled_at]) end + def far_enough?(scheduled_at) when is_binary(scheduled_at) do + with {:ok, scheduled_at} <- Ecto.Type.cast(:naive_datetime, scheduled_at) do + far_enough?(scheduled_at) + else + _ -> false + end + end + + def far_enough?(scheduled_at) do + now = NaiveDateTime.utc_now() + diff = NaiveDateTime.diff(scheduled_at, now, :millisecond) + diff > @min_offset + end + def new(%User{} = user, attrs) do %ScheduledActivity{user_id: user.id} |> changeset(attrs) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0916d84dc..863fc3954 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -425,12 +425,29 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do _ -> Ecto.UUID.generate() end - {:ok, activity} = - Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> CommonAPI.post(user, params) end) + scheduled_at = params["scheduled_at"] - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do + {:ok, scheduled_activity} = + Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> + ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) + end) + + conn + |> put_view(ScheduledActivityView) + |> render("show.json", %{scheduled_activity: scheduled_activity}) + else + params = Map.drop(params, ["scheduled_at"]) + + {:ok, activity} = + Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> + CommonAPI.post(user, params) + end) + + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end end def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do -- cgit v1.2.3 From fc92a0fd8d5be0352f4791b79bda04960f36f707 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Tue, 2 Apr 2019 01:31:01 +0300 Subject: Added limits and media attachments for scheduled activities. --- lib/pleroma/object.ex | 8 +++ lib/pleroma/scheduled_activity.ex | 83 ++++++++++++++++++---- .../web/mastodon_api/mastodon_api_controller.ex | 18 +++-- .../mastodon_api/views/scheduled_activity_view.ex | 32 ++++++++- 4 files changed, 121 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 013d62157..786d6296c 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -184,4 +184,12 @@ defmodule Pleroma.Object do _ -> {:error, "Not found"} end end + + def enforce_user_objects(user, object_ids) do + Object + |> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id)) + |> where([o], o.id in ^object_ids) + |> select([o], o.id) + |> Repo.all() + end end diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex index 9fdc13990..723eb6dc3 100644 --- a/lib/pleroma/scheduled_activity.ex +++ b/lib/pleroma/scheduled_activity.ex @@ -5,9 +5,12 @@ defmodule Pleroma.ScheduledActivity do use Ecto.Schema + alias Pleroma.Config + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.User + alias Pleroma.Web.CommonAPI.Utils import Ecto.Query import Ecto.Changeset @@ -25,11 +28,69 @@ defmodule Pleroma.ScheduledActivity do def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do scheduled_activity |> cast(attrs, [:scheduled_at, :params]) + |> validate_required([:scheduled_at, :params]) + |> validate_scheduled_at() + |> with_media_attachments() end + defp with_media_attachments( + %{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset + ) + when is_list(media_ids) do + user = User.get_cached_by_id(changeset.data.user_id) + media_ids = Object.enforce_user_objects(user, media_ids) |> Enum.map(&to_string(&1)) + media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids}) + + params = + params + |> Map.put("media_attachments", media_attachments) + |> Map.put("media_ids", media_ids) + + put_change(changeset, :params, params) + end + + defp with_media_attachments(changeset), do: changeset + def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do scheduled_activity |> cast(attrs, [:scheduled_at]) + |> validate_required([:scheduled_at]) + |> validate_scheduled_at() + end + + def validate_scheduled_at(changeset) do + validate_change(changeset, :scheduled_at, fn _, scheduled_at -> + cond do + not far_enough?(scheduled_at) -> + [scheduled_at: "must be at least 5 minutes from now"] + + exceeds_daily_user_limit?(changeset.data.user_id, scheduled_at) -> + [scheduled_at: "daily limit exceeded"] + + exceeds_total_user_limit?(changeset.data.user_id) -> + [scheduled_at: "total limit exceeded"] + + true -> + [] + end + end) + end + + def exceeds_daily_user_limit?(user_id, scheduled_at) do + ScheduledActivity + |> where(user_id: ^user_id) + |> where([s], type(s.scheduled_at, :date) == type(^scheduled_at, :date)) + |> select([u], count(u.id)) + |> Repo.one() + |> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit])) + end + + def exceeds_total_user_limit?(user_id) do + ScheduledActivity + |> where(user_id: ^user_id) + |> select([u], count(u.id)) + |> Repo.one() + |> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit])) end def far_enough?(scheduled_at) when is_binary(scheduled_at) do @@ -64,23 +125,15 @@ defmodule Pleroma.ScheduledActivity do |> Repo.one() end - def update(%User{} = user, scheduled_activity_id, attrs) do - with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do - scheduled_activity - |> update_changeset(attrs) - |> Repo.update() - else - nil -> {:error, :not_found} - end + def update(scheduled_activity, attrs) do + scheduled_activity + |> update_changeset(attrs) + |> Repo.update() end - def delete(%User{} = user, scheduled_activity_id) do - with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do - scheduled_activity - |> Repo.delete() - else - nil -> {:error, :not_found} - end + def delete(scheduled_activity) do + scheduled_activity + |> Repo.delete() end def for_user_query(%User{} = user) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 863fc3954..6cb5df378 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -390,18 +390,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do %{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id} = params ) do - with {:ok, scheduled_activity} <- - ScheduledActivity.update(user, scheduled_activity_id, params) do + with %ScheduledActivity{} = scheduled_activity <- + ScheduledActivity.get(user, scheduled_activity_id), + {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do conn |> put_view(ScheduledActivityView) |> render("show.json", %{scheduled_activity: scheduled_activity}) + else + nil -> {:error, :not_found} + error -> error end end def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do - with {:ok, %ScheduledActivity{}} <- ScheduledActivity.delete(user, scheduled_activity_id) do + with %ScheduledActivity{} = scheduled_activity <- + ScheduledActivity.get(user, scheduled_activity_id), + {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do conn - |> json(%{}) + |> put_view(ScheduledActivityView) + |> render("show.json", %{scheduled_activity: scheduled_activity}) + else + nil -> {:error, :not_found} + error -> error end end diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex index 87aa3729e..1ebff7aba 100644 --- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex +++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do alias Pleroma.ScheduledActivity alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ScheduledActivityView + alias Pleroma.Web.MastodonAPI.StatusView def render("index.json", %{scheduled_activities: scheduled_activities}) do render_many(scheduled_activities, ScheduledActivityView, "show.json") @@ -17,7 +18,36 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do %{ id: scheduled_activity.id |> to_string, scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(), - params: scheduled_activity.params + params: status_params(scheduled_activity.params) } + |> with_media_attachments(scheduled_activity) + end + + defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do + attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment) + Map.put(data, :media_attachments, attachments) + end + + defp with_media_attachments(data, _), do: data + + defp status_params(params) do + data = %{ + text: params["status"], + sensitive: params["sensitive"], + spoiler_text: params["spoiler_text"], + visibility: params["visibility"], + scheduled_at: params["scheduled_at"], + poll: params["poll"], + in_reply_to_id: params["in_reply_to_id"] + } + + data = + if media_ids = params["media_ids"] do + Map.put(data, :media_ids, media_ids) + else + data + end + + data end end -- cgit v1.2.3 From 2056efa714460faaf25f6bc03ab643f5a2e8cd3d Mon Sep 17 00:00:00 2001 From: eugenijm Date: Wed, 3 Apr 2019 18:55:04 +0300 Subject: Add scheduler for sending scheduled activities to the queue --- lib/pleroma/application.ex | 3 +- lib/pleroma/object.ex | 8 --- lib/pleroma/scheduled_activity.ex | 34 ++++++++++--- lib/pleroma/scheduled_activity_worker.ex | 58 ++++++++++++++++++++++ .../web/mastodon_api/mastodon_api_controller.ex | 26 +++++++--- .../mastodon_api/views/scheduled_activity_view.ex | 12 +++-- 6 files changed, 112 insertions(+), 29 deletions(-) create mode 100644 lib/pleroma/scheduled_activity_worker.ex (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 1fc3fb728..f0cb7d9a8 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -104,7 +104,8 @@ defmodule Pleroma.Application do ], id: :cachex_idem ), - worker(Pleroma.FlakeId, []) + worker(Pleroma.FlakeId, []), + worker(Pleroma.ScheduledActivityWorker, []) ] ++ hackney_pool_children() ++ [ diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 786d6296c..013d62157 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -184,12 +184,4 @@ defmodule Pleroma.Object do _ -> {:error, "Not found"} end end - - def enforce_user_objects(user, object_ids) do - Object - |> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id)) - |> where([o], o.id in ^object_ids) - |> select([o], o.id) - |> Repo.all() - end end diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex index 723eb6dc3..de0e54699 100644 --- a/lib/pleroma/scheduled_activity.ex +++ b/lib/pleroma/scheduled_activity.ex @@ -6,7 +6,6 @@ defmodule Pleroma.ScheduledActivity do use Ecto.Schema alias Pleroma.Config - alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.User @@ -37,8 +36,6 @@ defmodule Pleroma.ScheduledActivity do %{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset ) when is_list(media_ids) do - user = User.get_cached_by_id(changeset.data.user_id) - media_ids = Object.enforce_user_objects(user, media_ids) |> Enum.map(&to_string(&1)) media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids}) params = @@ -79,8 +76,8 @@ defmodule Pleroma.ScheduledActivity do def exceeds_daily_user_limit?(user_id, scheduled_at) do ScheduledActivity |> where(user_id: ^user_id) - |> where([s], type(s.scheduled_at, :date) == type(^scheduled_at, :date)) - |> select([u], count(u.id)) + |> where([sa], type(sa.scheduled_at, :date) == type(^scheduled_at, :date)) + |> select([sa], count(sa.id)) |> Repo.one() |> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit])) end @@ -88,7 +85,7 @@ defmodule Pleroma.ScheduledActivity do def exceeds_total_user_limit?(user_id) do ScheduledActivity |> where(user_id: ^user_id) - |> select([u], count(u.id)) + |> select([sa], count(sa.id)) |> Repo.one() |> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit])) end @@ -125,19 +122,40 @@ defmodule Pleroma.ScheduledActivity do |> Repo.one() end - def update(scheduled_activity, attrs) do + def update(%ScheduledActivity{} = scheduled_activity, attrs) do scheduled_activity |> update_changeset(attrs) |> Repo.update() end - def delete(scheduled_activity) do + def delete(%ScheduledActivity{} = scheduled_activity) do scheduled_activity |> Repo.delete() end + def delete(id) when is_binary(id) or is_integer(id) do + ScheduledActivity + |> where(id: ^id) + |> select([sa], sa) + |> Repo.delete_all() + |> case do + {1, [scheduled_activity]} -> {:ok, scheduled_activity} + _ -> :error + end + end + def for_user_query(%User{} = user) do ScheduledActivity |> where(user_id: ^user.id) end + + def due_activities(offset \\ 0) do + naive_datetime = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(offset, :millisecond) + + ScheduledActivity + |> where([sa], sa.scheduled_at < ^naive_datetime) + |> Repo.all() + end end diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex new file mode 100644 index 000000000..65b38622f --- /dev/null +++ b/lib/pleroma/scheduled_activity_worker.ex @@ -0,0 +1,58 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ScheduledActivityWorker do + @moduledoc """ + Sends scheduled activities to the job queue. + """ + + alias Pleroma.Config + alias Pleroma.ScheduledActivity + alias Pleroma.User + alias Pleroma.Web.CommonAPI + use GenServer + require Logger + + @schedule_interval :timer.minutes(1) + + def start_link do + GenServer.start_link(__MODULE__, nil) + end + + def init(_) do + if Config.get([ScheduledActivity, :enabled]) do + schedule_next() + {:ok, nil} + else + :ignore + end + end + + def perform(:execute, scheduled_activity_id) do + try do + {:ok, scheduled_activity} = ScheduledActivity.delete(scheduled_activity_id) + %User{} = user = User.get_cached_by_id(scheduled_activity.user_id) + {:ok, _result} = CommonAPI.post(user, scheduled_activity.params) + rescue + error -> + Logger.error( + "#{__MODULE__} Couldn't create a status from the scheduled activity: #{inspect(error)}" + ) + end + end + + def handle_info(:perform, state) do + ScheduledActivity.due_activities(@schedule_interval) + |> Enum.each(fn scheduled_activity -> + PleromaJobQueue.enqueue(:scheduled_activities, __MODULE__, [:execute, scheduled_activity.id]) + end) + + schedule_next() + {:noreply, state} + end + + defp schedule_next do + Process.send_after(self(), :perform, @schedule_interval) + end +end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 6cb5df378..fc8a2458c 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller + alias Ecto.Changeset alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Filter @@ -438,14 +439,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do scheduled_at = params["scheduled_at"] if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do - {:ok, scheduled_activity} = - Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> - ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) - end) - - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) + with {:ok, scheduled_activity} <- + ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do + conn + |> put_view(ScheduledActivityView) + |> render("show.json", %{scheduled_activity: scheduled_activity}) + end else params = Map.drop(params, ["scheduled_at"]) @@ -1474,6 +1473,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do # fallback action # + def errors(conn, {:error, %Changeset{} = changeset}) do + error_message = + changeset + |> Changeset.traverse_errors(fn {message, _opt} -> message end) + |> Enum.map_join(", ", fn {_k, v} -> v end) + + conn + |> put_status(422) + |> json(%{error: error_message}) + end + def errors(conn, {:error, :not_found}) do conn |> put_status(404) diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex index 1ebff7aba..0aae15ab9 100644 --- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex +++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex @@ -16,16 +16,20 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do %{ - id: scheduled_activity.id |> to_string, - scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(), + id: to_string(scheduled_activity.id), + scheduled_at: CommonAPI.Utils.to_masto_date(scheduled_activity.scheduled_at), params: status_params(scheduled_activity.params) } |> with_media_attachments(scheduled_activity) end defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do - attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment) - Map.put(data, :media_attachments, attachments) + try do + attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment) + Map.put(data, :media_attachments, attachments) + rescue + _ -> data + end end defp with_media_attachments(data, _), do: data -- cgit v1.2.3 From e3328bc1382315c9067c099995a29db70d9d0433 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 7 Apr 2019 11:08:37 +0300 Subject: [#923] Removed
elements from auth forms, adjusted docs, minor auth settings refactoring. --- lib/pleroma/web/auth/authenticator.ex | 7 +++++-- lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex | 2 -- lib/pleroma/web/templates/o_auth/o_auth/register.html.eex | 8 +------- 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index 4eeef5034..89d88af32 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -31,12 +31,15 @@ defmodule Pleroma.Web.Auth.Authenticator do @callback auth_template() :: String.t() | nil def auth_template do - implementation().auth_template() || Pleroma.Config.get(:auth_template, "show.html") + # Note: `config :pleroma, :auth_template, "..."` support is deprecated + implementation().auth_template() || + Pleroma.Config.get([:auth, :auth_template], Pleroma.Config.get(:auth_template)) || + "show.html" end @callback oauth_consumer_template() :: String.t() | nil def oauth_consumer_template do implementation().oauth_consumer_template() || - Pleroma.Config.get(:oauth_consumer_template, "consumer.html") + Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html") end end diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 9365c7c44..85f62ca64 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -1,5 +1,3 @@ -
-

Sign in with external provider

<%= form_for @conn, o_auth_path(@conn, :prepare_request), [method: "get"], fn f -> %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex index 2e806e5fb..126390391 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex @@ -7,10 +7,7 @@

Registration Details

-

If you'd like to register a new account, -
-please provide the details below.

-
+

If you'd like to register a new account, please provide the details below.

<%= form_for @conn, o_auth_path(@conn, :register), [], fn f -> %> @@ -25,9 +22,6 @@ please provide the details below.

<%= submit "Proceed as new user", name: "op", value: "register" %> -
-
-

Alternatively, sign in to connect to existing account.

-- cgit v1.2.3 From 36c0a10fdf47efa5067456030bad3204c2088e93 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Mon, 8 Apr 2019 11:03:10 +0000 Subject: adding language tag --- lib/pleroma/web/activity_pub/utils.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 32545937e..0b53f71c3 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -99,7 +99,10 @@ defmodule Pleroma.Web.ActivityPub.Utils do %{ "@context" => [ "https://www.w3.org/ns/activitystreams", - "#{Web.base_url()}/schemas/litepub-0.1.jsonld" + "#{Web.base_url()}/schemas/litepub-0.1.jsonld", + %{ + "@language" => "und" + } ] } end -- cgit v1.2.3