Merge branch 'webhooks_' into fork

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-03-14 23:06:25 +01:00
commit e9e2b18650
6 changed files with 187 additions and 2 deletions

1
changelog.d/webhooks.add Normal file
View file

@ -0,0 +1 @@
Add support for Mastodon-compatible webhooks

View file

@ -1751,3 +1751,92 @@ Note that this differs from the Mastodon API variant: Mastodon API only returns
```json
{}
```
## `GET /api/v1/pleroma/admin/webhooks`
### List webhooks
- Method: `GET`
- Response:
```json
[
{
"enabled": true,
"id": "2",
"events": ["account.created"],
"url": "https://webhook.example/",
"secret": "eb85d4ccd8510e78f912743949dc354e8146987d",
"updated_at": "2022-10-29T17:44:16.000Z",
"created_at": "2022-10-29T17:44:13.000Z"
}
]
```
## `GET /api/v1/pleroma/admin/webhooks/:id`
### Get an individual webhook
- Method: `GET`
- Params:
- `id`: **string** Webhook ID
- Response: A webhook
## `POST /api/v1/pleroma/admin/webhooks`
### Create a webhook
- Method: `POST`
- Params:
- `url`: **string** Webhook URL
- *optional* `events`: **[string]** Types of events to trigger on (`account.created`, `report.created`)
- *optional* `enabled`: **boolean** Whether webhook is enabled
- Response: A webhook
## `PATCH /api/v1/pleroma/admin/webhooks/:id`
### Update a webhook
- Method: `PATCH`
- Params:
- `id`: **string** Webhook ID
- *optional* `url`: **string** Webhook URL
- *optional* `events`: **[string]** Types of events to trigger on (`account.created`, `report.created`)
- *optional* `enabled`: **boolean** Whether webhook is enabled
- Response: A webhook
## `DELETE /api/v1/pleroma/admin/webhooks/:id`
### Delete a webhook
- Method: `DELETE`
- Params:
- `id`: **string** Webhook ID
- Response: A webhook
## `POST /api/v1/pleroma/admin/webhooks/:id/enable`
### Activate a webhook
- Method: `POST`
- Params:
- `id`: **string** Webhook ID
- Response: A webhook
## `POST /api/v1/pleroma/admin/webhooks/:id/disable`
### Deactivate a webhook
- Method: `POST`
- Params:
- `id`: **string** Webhook ID
- Response: A webhook
## `POST /api/v1/pleroma/admin/webhooks/:id/rotate_secret`
### Rotate webhook signing secret
- Method: `POST`
- Params:
- `id`: **string** Webhook ID
- Response: A webhook

View file

@ -317,6 +317,15 @@ defmodule Pleroma.Web.Router do
get("/announcements/:id", AnnouncementController, :show)
patch("/announcements/:id", AnnouncementController, :change)
delete("/announcements/:id", AnnouncementController, :delete)
get("/webhooks", WebhookController, :index)
get("/webhooks/:id", WebhookController, :show)
post("/webhooks", WebhookController, :create)
patch("/webhooks/:id", WebhookController, :update)
delete("/webhooks/:id", WebhookController, :delete)
post("/webhooks/:id/enable", WebhookController, :enable)
post("/webhooks/:id/disable", WebhookController, :disable)
post("/webhooks/:id/rotate_secret", WebhookController, :rotate_secret)
end
# AdminAPI: admins and mods (staff) can perform these actions (if privileged by role)

View file

@ -33,7 +33,7 @@ def get_by_type(type) do
def changeset(%__MODULE__{} = webhook, params) do
webhook
|> cast(params, [:url, :events, :enabled, :internal])
|> cast(params, [:url, :events, :enabled])
|> validate_required([:url, :events])
|> unique_constraint(:url)
|> strip_events()
@ -42,7 +42,7 @@ def changeset(%__MODULE__{} = webhook, params) do
def update_changeset(%__MODULE__{} = webhook, params \\ %{}) do
webhook
|> cast(params, [:url, :events, :enabled, :internal])
|> cast(params, [:url, :events, :enabled])
|> unique_constraint(:url)
|> strip_events()
end

View file

@ -0,0 +1,29 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Webhook.NotifyTest do
use Pleroma.DataCase, async: true
alias Pleroma.Webhook
alias Pleroma.Webhook.Notify
import Pleroma.Factory
test "notifies have a valid signature" do
activity = insert(:report_activity)
%{secret: secret} =
webhook = Webhook.create(%{url: "https://example.com/webhook", events: [:"report.created"]})
Tesla.Mock.mock(fn %{url: "https://example.com/webhook", body: body, headers: headers} = _ ->
{"X-Hub-Signature", "sha256=" <> signature} =
Enum.find(headers, fn {key, _} -> key == "X-Hub-Signature" end)
assert signature == :crypto.mac(:hmac, :sha256, secret, body) |> Base.encode16()
%Tesla.Env{status: 200, body: ""}
end)
Notify.report_created(webhook, activity)
end
end

View file

@ -0,0 +1,57 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.WebhookTest do
use Pleroma.DataCase, async: true
alias Pleroma.Repo
alias Pleroma.Webhook
test "creating a webhook" do
%{id: id} = Webhook.create(%{url: "https://example.com/webhook", events: [:"report.created"]})
assert %{url: "https://example.com/webhook"} = Webhook.get(id)
end
test "editing a webhook" do
%{id: id} =
webhook = Webhook.create(%{url: "https://example.com/webhook", events: [:"report.created"]})
Webhook.update(webhook, %{events: [:"account.created"]})
assert %{events: [:"account.created"]} = Webhook.get(id)
end
test "filter webhooks by type" do
%{id: id1} =
Webhook.create(%{url: "https://example.com/webhook1", events: [:"report.created"]})
%{id: id2} =
Webhook.create(%{
url: "https://example.com/webhook2",
events: [:"account.created", :"report.created"]
})
Webhook.create(%{url: "https://example.com/webhook3", events: [:"account.created"]})
assert [%{id: ^id1}, %{id: ^id2}] = Webhook.get_by_type(:"report.created")
end
test "change webhook state" do
%{id: id, enabled: true} =
webhook = Webhook.create(%{url: "https://example.com/webhook", events: [:"report.created"]})
Webhook.set_enabled(webhook, false)
assert %{enabled: false} = Webhook.get(id)
end
test "rotate webhook secrets" do
%{id: id, secret: secret} =
webhook = Webhook.create(%{url: "https://example.com/webhook", events: [:"report.created"]})
Webhook.rotate_secret(webhook)
%{secret: new_secret} = Webhook.get(id)
assert secret != new_secret
end
end