103 lines
2.8 KiB
Elixir
103 lines
2.8 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2021 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: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
|