diff options
author | Egor Kislitsyn <egor@kislitsyn.com> | 2018-12-06 19:29:04 +0700 |
---|---|---|
committer | Egor Kislitsyn <egor@kislitsyn.com> | 2018-12-06 19:29:04 +0700 |
commit | 04a48286e69704bf83429b85dbcdb70863bdcff1 (patch) | |
tree | 739a259dc937d1da0e59db0353c44b88649b5f2a /lib | |
parent | d94ee5cd50005a947c3c3a734b086fd5cd266c8d (diff) | |
download | pleroma-04a48286e69704bf83429b85dbcdb70863bdcff1.tar.gz |
Add web push support
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mix/tasks/generate_config.ex | 6 | ||||
-rw-r--r-- | lib/mix/tasks/sample_config.eex | 6 | ||||
-rw-r--r-- | lib/pleroma/application.ex | 3 | ||||
-rw-r--r-- | lib/pleroma/notification.ex | 1 | ||||
-rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/web/push/push.ex | 126 | ||||
-rw-r--r-- | lib/pleroma/web/push/subscription.ex | 2 | ||||
-rw-r--r-- | lib/pleroma/web/twitter_api/controllers/util_controller.ex | 6 |
8 files changed, 150 insertions, 6 deletions
diff --git a/lib/mix/tasks/generate_config.ex b/lib/mix/tasks/generate_config.ex index 70a110561..58ce3113b 100644 --- a/lib/mix/tasks/generate_config.ex +++ b/lib/mix/tasks/generate_config.ex @@ -14,6 +14,8 @@ defmodule Mix.Tasks.GenerateConfig do resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", dbpass: dbpass) + {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1) + result = EEx.eval_file( "lib/mix/tasks/sample_config.eex", @@ -21,7 +23,9 @@ defmodule Mix.Tasks.GenerateConfig do email: email, name: name, secret: secret, - dbpass: dbpass + dbpass: dbpass, + web_push_public_key: Base.url_encode64(web_push_public_key, padding: false), + web_push_private_key: Base.url_encode64(web_push_private_key, padding: false) ) IO.puts( diff --git a/lib/mix/tasks/sample_config.eex b/lib/mix/tasks/sample_config.eex index 3881ead26..f2272b10a 100644 --- a/lib/mix/tasks/sample_config.eex +++ b/lib/mix/tasks/sample_config.eex @@ -25,6 +25,12 @@ config :pleroma, Pleroma.Repo, hostname: "localhost", pool_size: 10 +# Configure web push notifications +config :web_push_encryption, :vapid_details, + subject: "mailto:<%= email %>", + public_key: "<%= web_push_public_key %>", + private_key: "<%= web_push_private_key %>" + # Configure S3 support if desired. # The public S3 endpoint is different depending on region and provider, # consult your S3 provider's documentation for details on what to use. diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index a89728471..565e938fd 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -41,7 +41,8 @@ defmodule Pleroma.Application do ), worker(Pleroma.Web.Federator, []), worker(Pleroma.Gopher.Server, []), - worker(Pleroma.Stats, []) + worker(Pleroma.Stats, []), + worker(Pleroma.Web.Push, []) ] ++ if Mix.env() == :test, do: [], diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index e0dcd9823..6163413c8 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -96,6 +96,7 @@ defmodule Pleroma.Notification do notification = %Notification{user_id: user.id, activity: activity} {:ok, notification} = Repo.insert(notification) Pleroma.Web.Streamer.stream("user", notification) + Pleroma.Web.Push.send(notification) notification end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 7f06ee607..de5b2696f 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1138,6 +1138,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, %{}) end + alias Pleroma.Web.MastodonAPI.PushSubscriptionView + def create_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do Pleroma.Web.Push.Subscription.delete_if_exists(user, token) {:ok, subscription} = Pleroma.Web.Push.Subscription.create(user, token, params) @@ -1145,7 +1147,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, view) end - def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do + def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do subscription = Pleroma.Web.Push.Subscription.get(user, token) view = PushSubscriptionView.render("push_subscription.json", subscription: subscription) json(conn, view) @@ -1160,7 +1162,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, view) end - def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do + def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do {:ok, _response} = Pleroma.Web.Push.Subscription.delete(user, token) json(conn, %{}) end diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex new file mode 100644 index 000000000..d27750ab6 --- /dev/null +++ b/lib/pleroma/web/push/push.ex @@ -0,0 +1,126 @@ +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.error( + "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" + ) + + {:error, %{}} + + _ -> + {:ok, %{}} + end + end + + def send(notification) do + GenServer.cast(Pleroma.Web.Push, {:send, notification}) + 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 + + data -> + Logger.error("Web Push Nonification failed with unknown error") + IO.inspect(data) + :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: get_avatar_url(actor) + } + end + + def format(%{activity: %{data: %{"type" => "Follow"}}}, actor) do + %{ + title: "New Follower", + body: "@#{actor.nickname} has followed you", + icon: get_avatar_url(actor) + } + end + + def format(%{activity: %{data: %{"type" => "Announce"}}}, actor) do + %{ + title: "New Announce", + body: "@#{actor.nickname} has announced your post", + icon: get_avatar_url(actor) + } + end + + def format(%{activity: %{data: %{"type" => "Like"}}}, actor) do + %{ + title: "New Like", + body: "@#{actor.nickname} has liked your post", + icon: get_avatar_url(actor) + } + end + + def get_avatar_url(%{avatar: %{"type" => "Image", "url" => urls}}) do + case List.first(urls) do + %{"href" => url} -> url + _ -> get_avatar_url(nil) + end + end + + def get_avatar_url(_) do + Pleroma.Web.Endpoint.static_url() <> "/images/avi.png" + end +end diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex index dc8fe9f33..cfab7a98e 100644 --- a/lib/pleroma/web/push/subscription.ex +++ b/lib/pleroma/web/push/subscription.ex @@ -1,6 +1,6 @@ defmodule Pleroma.Web.Push.Subscription do use Ecto.Schema - import Ecto.{Changeset, Query} + import Ecto.Changeset alias Pleroma.{Repo, User} alias Pleroma.Web.OAuth.Token alias Pleroma.Web.Push.Subscription diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 886b70f5f..f06020a3e 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -156,13 +156,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do |> send_resp(200, response) _ -> + vapid_public_key = + Keyword.get(Application.get_env(:web_push_encryption, :vapid_details), :public_key) + data = %{ name: Keyword.get(@instance, :name), description: Keyword.get(@instance, :description), server: Web.base_url(), textlimit: to_string(Keyword.get(@instance, :limit)), closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"), - private: if(Keyword.get(@instance, :public, true), do: "0", else: "1") + private: if(Keyword.get(@instance, :public, true), do: "0", else: "1"), + vapidPublicKey: vapid_public_key } pleroma_fe = %{ |