diff --git a/changelog.d/mrf-quietreply.add b/changelog.d/mrf-quietreply.add new file mode 100644 index 000000000..4ed20bce6 --- /dev/null +++ b/changelog.d/mrf-quietreply.add @@ -0,0 +1 @@ +Added MRF.QuietReply which prevents replies to public posts from being published to the timelines diff --git a/test/pleroma/web/o_auth/oauth_authorization_flow_test.exs b/test/pleroma/web/o_auth/oauth_authorization_flow_test.exs deleted file mode 100644 index fdd8cbdb4..000000000 --- a/test/pleroma/web/o_auth/oauth_authorization_flow_test.exs +++ /dev/null @@ -1,339 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.OAuthAuthorizationFlowTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Helpers.AuthHelper - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.OAuth.App - alias Pleroma.Web.OAuth.Authorization - alias Pleroma.Web.OAuth.OAuthController - alias Pleroma.Web.OAuth.Token - - @session_opts [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - setup do - clear_config([:instance, :account_activation_required], false) - clear_config([:instance, :account_approval_required], false) - end - - describe "OAuth authorization flow with external integration" do - test "complete OAuth flow: create user, create app, authorize, get token, use token" do - # Step 1: Create a user - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - # Step 2: Create a new OAuth client with the required scopes - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - redirect_uris: "urn:ietf:wg:oauth:2.0:oob" - ) - - # Step 3: Set up a logged in session - conn = - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> AuthHelper.put_session_token(insert(:oauth_token, user: user).token) - - # Step 4: Access the /oauth/authorize endpoint with the specified parameters - authorize_params = %{ - "client_id" => app.client_id, - "response_type" => "code", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "force_login" => "False", - "state" => "None", - "lang" => "None" - } - - # First, get the authorization page - conn = get(conn, "/oauth/authorize", authorize_params) - assert html_response(conn, 200) - - # Step 5: Submit the authorization (simulate user approving the app) - authorization_data = %{ - "authorization" => %{ - "client_id" => app.client_id, - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "state" => "None" - } - } - - conn = post(conn, "/oauth/authorize", authorization_data) - - # Should get the OOB authorization page with the code - assert html_response(conn, 200) - - # Extract the authorization code from the response - response = html_response(conn, 200) - assert response =~ "Successfully authorized" - assert response =~ "Token code is" - - # Parse the authorization code from the response - code_match = Regex.run(~r/Token code is
([a-zA-Z0-9_-]+)/, response) - assert code_match - [_, authorization_code] = code_match - - # Step 6: Exchange the authorization code for an access token - token_conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => authorization_code, - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - token_response = json_response(token_conn, 200) - assert %{"access_token" => access_token, "token_type" => "Bearer"} = token_response - assert token_response["scope"] == "read write follow push" - - # Verify the token was created in the database - token_record = Repo.get_by(Token, token: access_token) - assert token_record - assert token_record.scopes == ["read", "write", "follow", "push"] - assert token_record.user_id == user.id - assert token_record.app_id == app.id - - # Step 7: Use the token to access a protected endpoint - protected_conn = - build_conn() - |> put_req_header("authorization", "Bearer #{access_token}") - |> get("/api/v1/accounts/verify_credentials") - - # Should get a 200 response with user information - user_info = json_response(protected_conn, 200) - assert user_info["id"] == to_string(user.id) - assert user_info["username"] == user.nickname - assert user_info["acct"] == user.nickname - - # Step 8: Test that the token has the correct scopes by accessing different endpoints - # Test read:accounts scope (should work) - conn_with_token = - build_conn() - |> put_req_header("authorization", "Bearer #{access_token}") - - # This should work because we have "read" scope - conn_with_token - |> get("/api/v1/accounts/#{user.id}") - |> json_response(200) - - # Test write:accounts scope (should work) - with proper content-type - conn_with_token - |> put_req_header("content-type", "application/json") - |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "Test Name"}) - |> json_response(200) - - # Test that the token is properly associated with the user - assert token_record.user_id == user.id - assert token_record.app_id == app.id - end - - test "OAuth flow with force_login=false and existing session" do - # Create a user and app - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - redirect_uris: "urn:ietf:wg:oauth:2.0:oob" - ) - - # Create an existing token for the same user and app - existing_token = insert(:oauth_token, user: user, app: app, scopes: ["read", "write"]) - - # Set up a logged in session with the existing token - conn = - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> AuthHelper.put_session_token(existing_token.token) - - # Access the authorize endpoint with force_login=false - authorize_params = %{ - "client_id" => app.client_id, - "response_type" => "code", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "force_login" => "False", - "state" => "test_state" - } - - # Should redirect to the OOB page with the existing token - conn = get(conn, "/oauth/authorize", authorize_params) - assert html_response(conn, 200) - assert html_response(conn, 200) =~ "Authorization exists" - end - - test "OAuth flow with different scopes than existing token" do - # Create a user and app - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - redirect_uris: "urn:ietf:wg:oauth:2.0:oob" - ) - - # Create an existing token with different scopes - existing_token = insert(:oauth_token, user: user, app: app, scopes: ["read"]) - - # Set up a logged in session - conn = - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> AuthHelper.put_session_token(existing_token.token) - - # Access the authorize endpoint requesting more scopes - authorize_params = %{ - "client_id" => app.client_id, - "response_type" => "code", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "force_login" => "False", - "state" => "test_state" - } - - # Should show the authorization page because scopes are different - conn = get(conn, "/oauth/authorize", authorize_params) - assert html_response(conn, 200) - assert html_response(conn, 200) =~ "Authorization exists" - end - - test "OAuth flow with invalid client_id" do - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - conn = - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> AuthHelper.put_session_token(insert(:oauth_token, user: user).token) - - # Try to authorize with invalid client_id - authorize_params = %{ - "client_id" => "invalid_client_id", - "response_type" => "code", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "force_login" => "False" - } - - conn = get(conn, "/oauth/authorize", authorize_params) - # Should still render the page but with error or missing app info - assert html_response(conn, 200) - end - - test "OAuth flow with unlisted redirect_uri" do - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - # Different from requested - redirect_uris: "https://example.com/callback" - ) - - conn = - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - |> AuthHelper.put_session_token(insert(:oauth_token, user: user).token) - - # Try to authorize with unlisted redirect_uri - authorize_params = %{ - "client_id" => app.client_id, - "response_type" => "code", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read write follow push", - "force_login" => "False" - } - - conn = get(conn, "/oauth/authorize", authorize_params) - # Should still render the page but with error about unlisted redirect_uri - assert html_response(conn, 200) - end - - test "OAuth flow with expired authorization code" do - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - redirect_uris: "urn:ietf:wg:oauth:2.0:oob" - ) - - # Create an expired authorization - expired_auth = - insert(:oauth_authorization, - user: user, - app: app, - # 1 hour ago - valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -3600), - scopes: ["read", "write", "follow", "push"] - ) - - # Try to exchange expired code for token - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => expired_auth.token, - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - # Should get an error - response = json_response(conn, 400) - assert %{"error" => _} = response - end - - test "OAuth flow with used authorization code" do - user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test")) - - app = - insert(:oauth_app, - scopes: ["read", "write", "follow", "push"], - redirect_uris: "urn:ietf:wg:oauth:2.0:oob" - ) - - # Create an authorization and mark it as used - auth = - insert(:oauth_authorization, - user: user, - app: app, - scopes: ["read", "write", "follow", "push"] - ) - - {:ok, _} = Authorization.use_token(auth) - - # Try to exchange used code for token - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => auth.token, - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - # Should get an error - response = json_response(conn, 400) - assert %{"error" => _} = response - end - end -end