diff options
Diffstat (limited to 'lib/pleroma/web/push/subscription.ex')
| -rw-r--r-- | lib/pleroma/web/push/subscription.ex | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex new file mode 100644 index 0000000..6fc45bd --- /dev/null +++ b/lib/pleroma/web/push/subscription.ex @@ -0,0 +1,102 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Push.Subscription do + use Ecto.Schema + + import Ecto.Changeset + + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.Push.Subscription + + @type t :: %__MODULE__{} + + schema "push_subscriptions" do + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:token, Token) + field(:endpoint, :string) + field(:key_p256dh, :string) + field(:key_auth, :string) + field(:data, :map, default: %{}) + + timestamps() + end + + # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength + @supported_alert_types ~w[follow favourite mention reblog poll pleroma:chat_mention pleroma:emoji_reaction]a + + defp alerts(%{data: %{alerts: alerts}}) do + alerts = Map.take(alerts, @supported_alert_types) + %{"alerts" => alerts} + end + + def enabled?(subscription, "follow_request") do + enabled?(subscription, "follow") + end + + def enabled?(subscription, alert_type) do + get_in(subscription.data, ["alerts", alert_type]) + end + + def create( + %User{} = user, + %Token{} = token, + %{ + subscription: %{ + endpoint: endpoint, + keys: %{auth: key_auth, p256dh: key_p256dh} + } + } = params + ) do + Repo.insert(%Subscription{ + user_id: user.id, + token_id: token.id, + endpoint: endpoint, + key_auth: ensure_base64_urlsafe(key_auth), + key_p256dh: ensure_base64_urlsafe(key_p256dh), + data: alerts(params) + }) + end + + @doc "Gets subsciption by user & token" + @spec get(User.t(), Token.t()) :: {:ok, t()} | {:error, :not_found} + def get(%User{id: user_id}, %Token{id: token_id}) do + case Repo.get_by(Subscription, user_id: user_id, token_id: token_id) do + nil -> {:error, :not_found} + subscription -> {:ok, subscription} + end + end + + def update(user, token, params) do + with {:ok, subscription} <- get(user, token) do + subscription + |> change(data: alerts(params)) + |> Repo.update() + end + end + + def delete(user, token) do + with {:ok, subscription} <- get(user, token), + do: Repo.delete(subscription) + end + + def delete_if_exists(user, token) do + case get(user, token) do + {:error, _} -> {:ok, nil} + {:ok, sub} -> Repo.delete(sub) + end + end + + # Some webpush clients (e.g. iOS Toot!) use an non urlsafe base64 as an encoding for the key. + # However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library + # we use requires the key to be properly encoded. So we just convert base64 to urlsafe base64. + defp ensure_base64_urlsafe(string) do + string + |> String.replace("+", "-") + |> String.replace("/", "_") + |> String.replace("=", "") + end +end |
