OpenAPI: TwitterAPI Util Controller

This commit is contained in:
Haelwenn (lanodan) Monnier 2021-02-24 23:40:33 +01:00
parent 3732c51cf7
commit 0e511d7b80
No known key found for this signature in database
GPG Key ID: D5B7A8E43C997DEE
3 changed files with 385 additions and 87 deletions

View File

@ -0,0 +1,244 @@
# 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 notifications_read_operation do
%Operation{
tags: ["Notifications"],
summary: "Mark notification as read",
security: [%{"oAuth" => ["write:notifications"]}],
operationId: "UtilController.notifications_read",
parameters: [
Operation.parameter(
:id,
:query,
:integer,
"ID of the notification"
)
],
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 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

View 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"})

View 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")
|> post(
"/api/pleroma/change_email?#{
URI.encode_query(%{password: "hi", email: "test@test.com"})
}"
)
assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
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"
})
post(
conn,
"/api/pleroma/change_email?#{
URI.encode_query(%{password: "hi", email: "test@test.com"})
}"
)
assert json_response(conn, 200) == %{"error" => "Invalid password."}
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"
})
post(
conn,
"/api/pleroma/change_email?#{
URI.encode_query(%{password: "test", email: "cofe@foobar.com"})
}"
)
assert json_response(conn, 200) == %{"status" => "success"}
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")
|> post(
"/api/pleroma/change_password?#{
URI.encode_query(%{
password: "hi",
new_password: "newpass",
new_password_confirmation: "newpass"
})
}"
)
assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
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"
})
post(
conn,
"/api/pleroma/change_password?#{
URI.encode_query(%{
password: "hi",
new_password: "newpass",
new_password_confirmation: "newpass"
})
}"
)
assert json_response(conn, 200) == %{"error" => "Invalid password."}
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"
})
post(
conn,
"/api/pleroma/change_password?#{
URI.encode_query(%{
password: "test",
new_password: "newpass",
new_password_confirmation: "notnewpass"
})
}"
)
assert json_response(conn, 200) == %{
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" => ""
})
post(
conn,
"/api/pleroma/change_password?#{
URI.encode_query(%{password: "test", new_password: "", new_password_confirmation: ""})
}"
)
assert json_response(conn, 200) == %{
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"
})
post(
conn,
"/api/pleroma/change_password?#{
URI.encode_query(%{
password: "test",
new_password: "newpass",
new_password_confirmation: "newpass"
})
}"
)
assert json_response(conn, 200) == %{"status" => "success"}
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