summaryrefslogtreecommitdiff
path: root/lib/pleroma/web/push/push.ex
blob: 5a873ec19cf3231c4079ef731e71c7525ce983b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
defmodule Pleroma.Web.Push do
  use GenServer

  alias Pleroma.{Repo, User}
  alias Pleroma.Web.Push.Subscription

  require Logger
  import Ecto.Query

  @types ["Create", "Follow", "Announce", "Like"]

  @gcm_api_key nil

  def start_link() do
    GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    case Application.get_env(:web_push_encryption, :vapid_details) do
      nil ->
        Logger.warn(
          "VAPID key pair is not found. Please, add VAPID configuration to config. Run `mix web_push.gen.keypair` mix task to create a key pair"
        )

        :ignore

      _ ->
        {:ok, %{}}
    end
  end

  def send(notification) do
    if Application.get_env(:web_push_encryption, :vapid_details) do
      GenServer.cast(Pleroma.Web.Push, {:send, notification})
    end
  end

  def handle_cast(
        {:send, %{activity: %{data: %{"type" => type}}, user_id: user_id} = notification},
        state
      )
      when type in @types do
    actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
    body = notification |> format(actor) |> Jason.encode!()

    Subscription
    |> where(user_id: ^user_id)
    |> Repo.all()
    |> Enum.each(fn record ->
      subscription = %{
        keys: %{
          p256dh: record.key_p256dh,
          auth: record.key_auth
        },
        endpoint: record.endpoint
      }

      case WebPushEncryption.send_web_push(body, subscription, @gcm_api_key) do
        {:ok, %{status_code: code}} when 400 <= code and code < 500 ->
          Logger.debug("Removing subscription record")
          Repo.delete!(record)
          :ok

        {:ok, %{status_code: code}} when 200 <= code and code < 300 ->
          :ok

        {:ok, %{status_code: code}} ->
          Logger.error("Web Push Nonification failed with code: #{code}")
          :error

        _ ->
          Logger.error("Web Push Nonification failed with unknown error")
          :error
      end
    end)

    {:noreply, state}
  end

  def handle_cast({:send, _}, state) do
    Logger.warn("Unknown notification type")
    {:noreply, state}
  end

  def format(%{activity: %{data: %{"type" => "Create"}}}, actor) do
    %{
      title: "New Mention",
      body: "@#{actor.nickname} has mentiond you",
      icon: User.avatar_url(actor)
    }
  end

  def format(%{activity: %{data: %{"type" => "Follow"}}}, actor) do
    %{
      title: "New Follower",
      body: "@#{actor.nickname} has followed you",
      icon: User.avatar_url(actor)
    }
  end

  def format(%{activity: %{data: %{"type" => "Announce"}}}, actor) do
    %{
      title: "New Announce",
      body: "@#{actor.nickname} has announced your post",
      icon: User.avatar_url(actor)
    }
  end

  def format(%{activity: %{data: %{"type" => "Like"}}}, actor) do
    %{
      title: "New Like",
      body: "@#{actor.nickname} has liked your post",
      icon: User.avatar_url(actor)
    }
  end
end