Merge branch 'webhooks_' into fork
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
e9e2b18650
6 changed files with 187 additions and 2 deletions
1
changelog.d/webhooks.add
Normal file
1
changelog.d/webhooks.add
Normal file
|
@ -0,0 +1 @@
|
|||
Add support for Mastodon-compatible webhooks
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
29
test/pleroma/webhook/notify_test.ex
Normal file
29
test/pleroma/webhook/notify_test.ex
Normal 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
|
57
test/pleroma/webhook_test.ex
Normal file
57
test/pleroma/webhook_test.ex
Normal 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
|
Loading…
Reference in a new issue