From 719b5d65b545403adf5fcfbec5571936b5165be1 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 26 May 2026 14:30:50 +0400 Subject: [PATCH] Require webhook events --- docs/development/API/admin_api.md | 2 +- .../operations/admin/webhook_operation.ex | 10 +++++----- lib/pleroma/webhook.ex | 11 +++++++++++ test/pleroma/webhook_test.exs | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md index a30db9bad..ec58e8c19 100644 --- a/docs/development/API/admin_api.md +++ b/docs/development/API/admin_api.md @@ -1877,7 +1877,7 @@ Note that this differs from the Mastodon API variant: Mastodon API only returns - Method: `POST` - Params: - `url`: **string** Webhook URL - - *optional* `events`: **[string]** Types of events to trigger on (`account.created`, `report.created`) + - `events`: **[string]** Types of events to trigger on (`account.created`, `report.created`) - *optional* `enabled`: **boolean** Whether webhook is enabled - Response: A webhook diff --git a/lib/pleroma/web/api_spec/operations/admin/webhook_operation.ex b/lib/pleroma/web/api_spec/operations/admin/webhook_operation.ex index fd5f3a561..e2869ac44 100644 --- a/lib/pleroma/web/api_spec/operations/admin/webhook_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/webhook_operation.ex @@ -55,9 +55,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.WebhookOperation do %Schema{ description: "POST body for creating a webhook", type: :object, + required: [:url, :events], properties: %{ - url: %Schema{type: :string, format: :uri, required: true}, - events: event_type(true), + url: %Schema{type: :string, format: :uri}, + events: event_type(), enabled: %Schema{type: :boolean} } } @@ -179,15 +180,14 @@ defmodule Pleroma.Web.ApiSpec.Admin.WebhookOperation do } end - defp event_type(required \\ nil) do + defp event_type do %Schema{ type: :array, items: %Schema{ title: "Event", description: "Event type", type: :string, - enum: ["account.created", "report.created"], - required: required + enum: ["account.created", "report.created"] } } end diff --git a/lib/pleroma/webhook.ex b/lib/pleroma/webhook.ex index 9a1806f71..f4d65b1a6 100644 --- a/lib/pleroma/webhook.ex +++ b/lib/pleroma/webhook.ex @@ -36,6 +36,7 @@ defmodule Pleroma.Webhook do webhook |> cast(params, [:url, :events, :enabled, :internal]) |> validate_required([:url, :events]) + |> validate_events_present() |> unique_constraint(:url) |> put_secret() end @@ -43,6 +44,7 @@ defmodule Pleroma.Webhook do def update_changeset(%__MODULE__{} = webhook, params \\ %{}) do webhook |> cast(params, [:url, :events, :enabled, :internal]) + |> validate_events_present() |> unique_constraint(:url) end @@ -73,6 +75,15 @@ defmodule Pleroma.Webhook do |> Repo.update() end + defp validate_events_present(changeset) do + cond do + Keyword.has_key?(changeset.errors, :events) -> changeset + get_field(changeset, :internal) -> changeset + match?([_ | _], get_field(changeset, :events)) -> changeset + true -> add_error(changeset, :events, "can't be blank") + end + end + defp put_secret(changeset) do changeset |> put_change(:secret, generate_secret()) diff --git a/test/pleroma/webhook_test.exs b/test/pleroma/webhook_test.exs index 1f64d350f..df84abef6 100644 --- a/test/pleroma/webhook_test.exs +++ b/test/pleroma/webhook_test.exs @@ -33,6 +33,24 @@ defmodule Pleroma.WebhookTest do assert {:error, _changeset} = Webhook.update(webhook, %{events: [:"status.created"]}) end + test "rejects empty events for non-internal webhooks" do + assert {:error, changeset} = Webhook.create(%{url: "https://example.com/webhook", events: []}) + assert %{events: ["can't be blank"]} = errors_on(changeset) + + {:ok, webhook} = + Webhook.create(%{url: "https://example.com/valid-webhook", events: [:"report.created"]}) + + assert {:error, changeset} = Webhook.update(webhook, %{events: []}) + assert %{events: ["can't be blank"]} = errors_on(changeset) + + assert {:ok, _webhook} = + Webhook.create(%{ + url: "https://example.com/internal-webhook", + events: [], + internal: true + }) + end + test "filter webhooks by type" do {:ok, %{id: id1}} = Webhook.create(%{url: "https://example.com/webhook1", events: [:"report.created"]})