aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/pleroma/common.ex4
-rw-r--r--lib/mix/tasks/pleroma/instance.ex6
-rw-r--r--lib/mix/tasks/pleroma/relay.ex4
-rw-r--r--lib/mix/tasks/pleroma/uploads.ex4
-rw-r--r--lib/mix/tasks/pleroma/user.ex18
-rw-r--r--lib/pleroma/PasswordResetToken.ex4
-rw-r--r--lib/pleroma/activity.ex6
-rw-r--r--lib/pleroma/application.ex35
-rw-r--r--lib/pleroma/captcha/captcha.ex91
-rw-r--r--lib/pleroma/captcha/captcha_service.ex25
-rw-r--r--lib/pleroma/captcha/kocaptcha.ex62
-rw-r--r--lib/pleroma/config.ex4
-rw-r--r--lib/pleroma/emails/mailer.ex4
-rw-r--r--lib/pleroma/emails/user_email.ex29
-rw-r--r--lib/pleroma/emoji.ex4
-rw-r--r--lib/pleroma/filter.ex4
-rw-r--r--lib/pleroma/formatter.ex20
-rw-r--r--lib/pleroma/gopher/server.ex4
-rw-r--r--lib/pleroma/html.ex42
-rw-r--r--lib/pleroma/http/connection.ex5
-rw-r--r--lib/pleroma/http/http.ex7
-rw-r--r--lib/pleroma/http/request_builder.ex4
-rw-r--r--lib/pleroma/list.ex4
-rw-r--r--lib/pleroma/mime.ex4
-rw-r--r--lib/pleroma/notification.ex16
-rw-r--r--lib/pleroma/object.ex25
-rw-r--r--lib/pleroma/object_tombstone.ex4
-rw-r--r--lib/pleroma/plugs/admin_secret_authentication_plug.ex4
-rw-r--r--lib/pleroma/plugs/authentication_plug.ex4
-rw-r--r--lib/pleroma/plugs/basic_auth_decoder_plug.ex4
-rw-r--r--lib/pleroma/plugs/digest.ex4
-rw-r--r--lib/pleroma/plugs/ensure_authenticated_plug.ex4
-rw-r--r--lib/pleroma/plugs/ensure_user_key_plug.ex4
-rw-r--r--lib/pleroma/plugs/federating_plug.ex4
-rw-r--r--lib/pleroma/plugs/http_security_plug.ex4
-rw-r--r--lib/pleroma/plugs/http_signature.ex4
-rw-r--r--lib/pleroma/plugs/instance_static.ex4
-rw-r--r--lib/pleroma/plugs/legacy_authentication_plug.ex4
-rw-r--r--lib/pleroma/plugs/oauth_plug.ex4
-rw-r--r--lib/pleroma/plugs/session_authentication_plug.ex4
-rw-r--r--lib/pleroma/plugs/set_user_session_id_plug.ex4
-rw-r--r--lib/pleroma/plugs/uploaded_media.ex4
-rw-r--r--lib/pleroma/plugs/user_enabled_plug.ex4
-rw-r--r--lib/pleroma/plugs/user_fetcher_plug.ex4
-rw-r--r--lib/pleroma/plugs/user_is_admin_plug.ex4
-rw-r--r--lib/pleroma/repo.ex4
-rw-r--r--lib/pleroma/reverse_proxy.ex4
-rw-r--r--lib/pleroma/stats.ex4
-rw-r--r--lib/pleroma/upload.ex4
-rw-r--r--lib/pleroma/upload/filter.ex4
-rw-r--r--lib/pleroma/upload/filter/anonymize_filename.ex4
-rw-r--r--lib/pleroma/upload/filter/dedupe.ex4
-rw-r--r--lib/pleroma/upload/filter/mogrifun.ex4
-rw-r--r--lib/pleroma/upload/filter/mogrify.ex4
-rw-r--r--lib/pleroma/uploaders/local.ex4
-rw-r--r--lib/pleroma/uploaders/mdii.ex4
-rw-r--r--lib/pleroma/uploaders/s3.ex4
-rw-r--r--lib/pleroma/uploaders/swift/keystone.ex4
-rw-r--r--lib/pleroma/uploaders/swift/swift.ex4
-rw-r--r--lib/pleroma/uploaders/swift/uploader.ex4
-rw-r--r--lib/pleroma/uploaders/uploader.ex4
-rw-r--r--lib/pleroma/user.ex188
-rw-r--r--lib/pleroma/user/info.ex47
-rw-r--r--lib/pleroma/user_invite_token.ex4
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex59
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex101
-rw-r--r--lib/pleroma/web/activity_pub/mrf.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/drop_policy.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex22
-rw-r--r--lib/pleroma/web/activity_pub/mrf/noop_policy.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/normalize_markup.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/reject_non_public.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/simple_policy.ex4
-rw-r--r--lib/pleroma/web/activity_pub/mrf/user_allowlist.ex4
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex4
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex33
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex4
-rw-r--r--lib/pleroma/web/activity_pub/views/object_view.ex4
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex51
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex23
-rw-r--r--lib/pleroma/web/channels/user_socket.ex4
-rw-r--r--lib/pleroma/web/chat_channel.ex4
-rw-r--r--lib/pleroma/web/common_api/common_api.ex53
-rw-r--r--lib/pleroma/web/common_api/utils.ex6
-rw-r--r--lib/pleroma/web/controller_helper.ex4
-rw-r--r--lib/pleroma/web/endpoint.ex6
-rw-r--r--lib/pleroma/web/federator/federator.ex7
-rw-r--r--lib/pleroma/web/federator/retry_queue.ex199
-rw-r--r--lib/pleroma/web/gettext.ex4
-rw-r--r--lib/pleroma/web/http_signatures/http_signatures.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex58
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex89
-rw-r--r--lib/pleroma/web/mastodon_api/views/filter_view.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/views/list_view.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/views/mastodon_view.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/views/push_subscription_view.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex16
-rw-r--r--lib/pleroma/web/mastodon_api/websocket_handler.ex4
-rw-r--r--lib/pleroma/web/media_proxy/controller.ex4
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex4
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex8
-rw-r--r--lib/pleroma/web/oauth/app.ex4
-rw-r--r--lib/pleroma/web/oauth/authorization.ex4
-rw-r--r--lib/pleroma/web/oauth/fallback_controller.ex4
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex20
-rw-r--r--lib/pleroma/web/oauth/oauth_view.ex4
-rw-r--r--lib/pleroma/web/oauth/token.ex4
-rw-r--r--lib/pleroma/web/ostatus/activity_representer.ex4
-rw-r--r--lib/pleroma/web/ostatus/feed_representer.ex4
-rw-r--r--lib/pleroma/web/ostatus/handlers/delete_handler.ex4
-rw-r--r--lib/pleroma/web/ostatus/handlers/follow_handler.ex4
-rw-r--r--lib/pleroma/web/ostatus/handlers/note_handler.ex4
-rw-r--r--lib/pleroma/web/ostatus/handlers/unfollow_handler.ex4
-rw-r--r--lib/pleroma/web/ostatus/ostatus.ex4
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex36
-rw-r--r--lib/pleroma/web/ostatus/user_representer.ex4
-rw-r--r--lib/pleroma/web/push/push.ex4
-rw-r--r--lib/pleroma/web/push/subscription.ex4
-rw-r--r--lib/pleroma/web/rich_media/controllers/rich_media_controller.ex17
-rw-r--r--lib/pleroma/web/rich_media/parser.ex33
-rw-r--r--lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex30
-rw-r--r--lib/pleroma/web/rich_media/parsers/ogp.ex11
-rw-r--r--lib/pleroma/web/rich_media/parsers/twitter_card.ex11
-rw-r--r--lib/pleroma/web/router.ex47
-rw-r--r--lib/pleroma/web/salmon/salmon.ex22
-rw-r--r--lib/pleroma/web/streamer.ex4
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex35
-rw-r--r--lib/pleroma/web/twitter_api/representers/activity_representer.ex20
-rw-r--r--lib/pleroma/web/twitter_api/representers/base_representer.ex4
-rw-r--r--lib/pleroma/web/twitter_api/representers/object_representer.ex4
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex39
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex94
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex48
-rw-r--r--lib/pleroma/web/twitter_api/views/notification_view.ex4
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex63
-rw-r--r--lib/pleroma/web/twitter_api/views/util_view.ex4
-rw-r--r--lib/pleroma/web/views/error_helpers.ex4
-rw-r--r--lib/pleroma/web/views/error_view.ex4
-rw-r--r--lib/pleroma/web/views/layout_view.ex4
-rw-r--r--lib/pleroma/web/web.ex4
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex4
-rw-r--r--lib/pleroma/web/web_finger/web_finger_controller.ex4
-rw-r--r--lib/pleroma/web/websub/websub.ex4
-rw-r--r--lib/pleroma/web/websub/websub_client_subscription.ex4
-rw-r--r--lib/pleroma/web/websub/websub_controller.ex4
-rw-r--r--lib/pleroma/web/websub/websub_server_subscription.ex4
-rw-r--r--lib/pleroma/web/xml/xml.ex4
148 files changed, 1965 insertions, 322 deletions
diff --git a/lib/mix/tasks/pleroma/common.ex b/lib/mix/tasks/pleroma/common.ex
index 36432c291..48c0c1346 100644
--- a/lib/mix/tasks/pleroma/common.ex
+++ b/lib/mix/tasks/pleroma/common.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.Common do
@doc "Common functions to be reused in mix tasks"
def start_pleroma do
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index 02e1ce27d..0a2c891c0 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.Instance do
use Mix.Task
alias Mix.Tasks.Pleroma.Common
@@ -71,7 +75,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
name =
Common.get_option(
options,
- :name,
+ :instance_name,
"What is the name of your instance? (e.g. Pleroma/Soykaf)"
)
diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex
index 03586d6c3..cbe23f82e 100644
--- a/lib/mix/tasks/pleroma/relay.ex
+++ b/lib/mix/tasks/pleroma/relay.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.Relay do
use Mix.Task
alias Pleroma.Web.ActivityPub.Relay
diff --git a/lib/mix/tasks/pleroma/uploads.ex b/lib/mix/tasks/pleroma/uploads.ex
index 63299b2ae..f0eb13e1a 100644
--- a/lib/mix/tasks/pleroma/uploads.ex
+++ b/lib/mix/tasks/pleroma/uploads.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.Uploads do
use Mix.Task
alias Pleroma.{Upload, Uploaders.Local}
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 3d30e3a81..c311d48e0 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Ecto.Changeset
@@ -18,6 +22,7 @@ defmodule Mix.Tasks.Pleroma.User do
- `--password PASSWORD` - the user's password
- `--moderator`/`--no-moderator` - whether the user is a moderator
- `--admin`/`--no-admin` - whether the user is an admin
+ - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
## Generate an invite link.
@@ -57,7 +62,11 @@ defmodule Mix.Tasks.Pleroma.User do
bio: :string,
password: :string,
moderator: :boolean,
- admin: :boolean
+ admin: :boolean,
+ assume_yes: :boolean
+ ],
+ aliases: [
+ y: :assume_yes
]
)
@@ -75,6 +84,7 @@ defmodule Mix.Tasks.Pleroma.User do
moderator? = Keyword.get(options, :moderator, false)
admin? = Keyword.get(options, :admin, false)
+ assume_yes? = Keyword.get(options, :assume_yes, false)
Mix.shell().info("""
A user will be created with the following information:
@@ -89,7 +99,7 @@ defmodule Mix.Tasks.Pleroma.User do
- admin: #{if(admin?, do: "true", else: "false")}
""")
- proceed? = Mix.shell().yes?("Continue?")
+ proceed? = assume_yes? or Mix.shell().yes?("Continue?")
unless not proceed? do
Common.start_pleroma()
@@ -103,8 +113,8 @@ defmodule Mix.Tasks.Pleroma.User do
bio: bio
}
- user = User.register_changeset(%User{}, params)
- Repo.insert!(user)
+ changeset = User.register_changeset(%User{}, params, confirmed: true)
+ {:ok, _user} = User.register(changeset)
Mix.shell().info("User #{nickname} created")
diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
index 15750565b..1dccdadae 100644
--- a/lib/pleroma/PasswordResetToken.ex
+++ b/lib/pleroma/PasswordResetToken.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.PasswordResetToken do
use Ecto.Schema
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 200addd6e..353f9f6cd 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -1,8 +1,14 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Activity do
use Ecto.Schema
alias Pleroma.{Repo, Activity, Notification}
import Ecto.Query
+ @type t :: %__MODULE__{}
+
# https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19
@mastodon_notification_types %{
"Create" => "mention",
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index e15991957..ad2797209 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Application do
use Application
import Supervisor.Spec
@@ -28,6 +32,16 @@ defmodule Pleroma.Application do
worker(
Cachex,
[
+ :used_captcha_cache,
+ [
+ ttl_interval: :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid]))
+ ]
+ ],
+ id: :cachex_used_captcha_cache
+ ),
+ worker(
+ Cachex,
+ [
:user_cache,
[
default_ttl: 25000,
@@ -52,6 +66,27 @@ defmodule Pleroma.Application do
worker(
Cachex,
[
+ :rich_media_cache,
+ [
+ default_ttl: :timer.minutes(120),
+ limit: 5000
+ ]
+ ],
+ id: :cachex_rich_media
+ ),
+ worker(
+ Cachex,
+ [
+ :scrubber_cache,
+ [
+ limit: 2500
+ ]
+ ],
+ id: :cachex_scrubber
+ ),
+ worker(
+ Cachex,
+ [
:idempotency_cache,
[
expiration:
diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex
index 5630f6b57..0207bcbea 100644
--- a/lib/pleroma/captcha/captcha.ex
+++ b/lib/pleroma/captcha/captcha.ex
@@ -1,7 +1,13 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Captcha do
- use GenServer
+ alias Plug.Crypto.KeyGenerator
+ alias Plug.Crypto.MessageEncryptor
+ alias Calendar.DateTime
- @ets_options [:ordered_set, :private, :named_table, {:read_concurrency, true}]
+ use GenServer
@doc false
def start_link() do
@@ -10,14 +16,6 @@ defmodule Pleroma.Captcha do
@doc false
def init(_) do
- # Create a ETS table to store captchas
- ets_name = Module.concat(method(), Ets)
- ^ets_name = :ets.new(Module.concat(method(), Ets), @ets_options)
-
- # Clean up old captchas every few minutes
- seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained])
- Process.send_after(self(), :cleanup, 1000 * seconds_retained)
-
{:ok, nil}
end
@@ -31,8 +29,8 @@ defmodule Pleroma.Captcha do
@doc """
Ask the configured captcha service to validate the captcha
"""
- def validate(token, captcha) do
- GenServer.call(__MODULE__, {:validate, token, captcha})
+ def validate(token, captcha, answer_data) do
+ GenServer.call(__MODULE__, {:validate, token, captcha, answer_data})
end
@doc false
@@ -42,24 +40,71 @@ defmodule Pleroma.Captcha do
if !enabled do
{:reply, %{type: :none}, state}
else
- {:reply, method().new(), state}
+ new_captcha = method().new()
+
+ secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
+
+ # This make salt a little different for two keys
+ token = new_captcha[:token]
+ secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
+ sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
+ # Basicallty copy what Phoenix.Token does here, add the time to
+ # the actual data and make it a binary to then encrypt it
+ encrypted_captcha_answer =
+ %{
+ at: DateTime.now_utc(),
+ answer_data: new_captcha[:answer_data]
+ }
+ |> :erlang.term_to_binary()
+ |> MessageEncryptor.encrypt(secret, sign_secret)
+
+ {
+ :reply,
+ # Repalce the answer with the encrypted answer
+ %{new_captcha | answer_data: encrypted_captcha_answer},
+ state
+ }
end
end
@doc false
- def handle_call({:validate, token, captcha}, _from, state) do
- {:reply, method().validate(token, captcha), state}
- end
+ def handle_call({:validate, token, captcha, answer_data}, _from, state) do
+ secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
+ secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
+ sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
- @doc false
- def handle_info(:cleanup, state) do
- :ok = method().cleanup()
+ # If the time found is less than (current_time - seconds_valid), then the time has already passed.
+ # Later we check that the time found is more than the presumed invalidatation time, that means
+ # that the data is still valid and the captcha can be checked
+ seconds_valid = Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])
+ valid_if_after = DateTime.subtract!(DateTime.now_utc(), seconds_valid)
+
+ result =
+ with {:ok, data} <- MessageEncryptor.decrypt(answer_data, secret, sign_secret),
+ %{at: at, answer_data: answer_md5} <- :erlang.binary_to_term(data) do
+ try do
+ if DateTime.before?(at, valid_if_after), do: throw({:error, "CAPTCHA expired"})
+
+ if not is_nil(Cachex.get!(:used_captcha_cache, token)),
+ do: throw({:error, "CAPTCHA already used"})
+
+ res = method().validate(token, captcha, answer_md5)
+ # Throw if an error occurs
+ if res != :ok, do: throw(res)
+
+ # Mark this captcha as used
+ {:ok, _} =
+ Cachex.put(:used_captcha_cache, token, true, ttl: :timer.seconds(seconds_valid))
- seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained])
- # Schedule the next clenup
- Process.send_after(self(), :cleanup, 1000 * seconds_retained)
+ :ok
+ catch
+ :throw, e -> e
+ end
+ else
+ _ -> {:error, "Invalid answer data"}
+ end
- {:noreply, state}
+ {:reply, result, state}
end
defp method, do: Pleroma.Config.get!([__MODULE__, :method])
diff --git a/lib/pleroma/captcha/captcha_service.ex b/lib/pleroma/captcha/captcha_service.ex
index 8d0b76f86..8d27c04f1 100644
--- a/lib/pleroma/captcha/captcha_service.ex
+++ b/lib/pleroma/captcha/captcha_service.ex
@@ -1,12 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Captcha.Service do
@doc """
Request new captcha from a captcha service.
Returns:
- Service-specific data for using the newly created captcha
+ Type/Name of the service, the token to identify the captcha,
+ the data of the answer and service-specific data to use the newly created captcha
"""
- @callback new() :: map
+ @callback new() :: %{
+ type: atom(),
+ token: String.t(),
+ answer_data: any()
+ }
@doc """
Validated the provided captcha solution.
@@ -14,15 +23,15 @@ defmodule Pleroma.Captcha.Service do
Arguments:
* `token` the captcha is associated with
* `captcha` solution of the captcha to validate
+ * `answer_data` is the data needed to validate the answer (presumably encrypted)
Returns:
`true` if captcha is valid, `false` if not
"""
- @callback validate(token :: String.t(), captcha :: String.t()) :: boolean
-
- @doc """
- This function is called periodically to clean up old captchas
- """
- @callback cleanup() :: :ok
+ @callback validate(
+ token :: String.t(),
+ captcha :: String.t(),
+ answer_data :: any()
+ ) :: :ok | {:error, String.t()}
end
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
index 51900d123..34a611492 100644
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -1,11 +1,11 @@
-defmodule Pleroma.Captcha.Kocaptcha do
- alias Calendar.DateTime
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+defmodule Pleroma.Captcha.Kocaptcha do
alias Pleroma.Captcha.Service
@behaviour Service
- @ets __MODULE__.Ets
-
@impl Service
def new() do
endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
@@ -17,51 +17,21 @@ defmodule Pleroma.Captcha.Kocaptcha do
{:ok, res} ->
json_resp = Poison.decode!(res.body)
- token = json_resp["token"]
-
- true =
- :ets.insert(
- @ets,
- {token, json_resp["md5"], DateTime.now_utc() |> DateTime.Format.unix()}
- )
-
- %{type: :kocaptcha, token: token, url: endpoint <> json_resp["url"]}
- end
- end
-
- @impl Service
- def validate(token, captcha) do
- with false <- is_nil(captcha),
- [{^token, saved_md5, _}] <- :ets.lookup(@ets, token),
- true <- :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(saved_md5) do
- # Clear the saved value
- :ets.delete(@ets, token)
-
- true
- else
- _ -> false
+ %{
+ type: :kocaptcha,
+ token: json_resp["token"],
+ url: endpoint <> json_resp["url"],
+ answer_data: json_resp["md5"]
+ }
end
end
@impl Service
- def cleanup() do
- seconds_retained = Pleroma.Config.get!([Pleroma.Captcha, :seconds_retained])
- # If the time in ETS is less than current_time - seconds_retained, then the time has
- # already passed
- delete_after =
- DateTime.subtract!(DateTime.now_utc(), seconds_retained) |> DateTime.Format.unix()
-
- :ets.select_delete(
- @ets,
- [
- {
- {:_, :_, :"$1"},
- [{:<, :"$1", {:const, delete_after}}],
- [true]
- }
- ]
- )
-
- :ok
+ def validate(_token, captcha, answer_data) do
+ # Here the token is unsed, because the unencrypted captcha answer is just passed to method
+ if not is_nil(captcha) and
+ :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_data),
+ do: :ok,
+ else: {:error, "Invalid CAPTCHA"}
end
end
diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex
index 3876ddf1f..21507cd38 100644
--- a/lib/pleroma/config.ex
+++ b/lib/pleroma/config.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Config do
defmodule Error do
defexception [:message]
diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex
index 14ed32ea8..8d12641f2 100644
--- a/lib/pleroma/emails/mailer.ex
+++ b/lib/pleroma/emails/mailer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Mailer do
use Swoosh.Mailer, otp_app: :pleroma
end
diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex
index 7e3e9b020..c42c53c99 100644
--- a/lib/pleroma/emails/user_email.ex
+++ b/lib/pleroma/emails/user_email.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.UserEmail do
@moduledoc "User emails"
@@ -15,6 +19,7 @@ defmodule Pleroma.UserEmail do
defp recipient(email, nil), do: email
defp recipient(email, name), do: {name, email}
+ defp recipient(%Pleroma.User{} = user), do: recipient(user.email, user.name)
def password_reset_email(user, password_reset_token) when is_binary(password_reset_token) do
password_reset_url =
@@ -32,7 +37,7 @@ defmodule Pleroma.UserEmail do
"""
new()
- |> to(recipient(user.email, user.name))
+ |> to(recipient(user))
|> from(sender())
|> subject("Password reset")
|> html_body(html_body)
@@ -63,4 +68,26 @@ defmodule Pleroma.UserEmail do
|> subject("Invitation to #{instance_name()}")
|> html_body(html_body)
end
+
+ def account_confirmation_email(user) do
+ confirmation_url =
+ Router.Helpers.confirm_email_url(
+ Endpoint,
+ :confirm_email,
+ user.id,
+ to_string(user.info.confirmation_token)
+ )
+
+ html_body = """
+ <h3>Welcome to #{instance_name()}!</h3>
+ <p>Email confirmation is required to activate the account.</p>
+ <p>Click the following link to proceed: <a href="#{confirmation_url}">activate your account</a>.</p>
+ """
+
+ new()
+ |> to(recipient(user))
+ |> from(sender())
+ |> subject("#{instance_name()} account confirmation")
+ |> html_body(html_body)
+ end
end
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index bedad99d6..bb3190e08 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Emoji do
@moduledoc """
The emojis are loaded from:
diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex
index c57bd3bf8..df5374a5c 100644
--- a/lib/pleroma/filter.ex
+++ b/lib/pleroma/filter.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Filter do
use Ecto.Schema
import Ecto.{Changeset, Query}
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index 74626bbc1..49f7075e6 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Formatter do
alias Pleroma.User
alias Pleroma.Web.MediaProxy
@@ -7,6 +11,9 @@ defmodule Pleroma.Formatter do
@tag_regex ~r/((?<=[^&])|\A)(\#)(\w+)/u
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
+ # Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
+ @mentions_regex ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]*@?[a-zA-Z0-9_-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
+
def parse_tags(text, data \\ %{}) do
Regex.scan(@tag_regex, text)
|> Enum.map(fn ["#" <> tag = full_tag | _] -> {full_tag, String.downcase(tag)} end)
@@ -17,16 +24,15 @@ defmodule Pleroma.Formatter do
end).()
end
+ @doc "Parses mentions text and returns list {nickname, user}."
+ @spec parse_mentions(binary()) :: list({binary(), User.t()})
def parse_mentions(text) do
- # Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
- regex =
- ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]*@?[a-zA-Z0-9_-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
-
- Regex.scan(regex, text)
+ Regex.scan(@mentions_regex, text)
|> List.flatten()
|> Enum.uniq()
- |> Enum.map(fn "@" <> match = full_match ->
- {full_match, User.get_cached_by_nickname(match)}
+ |> Enum.map(fn nickname ->
+ with nickname <- String.trim_leading(nickname, "@"),
+ do: {"@" <> nickname, User.get_cached_by_nickname(nickname)}
end)
|> Enum.filter(fn {_match, user} -> user end)
end
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
index 4d582ef25..336142e9b 100644
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Gopher.Server do
use GenServer
require Logger
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 583f05aeb..0c5b0f03f 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.HTML do
alias HtmlSanitizeEx.Scrubber
@@ -11,8 +15,11 @@ defmodule Pleroma.HTML do
end
def filter_tags(html, nil) do
- get_scrubbers()
- |> Enum.reduce(html, fn scrubber, html ->
+ filter_tags(html, get_scrubbers())
+ end
+
+ def filter_tags(html, scrubbers) when is_list(scrubbers) do
+ Enum.reduce(scrubbers, html, fn scrubber, html ->
filter_tags(html, scrubber)
end)
end
@@ -20,6 +27,37 @@ defmodule Pleroma.HTML do
def filter_tags(html, scrubber), do: Scrubber.scrub(html, scrubber)
def filter_tags(html), do: filter_tags(html, nil)
def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags)
+
+ def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do
+ key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}"
+ Cachex.fetch!(:scrubber_cache, key, fn _key -> ensure_scrubbed_html(content, scrubbers) end)
+ end
+
+ def get_cached_stripped_html_for_object(content, object, module) do
+ get_cached_scrubbed_html_for_object(
+ content,
+ HtmlSanitizeEx.Scrubber.StripTags,
+ object,
+ module
+ )
+ end
+
+ def ensure_scrubbed_html(
+ content,
+ scrubbers
+ ) do
+ {:commit, filter_tags(content, scrubbers)}
+ end
+
+ defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do
+ generate_scrubber_signature([scrubber])
+ end
+
+ defp generate_scrubber_signature(scrubbers) do
+ Enum.reduce(scrubbers, "", fn scrubber, signature ->
+ "#{signature}#{to_string(scrubber)}"
+ end)
+ end
end
defmodule Pleroma.HTML.Scrubber.TwitterText do
diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex
index 7b11060b2..699d80cd7 100644
--- a/lib/pleroma/http/connection.ex
+++ b/lib/pleroma/http/connection.ex
@@ -1,10 +1,13 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.HTTP.Connection do
@moduledoc """
Connection for http-requests.
"""
@hackney_options [
- pool: :default,
timeout: 10000,
recv_timeout: 20000,
follow_redirect: true
diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex
index 3c0256575..b8103cef6 100644
--- a/lib/pleroma/http/http.ex
+++ b/lib/pleroma/http/http.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.HTTP do
@moduledoc """
@@ -6,6 +10,8 @@ defmodule Pleroma.HTTP do
alias Pleroma.HTTP.Connection
alias Pleroma.HTTP.RequestBuilder, as: Builder
+ @type t :: __MODULE__
+
@doc """
Builds and perform http request.
@@ -50,7 +56,6 @@ defmodule Pleroma.HTTP do
def process_request_options(options) do
config = Application.get_env(:pleroma, :http, [])
proxy = Keyword.get(config, :proxy_url, nil)
- options = options ++ [adapter: [pool: :default]]
case proxy do
nil -> options
diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex
index 5aee2b8ae..bffc7c6fe 100644
--- a/lib/pleroma/http/request_builder.ex
+++ b/lib/pleroma/http/request_builder.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.HTTP.RequestBuilder do
@moduledoc """
Helper functions for building Tesla requests
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index c5bf3e083..a75dc006e 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.List do
use Ecto.Schema
import Ecto.{Changeset, Query}
diff --git a/lib/pleroma/mime.ex b/lib/pleroma/mime.ex
index 2cb3d8bd1..84fb536e0 100644
--- a/lib/pleroma/mime.ex
+++ b/lib/pleroma/mime.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.MIME do
@moduledoc """
Returns the mime-type of a binary and optionally a normalized file-name.
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index 47f6b6ee7..c7d01f63b 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Notification do
use Ecto.Schema
alias Pleroma.{User, Activity, Notification, Repo, Object}
@@ -76,9 +80,8 @@ defmodule Pleroma.Notification do
end
def clear(user) do
- query = from(n in Notification, where: n.user_id == ^user.id)
-
- Repo.delete_all(query)
+ from(n in Notification, where: n.user_id == ^user.id)
+ |> Repo.delete_all()
end
def dismiss(%{id: user_id} = _user, id) do
@@ -106,7 +109,12 @@ defmodule Pleroma.Notification do
# TODO move to sql, too.
def create_notification(%Activity{} = activity, %User{} = user) do
unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
- user.ap_id == activity.data["actor"] do
+ user.ap_id == activity.data["actor"] or
+ (activity.data["type"] == "Follow" and
+ Enum.any?(Notification.for_user(user), fn notif ->
+ notif.activity.data["type"] == "Follow" and
+ notif.activity.data["actor"] == activity.data["actor"]
+ end)) do
notification = %Notification{user_id: user.id, activity: activity}
{:ok, notification} = Repo.insert(notification)
Pleroma.Web.Streamer.stream("user", notification)
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 31c8dd5bd..ff5eb9b27 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -1,6 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Object do
use Ecto.Schema
- alias Pleroma.{Repo, Object, User, Activity}
+ alias Pleroma.{Repo, Object, User, Activity, ObjectTombstone}
import Ecto.{Query, Changeset}
schema "objects" do
@@ -62,8 +66,25 @@ defmodule Pleroma.Object do
Object.change(%Object{}, %{data: %{"id" => context}})
end
+ def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do
+ %ObjectTombstone{
+ id: id,
+ formerType: type,
+ deleted: deleted
+ }
+ |> Map.from_struct()
+ end
+
+ def swap_object_with_tombstone(object) do
+ tombstone = make_tombstone(object)
+
+ object
+ |> Object.change(%{data: tombstone})
+ |> Repo.update()
+ end
+
def delete(%Object{data: %{"id" => id}} = object) do
- with Repo.delete(object),
+ with {:ok, _obj} = swap_object_with_tombstone(object),
Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
{:ok, object}
diff --git a/lib/pleroma/object_tombstone.ex b/lib/pleroma/object_tombstone.ex
new file mode 100644
index 000000000..64d836d3e
--- /dev/null
+++ b/lib/pleroma/object_tombstone.ex
@@ -0,0 +1,4 @@
+defmodule Pleroma.ObjectTombstone do
+ @enforce_keys [:id, :formerType, :deleted]
+ defstruct [:id, :formerType, :deleted, type: "Tombstone"]
+end
diff --git a/lib/pleroma/plugs/admin_secret_authentication_plug.ex b/lib/pleroma/plugs/admin_secret_authentication_plug.ex
index f61a6ee24..5baf8a691 100644
--- a/lib/pleroma/plugs/admin_secret_authentication_plug.ex
+++ b/lib/pleroma/plugs/admin_secret_authentication_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/plugs/authentication_plug.ex b/lib/pleroma/plugs/authentication_plug.ex
index b240ff29f..da4ed4226 100644
--- a/lib/pleroma/plugs/authentication_plug.ex
+++ b/lib/pleroma/plugs/authentication_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.AuthenticationPlug do
alias Comeonin.Pbkdf2
import Plug.Conn
diff --git a/lib/pleroma/plugs/basic_auth_decoder_plug.ex b/lib/pleroma/plugs/basic_auth_decoder_plug.ex
index f7ebf7db2..7eeeb1e5d 100644
--- a/lib/pleroma/plugs/basic_auth_decoder_plug.ex
+++ b/lib/pleroma/plugs/basic_auth_decoder_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.BasicAuthDecoderPlug do
import Plug.Conn
diff --git a/lib/pleroma/plugs/digest.ex b/lib/pleroma/plugs/digest.ex
index 9d6bbb085..0ba00845a 100644
--- a/lib/pleroma/plugs/digest.ex
+++ b/lib/pleroma/plugs/digest.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Plugs.DigestPlug do
alias Plug.Conn
require Logger
diff --git a/lib/pleroma/plugs/ensure_authenticated_plug.ex b/lib/pleroma/plugs/ensure_authenticated_plug.ex
index bca44eb2c..11c4342c4 100644
--- a/lib/pleroma/plugs/ensure_authenticated_plug.ex
+++ b/lib/pleroma/plugs/ensure_authenticated_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/plugs/ensure_user_key_plug.ex b/lib/pleroma/plugs/ensure_user_key_plug.ex
index 05a567757..c88ebfb3f 100644
--- a/lib/pleroma/plugs/ensure_user_key_plug.ex
+++ b/lib/pleroma/plugs/ensure_user_key_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.EnsureUserKeyPlug do
import Plug.Conn
diff --git a/lib/pleroma/plugs/federating_plug.ex b/lib/pleroma/plugs/federating_plug.ex
index b5326d97b..effc154bf 100644
--- a/lib/pleroma/plugs/federating_plug.ex
+++ b/lib/pleroma/plugs/federating_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.FederatingPlug do
import Plug.Conn
diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex
index f34f2364b..2a266c407 100644
--- a/lib/pleroma/plugs/http_security_plug.ex
+++ b/lib/pleroma/plugs/http_security_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.HTTPSecurityPlug do
alias Pleroma.Config
import Plug.Conn
diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex
index 9e53371b7..51bec910e 100644
--- a/lib/pleroma/plugs/http_signature.ex
+++ b/lib/pleroma/plugs/http_signature.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
alias Pleroma.Web.HTTPSignatures
alias Pleroma.Web.ActivityPub.Utils
diff --git a/lib/pleroma/plugs/instance_static.ex b/lib/pleroma/plugs/instance_static.ex
index 46ee77e11..af2f6f331 100644
--- a/lib/pleroma/plugs/instance_static.ex
+++ b/lib/pleroma/plugs/instance_static.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.InstanceStatic do
@moduledoc """
This is a shim to call `Plug.Static` but with runtime `from` configuration.
diff --git a/lib/pleroma/plugs/legacy_authentication_plug.ex b/lib/pleroma/plugs/legacy_authentication_plug.ex
index d22c1a647..78b7e388f 100644
--- a/lib/pleroma/plugs/legacy_authentication_plug.ex
+++ b/lib/pleroma/plugs/legacy_authentication_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.LegacyAuthenticationPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex
index 13c914c1b..437aa95b3 100644
--- a/lib/pleroma/plugs/oauth_plug.ex
+++ b/lib/pleroma/plugs/oauth_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.OAuthPlug do
import Plug.Conn
import Ecto.Query
diff --git a/lib/pleroma/plugs/session_authentication_plug.ex b/lib/pleroma/plugs/session_authentication_plug.ex
index aed619432..a08484b65 100644
--- a/lib/pleroma/plugs/session_authentication_plug.ex
+++ b/lib/pleroma/plugs/session_authentication_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.SessionAuthenticationPlug do
import Plug.Conn
diff --git a/lib/pleroma/plugs/set_user_session_id_plug.ex b/lib/pleroma/plugs/set_user_session_id_plug.ex
index adc0a42b5..9265cc116 100644
--- a/lib/pleroma/plugs/set_user_session_id_plug.ex
+++ b/lib/pleroma/plugs/set_user_session_id_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.SetUserSessionIdPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/plugs/uploaded_media.ex b/lib/pleroma/plugs/uploaded_media.ex
index 7e1e84126..be53ac00c 100644
--- a/lib/pleroma/plugs/uploaded_media.ex
+++ b/lib/pleroma/plugs/uploaded_media.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.UploadedMedia do
@moduledoc """
"""
diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex
index 01482f47d..da892c28b 100644
--- a/lib/pleroma/plugs/user_enabled_plug.ex
+++ b/lib/pleroma/plugs/user_enabled_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.UserEnabledPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/plugs/user_fetcher_plug.ex b/lib/pleroma/plugs/user_fetcher_plug.ex
index e24785ad1..f874e2f95 100644
--- a/lib/pleroma/plugs/user_fetcher_plug.ex
+++ b/lib/pleroma/plugs/user_fetcher_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.UserFetcherPlug do
import Plug.Conn
alias Pleroma.Repo
diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex
index cf22ce5d0..04329e919 100644
--- a/lib/pleroma/plugs/user_is_admin_plug.ex
+++ b/lib/pleroma/plugs/user_is_admin_plug.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Plugs.UserIsAdminPlug do
import Plug.Conn
alias Pleroma.User
diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex
index 7cecd7b38..e6a51b19e 100644
--- a/lib/pleroma/repo.ex
+++ b/lib/pleroma/repo.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Repo do
use Ecto.Repo, otp_app: :pleroma
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
index 7f328d00d..a3846c3bb 100644
--- a/lib/pleroma/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.ReverseProxy do
@keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since if-unmodified-since if-none-match if-range range)
@resp_cache_headers ~w(etag date last-modified cache-control)
diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
index 8478fe4ce..8a030ecd0 100644
--- a/lib/pleroma/stats.ex
+++ b/lib/pleroma/stats.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Stats do
import Ecto.Query
alias Pleroma.{User, Repo}
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
index 07031ac58..0b1bdeec4 100644
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload do
@moduledoc """
# Upload
diff --git a/lib/pleroma/upload/filter.ex b/lib/pleroma/upload/filter.ex
index d1384ddad..fa02a55de 100644
--- a/lib/pleroma/upload/filter.ex
+++ b/lib/pleroma/upload/filter.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload.Filter do
@moduledoc """
Upload Filter behaviour
diff --git a/lib/pleroma/upload/filter/anonymize_filename.ex b/lib/pleroma/upload/filter/anonymize_filename.ex
index 39eed7af3..5ca53a79b 100644
--- a/lib/pleroma/upload/filter/anonymize_filename.ex
+++ b/lib/pleroma/upload/filter/anonymize_filename.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload.Filter.AnonymizeFilename do
@moduledoc """
Replaces the original filename with a pre-defined text or randomly generated string.
diff --git a/lib/pleroma/upload/filter/dedupe.ex b/lib/pleroma/upload/filter/dedupe.ex
index 0657b2c8d..8fcce320f 100644
--- a/lib/pleroma/upload/filter/dedupe.ex
+++ b/lib/pleroma/upload/filter/dedupe.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload.Filter.Dedupe do
@behaviour Pleroma.Upload.Filter
alias Pleroma.Upload
diff --git a/lib/pleroma/upload/filter/mogrifun.ex b/lib/pleroma/upload/filter/mogrifun.ex
index 4d4f0b401..35a5a1381 100644
--- a/lib/pleroma/upload/filter/mogrifun.ex
+++ b/lib/pleroma/upload/filter/mogrifun.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload.Filter.Mogrifun do
@behaviour Pleroma.Upload.Filter
diff --git a/lib/pleroma/upload/filter/mogrify.ex b/lib/pleroma/upload/filter/mogrify.ex
index f106bd4b1..f459eeecb 100644
--- a/lib/pleroma/upload/filter/mogrify.ex
+++ b/lib/pleroma/upload/filter/mogrify.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Upload.Filter.Mogrify do
@behaviour Pleroma.Upload.Filter
diff --git a/lib/pleroma/uploaders/local.ex b/lib/pleroma/uploaders/local.ex
index 2994bcd51..fc533da23 100644
--- a/lib/pleroma/uploaders/local.ex
+++ b/lib/pleroma/uploaders/local.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.Local do
@behaviour Pleroma.Uploaders.Uploader
diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex
index f06755056..530b34362 100644
--- a/lib/pleroma/uploaders/mdii.ex
+++ b/lib/pleroma/uploaders/mdii.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.MDII do
alias Pleroma.Config
diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex
index 19832a7ec..108cf06b5 100644
--- a/lib/pleroma/uploaders/s3.ex
+++ b/lib/pleroma/uploaders/s3.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.S3 do
@behaviour Pleroma.Uploaders.Uploader
require Logger
diff --git a/lib/pleroma/uploaders/swift/keystone.ex b/lib/pleroma/uploaders/swift/keystone.ex
index 4aed977b1..b4f250f9d 100644
--- a/lib/pleroma/uploaders/swift/keystone.ex
+++ b/lib/pleroma/uploaders/swift/keystone.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.Swift.Keystone do
use HTTPoison.Base
diff --git a/lib/pleroma/uploaders/swift/swift.ex b/lib/pleroma/uploaders/swift/swift.ex
index d4e758bbb..2b0f2ad04 100644
--- a/lib/pleroma/uploaders/swift/swift.ex
+++ b/lib/pleroma/uploaders/swift/swift.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.Swift.Client do
use HTTPoison.Base
diff --git a/lib/pleroma/uploaders/swift/uploader.ex b/lib/pleroma/uploaders/swift/uploader.ex
index b35b9807b..d122b09e7 100644
--- a/lib/pleroma/uploaders/swift/uploader.ex
+++ b/lib/pleroma/uploaders/swift/uploader.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.Swift do
@behaviour Pleroma.Uploaders.Uploader
diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex
index afda5609e..0959d7a3e 100644
--- a/lib/pleroma/uploaders/uploader.ex
+++ b/lib/pleroma/uploaders/uploader.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Uploaders.Uploader do
@moduledoc """
Defines the contract to put and get an uploaded file to any backend.
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index c86ad4afe..3120b13b6 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.User do
use Ecto.Schema
@@ -9,6 +13,8 @@ defmodule Pleroma.User do
alias Pleroma.Web.{OStatus, Websub, OAuth}
alias Pleroma.Web.ActivityPub.{Utils, ActivityPub}
+ require Logger
+
@type t :: %__MODULE__{}
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
@@ -38,6 +44,29 @@ defmodule Pleroma.User do
timestamps()
end
+ def auth_active?(%User{local: false}), do: true
+
+ def auth_active?(%User{info: %User.Info{confirmation_pending: false}}), do: true
+
+ def auth_active?(%User{info: %User.Info{confirmation_pending: true}}),
+ do: !Pleroma.Config.get([:instance, :account_activation_required])
+
+ def auth_active?(_), do: false
+
+ def visible_for?(user, for_user \\ nil)
+
+ def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
+
+ def visible_for?(%User{} = user, for_user) do
+ auth_active?(user) || superuser?(for_user)
+ end
+
+ def visible_for?(_, _), do: false
+
+ def superuser?(%User{local: true, info: %User.Info{is_admin: true}}), do: true
+ def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true
+ def superuser?(_), do: false
+
def avatar_url(user) do
case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href
@@ -78,6 +107,7 @@ defmodule Pleroma.User do
note_count: user.info.note_count,
follower_count: user.info.follower_count,
locked: user.info.locked,
+ confirmation_pending: user.info.confirmation_pending,
default_scope: user.info.default_scope
}
end
@@ -168,7 +198,16 @@ defmodule Pleroma.User do
update_and_set_cache(password_update_changeset(user, data))
end
- def register_changeset(struct, params \\ %{}) do
+ def register_changeset(struct, params \\ %{}, opts \\ []) do
+ confirmation_status =
+ if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do
+ :confirmed
+ else
+ :unconfirmed
+ end
+
+ info_change = User.Info.confirmation_changeset(%User.Info{}, confirmation_status)
+
changeset =
struct
|> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation])
@@ -176,11 +215,12 @@ defmodule Pleroma.User do
|> validate_confirmation(:password)
|> unique_constraint(:email)
|> unique_constraint(:nickname)
+ |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames]))
|> validate_format(:nickname, local_nickname_regex())
|> validate_format(:email, @email_regex)
|> validate_length(:bio, max: 1000)
|> validate_length(:name, min: 1, max: 100)
- |> put_change(:info, %Pleroma.User.Info{})
+ |> put_change(:info, info_change)
if changeset.valid? do
hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
@@ -197,6 +237,39 @@ defmodule Pleroma.User do
end
end
+ defp autofollow_users(user) do
+ candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames])
+
+ autofollowed_users =
+ from(u in User,
+ where: u.local == true,
+ where: u.nickname in ^candidates
+ )
+ |> Repo.all()
+
+ follow_all(user, autofollowed_users)
+ end
+
+ @doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)"
+ def register(%Ecto.Changeset{} = changeset) do
+ with {:ok, user} <- Repo.insert(changeset),
+ {:ok, _} <- try_send_confirmation_email(user),
+ {:ok, user} <- autofollow_users(user) do
+ {:ok, user}
+ end
+ end
+
+ def try_send_confirmation_email(%User{} = user) do
+ if user.info.confirmation_pending &&
+ Pleroma.Config.get([:instance, :account_activation_required]) do
+ user
+ |> Pleroma.UserEmail.account_confirmation_email()
+ |> Pleroma.Mailer.deliver()
+ else
+ {:ok, :noop}
+ end
+ end
+
def needs_update?(%User{local: true}), do: false
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
@@ -231,6 +304,25 @@ defmodule Pleroma.User do
end
end
+ @doc "A mass follow for local users. Ignores blocks and has no side effects"
+ @spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()}
+ def follow_all(follower, followeds) do
+ following =
+ (follower.following ++ Enum.map(followeds, fn %{follower_address: fa} -> fa end))
+ |> Enum.uniq()
+
+ {:ok, follower} =
+ follower
+ |> follow_changeset(%{following: following})
+ |> update_and_set_cache
+
+ Enum.each(followeds, fn followed ->
+ update_follower_count(followed)
+ end)
+
+ {:ok, follower}
+ end
+
def follow(%User{} = follower, %User{info: info} = followed) do
user_config = Application.get_env(:pleroma, :user)
deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked)
@@ -290,6 +382,24 @@ defmodule Pleroma.User do
Enum.member?(follower.following, followed.follower_address)
end
+ def follow_import(%User{} = follower, followed_identifiers)
+ when is_list(followed_identifiers) do
+ Enum.map(
+ followed_identifiers,
+ fn followed_identifier ->
+ with %User{} = followed <- get_or_fetch(followed_identifier),
+ {:ok, follower} <- maybe_direct_follow(follower, followed),
+ {:ok, _} <- ActivityPub.follow(follower, followed) do
+ followed
+ else
+ err ->
+ Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}")
+ err
+ end
+ end
+ )
+ end
+
def locked?(%User{} = user) do
user.info.locked || false
end
@@ -302,6 +412,15 @@ defmodule Pleroma.User do
Repo.get_by(User, ap_id: ap_id)
end
+ # This is mostly an SPC migration fix. This guesses the user nickname (by taking the last part of the ap_id and the domain) and tries to get that user
+ def get_by_guessed_nickname(ap_id) do
+ domain = URI.parse(ap_id).host
+ name = List.last(String.split(ap_id, "/"))
+ nickname = "#{name}@#{domain}"
+
+ get_by_nickname(nickname)
+ end
+
def update_and_set_cache(changeset) do
with {:ok, user} <- Repo.update(changeset) do
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
@@ -339,7 +458,11 @@ defmodule Pleroma.User do
end
def get_by_nickname(nickname) do
- Repo.get_by(User, nickname: nickname)
+ Repo.get_by(User, nickname: nickname) ||
+ if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do
+ [local_nickname, _] = String.split(nickname, "@")
+ Repo.get_by(User, nickname: local_nickname)
+ end
end
def get_by_nickname_or_email(nickname_or_email) do
@@ -377,7 +500,7 @@ defmodule Pleroma.User do
end
end
- def get_followers_query(%User{id: id, follower_address: follower_address}) do
+ def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do
from(
u in User,
where: fragment("? <@ ?", ^[follower_address], u.following),
@@ -385,13 +508,23 @@ defmodule Pleroma.User do
)
end
- def get_followers(user) do
- q = get_followers_query(user)
+ def get_followers_query(user, page) do
+ from(
+ u in get_followers_query(user, nil),
+ limit: 20,
+ offset: ^((page - 1) * 20)
+ )
+ end
+
+ def get_followers_query(user), do: get_followers_query(user, nil)
+
+ def get_followers(user, page \\ nil) do
+ q = get_followers_query(user, page)
{:ok, Repo.all(q)}
end
- def get_friends_query(%User{id: id, following: following}) do
+ def get_friends_query(%User{id: id, following: following}, nil) do
from(
u in User,
where: u.follower_address in ^following,
@@ -399,8 +532,18 @@ defmodule Pleroma.User do
)
end
- def get_friends(user) do
- q = get_friends_query(user)
+ def get_friends_query(user, page) do
+ from(
+ u in get_friends_query(user, nil),
+ limit: 20,
+ offset: ^((page - 1) * 20)
+ )
+ end
+
+ def get_friends_query(user), do: get_friends_query(user, nil)
+
+ def get_friends(user, page \\ nil) do
+ q = get_friends_query(user, page)
{:ok, Repo.all(q)}
end
@@ -435,6 +578,7 @@ defmodule Pleroma.User do
Enum.map(reqs, fn req -> req.actor end)
|> Enum.uniq()
|> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
+ |> Enum.filter(fn u -> !is_nil(u) end)
|> Enum.filter(fn u -> !following?(u, user) end)
{:ok, users}
@@ -549,7 +693,7 @@ defmodule Pleroma.User do
select_merge: %{
search_distance:
fragment(
- "? <-> (? || ?)",
+ "? <-> (? || coalesce(?, ''))",
^query,
u.nickname,
u.name
@@ -568,6 +712,23 @@ defmodule Pleroma.User do
Repo.all(q)
end
+ def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do
+ Enum.map(
+ blocked_identifiers,
+ fn blocked_identifier ->
+ with %User{} = blocked <- get_or_fetch(blocked_identifier),
+ {:ok, blocker} <- block(blocker, blocked),
+ {:ok, _} <- ActivityPub.block(blocker, blocked) do
+ blocked
+ else
+ err ->
+ Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}")
+ err
+ end
+ end
+ )
+ end
+
def block(blocker, %User{ap_id: ap_id} = blocked) do
# sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
blocker =
@@ -621,6 +782,9 @@ defmodule Pleroma.User do
end)
end
+ def blocked_users(user),
+ do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks))
+
def block_domain(user, domain) do
info_cng =
user.info
@@ -706,7 +870,9 @@ defmodule Pleroma.User do
Pleroma.HTML.Scrubber.TwitterText
end
- def html_filter_policy(_), do: nil
+ @default_scrubbers Pleroma.Config.get([:markup, :scrub_policy])
+
+ def html_filter_policy(_), do: @default_scrubbers
def get_or_fetch_by_ap_id(ap_id) do
user = get_by_ap_id(ap_id)
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index a3785447c..fb1791c20 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.User.Info do
use Ecto.Schema
import Ecto.Changeset
@@ -9,6 +13,8 @@ defmodule Pleroma.User.Info do
field(:note_count, :integer, default: 0)
field(:follower_count, :integer, default: 0)
field(:locked, :boolean, default: false)
+ field(:confirmation_pending, :boolean, default: false)
+ field(:confirmation_token, :string, default: nil)
field(:default_scope, :string, default: "public")
field(:blocks, {:array, :string}, default: [])
field(:domain_blocks, {:array, :string}, default: [])
@@ -25,6 +31,7 @@ defmodule Pleroma.User.Info do
field(:hub, :string, default: nil)
field(:salmon, :string, default: nil)
field(:hide_network, :boolean, default: false)
+ field(:pinned_activities, {:array, :integer}, default: [])
# Found in the wild
# ap_id -> Where is this used?
@@ -141,6 +148,24 @@ defmodule Pleroma.User.Info do
])
end
+ def confirmation_changeset(info, :confirmed) do
+ confirmation_changeset(info, %{
+ confirmation_pending: false,
+ confirmation_token: nil
+ })
+ end
+
+ def confirmation_changeset(info, :unconfirmed) do
+ confirmation_changeset(info, %{
+ confirmation_pending: true,
+ confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64()
+ })
+ end
+
+ def confirmation_changeset(info, params) do
+ cast(info, params, [:confirmation_pending, :confirmation_token])
+ end
+
def mastodon_profile_update(info, params) do
info
|> cast(params, [
@@ -172,4 +197,26 @@ defmodule Pleroma.User.Info do
:is_admin
])
end
+
+ def add_pinnned_activity(info, %Pleroma.Activity{id: id}) do
+ if id not in info.pinned_activities do
+ max_pinned_statuses = Pleroma.Config.get([:instance, :max_pinned_statuses], 0)
+ params = %{pinned_activities: info.pinned_activities ++ [id]}
+
+ info
+ |> cast(params, [:pinned_activities])
+ |> validate_length(:pinned_activities,
+ max: max_pinned_statuses,
+ message: "You have already pinned the maximum number of statuses"
+ )
+ else
+ change(info)
+ end
+ end
+
+ def remove_pinnned_activity(info, %Pleroma.Activity{id: id}) do
+ params = %{pinned_activities: List.delete(info.pinned_activities, id)}
+
+ cast(info, params, [:pinned_activities])
+ end
end
diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex
index ce804f78e..5a448114c 100644
--- a/lib/pleroma/user_invite_token.ex
+++ b/lib/pleroma/user_invite_token.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.UserInviteToken do
use Ecto.Schema
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 31455343c..9c1eb377f 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.{Activity, Repo, Object, Upload, User, Notification}
alias Pleroma.Web.ActivityPub.{Transmogrifier, MRF}
@@ -52,10 +56,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ defp check_remote_limit(%{"object" => %{"content" => content}}) do
+ limit = Pleroma.Config.get([:instance, :remote_limit])
+ String.length(content) <= limit
+ end
+
+ defp check_remote_limit(_), do: true
+
def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map),
:ok <- check_actor_is_active(map["actor"]),
+ {_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
:ok <- insert_full_object(map) do
{recipients, _, _} = get_recipients(map)
@@ -352,21 +364,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
@valid_visibilities ~w[direct unlisted public private]
- defp restrict_visibility(query, %{visibility: "direct"}) do
- public = "https://www.w3.org/ns/activitystreams#Public"
+ defp restrict_visibility(query, %{visibility: visibility})
+ when visibility in @valid_visibilities do
+ query =
+ from(
+ a in query,
+ where:
+ fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility)
+ )
- from(
- activity in query,
- join: sender in User,
- on: sender.ap_id == activity.actor,
- # Are non-direct statuses with no to/cc possible?
- where:
- fragment(
- "not (? && ?)",
- [^public, sender.follower_address],
- activity.recipients
- )
- )
+ Ecto.Adapters.SQL.to_sql(:all, Repo, query)
+
+ query
end
defp restrict_visibility(_query, %{visibility: visibility})
@@ -382,6 +391,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> Map.put("type", ["Create", "Announce"])
|> Map.put("actor_id", user.ap_id)
|> Map.put("whole_db", true)
+ |> Map.put("pinned_activity_ids", user.info.pinned_activities)
recipients =
if reading_user do
@@ -499,6 +509,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_replies(query, _), do: query
+ defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or val == "1" do
+ from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
+ end
+
+ defp restrict_reblogs(query, _), do: query
+
# Only search through last 100_000 activities by default
defp restrict_recent(query, %{"whole_db" => true}), do: query
@@ -534,6 +550,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
)
end
+ defp restrict_pinned(query, %{"pinned" => "true", "pinned_activity_ids" => ids}) do
+ from(activity in query, where: activity.id in ^ids)
+ end
+
+ defp restrict_pinned(query, _), do: query
+
def fetch_activities_query(recipients, opts \\ %{}) do
base_query =
from(
@@ -557,6 +579,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_media(opts)
|> restrict_visibility(opts)
|> restrict_replies(opts)
+ |> restrict_reblogs(opts)
+ |> restrict_pinned(opts)
end
def fetch_activities(recipients, opts \\ %{}) do
@@ -722,8 +746,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{"Content-Type", "application/activity+json"},
{"signature", signature},
{"digest", digest}
- ],
- hackney: [pool: :default]
+ ]
)
end
@@ -783,6 +806,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ def is_public?(%Object{data: %{"type" => "Tombstone"}}) do
+ false
+ end
+
def is_public?(activity) do
"https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++
(activity.data["cc"] || []))
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 0317f3c8c..73ca07e84 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -1,10 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
use Pleroma.Web, :controller
- alias Pleroma.{User, Object}
+ alias Pleroma.{Activity, User, Object}
alias Pleroma.Web.ActivityPub.{ObjectView, UserView}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.Federator
require Logger
@@ -49,6 +54,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
+ def activity(conn, %{"uuid" => uuid}) do
+ with ap_id <- o_status_url(conn, :activity, uuid),
+ %Activity{} = activity <- Activity.normalize(ap_id),
+ {_, true} <- {:public?, ActivityPub.is_public?(activity)} do
+ conn
+ |> put_resp_header("content-type", "application/activity+json")
+ |> json(ObjectView.render("object.json", %{object: activity}))
+ else
+ {:public?, false} ->
+ {:error, :not_found}
+ end
+ end
+
def following(conn, %{"nickname" => nickname, "page" => page}) do
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
@@ -89,19 +107,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def outbox(conn, %{"nickname" => nickname, "max_id" => max_id}) do
+ def outbox(conn, %{"nickname" => nickname} = params) do
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
conn
|> put_resp_header("content-type", "application/activity+json")
- |> json(UserView.render("outbox.json", %{user: user, max_id: max_id}))
+ |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]}))
end
end
- def outbox(conn, %{"nickname" => nickname}) do
- outbox(conn, %{"nickname" => nickname, "max_id" => nil})
- end
-
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
with %User{} = user <- User.get_cached_by_nickname(nickname),
true <- Utils.recipient_in_message(user.ap_id, params),
@@ -152,6 +166,79 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
+ def read_inbox(%{assigns: %{user: user}} = conn, %{"nickname" => nickname} = params) do
+ if nickname == user.nickname do
+ conn
+ |> put_resp_header("content-type", "application/activity+json")
+ |> json(UserView.render("inbox.json", %{user: user, max_id: params["max_id"]}))
+ else
+ conn
+ |> put_status(:forbidden)
+ |> json("can't read inbox of #{nickname} as #{user.nickname}")
+ end
+ end
+
+ def handle_user_activity(user, %{"type" => "Create"} = params) do
+ object =
+ params["object"]
+ |> Map.merge(Map.take(params, ["to", "cc"]))
+ |> Map.put("attributedTo", user.ap_id())
+ |> Transmogrifier.fix_object()
+
+ ActivityPub.create(%{
+ to: params["to"],
+ actor: user,
+ context: object["context"],
+ object: object,
+ additional: Map.take(params, ["cc"])
+ })
+ end
+
+ def handle_user_activity(user, %{"type" => "Delete"} = params) do
+ with %Object{} = object <- Object.normalize(params["object"]),
+ true <- user.info.is_moderator || user.ap_id == object.data["actor"],
+ {:ok, delete} <- ActivityPub.delete(object) do
+ {:ok, delete}
+ else
+ _ -> {:error, "Can't delete object"}
+ end
+ end
+
+ def handle_user_activity(_, _) do
+ {:error, "Unhandled activity type"}
+ end
+
+ def update_outbox(
+ %{assigns: %{user: user}} = conn,
+ %{"nickname" => nickname} = params
+ ) do
+ if nickname == user.nickname do
+ actor = user.ap_id()
+
+ params =
+ params
+ |> Map.drop(["id"])
+ |> Map.put("actor", actor)
+ |> Transmogrifier.fix_addressing()
+
+ with {:ok, %Activity{} = activity} <- handle_user_activity(user, params) do
+ conn
+ |> put_status(:created)
+ |> put_resp_header("location", activity.data["id"])
+ |> json(activity.data)
+ else
+ {:error, message} ->
+ conn
+ |> put_status(:bad_request)
+ |> json(message)
+ end
+ else
+ conn
+ |> put_status(:forbidden)
+ |> json("can't update outbox of #{nickname} as #{user.nickname}")
+ end
+ end
+
def errors(conn, {:error, :not_found}) do
conn
|> put_status(404)
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index 0a4e2bf80..eebea207c 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF do
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
index 811947943..a93ccf386 100644
--- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
require Logger
@behaviour Pleroma.Web.ActivityPub.MRF
diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
index 6fa48454a..895376c9d 100644
--- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
+++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
alias Pleroma.Object
diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
new file mode 100644
index 000000000..a3f516ae7
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
@@ -0,0 +1,22 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ @impl true
+ def filter(%{"type" => "Create"} = object) do
+ threshold = Pleroma.Config.get([:mrf_hellthread, :threshold])
+ recipients = (object["to"] || []) ++ (object["cc"] || [])
+
+ if length(recipients) > threshold do
+ {:reject, nil}
+ else
+ {:ok, object}
+ end
+ end
+
+ @impl true
+ def filter(object), do: {:ok, object}
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
index e26f60d26..40f37bdb1 100644
--- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
@behaviour Pleroma.Web.ActivityPub.MRF
diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
index c53cb1ad2..3d13cdb32 100644
--- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
+++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
alias Pleroma.HTML
diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
index 627284083..4197be847 100644
--- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
+++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
alias Pleroma.User
@behaviour Pleroma.Web.ActivityPub.MRF
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index 12fc3b181..798ba9687 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
alias Pleroma.User
@behaviour Pleroma.Web.ActivityPub.MRF
diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex
index 3503d8692..a3b1f8aa0 100644
--- a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex
+++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
alias Pleroma.Config
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index fcdc6b1c0..abddbc790 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.{User, Object, Activity}
alias Pleroma.Web.ActivityPub.ActivityPub
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index e6af4b211..87b7fc07f 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.Transmogrifier do
@moduledoc """
A module to handle coding from internal to wire ActivityPub and back.
@@ -69,8 +73,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_object(object) do
object
|> fix_actor
- |> fix_attachments
|> fix_url
+ |> fix_attachments
|> fix_context
|> fix_in_reply_to
|> fix_emoji
@@ -170,8 +174,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
attachments =
attachment
|> Enum.map(fn data ->
- url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}]
- Map.put(data, "url", url)
+ media_type = data["mediaType"] || data["mimeType"]
+ href = data["url"] || data["href"]
+
+ url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}]
+
+ data
+ |> Map.put("mediaType", media_type)
+ |> Map.put("url", url)
end)
object
@@ -190,7 +200,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("url", url["href"])
end
- def fix_url(%{"url" => url} = object) when is_list(url) do
+ def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do
+ first_element = Enum.at(url, 0)
+
+ link_element =
+ url
+ |> Enum.filter(fn x -> is_map(x) end)
+ |> Enum.filter(fn x -> x["mimeType"] == "text/html" end)
+ |> Enum.at(0)
+
+ object
+ |> Map.put("attachment", [first_element])
+ |> Map.put("url", link_element["href"])
+ end
+
+ def fix_url(%{"type" => object_type, "url" => url} = object)
+ when object_type != "Video" and is_list(url) do
first_element = Enum.at(url, 0)
url_string =
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 074622f2b..b313996db 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.{Repo, Web, Object, Activity, User, Notification}
alias Pleroma.Web.Router.Helpers
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
index ff664636c..b5c9bf8d0 100644
--- a/lib/pleroma/web/activity_pub/views/object_view.ex
+++ b/lib/pleroma/web/activity_pub/views/object_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.ObjectView do
use Pleroma.Web, :view
alias Pleroma.{Object, Activity}
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 869934172..fe8248107 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.UserView do
use Pleroma.Web, :view
alias Pleroma.Web.Salmon
@@ -172,6 +176,53 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end
end
+ def render("inbox.json", %{user: user, max_id: max_qid}) do
+ params = %{
+ "limit" => "10"
+ }
+
+ params =
+ if max_qid != nil do
+ Map.put(params, "max_id", max_qid)
+ else
+ params
+ end
+
+ activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
+
+ min_id = Enum.at(Enum.reverse(activities), 0).id
+ max_id = Enum.at(activities, 0).id
+
+ collection =
+ Enum.map(activities, fn act ->
+ {:ok, data} = Transmogrifier.prepare_outgoing(act.data)
+ data
+ end)
+
+ iri = "#{user.ap_id}/inbox"
+
+ page = %{
+ "id" => "#{iri}?max_id=#{max_id}",
+ "type" => "OrderedCollectionPage",
+ "partOf" => iri,
+ "totalItems" => -1,
+ "orderedItems" => collection,
+ "next" => "#{iri}?max_id=#{min_id - 1}"
+ }
+
+ if max_qid == nil do
+ %{
+ "id" => iri,
+ "type" => "OrderedCollection",
+ "totalItems" => -1,
+ "first" => page
+ }
+ |> Map.merge(Utils.make_json_ld_header())
+ else
+ page |> Map.merge(Utils.make_json_ld_header())
+ end
+ end
+
def collection(collection, iri, page, show_items \\ true, total \\ nil) do
offset = (page - 1) * 10
items = Enum.slice(collection, offset, 10)
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 4d73cf219..dc01f46f3 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -1,6 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller
- alias Pleroma.{User, Repo}
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
@@ -10,13 +14,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
action_fallback(:errors)
def user_delete(conn, %{"nickname" => nickname}) do
- user = User.get_by_nickname(nickname)
-
- if user.local == true do
- User.delete(user)
- else
- User.delete(user)
- end
+ User.get_by_nickname(nickname)
+ |> User.delete()
conn
|> json(nickname)
@@ -26,7 +25,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn,
%{"nickname" => nickname, "email" => email, "password" => password}
) do
- new_user = %{
+ user_data = %{
nickname: nickname,
name: nickname,
email: email,
@@ -35,11 +34,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
bio: "."
}
- User.register_changeset(%User{}, new_user)
- |> Repo.insert!()
+ changeset = User.register_changeset(%User{}, user_data, confirmed: true)
+ {:ok, user} = User.register(changeset)
conn
- |> json(new_user.nickname)
+ |> json(user.nickname)
end
def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 9918d3b49..aed8475fd 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.UserSocket do
use Phoenix.Socket
alias Pleroma.User
diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex
index 37eba8c3f..fe63ede66 100644
--- a/lib/pleroma/web/chat_channel.ex
+++ b/lib/pleroma/web/chat_channel.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ChatChannel do
use Phoenix.Channel
alias Pleroma.Web.ChatChannel.ChatChannelState
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index f01d36370..2902905fd 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.CommonAPI do
alias Pleroma.{User, Repo, Activity, Object}
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -10,6 +14,7 @@ defmodule Pleroma.Web.CommonAPI do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.normalize(object_id),
true <- user.info.is_moderator || user.ap_id == object.data["actor"],
+ {:ok, _} <- unpin(activity_id, user),
{:ok, delete} <- ActivityPub.delete(object) do
{:ok, delete}
end
@@ -98,7 +103,7 @@ defmodule Pleroma.Web.CommonAPI do
attachments,
tags,
get_content_type(data["content_type"]),
- data["no_attachment_links"]
+ Enum.member?([true, "true"], data["no_attachment_links"])
),
context <- make_context(inReplyTo),
cw <- data["spoiler_text"],
@@ -120,7 +125,7 @@ defmodule Pleroma.Web.CommonAPI do
Map.put(
object,
"emoji",
- Formatter.get_emoji(status)
+ (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"]))
|> Enum.reduce(%{}, fn {name, file}, acc ->
Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
end)
@@ -160,4 +165,48 @@ defmodule Pleroma.Web.CommonAPI do
object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
})
end
+
+ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
+ with %Activity{
+ actor: ^user_ap_id,
+ data: %{
+ "type" => "Create",
+ "object" => %{
+ "to" => object_to,
+ "type" => "Note"
+ }
+ }
+ } = activity <- get_by_id_or_ap_id(id_or_ap_id),
+ true <- Enum.member?(object_to, "https://www.w3.org/ns/activitystreams#Public"),
+ %{valid?: true} = info_changeset <-
+ Pleroma.User.Info.add_pinnned_activity(user.info, activity),
+ changeset <-
+ Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
+ {:ok, _user} <- User.update_and_set_cache(changeset) do
+ {:ok, activity}
+ else
+ %{errors: [pinned_activities: {err, _}]} ->
+ {:error, err}
+
+ _ ->
+ {:error, "Could not pin"}
+ end
+ end
+
+ def unpin(id_or_ap_id, user) do
+ with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
+ %{valid?: true} = info_changeset <-
+ Pleroma.User.Info.remove_pinnned_activity(user.info, activity),
+ changeset <-
+ Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
+ {:ok, _user} <- User.update_and_set_cache(changeset) do
+ {:ok, activity}
+ else
+ %{errors: [pinned_activities: {err, _}]} ->
+ {:error, err}
+
+ _ ->
+ {:error, "Could not unpin"}
+ end
+ end
end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 142283684..7e30d224c 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.CommonAPI.Utils do
alias Calendar.Strftime
alias Comeonin.Pbkdf2
@@ -132,7 +136,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def format_input(text, mentions, _tags, "text/html") do
text
|> Formatter.html_escape("text/html")
- |> String.replace(~r/\r?\n/, "<br>")
|> (&{[], &1}).()
|> Formatter.add_user_links(mentions)
|> Formatter.finalize()
@@ -146,7 +149,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|> Formatter.mentions_escape(mentions)
|> Earmark.as_html!()
|> Formatter.html_escape("text/html")
- |> String.replace(~r/\r?\n/, "")
|> (&{[], &1}).()
|> Formatter.add_user_links(mentions)
|> Formatter.add_hashtag_links(tags)
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index ddf958811..14e3d19fd 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index d79f61b2e..0b4ce9cc4 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Endpoint do
use Phoenix.Endpoint, otp_app: :pleroma
@@ -21,7 +25,7 @@ defmodule Pleroma.Web.Endpoint do
at: "/",
from: :pleroma,
only:
- ~w(index.html static finmoji emoji packs sounds images instance sw.js favicon.png schemas)
+ ~w(index.html static finmoji emoji packs sounds images instance sw.js favicon.png schemas doc)
)
# Code reloading can be explicitly enabled under the
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index a9c7aecd5..f3a0e18b8 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Federator do
use GenServer
alias Pleroma.User
@@ -13,7 +17,6 @@ defmodule Pleroma.Web.Federator do
@websub Application.get_env(:pleroma, :websub)
@ostatus Application.get_env(:pleroma, :ostatus)
- @max_jobs 20
def init(args) do
{:ok, args}
@@ -164,7 +167,7 @@ defmodule Pleroma.Web.Federator do
end
def maybe_start_job(running_jobs, queue) do
- if :sets.size(running_jobs) < @max_jobs && queue != [] do
+ if :sets.size(running_jobs) < Pleroma.Config.get([__MODULE__, :max_jobs]) && queue != [] do
{{type, payload}, queue} = queue_pop(queue)
{:ok, pid} = Task.start(fn -> handle(type, payload) end)
mref = Process.monitor(pid)
diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex
index 510b4315d..e0ce251d2 100644
--- a/lib/pleroma/web/federator/retry_queue.ex
+++ b/lib/pleroma/web/federator/retry_queue.ex
@@ -1,22 +1,34 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Federator.RetryQueue do
use GenServer
require Logger
- # initial timeout, 5 min
- @initial_timeout 30_000
- @max_retries 5
-
def init(args) do
- {:ok, args}
+ queue_table = :ets.new(:pleroma_retry_queue, [:bag, :protected])
+
+ {:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
end
def start_link() do
- enabled = Pleroma.Config.get([:retry_queue, :enabled], false)
+ enabled =
+ if Mix.env() == :test, do: true, else: Pleroma.Config.get([__MODULE__, :enabled], false)
if enabled do
Logger.info("Starting retry queue")
- GenServer.start_link(__MODULE__, %{delivered: 0, dropped: 0}, name: __MODULE__)
+
+ linkres =
+ GenServer.start_link(
+ __MODULE__,
+ %{delivered: 0, dropped: 0, queue_table: nil, running_jobs: nil},
+ name: __MODULE__
+ )
+
+ maybe_kickoff_timer()
+ linkres
else
Logger.info("Retry queue disabled")
:ignore
@@ -27,24 +39,133 @@ defmodule Pleroma.Web.Federator.RetryQueue do
GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1})
end
+ def get_stats() do
+ GenServer.call(__MODULE__, :get_stats)
+ end
+
+ def reset_stats() do
+ GenServer.call(__MODULE__, :reset_stats)
+ end
+
def get_retry_params(retries) do
- if retries > @max_retries do
+ if retries > Pleroma.Config.get([__MODULE__, :max_retries]) do
{:drop, "Max retries reached"}
else
{:retry, growth_function(retries)}
end
end
- def handle_cast({:maybe_enqueue, data, transport, retries}, %{dropped: drop_count} = state) do
+ def get_retry_timer_interval() do
+ Pleroma.Config.get([:retry_queue, :interval], 1000)
+ end
+
+ defp ets_count_expires(table, current_time) do
+ :ets.select_count(
+ table,
+ [
+ {
+ {:"$1", :"$2"},
+ [{:"=<", :"$1", {:const, current_time}}],
+ [true]
+ }
+ ]
+ )
+ end
+
+ defp ets_pop_n_expired(table, current_time, desired) do
+ {popped, _continuation} =
+ :ets.select(
+ table,
+ [
+ {
+ {:"$1", :"$2"},
+ [{:"=<", :"$1", {:const, current_time}}],
+ [:"$_"]
+ }
+ ],
+ desired
+ )
+
+ popped
+ |> Enum.each(fn e ->
+ :ets.delete_object(table, e)
+ end)
+
+ popped
+ end
+
+ def maybe_start_job(running_jobs, queue_table) do
+ # we don't want to hit the ets or the DateTime more times than we have to
+ # could optimize slightly further by not using the count, and instead grabbing
+ # up to N objects early...
+ current_time = DateTime.to_unix(DateTime.utc_now())
+ n_running_jobs = :sets.size(running_jobs)
+
+ if n_running_jobs < Pleroma.Config.get([__MODULE__, :max_jobs]) do
+ n_ready_jobs = ets_count_expires(queue_table, current_time)
+
+ if n_ready_jobs > 0 do
+ # figure out how many we could start
+ available_job_slots = Pleroma.Config.get([__MODULE__, :max_jobs]) - n_running_jobs
+ start_n_jobs(running_jobs, queue_table, current_time, available_job_slots)
+ else
+ running_jobs
+ end
+ else
+ running_jobs
+ end
+ end
+
+ defp start_n_jobs(running_jobs, _queue_table, _current_time, 0) do
+ running_jobs
+ end
+
+ defp start_n_jobs(running_jobs, queue_table, current_time, available_job_slots)
+ when available_job_slots > 0 do
+ candidates = ets_pop_n_expired(queue_table, current_time, available_job_slots)
+
+ candidates
+ |> List.foldl(running_jobs, fn {_, e}, rj ->
+ {:ok, pid} = Task.start(fn -> worker(e) end)
+ mref = Process.monitor(pid)
+ :sets.add_element(mref, rj)
+ end)
+ end
+
+ def worker({:send, data, transport, retries}) do
+ case transport.publish_one(data) do
+ {:ok, _} ->
+ GenServer.cast(__MODULE__, :inc_delivered)
+ :delivered
+
+ {:error, _reason} ->
+ enqueue(data, transport, retries)
+ :retry
+ end
+ end
+
+ def handle_call(:get_stats, _from, %{delivered: delivery_count, dropped: drop_count} = state) do
+ {:reply, %{delivered: delivery_count, dropped: drop_count}, state}
+ end
+
+ def handle_call(:reset_stats, _from, %{delivered: delivery_count, dropped: drop_count} = state) do
+ {:reply, %{delivered: delivery_count, dropped: drop_count},
+ %{state | delivered: 0, dropped: 0}}
+ end
+
+ def handle_cast(:reset_stats, state) do
+ {:noreply, %{state | delivered: 0, dropped: 0}}
+ end
+
+ def handle_cast(
+ {:maybe_enqueue, data, transport, retries},
+ %{dropped: drop_count, queue_table: queue_table, running_jobs: running_jobs} = state
+ ) do
case get_retry_params(retries) do
{:retry, timeout} ->
- Process.send_after(
- __MODULE__,
- {:send, data, transport, retries},
- timeout
- )
-
- {:noreply, state}
+ :ets.insert(queue_table, {timeout, {:send, data, transport, retries}})
+ running_jobs = maybe_start_job(running_jobs, queue_table)
+ {:noreply, %{state | running_jobs: running_jobs}}
{:drop, message} ->
Logger.debug(message)
@@ -52,6 +173,20 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end
+ def handle_cast(:kickoff_timer, state) do
+ retry_interval = get_retry_timer_interval()
+ Process.send_after(__MODULE__, :retry_timer_run, retry_interval)
+ {:noreply, state}
+ end
+
+ def handle_cast(:inc_delivered, %{delivered: delivery_count} = state) do
+ {:noreply, %{state | delivered: delivery_count + 1}}
+ end
+
+ def handle_cast(:inc_dropped, %{dropped: drop_count} = state) do
+ {:noreply, %{state | dropped: drop_count + 1}}
+ end
+
def handle_info({:send, data, transport, retries}, %{delivered: delivery_count} = state) do
case transport.publish_one(data) do
{:ok, _} ->
@@ -63,12 +198,40 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end
+ def handle_info(
+ :retry_timer_run,
+ %{queue_table: queue_table, running_jobs: running_jobs} = state
+ ) do
+ maybe_kickoff_timer()
+ running_jobs = maybe_start_job(running_jobs, queue_table)
+ {:noreply, %{state | running_jobs: running_jobs}}
+ end
+
+ def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do
+ %{running_jobs: running_jobs, queue_table: queue_table} = state
+ running_jobs = :sets.del_element(ref, running_jobs)
+ running_jobs = maybe_start_job(running_jobs, queue_table)
+ {:noreply, %{state | running_jobs: running_jobs}}
+ end
+
def handle_info(unknown, state) do
Logger.debug("RetryQueue: don't know what to do with #{inspect(unknown)}, ignoring")
{:noreply, state}
end
- defp growth_function(retries) do
- round(@initial_timeout * :math.pow(retries, 3))
+ if Mix.env() == :test do
+ defp growth_function(_retries) do
+ _shutit = Pleroma.Config.get([__MODULE__, :initial_timeout])
+ DateTime.to_unix(DateTime.utc_now()) - 1
+ end
+ else
+ defp growth_function(retries) do
+ round(Pleroma.Config.get([__MODULE__, :initial_timeout]) * :math.pow(retries, 3)) +
+ DateTime.to_unix(DateTime.utc_now())
+ end
+ end
+
+ defp maybe_kickoff_timer() do
+ GenServer.cast(__MODULE__, :kickoff_timer)
end
end
diff --git a/lib/pleroma/web/gettext.ex b/lib/pleroma/web/gettext.ex
index 501545581..1328b46cc 100644
--- a/lib/pleroma/web/gettext.ex
+++ b/lib/pleroma/web/gettext.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Gettext do
@moduledoc """
A module providing Internationalization with a gettext-based API.
diff --git a/lib/pleroma/web/http_signatures/http_signatures.ex b/lib/pleroma/web/http_signatures/http_signatures.ex
index 0e54debd5..e81f9e27a 100644
--- a/lib/pleroma/web/http_signatures/http_signatures.ex
+++ b/lib/pleroma/web/http_signatures/http_signatures.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
# https://tools.ietf.org/html/draft-cavage-http-signatures-08
defmodule Pleroma.Web.HTTPSignatures do
alias Pleroma.User
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 665b75437..e00a3fb87 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Pleroma.{Repo, Object, Activity, User, Notification, Stats}
@@ -110,7 +114,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def user(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
- with %User{} = user <- Repo.get(User, id) do
+ with %User{} = user <- Repo.get(User, id),
+ true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do
account = AccountView.render("account.json", %{user: user, for: for_user})
json(conn, account)
else
@@ -251,13 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
with %User{} = user <- Repo.get(User, params["id"]) do
- # Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
- activities =
- if params["pinned"] == "true" do
- []
- else
- ActivityPub.fetch_user_activities(user, reading_user, params)
- end
+ activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
|> add_link_headers(:user_statuses, activities, params["id"])
@@ -404,6 +403,27 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def pin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ else
+ {:error, reason} ->
+ conn
+ |> put_resp_content_type("application/json")
+ |> send_resp(:bad_request, Jason.encode!(%{"error" => reason}))
+ end
+ end
+
+ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
def notifications(%{assigns: %{user: user}} = conn, params) do
notifications = Notification.for_user(user, params)
@@ -699,11 +719,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
- # TODO: Use proper query
def blocks(%{assigns: %{user: user}} = conn, _) do
- with blocked_users <- user.info.blocks || [],
- accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do
- res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
+ with blocked_accounts <- User.blocked_users(user) do
+ res = AccountView.render("accounts.json", users: blocked_accounts, for: user, as: :user)
json(conn, res)
end
end
@@ -722,11 +740,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
end
- def status_search(query) do
+ def status_search(user, query) do
fetched =
if Regex.match?(~r/https?:/, query) do
- with {:ok, object} <- ActivityPub.fetch_object_from_id(query) do
- [Activity.get_create_activity_by_object_ap_id(object.data["id"])]
+ with {:ok, object} <- ActivityPub.fetch_object_from_id(query),
+ %Activity{} = activity <-
+ Activity.get_create_activity_by_object_ap_id(object.data["id"]),
+ true <- ActivityPub.visible_for_user?(activity, user) do
+ [activity]
else
_e -> []
end
@@ -753,7 +774,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true")
- statuses = status_search(query)
+ statuses = status_search(user, query)
tags_path = Web.base_url() <> "/tag/"
@@ -777,7 +798,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true")
- statuses = status_search(query)
+ statuses = status_search(user, query)
tags =
String.split(query)
@@ -961,7 +982,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
max_toot_chars: limit
},
rights: %{
- delete_others_notice: !!user.info.is_moderator
+ delete_others_notice: !!user.info.is_moderator,
+ admin: !!user.info.is_admin
},
compose: %{
me: "#{user.id}",
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index ebcf9230b..bfd6b8b22 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.AccountView do
use Pleroma.Web, :view
alias Pleroma.User
@@ -7,10 +11,55 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
alias Pleroma.HTML
def render("accounts.json", %{users: users} = opts) do
- render_many(users, AccountView, "account.json", opts)
+ users
+ |> render_many(AccountView, "account.json", opts)
+ |> Enum.filter(&Enum.any?/1)
end
def render("account.json", %{user: user} = opts) do
+ if User.visible_for?(user, opts[:for]),
+ do: do_render("account.json", opts),
+ else: %{}
+ end
+
+ def render("mention.json", %{user: user}) do
+ %{
+ id: to_string(user.id),
+ acct: user.nickname,
+ username: username_from_nickname(user.nickname),
+ url: user.ap_id
+ }
+ end
+
+ def render("relationship.json", %{user: user, target: target}) do
+ follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target)
+
+ requested =
+ if follow_activity do
+ follow_activity.data["state"] == "pending"
+ else
+ false
+ end
+
+ %{
+ id: to_string(target.id),
+ following: User.following?(user, target),
+ followed_by: User.following?(target, user),
+ blocking: User.blocks?(user, target),
+ muting: false,
+ muting_notifications: false,
+ requested: requested,
+ domain_blocking: false,
+ showing_reblogs: false,
+ endorsed: false
+ }
+ end
+
+ def render("relationships.json", %{user: user, targets: targets}) do
+ render_many(targets, AccountView, "relationship.json", user: user, as: :target)
+ end
+
+ defp do_render("account.json", %{user: user} = opts) do
image = User.avatar_url(user) |> MediaProxy.url()
header = User.banner_url(user) |> MediaProxy.url()
user_info = User.user_info(user)
@@ -62,48 +111,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
# Pleroma extension
pleroma: %{
+ confirmation_pending: user_info.confirmation_pending,
tags: user.tags
}
}
end
- def render("mention.json", %{user: user}) do
- %{
- id: to_string(user.id),
- acct: user.nickname,
- username: username_from_nickname(user.nickname),
- url: user.ap_id
- }
- end
-
- def render("relationship.json", %{user: user, target: target}) do
- follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target)
-
- requested =
- if follow_activity do
- follow_activity.data["state"] == "pending"
- else
- false
- end
-
- %{
- id: to_string(target.id),
- following: User.following?(user, target),
- followed_by: User.following?(target, user),
- blocking: User.blocks?(user, target),
- muting: false,
- muting_notifications: false,
- requested: requested,
- domain_blocking: false,
- showing_reblogs: false,
- endorsed: false
- }
- end
-
- def render("relationships.json", %{user: user, targets: targets}) do
- render_many(targets, AccountView, "relationship.json", user: user, as: :target)
- end
-
defp username_from_nickname(string) when is_binary(string) do
hd(String.split(string, "@"))
end
diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
index 6bd687d46..1052a449d 100644
--- a/lib/pleroma/web/mastodon_api/views/filter_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/filter_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.FilterView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.FilterView
diff --git a/lib/pleroma/web/mastodon_api/views/list_view.ex b/lib/pleroma/web/mastodon_api/views/list_view.ex
index 1a1b7430b..0f86e2512 100644
--- a/lib/pleroma/web/mastodon_api/views/list_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/list_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.ListView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.ListView
diff --git a/lib/pleroma/web/mastodon_api/views/mastodon_view.ex b/lib/pleroma/web/mastodon_api/views/mastodon_view.ex
index 1fd05d9f1..33b9a74be 100644
--- a/lib/pleroma/web/mastodon_api/views/mastodon_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/mastodon_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.MastodonView do
use Pleroma.Web, :view
import Phoenix.HTML
diff --git a/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex b/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
index 67e86294e..e86b789c5 100644
--- a/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
use Pleroma.Web, :view
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 46c559e3a..db543ffe5 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.StatusView do
use Pleroma.Web, :view
@@ -72,6 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogged: false,
favourited: false,
muted: false,
+ pinned: pinned?(activity, user),
sensitive: false,
spoiler_text: "",
visibility: "public",
@@ -106,7 +111,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
attachment_data = object["attachment"] || []
- attachment_data = attachment_data ++ if object["type"] == "Video", do: [object], else: []
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
created_at = Utils.to_masto_date(object["published"])
@@ -117,7 +121,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
content =
object
|> render_content()
- |> HTML.filter_tags(User.html_filter_policy(opts[:for]))
+ |> HTML.get_cached_scrubbed_html_for_object(
+ User.html_filter_policy(opts[:for]),
+ activity,
+ __MODULE__
+ )
%{
id: to_string(activity.id),
@@ -135,6 +143,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogged: present?(repeated),
favourited: present?(favorited),
muted: false,
+ pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: object["summary"] || "",
visibility: get_visibility(object),
@@ -288,4 +297,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
defp present?(nil), do: false
defp present?(false), do: false
defp present?(_), do: true
+
+ defp pinned?(%Activity{id: id}, %User{info: %{pinned_activities: pinned_activities}}),
+ do: id in pinned_activities
end
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 11e0e1696..c0254c8e6 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
require Logger
diff --git a/lib/pleroma/web/media_proxy/controller.ex b/lib/pleroma/web/media_proxy/controller.ex
index 63140feb9..de79cad73 100644
--- a/lib/pleroma/web/media_proxy/controller.ex
+++ b/lib/pleroma/web/media_proxy/controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MediaProxy.MediaProxyController do
use Pleroma.Web, :controller
alias Pleroma.{Web.MediaProxy, ReverseProxy}
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 902ab1b77..e1eb1472d 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MediaProxy do
@base64_opts [padding: false]
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 44c11f40a..11b97164d 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
use Pleroma.Web, :controller
@@ -132,8 +136,10 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
banner: Keyword.get(instance, :banner_upload_limit),
background: Keyword.get(instance, :background_upload_limit)
},
+ accountActivationRequired: Keyword.get(instance, :account_activation_required, false),
invitesEnabled: Keyword.get(instance, :invites_enabled, false),
- features: features
+ features: features,
+ restrictedNicknames: Pleroma.Config.get([Pleroma.User, :restricted_nicknames])
}
}
diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex
index b3273bc6e..967ac04b5 100644
--- a/lib/pleroma/web/oauth/app.ex
+++ b/lib/pleroma/web/oauth/app.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.App do
use Ecto.Schema
import Ecto.{Changeset}
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
index 2cad4550a..cc4b74bc5 100644
--- a/lib/pleroma/web/oauth/authorization.ex
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.Authorization do
use Ecto.Schema
diff --git a/lib/pleroma/web/oauth/fallback_controller.ex b/lib/pleroma/web/oauth/fallback_controller.ex
index 3927cdb64..1eeda3d24 100644
--- a/lib/pleroma/web/oauth/fallback_controller.ex
+++ b/lib/pleroma/web/oauth/fallback_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.FallbackController do
use Pleroma.Web, :controller
alias Pleroma.Web.OAuth.OAuthController
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 20c2e799b..4d4e85836 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
@@ -31,6 +35,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
}) do
with %User{} = user <- User.get_by_nickname_or_email(name),
true <- Pbkdf2.checkpw(password, user.password_hash),
+ {:auth_active, true} <- {:auth_active, User.auth_active?(user)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
{:ok, auth} <- Authorization.create_authorization(app, user) do
# Special case: Local MastodonFE.
@@ -63,6 +68,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do
redirect(conn, external: url)
end
+ else
+ {:auth_active, false} ->
+ conn
+ |> put_flash(:error, "Account confirmation pending")
+ |> put_status(:forbidden)
+ |> authorize(params)
+
+ error ->
+ error
end
end
@@ -101,6 +115,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
with %App{} = app <- get_app_from_request(conn, params),
%User{} = user <- User.get_by_nickname_or_email(name),
true <- Pbkdf2.checkpw(password, user.password_hash),
+ {:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user),
{:ok, token} <- Token.exchange_token(app, auth) do
response = %{
@@ -113,6 +128,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do
json(conn, response)
else
+ {:auth_active, false} ->
+ conn
+ |> put_status(:forbidden)
+ |> json(%{error: "Account confirmation pending"})
+
_error ->
put_status(conn, 400)
|> json(%{error: "Invalid credentials"})
diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex
index b3923fcf5..9b37a91c5 100644
--- a/lib/pleroma/web/oauth/oauth_view.ex
+++ b/lib/pleroma/web/oauth/oauth_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.OAuthView do
use Pleroma.Web, :view
import Phoenix.HTML.Form
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index a77d5af35..f0ebc63f6 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OAuth.Token do
use Ecto.Schema
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index 537bd9f77..94b1a7ad1 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
alias Pleroma.{Activity, User, Object}
alias Pleroma.Web.OStatus.UserRepresenter
diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex
index 279672673..934d4042f 100644
--- a/lib/pleroma/web/ostatus/feed_representer.ex
+++ b/lib/pleroma/web/ostatus/feed_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.FeedRepresenter do
alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.{UserRepresenter, ActivityRepresenter}
diff --git a/lib/pleroma/web/ostatus/handlers/delete_handler.ex b/lib/pleroma/web/ostatus/handlers/delete_handler.ex
index 6330d7f64..01b52f08f 100644
--- a/lib/pleroma/web/ostatus/handlers/delete_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/delete_handler.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.DeleteHandler do
require Logger
alias Pleroma.Web.XML
diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
index 162407e04..becdf2fbf 100644
--- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.FollowHandler do
alias Pleroma.Web.{XML, OStatus}
alias Pleroma.Web.ActivityPub.ActivityPub
diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex
index 0d4080291..5aeed46f0 100644
--- a/lib/pleroma/web/ostatus/handlers/note_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.NoteHandler do
require Logger
alias Pleroma.Web.{XML, OStatus}
diff --git a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
index a115bf4c8..1c64f3c3d 100644
--- a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.UnfollowHandler do
alias Pleroma.Web.{XML, OStatus}
alias Pleroma.Web.ActivityPub.ActivityPub
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index c6440c20e..bb28cd786 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus do
@httpoison Application.get_env(:pleroma, :httpoison)
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 5dbee20e1..be648a6ee 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.OStatusController do
use Pleroma.Web, :controller
@@ -112,23 +116,27 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end
def activity(conn, %{"uuid" => uuid}) do
- with id <- o_status_url(conn, :activity, uuid),
- {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
- {_, true} <- {:public?, ActivityPub.is_public?(activity)},
- %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
- case format = get_format(conn) do
- "html" -> redirect(conn, to: "/notice/#{activity.id}")
- _ -> represent_activity(conn, format, activity, user)
- end
+ if get_format(conn) == "activity+json" do
+ ActivityPubController.call(conn, :activity)
else
- {:public?, false} ->
- {:error, :not_found}
+ with id <- o_status_url(conn, :activity, uuid),
+ {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
+ {_, true} <- {:public?, ActivityPub.is_public?(activity)},
+ %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
+ case format = get_format(conn) do
+ "html" -> redirect(conn, to: "/notice/#{activity.id}")
+ _ -> represent_activity(conn, format, activity, user)
+ end
+ else
+ {:public?, false} ->
+ {:error, :not_found}
- {:activity, nil} ->
- {:error, :not_found}
+ {:activity, nil} ->
+ {:error, :not_found}
- e ->
- e
+ e ->
+ e
+ end
end
end
diff --git a/lib/pleroma/web/ostatus/user_representer.ex b/lib/pleroma/web/ostatus/user_representer.ex
index 2e696506e..852be6eb4 100644
--- a/lib/pleroma/web/ostatus/user_representer.ex
+++ b/lib/pleroma/web/ostatus/user_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.UserRepresenter do
alias Pleroma.User
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index 477943450..ffd2aac91 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Push do
use GenServer
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex
index 1ad405daf..82b30950c 100644
--- a/lib/pleroma/web/push/subscription.ex
+++ b/lib/pleroma/web/push/subscription.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Push.Subscription do
use Ecto.Schema
import Ecto.Changeset
diff --git a/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex b/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex
new file mode 100644
index 000000000..91019961d
--- /dev/null
+++ b/lib/pleroma/web/rich_media/controllers/rich_media_controller.ex
@@ -0,0 +1,17 @@
+defmodule Pleroma.Web.RichMedia.RichMediaController do
+ use Pleroma.Web, :controller
+
+ import Pleroma.Web.ControllerHelper, only: [json_response: 3]
+
+ def parse(conn, %{"url" => url}) do
+ case Pleroma.Web.RichMedia.Parser.parse(url) do
+ {:ok, data} ->
+ conn
+ |> json_response(200, data)
+
+ {:error, msg} ->
+ conn
+ |> json_response(404, msg)
+ end
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
new file mode 100644
index 000000000..fe092bf19
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -0,0 +1,33 @@
+defmodule Pleroma.Web.RichMedia.Parser do
+ @parsers [Pleroma.Web.RichMedia.Parsers.OGP, Pleroma.Web.RichMedia.Parsers.TwitterCard]
+
+ if Mix.env() == :test do
+ def parse(url), do: parse_url(url)
+ else
+ def parse(url),
+ do: Cachex.fetch!(:rich_media_cache, url, fn _ -> parse_url(url) end)
+ end
+
+ defp parse_url(url) do
+ {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url)
+
+ html |> maybe_parse() |> get_parsed_data()
+ end
+
+ defp maybe_parse(html) do
+ Enum.reduce_while(@parsers, %{}, fn parser, acc ->
+ case parser.parse(html, acc) do
+ {:ok, data} -> {:halt, data}
+ {:error, _msg} -> {:cont, acc}
+ end
+ end)
+ end
+
+ defp get_parsed_data(data) when data == %{} do
+ {:error, "No metadata found"}
+ end
+
+ defp get_parsed_data(data) do
+ {:ok, data}
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
new file mode 100644
index 000000000..4a7c5eae0
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
@@ -0,0 +1,30 @@
+defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do
+ def parse(html, data, prefix, error_message, key_name, value_name \\ "content") do
+ with elements = [_ | _] <- get_elements(html, key_name, prefix),
+ meta_data =
+ Enum.reduce(elements, data, fn el, acc ->
+ attributes = normalize_attributes(el, prefix, key_name, value_name)
+
+ Map.merge(acc, attributes)
+ end) do
+ {:ok, meta_data}
+ else
+ _e -> {:error, error_message}
+ end
+ end
+
+ defp get_elements(html, key_name, prefix) do
+ html |> Floki.find("meta[#{key_name}^='#{prefix}:']")
+ end
+
+ defp normalize_attributes(html_node, prefix, key_name, value_name) do
+ {_tag, attributes, _children} = html_node
+
+ data =
+ Enum.into(attributes, %{}, fn {name, value} ->
+ {name, String.trim_leading(value, "#{prefix}:")}
+ end)
+
+ %{String.to_atom(data[key_name]) => data[value_name]}
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parsers/ogp.ex b/lib/pleroma/web/rich_media/parsers/ogp.ex
new file mode 100644
index 000000000..0e1a0e719
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parsers/ogp.ex
@@ -0,0 +1,11 @@
+defmodule Pleroma.Web.RichMedia.Parsers.OGP do
+ def parse(html, data) do
+ Pleroma.Web.RichMedia.Parsers.MetaTagsParser.parse(
+ html,
+ data,
+ "og",
+ "No OGP metadata found",
+ "property"
+ )
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parsers/twitter_card.ex b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
new file mode 100644
index 000000000..a317c3e78
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
@@ -0,0 +1,11 @@
+defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do
+ def parse(html, data) do
+ Pleroma.Web.RichMedia.Parsers.MetaTagsParser.parse(
+ html,
+ data,
+ "twitter",
+ "No twitter card metadata found",
+ "name"
+ )
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 59784549d..5ef99bec5 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
@@ -133,6 +137,7 @@ defmodule Pleroma.Web.Router do
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:authenticated_api)
+ post("/blocks_import", UtilController, :blocks_import)
post("/follow_import", UtilController, :follow_import)
post("/change_password", UtilController, :change_password)
post("/delete_account", UtilController, :delete_account)
@@ -183,6 +188,8 @@ defmodule Pleroma.Web.Router do
post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
+ post("/statuses/:id/pin", MastodonAPIController, :pin_status)
+ post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
post("/notifications/clear", MastodonAPIController, :clear_notifications)
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
@@ -227,6 +234,12 @@ defmodule Pleroma.Web.Router do
put("/settings", MastodonAPIController, :put_settings)
end
+ scope "/api", Pleroma.Web.RichMedia do
+ pipe_through(:authenticated_api)
+
+ get("/rich_media/parse", RichMediaController, :parse)
+ end
+
scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/instance", MastodonAPIController, :masto_instance)
@@ -277,12 +290,22 @@ defmodule Pleroma.Web.Router do
get("/statuses/followers", TwitterAPI.Controller, :followers)
get("/statuses/friends", TwitterAPI.Controller, :friends)
+ get("/statuses/blocks", TwitterAPI.Controller, :blocks)
get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status)
get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation)
post("/account/register", TwitterAPI.Controller, :register)
post("/account/password_reset", TwitterAPI.Controller, :password_reset)
+ get(
+ "/account/confirm_email/:user_id/:token",
+ TwitterAPI.Controller,
+ :confirm_email,
+ as: :confirm_email
+ )
+
+ post("/account/resend_confirmation_email", TwitterAPI.Controller, :resend_confirmation_email)
+
get("/search", TwitterAPI.Controller, :search)
get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline)
end
@@ -332,6 +355,9 @@ defmodule Pleroma.Web.Router do
post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet)
post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
+ post("/statuses/pin/:id", TwitterAPI.Controller, :pin)
+ post("/statuses/unpin/:id", TwitterAPI.Controller, :unpin)
+
get("/pleroma/friend_requests", TwitterAPI.Controller, :friend_requests)
post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request)
post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request)
@@ -407,6 +433,27 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/outbox", ActivityPubController, :outbox)
end
+ pipeline :activitypub_client do
+ plug(:accepts, ["activity+json"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.BasicAuthDecoderPlug)
+ plug(Pleroma.Plugs.UserFetcherPlug)
+ plug(Pleroma.Plugs.SessionAuthenticationPlug)
+ plug(Pleroma.Plugs.LegacyAuthenticationPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug)
+ plug(Pleroma.Plugs.UserEnabledPlug)
+ plug(Pleroma.Plugs.SetUserSessionIdPlug)
+ plug(Pleroma.Plugs.EnsureUserKeyPlug)
+ end
+
+ scope "/", Pleroma.Web.ActivityPub do
+ pipe_through([:activitypub_client])
+
+ get("/users/:nickname/inbox", ActivityPubController, :read_inbox)
+ post("/users/:nickname/outbox", ActivityPubController, :update_outbox)
+ end
+
scope "/relay", Pleroma.Web.ActivityPub do
pipe_through(:ap_relay)
get("/", ActivityPubController, :relay)
diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex
index b67b1333f..e41657da1 100644
--- a/lib/pleroma/web/salmon/salmon.ex
+++ b/lib/pleroma/web/salmon/salmon.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Salmon do
@httpoison Application.get_env(:pleroma, :httpoison)
@@ -157,16 +161,21 @@ defmodule Pleroma.Web.Salmon do
|> Enum.filter(fn user -> user && !user.local end)
end
- defp send_to_user(%{info: %{salmon: salmon}}, feed, poster) do
+ # push an activity to remote accounts
+ #
+ defp send_to_user(%{info: %{salmon: salmon}}, feed, poster),
+ do: send_to_user(salmon, feed, poster)
+
+ defp send_to_user(url, feed, poster) when is_binary(url) do
with {:ok, %{status: code}} <-
poster.(
- salmon,
+ url,
feed,
[{"Content-Type", "application/magic-envelope+xml"}]
) do
- Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end)
+ Logger.debug(fn -> "Pushed to #{url}, code #{code}" end)
else
- e -> Logger.debug(fn -> "Pushing Salmon to #{salmon} failed, #{inspect(e)}" end)
+ e -> Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end)
end
end
@@ -180,6 +189,11 @@ defmodule Pleroma.Web.Salmon do
"Undo",
"Delete"
]
+
+ @doc """
+ Publishes an activity to remote accounts
+ """
+ @spec publish(User.t(), Pleroma.Activity.t(), Pleroma.HTTP.t()) :: none
def publish(user, activity, poster \\ &@httpoison.post/3)
def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster)
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index e1eecba4d..3136b1b9d 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Streamer do
use GenServer
require Logger
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 38653f0b8..a79072f3d 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.UtilController do
use Pleroma.Web, :controller
require Logger
@@ -174,6 +178,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
vapidPublicKey: vapid_public_key,
+ accountActivationRequired:
+ if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0")
}
@@ -234,21 +240,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
follow_import(conn, %{"list" => File.read!(listfile.path)})
end
- def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do
- Task.start(fn ->
- String.split(list)
- |> Enum.map(fn account ->
- with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id),
- %User{} = followed <- User.get_or_fetch(account),
- {:ok, follower} <- User.maybe_direct_follow(follower, followed) do
- ActivityPub.follow(follower, followed)
- else
- err -> Logger.debug("follow_import: following #{account} failed with #{inspect(err)}")
- end
- end)
- end)
+ def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
+ with followed_identifiers <- String.split(list),
+ {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do
+ json(conn, "job started")
+ end
+ end
+
+ def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
+ blocks_import(conn, %{"list" => File.read!(listfile.path)})
+ end
- json(conn, "job started")
+ def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
+ with blocked_identifiers <- String.split(list),
+ {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do
+ json(conn, "job started")
+ end
end
def change_password(%{assigns: %{user: user}} = conn, params) do
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 2808192b0..4f8f228ab 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
# THIS MODULE IS DEPRECATED! DON'T USE IT!
# USE THE Pleroma.Web.TwitterAPI.Views.ActivityView MODULE!
defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
@@ -149,6 +153,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
+ pinned = activity.id in user.info.pinned_activities
mentions = opts[:mentioned] || []
@@ -171,19 +176,14 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
HTML.filter_tags(content, User.html_filter_policy(opts[:for]))
|> Formatter.emojify(object["emoji"])
- video =
- if object["type"] == "Video" do
- [object]
- else
- []
- end
-
- attachments = (object["attachment"] || []) ++ video
+ attachments = object["attachment"] || []
reply_parent = Activity.get_in_reply_to_activity(activity)
reply_user = reply_parent && User.get_cached_by_ap_id(reply_parent.actor)
+ summary = HTML.strip_tags(object["summary"])
+
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
@@ -205,12 +205,14 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
"repeat_num" => announcement_count,
"favorited" => to_boolean(favorited),
"repeated" => to_boolean(repeated),
+ "pinned" => pinned,
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
"possibly_sensitive" => possibly_sensitive,
"visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
- "summary" => object["summary"]
+ "summary" => summary,
+ "summary_html" => summary |> Formatter.emojify(object["emoji"])
}
end
diff --git a/lib/pleroma/web/twitter_api/representers/base_representer.ex b/lib/pleroma/web/twitter_api/representers/base_representer.ex
index f32a21d47..3d31e6079 100644
--- a/lib/pleroma/web/twitter_api/representers/base_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/base_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.Representers.BaseRepresenter do
defmacro __using__(_opts) do
quote do
diff --git a/lib/pleroma/web/twitter_api/representers/object_representer.ex b/lib/pleroma/web/twitter_api/representers/object_representer.ex
index d5291a397..47130ba06 100644
--- a/lib/pleroma/web/twitter_api/representers/object_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/object_representer.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter do
use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
alias Pleroma.Object
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 90b8345c5..7a63724f1 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -1,8 +1,14 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
alias Pleroma.{UserInviteToken, User, Activity, Repo, Object}
+ alias Pleroma.{UserEmail, Mailer}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.TwitterAPI.UserView
alias Pleroma.Web.CommonAPI
+
import Ecto.Query
def create_status(%User{} = user, %{"status" => _} = data) do
@@ -76,6 +82,14 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
end
+ def pin(%User{} = user, ap_id_or_id) do
+ CommonAPI.pin(ap_id_or_id, user)
+ end
+
+ def unpin(%User{} = user, ap_id_or_id) do
+ CommonAPI.unpin(ap_id_or_id, user)
+ end
+
def fav(%User{} = user, ap_id_or_id) do
with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
@@ -134,22 +148,28 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
password: params["password"],
password_confirmation: params["confirm"],
captcha_solution: params["captcha_solution"],
- captcha_token: params["captcha_token"]
+ captcha_token: params["captcha_token"],
+ captcha_answer_data: params["captcha_answer_data"]
}
captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled])
# true if captcha is disabled or enabled and valid, false otherwise
captcha_ok =
if !captcha_enabled do
- true
+ :ok
else
- Pleroma.Captcha.validate(params[:captcha_token], params[:captcha_solution])
+ Pleroma.Captcha.validate(
+ params[:captcha_token],
+ params[:captcha_solution],
+ params[:captcha_answer_data]
+ )
end
# Captcha invalid
- if not captcha_ok do
+ if captcha_ok != :ok do
+ {:error, error} = captcha_ok
# I have no idea how this error handling works
- {:error, %{error: Jason.encode!(%{captcha: ["Invalid CAPTCHA"]})}}
+ {:error, %{error: Jason.encode!(%{captcha: [error]})}}
else
registrations_open = Pleroma.Config.get([:instance, :registrations_open])
@@ -161,10 +181,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
cond do
registrations_open || (!is_nil(token) && !token.used) ->
- changeset = User.register_changeset(%User{info: %{}}, params)
+ changeset = User.register_changeset(%User{}, params)
- with {:ok, user} <- Repo.insert(changeset) do
+ with {:ok, user} <- User.register(changeset) do
!registrations_open && UserInviteToken.mark_as_used(token.token)
+
{:ok, user}
else
{:error, changeset} ->
@@ -189,8 +210,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
%User{local: true} = user <- User.get_by_nickname_or_email(nickname_or_email),
{:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
user
- |> Pleroma.UserEmail.password_reset_email(token_record.token)
- |> Pleroma.Mailer.deliver()
+ |> UserEmail.password_reset_email(token_record.token)
+ |> Mailer.deliver()
else
false ->
{:error, "bad user identifier"}
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 327620302..1c728166c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.Controller do
use Pleroma.Web, :controller
@@ -96,10 +100,15 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def show_user(conn, params) do
- with {:ok, shown} <- TwitterAPI.get_user(params) do
+ for_user = conn.assigns.user
+
+ with {:ok, shown} <- TwitterAPI.get_user(params),
+ true <-
+ User.auth_active?(shown) ||
+ (for_user && (for_user.id == shown.id || User.superuser?(for_user))) do
params =
- if user = conn.assigns.user do
- %{user: shown, for: user}
+ if for_user do
+ %{user: shown, for: for_user}
else
%{user: shown}
end
@@ -110,12 +119,26 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
else
{:error, msg} ->
bad_request_reply(conn, msg)
+
+ false ->
+ conn
+ |> put_status(404)
+ |> json(%{error: "Unconfirmed user"})
end
end
def user_timeline(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.get_user(user, params) do
{:ok, target_user} ->
+ # Twitter and ActivityPub use a different name and sense for this parameter.
+ {include_rts, params} = Map.pop(params, "include_rts")
+
+ params =
+ case include_rts do
+ x when x == "false" or x == "0" -> Map.put(params, "exclude_reblogs", "true")
+ _ -> params
+ end
+
activities = ActivityPub.fetch_user_activities(target_user, user, params)
conn
@@ -352,6 +375,30 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
end
+ def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+ {:ok, activity} <- TwitterAPI.pin(user, id) do
+ conn
+ |> put_view(ActivityView)
+ |> render("activity.json", %{activity: activity, for: user})
+ else
+ {:error, message} -> bad_request_reply(conn, message)
+ err -> err
+ end
+ end
+
+ def unpin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+ {:ok, activity} <- TwitterAPI.unpin(user, id) do
+ conn
+ |> put_view(ActivityView)
+ |> render("activity.json", %{activity: activity, for: user})
+ else
+ {:error, message} -> bad_request_reply(conn, message)
+ err -> err
+ end
+ end
+
def register(conn, params) do
with {:ok, user} <- TwitterAPI.register_user(params) do
conn
@@ -372,6 +419,29 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
end
+ def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
+ with %User{} = user <- Repo.get(User, uid),
+ true <- user.local,
+ true <- user.info.confirmation_pending,
+ true <- user.info.confirmation_token == token,
+ info_change <- User.Info.confirmation_changeset(user.info, :confirmed),
+ changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_change),
+ {:ok, _} <- User.update_and_set_cache(changeset) do
+ conn
+ |> redirect(to: "/")
+ end
+ end
+
+ def resend_confirmation_email(conn, params) do
+ nickname_or_email = params["email"] || params["nickname"]
+
+ with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
+ {:ok, _} <- User.try_send_confirmation_email(user) do
+ conn
+ |> json_response(:no_content, "")
+ end
+ end
+
def update_avatar(%{assigns: %{user: user}} = conn, params) do
{:ok, object} = ActivityPub.upload(params, type: :avatar)
change = Changeset.change(user, %{avatar: object.data})
@@ -426,8 +496,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def followers(%{assigns: %{user: for_user}} = conn, params) do
+ {:ok, page} = Ecto.Type.cast(:integer, params["page"] || 1)
+
with {:ok, user} <- TwitterAPI.get_user(for_user, params),
- {:ok, followers} <- User.get_followers(user) do
+ {:ok, followers} <- User.get_followers(user, page) do
followers =
cond do
for_user && user.id == for_user.id -> followers
@@ -444,8 +516,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def friends(%{assigns: %{user: for_user}} = conn, params) do
+ {:ok, page} = Ecto.Type.cast(:integer, params["page"] || 1)
+
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
- {:ok, friends} <- User.get_friends(user) do
+ {:ok, friends} <- User.get_friends(user, page) do
friends =
cond do
for_user && user.id == for_user.id -> friends
@@ -461,6 +535,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
end
+ def blocks(%{assigns: %{user: user}} = conn, _params) do
+ with blocked_users <- User.blocked_users(user) do
+ conn
+ |> put_view(UserView)
+ |> render("index.json", %{users: blocked_users, for: user})
+ end
+ end
+
def friend_requests(conn, params) do
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
{:ok, friend_requests} <- User.get_follow_requests(user) do
@@ -616,7 +698,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
json_reply(conn, 403, json)
end
- def only_if_public_instance(conn = %{conn: %{assigns: %{user: _user}}}, _), do: conn
+ def only_if_public_instance(%{assigns: %{user: %User{}}} = conn, _), do: conn
def only_if_public_instance(conn, _) do
if Keyword.get(Application.get_env(:pleroma, :instance), :public) do
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 91d086740..108e7bfc5 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.ActivityView do
use Pleroma.Web, :view
alias Pleroma.Web.CommonAPI.Utils
@@ -7,11 +11,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
alias Pleroma.Activity
+ alias Pleroma.HTML
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Formatter
- alias Pleroma.HTML
import Ecto.Query
require Logger
@@ -90,11 +94,27 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
nil
+ user = User.get_cached_by_ap_id(ap_id) ->
+ user
+
+ user = User.get_by_guessed_nickname(ap_id) ->
+ user
+
true ->
- User.get_cached_by_ap_id(ap_id)
+ error_user(ap_id)
end
end
+ defp error_user(ap_id) do
+ %User{
+ name: ap_id,
+ ap_id: ap_id,
+ info: %User.Info{},
+ nickname: "erroruser@example.com",
+ inserted_at: NaiveDateTime.utc_now()
+ }
+ end
+
def render("index.json", opts) do
context_ids = collect_context_ids(opts.activities)
users = collect_users(opts.activities)
@@ -223,6 +243,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
+ pinned = activity.id in user.info.pinned_activities
attentions =
activity.recipients
@@ -241,18 +262,26 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
html =
content
- |> HTML.filter_tags(User.html_filter_policy(opts[:for]))
+ |> HTML.get_cached_scrubbed_html_for_object(
+ User.html_filter_policy(opts[:for]),
+ activity,
+ __MODULE__
+ )
|> Formatter.emojify(object["emoji"])
text =
- content
- |> String.replace(~r/<br\s?\/?>/, "\n")
- |> HTML.strip_tags()
+ if content do
+ content
+ |> String.replace(~r/<br\s?\/?>/, "\n")
+ |> HTML.get_cached_stripped_html_for_object(activity, __MODULE__)
+ end
reply_parent = Activity.get_in_reply_to_activity(activity)
reply_user = reply_parent && User.get_cached_by_ap_id(reply_parent.actor)
+ summary = HTML.strip_tags(summary)
+
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
@@ -274,12 +303,14 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
"repeat_num" => announcement_count,
"favorited" => !!favorited,
"repeated" => !!repeated,
+ "pinned" => pinned,
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
"possibly_sensitive" => possibly_sensitive,
"visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
- "summary" => summary
+ "summary" => summary,
+ "summary_html" => summary |> Formatter.emojify(object["emoji"])
}
end
@@ -301,7 +332,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
{summary, content}
end
- def render_content(%{"type" => object_type} = object) when object_type in ["Article", "Page"] do
+ def render_content(%{"type" => object_type} = object)
+ when object_type in ["Article", "Page", "Video"] do
summary = object["name"] || object["summary"]
content =
diff --git a/lib/pleroma/web/twitter_api/views/notification_view.ex b/lib/pleroma/web/twitter_api/views/notification_view.ex
index 9eeb3afdc..d6a1c0a4d 100644
--- a/lib/pleroma/web/twitter_api/views/notification_view.ex
+++ b/lib/pleroma/web/twitter_api/views/notification_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.NotificationView do
use Pleroma.Web, :view
alias Pleroma.{Notification, User}
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 8a88d72b1..a8cf83613 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.UserView do
use Pleroma.Web, :view
alias Pleroma.User
@@ -11,18 +15,44 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
end
def render("index.json", %{users: users, for: user}) do
- render_many(users, Pleroma.Web.TwitterAPI.UserView, "user.json", for: user)
+ users
+ |> render_many(Pleroma.Web.TwitterAPI.UserView, "user.json", for: user)
+ |> Enum.filter(&Enum.any?/1)
end
def render("user.json", %{user: user = %User{}} = assigns) do
+ if User.visible_for?(user, assigns[:for]),
+ do: do_render("user.json", assigns),
+ else: %{}
+ end
+
+ def render("short.json", %{
+ user: %User{
+ nickname: nickname,
+ id: id,
+ ap_id: ap_id,
+ name: name
+ }
+ }) do
+ %{
+ "fullname" => name,
+ "id" => id,
+ "ostatus_uri" => ap_id,
+ "profile_url" => ap_id,
+ "screen_name" => nickname
+ }
+ end
+
+ defp do_render("user.json", %{user: user = %User{}} = assigns) do
+ for_user = assigns[:for]
image = User.avatar_url(user) |> MediaProxy.url()
{following, follows_you, statusnet_blocking} =
- if assigns[:for] do
+ if for_user do
{
- User.following?(assigns[:for], user),
- User.following?(user, assigns[:for]),
- User.blocks?(assigns[:for], user)
+ User.following?(for_user, user),
+ User.following?(user, for_user),
+ User.blocks?(for_user, user)
}
else
{false, false, false}
@@ -47,7 +77,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
data = %{
"created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
- "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(assigns[:for])),
+ "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)),
"favourites_count" => 0,
"followers_count" => user_info[:follower_count],
"following" => following,
@@ -66,7 +96,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
"profile_image_url_profile_size" => image,
"profile_image_url_original" => image,
"rights" => %{
- "delete_others_notice" => !!user.info.is_moderator
+ "delete_others_notice" => !!user.info.is_moderator,
+ "admin" => !!user.info.is_admin
},
"screen_name" => user.nickname,
"statuses_count" => user_info[:note_count],
@@ -81,6 +112,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
# Pleroma extension
"pleroma" => %{
+ "confirmation_pending" => user_info.confirmation_pending,
"tags" => user.tags
}
}
@@ -92,23 +124,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
end
end
- def render("short.json", %{
- user: %User{
- nickname: nickname,
- id: id,
- ap_id: ap_id,
- name: name
- }
- }) do
- %{
- "fullname" => name,
- "id" => id,
- "ostatus_uri" => ap_id,
- "profile_url" => ap_id,
- "screen_name" => nickname
- }
- end
-
defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
defp image_url(_), do: nil
diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex
index 71b04e6cc..f4050650e 100644
--- a/lib/pleroma/web/twitter_api/views/util_view.ex
+++ b/lib/pleroma/web/twitter_api/views/util_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.UtilView do
use Pleroma.Web, :view
import Phoenix.HTML.Form
diff --git a/lib/pleroma/web/views/error_helpers.ex b/lib/pleroma/web/views/error_helpers.ex
index 3981b270d..bc08e60e4 100644
--- a/lib/pleroma/web/views/error_helpers.ex
+++ b/lib/pleroma/web/views/error_helpers.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ErrorHelpers do
@moduledoc """
Conveniences for translating and building error messages.
diff --git a/lib/pleroma/web/views/error_view.ex b/lib/pleroma/web/views/error_view.ex
index 7106031ae..86a1744b7 100644
--- a/lib/pleroma/web/views/error_view.ex
+++ b/lib/pleroma/web/views/error_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ErrorView do
use Pleroma.Web, :view
diff --git a/lib/pleroma/web/views/layout_view.ex b/lib/pleroma/web/views/layout_view.ex
index d4d4c3bd3..e5183701d 100644
--- a/lib/pleroma/web/views/layout_view.ex
+++ b/lib/pleroma/web/views/layout_view.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.LayoutView do
use Pleroma.Web, :view
end
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index b82242a78..74b13f929 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web do
@moduledoc """
A module that keeps using definitions for controllers,
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 47c733da2..0a6338312 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.WebFinger do
@httpoison Application.get_env(:pleroma, :httpoison)
diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex
index 8c60300a4..b77c75ec5 100644
--- a/lib/pleroma/web/web_finger/web_finger_controller.ex
+++ b/lib/pleroma/web/web_finger/web_finger_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.WebFinger.WebFingerController do
use Pleroma.Web, :controller
diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex
index 8cb07006f..3a287edd9 100644
--- a/lib/pleroma/web/websub/websub.ex
+++ b/lib/pleroma/web/websub/websub.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Websub do
alias Ecto.Changeset
alias Pleroma.Repo
diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex
index 8cea02939..105b0069f 100644
--- a/lib/pleroma/web/websub/websub_client_subscription.ex
+++ b/lib/pleroma/web/websub/websub_client_subscription.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Websub.WebsubClientSubscription do
use Ecto.Schema
alias Pleroma.User
diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex
index c1934ba92..27304d988 100644
--- a/lib/pleroma/web/websub/websub_controller.ex
+++ b/lib/pleroma/web/websub/websub_controller.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Websub.WebsubController do
use Pleroma.Web, :controller
alias Pleroma.{Repo, User}
diff --git a/lib/pleroma/web/websub/websub_server_subscription.ex b/lib/pleroma/web/websub/websub_server_subscription.ex
index 0e5248a73..d0ef548da 100644
--- a/lib/pleroma/web/websub/websub_server_subscription.ex
+++ b/lib/pleroma/web/websub/websub_server_subscription.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Websub.WebsubServerSubscription do
use Ecto.Schema
diff --git a/lib/pleroma/web/xml/xml.ex b/lib/pleroma/web/xml/xml.ex
index b3ccf4a55..df50aac9c 100644
--- a/lib/pleroma/web/xml/xml.ex
+++ b/lib/pleroma/web/xml/xml.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.XML do
require Logger