OpenAPI: TwitterAPI Util Controller
authorHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Wed, 24 Feb 2021 22:40:33 +0000 (23:40 +0100)
committerHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Mon, 15 Mar 2021 05:47:07 +0000 (06:47 +0100)
lib/pleroma/web/api_spec/operations/twitter_util_operation.ex [new file with mode: 0644]
lib/pleroma/web/twitter_api/controllers/util_controller.ex
test/pleroma/web/twitter_api/util_controller_test.exs

diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
new file mode 100644 (file)
index 0000000..62c9826
--- /dev/null
@@ -0,0 +1,219 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
+  alias OpenApiSpex.Operation
+  alias OpenApiSpex.Schema
+  alias Pleroma.Web.ApiSpec.Schemas.ApiError
+  alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
+
+  def open_api_operation(action) do
+    operation = String.to_existing_atom("#{action}_operation")
+    apply(__MODULE__, operation, [])
+  end
+
+  def emoji_operation do
+    %Operation{
+      tags: ["Emojis"],
+      summary: "List all custom emojis",
+      operationId: "UtilController.emoji",
+      parameters: [],
+      responses: %{
+        200 =>
+          Operation.response("List", "application/json", %Schema{
+            type: :object,
+            additionalProperties: %Schema{
+              type: :object,
+              properties: %{
+                image_url: %Schema{type: :string},
+                tags: %Schema{type: :array, items: %Schema{type: :string}}
+              }
+            },
+            example: %{
+              "firefox" => %{
+                "image_url" => "/emoji/firefox.png",
+                "tag" => ["Fun"]
+              }
+            }
+          })
+      }
+    }
+  end
+
+  def frontend_configurations_operation do
+    %Operation{
+      tags: ["Configuration"],
+      summary: "Dump frontend configurations",
+      operationId: "UtilController.frontend_configurations",
+      parameters: [],
+      responses: %{
+        200 =>
+          Operation.response("List", "application/json", %Schema{
+            type: :object,
+            additionalProperties: %Schema{type: :object}
+          })
+      }
+    }
+  end
+
+  def change_password_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Change account password",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.change_password",
+      parameters: [
+        Operation.parameter(:password, :query, :string, "Current password", required: true),
+        Operation.parameter(:new_password, :query, :string, "New password", required: true),
+        Operation.parameter(
+          :new_password_confirmation,
+          :query,
+          :string,
+          "New password, confirmation",
+          required: true
+        )
+      ],
+      responses: %{
+        200 =>
+          Operation.response("Success", "application/json", %Schema{
+            type: :object,
+            properties: %{status: %Schema{type: :string, example: "success"}}
+          }),
+        400 => Operation.response("Error", "application/json", ApiError),
+        403 => Operation.response("Error", "application/json", ApiError)
+      }
+    }
+  end
+
+  def change_email_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Change account email",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.change_email",
+      parameters: [
+        Operation.parameter(:password, :query, :string, "Current password", required: true),
+        Operation.parameter(:email, :query, :string, "New email", required: true)
+      ],
+      requestBody: nil,
+      responses: %{
+        200 =>
+          Operation.response("Success", "application/json", %Schema{
+            type: :object,
+            properties: %{status: %Schema{type: :string, example: "success"}}
+          }),
+        400 => Operation.response("Error", "application/json", ApiError),
+        403 => Operation.response("Error", "application/json", ApiError)
+      }
+    }
+  end
+
+  def update_notificaton_settings_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Update Notification Settings",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.update_notificaton_settings",
+      parameters: [
+        Operation.parameter(
+          :block_from_strangers,
+          :query,
+          BooleanLike,
+          "blocks notifications from accounts you do not follow"
+        ),
+        Operation.parameter(
+          :hide_notification_contents,
+          :query,
+          BooleanLike,
+          "removes the contents of a message from the push notification"
+        )
+      ],
+      requestBody: nil,
+      responses: %{
+        200 =>
+          Operation.response("Success", "application/json", %Schema{
+            type: :object,
+            properties: %{status: %Schema{type: :string, example: "success"}}
+          }),
+        400 => Operation.response("Error", "application/json", ApiError)
+      }
+    }
+  end
+
+  def disable_account_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Disable Account",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.disable_account",
+      parameters: [
+        Operation.parameter(:password, :query, :string, "Password")
+      ],
+      responses: %{
+        200 =>
+          Operation.response("Success", "application/json", %Schema{
+            type: :object,
+            properties: %{status: %Schema{type: :string, example: "success"}}
+          }),
+        403 => Operation.response("Error", "application/json", ApiError)
+      }
+    }
+  end
+
+  def delete_account_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Delete Account",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.delete_account",
+      parameters: [
+        Operation.parameter(:password, :query, :string, "Password")
+      ],
+      responses: %{
+        200 =>
+          Operation.response("Success", "application/json", %Schema{
+            type: :object,
+            properties: %{status: %Schema{type: :string, example: "success"}}
+          }),
+        403 => Operation.response("Error", "application/json", ApiError)
+      }
+    }
+  end
+
+  def captcha_operation do
+    %Operation{
+      summary: "Get a captcha",
+      operationId: "UtilController.captcha",
+      parameters: [],
+      responses: %{
+        200 => Operation.response("Success", "application/json", %Schema{type: :object})
+      }
+    }
+  end
+
+  def healthcheck_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Disable Account",
+      security: [%{"oAuth" => ["write:accounts"]}],
+      operationId: "UtilController.healthcheck",
+      parameters: [],
+      responses: %{
+        200 => Operation.response("Healthy", "application/json", %Schema{type: :object}),
+        503 =>
+          Operation.response("Disabled or Unhealthy", "application/json", %Schema{type: :object})
+      }
+    }
+  end
+
+  def remote_subscribe_operation do
+    %Operation{
+      tags: ["Accounts"],
+      summary: "Remote Subscribe",
+      operationId: "UtilController.remote_subscribe",
+      parameters: [],
+      responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
+    }
+  end
+end
index 60266aaab694112071604995e91c184a11d0587d..a2e69666e46be00c27ce7d93a7a64984d13103d9 100644 (file)
@@ -15,6 +15,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   alias Pleroma.Web.Plugs.OAuthScopesPlug
   alias Pleroma.Web.WebFinger
 
+  plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe)
   plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe)
 
   plug(
@@ -29,6 +30,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
          ]
   )
 
+  defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation
 
   def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
     with %User{} = user <- User.get_cached_by_nickname(nick),
@@ -79,13 +81,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
-  def change_password(%{assigns: %{user: user}} = conn, params) do
-    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+  def change_password(%{assigns: %{user: user}} = conn, %{
+        password: password,
+        new_password: new_password,
+        new_password_confirmation: new_password_confirmation
+      }) do
+    case CommonAPI.Utils.confirm_current_password(user, password) do
       {:ok, user} ->
         with {:ok, _user} <-
                User.reset_password(user, %{
-                 password: params["new_password"],
-                 password_confirmation: params["new_password_confirmation"]
+                 password: new_password,
+                 password_confirmation: new_password_confirmation
                }) do
           json(conn, %{status: "success"})
         else
@@ -102,10 +108,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
-  def change_email(%{assigns: %{user: user}} = conn, params) do
-    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+  def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do
+    case CommonAPI.Utils.confirm_current_password(user, password) do
       {:ok, user} ->
-        with {:ok, _user} <- User.change_email(user, params["email"]) do
+        with {:ok, _user} <- User.change_email(user, email) do
           json(conn, %{status: "success"})
         else
           {:error, changeset} ->
@@ -122,7 +128,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   end
 
   def delete_account(%{assigns: %{user: user}} = conn, params) do
-    password = params["password"] || ""
+    password = params[:password] || ""
 
     case CommonAPI.Utils.confirm_current_password(user, password) do
       {:ok, user} ->
@@ -135,7 +141,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   end
 
   def disable_account(%{assigns: %{user: user}} = conn, params) do
-    case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+    case CommonAPI.Utils.confirm_current_password(user, params[:password]) do
       {:ok, user} ->
         User.set_activation_async(user, false)
         json(conn, %{status: "success"})
index bdbc478c367fb0661e3417c3bf07c34b407c5f86..cc17940b5c078dfc3bf6f05a7de8ddfa47d02228 100644 (file)
@@ -25,11 +25,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
 
     test "it updates notification settings", %{user: user, conn: conn} do
       conn
-      |> put("/api/pleroma/notification_settings", %{
-        "block_from_strangers" => true,
-        "bar" => 1
-      })
-      |> json_response(:ok)
+      |> put(
+        "/api/pleroma/notification_settings?#{
+          URI.encode_query(%{
+            block_from_strangers: true
+          })
+        }"
+      )
+      |> json_response_and_validate_schema(:ok)
 
       user = refresh_record(user)
 
@@ -41,8 +44,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
 
     test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do
       conn
-      |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"})
-      |> json_response(:ok)
+      |> put(
+        "/api/pleroma/notification_settings?#{
+          URI.encode_query(%{
+            hide_notification_contents: 1
+          })
+        }"
+      )
+      |> json_response_and_validate_schema(:ok)
 
       user = refresh_record(user)
 
@@ -70,7 +79,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       response =
         conn
         |> get("/api/pleroma/frontend_configurations")
-        |> json_response(:ok)
+        |> json_response_and_validate_schema(:ok)
 
       assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
     end
@@ -81,7 +90,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       emoji =
         conn
         |> get("/api/pleroma/emoji")
-        |> json_response(200)
+        |> json_response_and_validate_schema(200)
 
       assert Enum.all?(emoji, fn
                {_key,
@@ -103,7 +112,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       response =
         conn
         |> get("/api/pleroma/healthcheck")
-        |> json_response(503)
+        |> json_response_and_validate_schema(503)
 
       assert response == %{}
     end
@@ -116,7 +125,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
         response =
           conn
           |> get("/api/pleroma/healthcheck")
-          |> json_response(200)
+          |> json_response_and_validate_schema(200)
 
         assert %{
                  "active" => _,
@@ -136,7 +145,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
         response =
           conn
           |> get("/api/pleroma/healthcheck")
-          |> json_response(503)
+          |> json_response_and_validate_schema(503)
 
         assert %{
                  "active" => _,
@@ -155,8 +164,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
     test "with valid permissions and password, it disables the account", %{conn: conn, user: user} do
       response =
         conn
-        |> post("/api/pleroma/disable_account", %{"password" => "test"})
-        |> json_response(:ok)
+        |> post("/api/pleroma/disable_account?password=test")
+        |> json_response_and_validate_schema(:ok)
 
       assert response == %{"status" => "success"}
       ObanHelpers.perform_all()
@@ -171,8 +180,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
 
       response =
         conn
-        |> post("/api/pleroma/disable_account", %{"password" => "test1"})
-        |> json_response(:ok)
+        |> post("/api/pleroma/disable_account?password=test1")
+        |> json_response_and_validate_schema(:ok)
 
       assert response == %{"error" => "Invalid password."}
       user = User.get_cached_by_id(user.id)
@@ -252,54 +261,61 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       conn =
         conn
         |> assign(:token, nil)
-        |> post("/api/pleroma/change_email")
-
-      assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+        |> post(
+          "/api/pleroma/change_email?#{
+            URI.encode_query(%{password: "hi", email: "test@test.com"})
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 403) == %{
+               "error" => "Insufficient permissions: write:accounts."
+             }
     end
 
     test "with proper permissions and invalid password", %{conn: conn} do
       conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "hi",
-          "email" => "test@test.com"
-        })
-
-      assert json_response(conn, 200) == %{"error" => "Invalid password."}
+        post(
+          conn,
+          "/api/pleroma/change_email?#{
+            URI.encode_query(%{password: "hi", email: "test@test.com"})
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
     end
 
     test "with proper permissions, valid password and invalid email", %{
       conn: conn
     } do
       conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "test",
-          "email" => "foobar"
-        })
+        post(
+          conn,
+          "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: "foobar"})}"
+        )
 
-      assert json_response(conn, 200) == %{"error" => "Email has invalid format."}
+      assert json_response_and_validate_schema(conn, 200) == %{
+               "error" => "Email has invalid format."
+             }
     end
 
     test "with proper permissions, valid password and no email", %{
       conn: conn
     } do
-      conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "test"
-        })
+      conn = post(conn, "/api/pleroma/change_email?#{URI.encode_query(%{password: "test"})}")
 
-      assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+      assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400)
     end
 
     test "with proper permissions, valid password and blank email", %{
       conn: conn
     } do
       conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "test",
-          "email" => ""
-        })
+        post(
+          conn,
+          "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: ""})}"
+        )
 
-      assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+      assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."}
     end
 
     test "with proper permissions, valid password and non unique email", %{
@@ -308,24 +324,28 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       user = insert(:user)
 
       conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "test",
-          "email" => user.email
-        })
+        post(
+          conn,
+          "/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: user.email})}"
+        )
 
-      assert json_response(conn, 200) == %{"error" => "Email has already been taken."}
+      assert json_response_and_validate_schema(conn, 200) == %{
+               "error" => "Email has already been taken."
+             }
     end
 
     test "with proper permissions, valid password and valid email", %{
       conn: conn
     } do
       conn =
-        post(conn, "/api/pleroma/change_email", %{
-          "password" => "test",
-          "email" => "cofe@foobar.com"
-        })
-
-      assert json_response(conn, 200) == %{"status" => "success"}
+        post(
+          conn,
+          "/api/pleroma/change_email?#{
+            URI.encode_query(%{password: "test", email: "cofe@foobar.com"})
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
     end
   end
 
@@ -336,20 +356,35 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       conn =
         conn
         |> assign(:token, nil)
-        |> post("/api/pleroma/change_password")
-
-      assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+        |> post(
+          "/api/pleroma/change_password?#{
+            URI.encode_query(%{
+              password: "hi",
+              new_password: "newpass",
+              new_password_confirmation: "newpass"
+            })
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 403) == %{
+               "error" => "Insufficient permissions: write:accounts."
+             }
     end
 
     test "with proper permissions and invalid password", %{conn: conn} do
       conn =
-        post(conn, "/api/pleroma/change_password", %{
-          "password" => "hi",
-          "new_password" => "newpass",
-          "new_password_confirmation" => "newpass"
-        })
-
-      assert json_response(conn, 200) == %{"error" => "Invalid password."}
+        post(
+          conn,
+          "/api/pleroma/change_password?#{
+            URI.encode_query(%{
+              password: "hi",
+              new_password: "newpass",
+              new_password_confirmation: "newpass"
+            })
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
     end
 
     test "with proper permissions, valid password and new password and confirmation not matching",
@@ -357,13 +392,18 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
            conn: conn
          } do
       conn =
-        post(conn, "/api/pleroma/change_password", %{
-          "password" => "test",
-          "new_password" => "newpass",
-          "new_password_confirmation" => "notnewpass"
-        })
-
-      assert json_response(conn, 200) == %{
+        post(
+          conn,
+          "/api/pleroma/change_password?#{
+            URI.encode_query(%{
+              password: "test",
+              new_password: "newpass",
+              new_password_confirmation: "notnewpass"
+            })
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{
                "error" => "New password does not match confirmation."
              }
     end
@@ -372,13 +412,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       conn: conn
     } do
       conn =
-        post(conn, "/api/pleroma/change_password", %{
-          "password" => "test",
-          "new_password" => "",
-          "new_password_confirmation" => ""
-        })
-
-      assert json_response(conn, 200) == %{
+        post(
+          conn,
+          "/api/pleroma/change_password?#{
+            URI.encode_query(%{password: "test", new_password: "", new_password_confirmation: ""})
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{
                "error" => "New password can't be blank."
              }
     end
@@ -388,13 +429,18 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       user: user
     } do
       conn =
-        post(conn, "/api/pleroma/change_password", %{
-          "password" => "test",
-          "new_password" => "newpass",
-          "new_password_confirmation" => "newpass"
-        })
-
-      assert json_response(conn, 200) == %{"status" => "success"}
+        post(
+          conn,
+          "/api/pleroma/change_password?#{
+            URI.encode_query(%{
+              password: "test",
+              new_password: "newpass",
+              new_password_confirmation: "newpass"
+            })
+          }"
+        )
+
+      assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
       fetched_user = User.get_cached_by_id(user.id)
       assert Pleroma.Password.Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true
     end
@@ -409,7 +455,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
         |> assign(:token, nil)
         |> post("/api/pleroma/delete_account")
 
-      assert json_response(conn, 403) ==
+      assert json_response_and_validate_schema(conn, 403) ==
                %{"error" => "Insufficient permissions: write:accounts."}
     end
 
@@ -417,14 +463,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       for params <- [%{"password" => "hi"}, %{}] do
         ret_conn = post(conn, "/api/pleroma/delete_account", params)
 
-        assert json_response(ret_conn, 200) == %{"error" => "Invalid password."}
+        assert json_response_and_validate_schema(ret_conn, 200) == %{
+                 "error" => "Invalid password."
+               }
       end
     end
 
     test "with proper permissions and valid password", %{conn: conn, user: user} do
-      conn = post(conn, "/api/pleroma/delete_account", %{"password" => "test"})
+      conn = post(conn, "/api/pleroma/delete_account?password=test")
       ObanHelpers.perform_all()
-      assert json_response(conn, 200) == %{"status" => "success"}
+      assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
 
       user = User.get_by_id(user.id)
       refute user.is_active