aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Tashkinov <ivantashkinov@gmail.com>2020-11-28 21:51:06 +0300
committerIvan Tashkinov <ivantashkinov@gmail.com>2020-11-28 21:51:06 +0300
commitf1b07a2b2b6439579f0a35694f693712fb5ec5f4 (patch)
tree9a2e5f94b6a4fb8974554cc21b71e806702a7312
parent62993db499ca565cdb0a404f9668528971adf9dd (diff)
downloadpleroma-f1b07a2b2b6439579f0a35694f693712fb5ec5f4.tar.gz
OAuth form user remembering feature. Local MastoFE login / logout fixes.
-rw-r--r--.gitattributes7
-rw-r--r--CHANGELOG.md1
-rw-r--r--docs/configuration/static_dir.md5
-rw-r--r--lib/pleroma/user.ex4
-rw-r--r--lib/pleroma/web/masto_fe_controller.ex34
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/auth_controller.ex64
-rw-r--r--lib/pleroma/web/o_auth/o_auth_controller.ex21
-rw-r--r--lib/pleroma/web/templates/layout/app.html.eex236
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/show.html.eex66
-rw-r--r--priv/static/instance/static.css296
-rw-r--r--test/pleroma/user_test.exs5
-rw-r--r--test/pleroma/web/mastodon_api/controllers/auth_controller_test.exs4
-rw-r--r--test/pleroma/web/mastodon_api/masto_fe_controller_test.exs3
-rw-r--r--test/pleroma/web/o_auth/o_auth_controller_test.exs39
14 files changed, 488 insertions, 297 deletions
diff --git a/.gitattributes b/.gitattributes
index 68895bf88..355e17f3c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,8 +1,9 @@
*.ex diff=elixir
*.exs diff=elixir
-# At the time of writing all js/css files included
-# in the repo are minified bundles, and we don't want
-# to search/diff those as text files.
+
+# Most os js/css files included in the repo are minified bundles,
+# and we don't want to search/diff those as text files. Exceptions are listed below.
*.js binary
*.js.map binary
*.css binary
+priv/static/instance/static.css diff=css
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4ef66408..4b3ae2193 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Ability to view remote timelines, with ex. `/api/v1/timelines/public?instance=lain.com` and streams `public:remote` and `public:remote:media`.
- The site title is now injected as a `title` tag like preloads or metadata.
- Password reset tokens now are not accepted after a certain age.
+- OAuth form improvements: users are remembered by their cookie, the CSS is overridable by the admin, and the style has been improved.
<details>
<summary>API Changes</summary>
diff --git a/docs/configuration/static_dir.md b/docs/configuration/static_dir.md
index 8ac07b725..a294bb604 100644
--- a/docs/configuration/static_dir.md
+++ b/docs/configuration/static_dir.md
@@ -88,3 +88,8 @@ config :pleroma, :frontend_configurations,
Note the extra `static` folder for the terms-of-service.html
Terms of Service will be shown to all users on the registration page. It's the best place where to write down the rules for your instance. You can modify the rules by adding and changing `$static_dir/static/terms-of-service.html`.
+
+
+## Styling rendered pages
+
+To overwrite the CSS stylesheet of the OAuth form and other static pages, you can upload your own CSS file to `instance/static/static.css`. This will completely replace the CSS used by those pages, so it might be a good idea to copy the one from `priv/static/instance/static.css` and make your changes.
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index bcd5256c8..6a5a43a25 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -2406,4 +2406,8 @@ defmodule Pleroma.User do
|> Map.put(:bio, HTML.filter_tags(user.bio, filter))
|> Map.put(:fields, fields)
end
+
+ def get_host(%User{ap_id: ap_id} = _user) do
+ URI.parse(ap_id).host
+ end
end
diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex
index 08f92d55f..7011ae214 100644
--- a/lib/pleroma/web/masto_fe_controller.ex
+++ b/lib/pleroma/web/masto_fe_controller.ex
@@ -6,6 +6,8 @@ defmodule Pleroma.Web.MastoFEController do
use Pleroma.Web, :controller
alias Pleroma.User
+ alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.MastodonAPI.AuthController
alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
alias Pleroma.Web.Plugs.OAuthScopesPlug
@@ -26,27 +28,27 @@ defmodule Pleroma.Web.MastoFEController do
)
@doc "GET /web/*path"
- def index(%{assigns: %{user: user, token: token}} = conn, _params)
- when not is_nil(user) and not is_nil(token) do
- conn
- |> put_layout(false)
- |> render("index.html",
- token: token.token,
- user: user,
- custom_emojis: Pleroma.Emoji.get_all()
- )
- end
-
def index(conn, _params) do
- conn
- |> put_session(:return_to, conn.request_path)
- |> redirect(to: "/web/login")
+ with %{assigns: %{user: %User{} = user, token: %Token{app_id: token_app_id} = token}} <- conn,
+ {:ok, %{id: ^token_app_id}} <- AuthController.local_mastofe_app() do
+ conn
+ |> put_layout(false)
+ |> render("index.html",
+ token: token.token,
+ user: user,
+ custom_emojis: Pleroma.Emoji.get_all()
+ )
+ else
+ _ ->
+ conn
+ |> put_session(:return_to, conn.request_path)
+ |> redirect(to: "/web/login")
+ end
end
@doc "GET /web/manifest.json"
def manifest(conn, _params) do
- conn
- |> render("manifest.json")
+ render(conn, "manifest.json")
end
@doc "PUT /api/web/settings: Backend-obscure settings blob for MastoFE, don't parse/reuse elsewhere"
diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
index fa582dcfc..93d057a79 100644
--- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
@@ -8,10 +8,12 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
alias Pleroma.Helpers.AuthHelper
+ alias Pleroma.Helpers.UriHelper
alias Pleroma.User
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
alias Pleroma.Web.TwitterAPI.TwitterAPI
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
@@ -21,24 +23,35 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
@local_mastodon_name "Mastodon-Local"
@doc "GET /web/login"
- def login(%{assigns: %{user: %User{}}} = conn, _params) do
- redirect(conn, to: local_mastodon_root_path(conn))
- end
-
- # Local Mastodon FE login init action
- def login(conn, %{"code" => auth_token}) do
- with {:ok, app} <- get_or_make_app(),
+ # Local Mastodon FE login callback action
+ def login(conn, %{"code" => auth_token} = params) do
+ with {:ok, app} <- local_mastofe_app(),
{:ok, auth} <- Authorization.get_by_token(app, auth_token),
- {:ok, token} <- Token.exchange_token(app, auth) do
+ {:ok, oauth_token} <- Token.exchange_token(app, auth) do
+ redirect_to =
+ conn
+ |> local_mastodon_post_login_path()
+ |> UriHelper.modify_uri_params(%{"access_token" => oauth_token.token})
+
conn
- |> AuthHelper.put_session_token(token.token)
- |> redirect(to: local_mastodon_root_path(conn))
+ |> AuthHelper.put_session_token(oauth_token.token)
+ |> redirect(to: redirect_to)
+ else
+ _ -> redirect_to_oauth_form(conn, params)
+ end
+ end
+
+ def login(conn, params) do
+ with %{assigns: %{user: %User{}, token: %Token{app_id: app_id}}} <- conn,
+ {:ok, %{id: ^app_id}} <- local_mastofe_app() do
+ redirect(conn, to: local_mastodon_post_login_path(conn))
+ else
+ _ -> redirect_to_oauth_form(conn, params)
end
end
- # Local Mastodon FE callback action
- def login(conn, _) do
- with {:ok, app} <- get_or_make_app() do
+ defp redirect_to_oauth_form(conn, _params) do
+ with {:ok, app} <- local_mastofe_app() do
path =
o_auth_path(conn, :authorize,
response_type: "code",
@@ -53,9 +66,16 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
@doc "DELETE /auth/sign_out"
def logout(conn, _) do
- conn
- |> clear_session()
- |> redirect(to: "/")
+ conn =
+ with %{assigns: %{token: %Token{} = oauth_token}} <- conn,
+ session_token = AuthHelper.get_session_token(conn),
+ {:ok, %Token{token: ^session_token}} <- RevokeToken.revoke(oauth_token) do
+ AuthHelper.delete_session_token(conn)
+ else
+ _ -> conn
+ end
+
+ redirect(conn, to: "/")
end
@doc "POST /auth/password"
@@ -67,7 +87,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
json_response(conn, :no_content, "")
end
- defp local_mastodon_root_path(conn) do
+ defp local_mastodon_post_login_path(conn) do
case get_session(conn, :return_to) do
nil ->
masto_fe_path(conn, :index, ["getting-started"])
@@ -78,9 +98,11 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
end
end
- @spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
- defp get_or_make_app do
- %{client_name: @local_mastodon_name, redirect_uris: "."}
- |> App.get_or_make(["read", "write", "follow", "push", "admin"])
+ @spec local_mastofe_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
+ def local_mastofe_app do
+ App.get_or_make(
+ %{client_name: @local_mastodon_name, redirect_uris: "."},
+ ["read", "write", "follow", "push", "admin"]
+ )
end
end
diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex
index 8103395b3..965c0f879 100644
--- a/lib/pleroma/web/o_auth/o_auth_controller.ex
+++ b/lib/pleroma/web/o_auth/o_auth_controller.ex
@@ -80,6 +80,13 @@ defmodule Pleroma.Web.OAuth.OAuthController do
available_scopes = (app && app.scopes) || []
scopes = Scopes.fetch_scopes(params, available_scopes)
+ user =
+ with %{assigns: %{user: %User{} = user}} <- conn do
+ user
+ else
+ _ -> nil
+ end
+
scopes =
if scopes == [] do
available_scopes
@@ -89,6 +96,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
# Note: `params` might differ from `conn.params`; use `@params` not `@conn.params` in template
render(conn, Authenticator.auth_template(), %{
+ user: user,
+ app: app && Map.delete(app, :client_secret),
response_type: params["response_type"],
client_id: params["client_id"],
available_scopes: available_scopes,
@@ -132,11 +141,13 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
- def create_authorization(
- %Plug.Conn{} = conn,
- %{"authorization" => _} = params,
- opts \\ []
- ) do
+ def create_authorization(_, _, opts \\ [])
+
+ def create_authorization(%Plug.Conn{assigns: %{user: %User{} = user}} = conn, params, []) do
+ create_authorization(conn, params, user: user)
+ end
+
+ def create_authorization(%Plug.Conn{} = conn, %{"authorization" => _} = params, opts) do
with {:ok, auth, user} <- do_create_authorization(conn, params, opts[:user]),
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)} do
after_create_authorization(conn, auth, params)
diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex
index 3f28f1920..1ede59fd8 100644
--- a/lib/pleroma/web/templates/layout/app.html.eex
+++ b/lib/pleroma/web/templates/layout/app.html.eex
@@ -1,233 +1,19 @@
<!DOCTYPE html>
-<html>
+<html lang="en">
<head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui" />
- <title>
- <%= Pleroma.Config.get([:instance, :name]) %>
- </title>
- <style>
- body {
- background-color: #121a24;
- font-family: sans-serif;
- color: #b9b9ba;
- text-align: center;
- }
-
- .container {
- max-width: 420px;
- padding: 20px;
- background-color: #182230;
- border-radius: 4px;
- margin: auto;
- margin-top: 10vh;
- box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5);
- }
-
- h1 {
- margin: 0;
- font-size: 24px;
- }
-
- h2 {
- color: #b9b9ba;
- font-weight: normal;
- font-size: 18px;
- margin-bottom: 20px;
- }
-
- a {
- color: #d8a070;
- text-decoration: none;
- }
-
- form {
- width: 100%;
- }
-
- .input {
- text-align: left;
- color: #89898a;
- display: flex;
- flex-direction: column;
- }
-
- input {
- box-sizing: content-box;
- padding: 10px;
- margin-top: 5px;
- margin-bottom: 10px;
- background-color: #121a24;
- color: #b9b9ba;
- border: 0;
- transition-property: border-bottom;
- transition-duration: 0.35s;
- border-bottom: 2px solid #2a384a;
- font-size: 14px;
- }
-
- .scopes-input {
- display: flex;
- flex-direction: column;
- margin-top: 1em;
- text-align: left;
- color: #89898a;
- }
-
- .scopes-input label:first-child {
- height: 2em;
- }
-
- .scopes {
- display: flex;
- flex-wrap: wrap;
- text-align: left;
- color: #b9b9ba;
- }
-
- .scope {
- display: flex;
- flex-basis: 100%;
- height: 2em;
- align-items: center;
- }
-
- .scope:before {
- color: #b9b9ba;
- content: "✔\fe0e";
- margin-left: 1em;
- margin-right: 1em;
- }
-
- [type="checkbox"] + label {
- display: none;
- cursor: pointer;
- margin: 0.5em;
- }
-
- [type="checkbox"] {
- display: none;
- }
-
- [type="checkbox"] + label:before {
- cursor: pointer;
- display: inline-block;
- color: white;
- background-color: #121a24;
- border: 4px solid #121a24;
- box-shadow: 0px 0px 1px 0 #d8a070;
- box-sizing: border-box;
- width: 1.2em;
- height: 1.2em;
- margin-right: 1.0em;
- content: "";
- transition-property: background-color;
- transition-duration: 0.35s;
- color: #121a24;
- margin-bottom: -0.2em;
- border-radius: 2px;
- }
-
- [type="checkbox"]:checked + label:before {
- background-color: #d8a070;
- }
-
- input:focus {
- outline: none;
- border-bottom: 2px solid #d8a070;
- }
-
- button {
- box-sizing: border-box;
- width: 100%;
- background-color: #1c2a3a;
- color: #b9b9ba;
- border-radius: 4px;
- border: none;
- padding: 10px;
- margin-top: 20px;
- margin-bottom: 20px;
- text-transform: uppercase;
- font-size: 16px;
- box-shadow: 0px 0px 2px 0px black,
- 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
- 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
- }
-
- button:hover {
- cursor: pointer;
- box-shadow: 0px 0px 0px 1px #d8a070,
- 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
- 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
- }
-
- .alert-danger {
- box-sizing: border-box;
- width: 100%;
- background-color: #931014;
- border: 1px solid #a06060;
- border-radius: 4px;
- padding: 10px;
- margin-top: 20px;
- font-weight: 500;
- font-size: 16px;
- }
-
- .alert-info {
- box-sizing: border-box;
- width: 100%;
- border-radius: 4px;
- border: 1px solid #7d796a;
- padding: 10px;
- margin-top: 20px;
- font-weight: 500;
- font-size: 16px;
- }
-
- @media all and (max-width: 440px) {
- .container {
- margin-top: 0
- }
-
- .scope {
- flex-basis: 0%;
- }
-
- .scope:before {
- content: "";
- margin-left: 0em;
- margin-right: 1em;
- }
-
- .scope:first-child:before {
- margin-left: 1em;
- content: "✔\fe0e";
- }
-
- .scope:after {
- content: ",";
- }
-
- .scope:last-child:after {
- content: "";
- }
- }
- .form-row {
- display: flex;
- }
- .form-row > label {
- text-align: left;
- line-height: 47px;
- flex: 1;
- }
- .form-row > input {
- flex: 2;
- }
- </style>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui">
+ <title><%= Pleroma.Config.get([:instance, :name]) %></title>
+ <link rel="stylesheet" href="/instance/static.css">
</head>
<body>
+ <div class="instance-header">
+ <a class="instance-header__content" href="/">
+ <img class="instance-header__thumbnail" src="<%= Pleroma.Config.get([:instance, :instance_thumbnail]) %>">
+ <h1 class="instance-header__title"><%= Pleroma.Config.get([:instance, :name]) %></h1>
+ </a>
+ </div>
<div class="container">
- <h1><%= Pleroma.Config.get([:instance, :name]) %></h1>
<%= @inner_content %>
</div>
</body>
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 b17142ff8..1a85818ec 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
@@ -5,32 +5,55 @@
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<% end %>
-<h2>OAuth Authorization</h2>
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
-<%= if @params["registration"] in ["true", true] do %>
- <h3>This is the first time you visit! Please enter your Pleroma handle.</h3>
- <p>Choose carefully! You won't be able to change this later. You will be able to change your display name, though.</p>
- <div class="input">
- <%= label f, :nickname, "Pleroma Handle" %>
- <%= text_input f, :nickname, placeholder: "lain" %>
+<%= if @user do %>
+ <div class="account-header">
+ <div class="account-header__banner" style="background-image: url('<%= Pleroma.User.banner_url(@user) %>')"></div>
+ <div class="account-header__avatar" style="background-image: url('<%= Pleroma.User.avatar_url(@user) %>')"></div>
+ <div class="account-header__meta">
+ <div class="account-header__display-name"><%= @user.name %></div>
+ <div class="account-header__nickname">@<%= @user.nickname %>@<%= Pleroma.User.get_host(@user) %></div>
+ </div>
</div>
- <%= hidden_input f, :name, value: @params["name"] %>
- <%= hidden_input f, :password, value: @params["password"] %>
- <br>
-<% else %>
- <div class="input">
- <%= label f, :name, "Username" %>
- <%= text_input f, :name %>
- </div>
- <div class="input">
- <%= label f, :password, "Password" %>
- <%= password_input f, :password %>
- </div>
- <%= submit "Log In" %>
- <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
<% end %>
+<div class="container__content">
+ <%= if @app do %>
+ <p>Application <strong><%= @app.client_name %></strong> is requesting access to your account.</p>
+ <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
+ <% end %>
+
+ <%= if @user do %>
+ <div class="actions">
+ <a class="button button--cancel" href="/">Cancel</a>
+ <%= submit "Approve", class: "button--approve" %>
+ </div>
+ <% else %>
+ <%= if @params["registration"] in ["true", true] do %>
+ <h3>This is the first time you visit! Please enter your Pleroma handle.</h3>
+ <p>Choose carefully! You won't be able to change this later. You will be able to change your display name, though.</p>
+ <div class="input">
+ <%= label f, :nickname, "Pleroma Handle" %>
+ <%= text_input f, :nickname, placeholder: "lain" %>
+ </div>
+ <%= hidden_input f, :name, value: @params["name"] %>
+ <%= hidden_input f, :password, value: @params["password"] %>
+ <br>
+ <% else %>
+ <div class="input">
+ <%= label f, :name, "Username" %>
+ <%= text_input f, :name %>
+ </div>
+ <div class="input">
+ <%= label f, :password, "Password" %>
+ <%= password_input f, :password %>
+ </div>
+ <%= submit "Log In" %>
+ <% end %>
+ <% end %>
+</div>
+
<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :response_type, value: @response_type %>
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
@@ -40,4 +63,3 @@
<%= if Pleroma.Config.oauth_consumer_enabled?() do %>
<%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %>
<% end %>
-
diff --git a/priv/static/instance/static.css b/priv/static/instance/static.css
new file mode 100644
index 000000000..487e1ec27
--- /dev/null
+++ b/priv/static/instance/static.css
@@ -0,0 +1,296 @@
+* {
+ box-sizing: border-box;
+}
+
+:root {
+ --brand-color: #d8a070;
+ --background-color: #121a24;
+ --foreground-color: #182230;
+ --primary-text-color: #b9b9ba;
+ --muted-text-color: #89898a;
+}
+
+body {
+ background-color: var(--background-color);
+ font-family: sans-serif;
+ color: var(--primary-text-color);
+ padding: 0;
+ margin: 0;
+}
+
+.instance-header {
+ height: 60px;
+ padding: 10px;
+ background: var(--foreground-color);
+ box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5);
+}
+
+.instance-header__content {
+ display: flex;
+ align-items: center;
+ max-width: 400px;
+ margin: 0 auto;
+}
+
+.instance-header__thumbnail {
+ max-width: 40px;
+ border-radius: 4px;
+ margin-right: 12px;
+}
+
+.instance-header__title {
+ font-size: 16px;
+ font-weight: bold;
+ color: var(--primary-text-color);
+}
+
+.container {
+ max-width: 400px;
+ background-color: var(--foreground-color);
+ border-radius: 4px;
+ overflow: hidden;
+ margin: 35px auto;
+ box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5);
+}
+
+.container__content {
+ padding: 0 20px;
+}
+
+h1 {
+ margin: 0;
+ font-size: 24px;
+ text-align: center;
+}
+
+h2 {
+ color: var(--primary-text-color);
+ font-weight: normal;
+ font-size: 18px;
+ margin-bottom: 20px;
+}
+
+a {
+ color: var(--brand-color);
+ text-decoration: none;
+}
+
+form {
+ width: 100%;
+}
+
+.input {
+ color: var(--muted-text-color);
+ display: flex;
+ flex-direction: column;
+}
+
+input {
+ box-sizing: content-box;
+ padding: 10px;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ background-color: var(--background-color);
+ color: var(--primary-text-color);
+ border: 0;
+ transition-property: border-bottom;
+ transition-duration: 0.35s;
+ border-bottom: 2px solid #2a384a;
+ font-size: 14px;
+}
+
+.scopes-input {
+ display: flex;
+ flex-direction: column;
+ margin: 1em 0;
+ color: var(--muted-text-color);
+}
+
+.scopes-input label:first-child {
+ height: 2em;
+}
+
+.scopes {
+ display: flex;
+ flex-wrap: wrap;
+ color: var(--primary-text-color);
+}
+
+.scope {
+ display: flex;
+ flex-basis: 100%;
+ height: 2em;
+ align-items: center;
+}
+
+.scope:before {
+ color: var(--primary-text-color);
+ content: "✔\fe0e";
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+[type="checkbox"] + label {
+ display: none;
+ cursor: pointer;
+ margin: 0.5em;
+}
+
+[type="checkbox"] {
+ display: none;
+}
+
+[type="checkbox"] + label:before {
+ cursor: pointer;
+ display: inline-block;
+ color: white;
+ background-color: var(--background-color);
+ border: 4px solid var(--background-color);
+ box-shadow: 0px 0px 1px 0 var(--brand-color);
+ width: 1.2em;
+ height: 1.2em;
+ margin-right: 1.0em;
+ content: "";
+ transition-property: background-color;
+ transition-duration: 0.35s;
+ color: var(--background-color);
+ margin-bottom: -0.2em;
+ border-radius: 2px;
+}
+
+[type="checkbox"]:checked + label:before {
+ background-color: var(--brand-color);
+}
+
+input:focus {
+ outline: none;
+ border-bottom: 2px solid var(--brand-color);
+}
+
+.actions {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.actions button,
+.actions a.button {
+ width: auto;
+ margin-left: 10px;
+}
+
+a.button,
+button {
+ width: 100%;
+ background-color: #1c2a3a;
+ color: var(--primary-text-color);
+ border-radius: 4px;
+ border: none;
+ padding: 10px 16px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ text-transform: uppercase;
+ font-size: 16px;
+ box-shadow: 0px 0px 2px 0px black,
+ 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
+ 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
+}
+
+a.button:hover,
+button:hover {
+ cursor: pointer;
+ box-shadow: 0px 0px 0px 1px var(--brand-color),
+ 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
+ 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
+}
+
+.alert-danger {
+ width: 100%;
+ background-color: #931014;
+ border: 1px solid #a06060;
+ border-radius: 4px;
+ padding: 10px;
+ margin-top: 20px;
+ font-weight: 500;
+ font-size: 16px;
+}
+
+.alert-info {
+ width: 100%;
+ border-radius: 4px;
+ border: 1px solid #7d796a;
+ padding: 10px;
+ margin-top: 20px;
+ font-weight: 500;
+ font-size: 16px;
+}
+
+.account-header__banner {
+ width: 100%;
+ height: 112px;
+ background-size: cover;
+ background-position: center;
+}
+
+.account-header__avatar {
+ width: 94px;
+ height: 94px;
+ background-size: cover;
+ background-position: center;
+ margin: -47px 10px 0;
+ border: 6px solid var(--foreground-color);
+ border-radius: 999px;
+}
+
+.account-header__meta {
+ padding: 6px 20px 17px;
+}
+
+.account-header__display-name {
+ font-size: 20px;
+ font-weight: bold;
+}
+
+.account-header__nickname {
+ font-size: 14px;
+ color: var(--muted-text-color);
+}
+
+@media all and (max-width: 420px) {
+ .container {
+ margin: 0 auto;
+ border-radius: 0;
+ }
+
+ .scope {
+ flex-basis: 0%;
+ }
+
+ .scope:before {
+ content: "";
+ margin-left: 0em;
+ margin-right: 1em;
+ }
+
+ .scope:first-child:before {
+ margin-left: 1em;
+ content: "✔\fe0e";
+ }
+
+ .scope:after {
+ content: ",";
+ }
+
+ .scope:last-child:after {
+ content: "";
+ }
+}
+.form-row {
+ display: flex;
+}
+.form-row > label {
+ line-height: 47px;
+ flex: 1;
+}
+.form-row > input {
+ flex: 2;
+}
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index c678dadb3..1ba7f2a2f 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -2171,4 +2171,9 @@ defmodule Pleroma.UserTest do
assert User.avatar_url(user, no_default: true) == nil
end
+
+ test "get_host/1" do
+ user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
+ assert User.get_host(user) == "lain.com"
+ end
end
diff --git a/test/pleroma/web/mastodon_api/controllers/auth_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/auth_controller_test.exs
index bf2438fe2..d7834c876 100644
--- a/test/pleroma/web/mastodon_api/controllers/auth_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/auth_controller_test.exs
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|> get("/web/login", %{code: auth.token})
assert conn.status == 302
- assert redirected_to(conn) == path
+ assert redirected_to(conn) =~ path
end
test "redirects to the getting-started page when referer is not present", %{conn: conn} do
@@ -49,7 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
conn = get(conn, "/web/login", %{code: auth.token})
assert conn.status == 302
- assert redirected_to(conn) == "/web/getting-started"
+ assert redirected_to(conn) =~ "/web/getting-started"
end
end
diff --git a/test/pleroma/web/mastodon_api/masto_fe_controller_test.exs b/test/pleroma/web/mastodon_api/masto_fe_controller_test.exs
index ed8add8d2..b9cd050df 100644
--- a/test/pleroma/web/mastodon_api/masto_fe_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/masto_fe_controller_test.exs
@@ -64,7 +64,8 @@ defmodule Pleroma.Web.MastodonAPI.MastoFEControllerTest do
end
test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
- token = insert(:oauth_token, scopes: ["read"])
+ {:ok, app} = Pleroma.Web.MastodonAPI.AuthController.local_mastofe_app()
+ token = insert(:oauth_token, app: app, scopes: ["read"])
conn =
conn
diff --git a/test/pleroma/web/o_auth/o_auth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs
index 9c1debd06..b7fe5785f 100644
--- a/test/pleroma/web/o_auth/o_auth_controller_test.exs
+++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs
@@ -611,6 +611,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
+ test "authorize from cookie" do
+ user = insert(:user)
+ app = insert(:oauth_app)
+ oauth_token = insert(:oauth_token, user: user, app: app)
+ redirect_uri = OAuthController.default_redirect_uri(app)
+
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session()
+ |> AuthHelper.put_session_token(oauth_token.token)
+ |> post(
+ "/oauth/authorize",
+ %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "client_id" => app.client_id,
+ "redirect_uri" => redirect_uri,
+ "scope" => app.scopes,
+ "state" => "statepassed"
+ }
+ }
+ )
+
+ target = redirected_to(conn)
+ assert target =~ redirect_uri
+
+ query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+ assert %{"state" => "statepassed", "code" => code} = query
+ auth = Repo.get_by(Authorization, token: code)
+ assert auth
+ assert auth.scopes == app.scopes
+ end
+
test "redirect to on two-factor auth page" do
otp_secret = TOTP.generate_secret()
@@ -1221,8 +1256,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
- describe "POST /oauth/revoke - bad request" do
- test "returns 500" do
+ describe "POST /oauth/revoke" do
+ test "returns 500 on bad request" do
response =
build_conn()
|> post("/oauth/revoke", %{})