Explorar el Código

Merge remote-tracking branch 'upstream/develop' into feature/openldap-support

tags/v1.1.4
link0ff hace 5 años
padre
commit
54e7087ab4
Se han modificado 100 ficheros con 1072 adiciones y 613 borrados
  1. +5
    -7
      .credo.exs
  2. +7
    -1
      .gitlab-ci.yml
  3. +0
    -12
      TODO.txt
  4. +15
    -1
      config/config.exs
  5. +2
    -0
      config/test.exs
  6. +5
    -30
      docs/Admin-API.md
  7. +10
    -10
      docs/Clients.md
  8. +10
    -0
      docs/Differences-in-MastodonAPI-Responses.md
  9. +5
    -1
      docs/config.md
  10. +1
    -1
      lib/mix/tasks/pleroma/relay.ex
  11. +1
    -2
      lib/mix/tasks/pleroma/uploads.ex
  12. +1
    -1
      lib/mix/tasks/pleroma/user.ex
  13. +2
    -2
      lib/pleroma/PasswordResetToken.ex
  14. +13
    -1
      lib/pleroma/activity.ex
  15. +10
    -10
      lib/pleroma/application.ex
  16. +3
    -3
      lib/pleroma/captcha/captcha.ex
  17. +1
    -1
      lib/pleroma/captcha/kocaptcha.ex
  18. +4
    -4
      lib/pleroma/clippy.ex
  19. +1
    -1
      lib/pleroma/config/deprecation_warnings.ex
  20. +4
    -4
      lib/pleroma/emoji.ex
  21. +1
    -1
      lib/pleroma/filter.ex
  22. +2
    -2
      lib/pleroma/flake_id.ex
  23. +1
    -0
      lib/pleroma/formatter.ex
  24. +4
    -4
      lib/pleroma/gopher/server.ex
  25. +1
    -1
      lib/pleroma/html.ex
  26. +7
    -3
      lib/pleroma/http/connection.ex
  27. +23
    -15
      lib/pleroma/http/http.ex
  28. +1
    -1
      lib/pleroma/instances/instance.ex
  29. +2
    -2
      lib/pleroma/notification.ex
  30. +5
    -5
      lib/pleroma/object.ex
  31. +6
    -3
      lib/pleroma/plugs/http_security_plug.ex
  32. +1
    -1
      lib/pleroma/plugs/http_signature.ex
  33. +2
    -1
      lib/pleroma/plugs/oauth_plug.ex
  34. +1
    -1
      lib/pleroma/plugs/user_fetcher_plug.ex
  35. +6
    -4
      lib/pleroma/reverse_proxy.ex
  36. +1
    -1
      lib/pleroma/stats.ex
  37. +5
    -1
      lib/pleroma/thread_mute.ex
  38. +5
    -3
      lib/pleroma/upload.ex
  39. +2
    -1
      lib/pleroma/uploaders/s3.ex
  40. +1
    -1
      lib/pleroma/uploaders/swift/keystone.ex
  41. +0
    -1
      lib/pleroma/uploaders/uploader.ex
  42. +81
    -39
      lib/pleroma/user.ex
  43. +9
    -0
      lib/pleroma/user/info.ex
  44. +2
    -2
      lib/pleroma/user/welcome_message.ex
  45. +1
    -1
      lib/pleroma/user_invite_token.ex
  46. +24
    -21
      lib/pleroma/web/activity_pub/activity_pub.ex
  47. +4
    -4
      lib/pleroma/web/activity_pub/activity_pub_controller.ex
  48. +1
    -1
      lib/pleroma/web/activity_pub/mrf.ex
  49. +9
    -3
      lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
  50. +8
    -7
      lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
  51. +2
    -2
      lib/pleroma/web/activity_pub/relay.ex
  52. +10
    -8
      lib/pleroma/web/activity_pub/transmogrifier.ex
  53. +68
    -10
      lib/pleroma/web/activity_pub/utils.ex
  54. +4
    -4
      lib/pleroma/web/activity_pub/views/user_view.ex
  55. +5
    -19
      lib/pleroma/web/admin_api/admin_api_controller.ex
  56. +7
    -3
      lib/pleroma/web/admin_api/views/account_view.ex
  57. +1
    -1
      lib/pleroma/web/auth/pleroma_authenticator.ex
  58. +1
    -1
      lib/pleroma/web/channels/user_socket.ex
  59. +2
    -2
      lib/pleroma/web/chat_channel.ex
  60. +59
    -10
      lib/pleroma/web/common_api/common_api.ex
  61. +2
    -2
      lib/pleroma/web/common_api/utils.ex
  62. +2
    -1
      lib/pleroma/web/controller_helper.ex
  63. +1
    -0
      lib/pleroma/web/endpoint.ex
  64. +8
    -8
      lib/pleroma/web/federator/federator.ex
  65. +5
    -5
      lib/pleroma/web/federator/retry_queue.ex
  66. +62
    -0
      lib/pleroma/web/mastodon_api/mastodon_api.ex
  67. +39
    -86
      lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
  68. +71
    -0
      lib/pleroma/web/mastodon_api/subscription_controller.ex
  69. +2
    -3
      lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
  70. +8
    -2
      lib/pleroma/web/mastodon_api/views/status_view.ex
  71. +1
    -1
      lib/pleroma/web/mastodon_api/websocket_handler.ex
  72. +2
    -1
      lib/pleroma/web/media_proxy/media_proxy.ex
  73. +1
    -1
      lib/pleroma/web/metadata/opengraph.ex
  74. +2
    -1
      lib/pleroma/web/metadata/twitter_card.ex
  75. +4
    -4
      lib/pleroma/web/metadata/utils.ex
  76. +0
    -1
      lib/pleroma/web/nodeinfo/nodeinfo.ex
  77. +1
    -3
      lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
  78. +2
    -2
      lib/pleroma/web/oauth/authorization.ex
  79. +3
    -3
      lib/pleroma/web/oauth/oauth_controller.ex
  80. +2
    -2
      lib/pleroma/web/oauth/token.ex
  81. +1
    -1
      lib/pleroma/web/ostatus/activity_representer.ex
  82. +1
    -1
      lib/pleroma/web/ostatus/feed_representer.ex
  83. +1
    -1
      lib/pleroma/web/ostatus/handlers/delete_handler.ex
  84. +3
    -3
      lib/pleroma/web/ostatus/handlers/follow_handler.ex
  85. +17
    -15
      lib/pleroma/web/ostatus/handlers/note_handler.ex
  86. +3
    -3
      lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
  87. +6
    -6
      lib/pleroma/web/ostatus/ostatus.ex
  88. +3
    -3
      lib/pleroma/web/ostatus/ostatus_controller.ex
  89. +133
    -0
      lib/pleroma/web/push/impl.ex
  90. +22
    -97
      lib/pleroma/web/push/push.ex
  91. +19
    -9
      lib/pleroma/web/push/subscription.ex
  92. +2
    -2
      lib/pleroma/web/rel_me.ex
  93. +15
    -1
      lib/pleroma/web/rich_media/helpers.ex
  94. +0
    -1
      lib/pleroma/web/rich_media/parser.ex
  95. +5
    -6
      lib/pleroma/web/router.ex
  96. +3
    -3
      lib/pleroma/web/salmon/salmon.ex
  97. +13
    -6
      lib/pleroma/web/streamer.ex
  98. +111
    -29
      lib/pleroma/web/templates/layout/app.html.eex
  99. +19
    -16
      lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
  100. +2
    -2
      lib/pleroma/web/twitter_api/controllers/util_controller.ex

+ 5
- 7
.credo.exs Ver fichero

@@ -69,8 +69,8 @@
# You can also customize the exit_status of each check.
# If you don't want TODO comments to cause `mix credo` to fail, just
# set this value to 0 (zero).
{Credo.Check.Design.TagTODO, exit_status: 2},
{Credo.Check.Design.TagFIXME},
{Credo.Check.Design.TagTODO, exit_status: 0},
{Credo.Check.Design.TagFIXME, exit_status: 0},

{Credo.Check.Readability.FunctionNames},
{Credo.Check.Readability.LargeNumbers},
@@ -81,7 +81,9 @@
{Credo.Check.Readability.ParenthesesOnZeroArityDefs},
{Credo.Check.Readability.ParenthesesInCondition},
{Credo.Check.Readability.PredicateFunctionNames},
{Credo.Check.Readability.PreferImplicitTry},
# lanodan: I think PreferImplicitTry should be consistency, and the behaviour seems
# inconsistent, see: https://github.com/rrrene/credo/issues/224
{Credo.Check.Readability.PreferImplicitTry, false},
{Credo.Check.Readability.RedundantBlankLines},
{Credo.Check.Readability.StringSigils},
{Credo.Check.Readability.TrailingBlankLine},
@@ -126,10 +128,6 @@

# Deprecated checks (these will be deleted after a grace period)
{Credo.Check.Readability.Specs, false},
{Credo.Check.Warning.NameRedeclarationByAssignment, false},
{Credo.Check.Warning.NameRedeclarationByCase, false},
{Credo.Check.Warning.NameRedeclarationByDef, false},
{Credo.Check.Warning.NameRedeclarationByFn, false},

# Custom checks can be created using `mix credo.gen.check`.
#


+ 7
- 1
.gitlab-ci.yml Ver fichero

@@ -1,4 +1,4 @@
image: elixir:1.7.2
image: elixir:1.8.1

services:
- name: postgres:9.6.2
@@ -19,6 +19,7 @@ cache:
stages:
- lint
- test
- analysis

before_script:
- mix local.hex --force
@@ -37,3 +38,8 @@ unit-testing:
stage: test
script:
- mix test --trace --preload-modules

analysis:
stage: analysis
script:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability

+ 0
- 12
TODO.txt Ver fichero

@@ -1,12 +0,0 @@
Unliking:

- Add a proper undo activity, find out how to ignore those in twitter api.

WEBSUB:

- Add unsubscription

OSTATUS:

- Save and output 'updated'


+ 15
- 1
config/config.exs Ver fichero

@@ -133,7 +133,14 @@ config :pleroma, :httpoison, Pleroma.HTTP
config :tesla, adapter: Tesla.Adapter.Hackney

# Configures http settings, upstream proxy etc.
config :pleroma, :http, proxy_url: nil
config :pleroma, :http,
proxy_url: nil,
adapter: [
ssl_options: [
# We don't support TLS v1.3 yet
versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]
]
]

config :pleroma, :instance,
name: "Pleroma",
@@ -215,6 +222,9 @@ config :pleroma, :frontend_configurations,
scopeCopy: true,
subjectLineBehavior: "email",
alwaysShowSubjectInput: true
},
masto_fe: %{
showInstanceSpecificPanel: true
}

config :pleroma, :activitypub,
@@ -345,6 +355,10 @@ config :pleroma, Pleroma.Jobs,
federator_outgoing: [max_jobs: 50],
mailer: [max_jobs: 10]

config :pleroma, :fetch_initial_posts,
enabled: false,
pages: 5

config :auto_linker,
opts: [
scheme: true,


+ 2
- 0
config/test.exs Ver fichero

@@ -44,6 +44,8 @@ config :web_push_encryption, :vapid_details,
"BLH1qVhJItRGCfxgTtONfsOKDc9VRAraXw-3NsmjMngWSh7NxOizN6bkuRA7iLTMPS82PjwJAr3UoK9EC1IFrz4",
private_key: "_-XZ0iebPrRfZ_o0-IatTdszYa8VCH1yLN-JauK7HHA"

config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock

config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2]

try do


+ 5
- 30
docs/Admin-API.md Ver fichero

@@ -7,36 +7,11 @@ Authentication is required and the user must be an admin.
### List users

- Method `GET`
- Params:
- `page`: **integer** page number
- `page_size`: **integer** number of users per page (default is `50`)
- Response:

```JSON
{
"page_size": integer,
"count": integer,
"users": [
{
"deactivated": bool,
"id": integer,
"nickname": string
},
...
]
}
```

## `/api/pleroma/admin/users/search?query={query}&local={local}&page={page}&page_size={page_size}`

### Search users by name or nickname

- Method `GET`
- Params:
- `query`: **string** search term
- `local`: **bool** whether to return only local users
- `page`: **integer** page number
- `page_size`: **integer** number of users per page (default is `50`)
- Query Params:
- `query`: **string** *optional* search term
- `local_only`: **bool** *optional* whether to return only local users
- `page`: **integer** *optional* page number
- `page_size`: **integer** *optional* number of users per page (default is `50`)
- Response:

```JSON


+ 10
- 10
docs/Clients.md Ver fichero

@@ -4,8 +4,8 @@ Feel free to contact us to be added to this list!

## Desktop
### Roma for Desktop
- Homepage: <http://www.pleroma.com/desktop-app/>
- Source Code: ???
- Homepage: <https://www.pleroma.com/#desktopApp>
- Source Code: <https://github.com/roma-apps/roma-desktop>
- Platforms: Windows, Mac, (Linux?)
- Features: Streaming Ready

@@ -30,6 +30,12 @@ Feel free to contact us to be added to this list!
- Platforms: iOS
- Features: No Streaming

### Fedilab
- Source Code: <https://gitlab.com/tom79/mastalab/>
- Contact: [@tom79@mastodon.social](https://mastodon.social/users/tom79)
- Platforms: Android
- Features: Streaming Ready

### Nekonium
- Homepage: [F-Droid Repository](https://repo.gdgd.jp.net/), [Google Play](https://play.google.com/store/apps/details?id=com.apps.nekonium), [Amazon](https://www.amazon.co.jp/dp/B076FXPRBC/)
- Source: <https://git.gdgd.jp.net/lin/nekonium/>
@@ -37,15 +43,9 @@ Feel free to contact us to be added to this list!
- Platforms: Android
- Features: Streaming Ready

### Mastalab
- Source Code: <https://gitlab.com/tom79/mastalab/>
- Contact: [@tom79@mastodon.social](https://mastodon.social/users/tom79)
- Platforms: Android
- Features: Streaming Ready

### Roma
- Homepage: <http://www.pleroma.com/>
- Source Code: ???
- Homepage: <https://www.pleroma.com/#mobileApps>
- Source Code: [iOS](https://github.com/roma-apps/roma-ios), [Android](https://github.com/roma-apps/roma-android)
- Platforms: iOS, Android
- Features: No Streaming



+ 10
- 0
docs/Differences-in-MastodonAPI-Responses.md Ver fichero

@@ -13,3 +13,13 @@ Some apps operate under the assumption that no more than 4 attachments can be re
## Timelines

Adding the parameter `with_muted=true` to the timeline queries will also return activities by muted (not by blocked!) users.

## Statuses

Has these additional fields under the `pleroma` object:

- `local`: true if the post was made on the local instance.

## Accounts

- `/api/v1/accounts/:id`: The `id` parameter can also be the `nickname` of the user. This only works in this endpoint, not the deeper nested ones for following etc.

+ 5
- 1
docs/config.md Ver fichero

@@ -129,7 +129,7 @@ See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_s

## :frontend_configurations

This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` are configured.
This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured.

Frontends can access these settings at `/api/pleroma/frontend_configurations`

@@ -285,6 +285,10 @@ This config contains two queues: `federator_incoming` and `federator_outgoing`.
## :rich_media
* `enabled`: if enabled the instance will parse metadata from attached links to generate link previews

## :fetch_initial_posts
* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts
* `pages`: the amount of pages to fetch

## :hackney_pools

Advanced. Tweaks Hackney (http client) connections pools.


+ 1
- 1
lib/mix/tasks/pleroma/relay.ex Ver fichero

@@ -4,8 +4,8 @@

defmodule Mix.Tasks.Pleroma.Relay do
use Mix.Task
alias Pleroma.Web.ActivityPub.Relay
alias Mix.Tasks.Pleroma.Common
alias Pleroma.Web.ActivityPub.Relay

@shortdoc "Manages remote relays"
@moduledoc """


+ 1
- 2
lib/mix/tasks/pleroma/uploads.ex Ver fichero

@@ -4,9 +4,9 @@

defmodule Mix.Tasks.Pleroma.Uploads do
use Mix.Task
alias Mix.Tasks.Pleroma.Common
alias Pleroma.Upload
alias Pleroma.Uploaders.Local
alias Mix.Tasks.Pleroma.Common
require Logger

@log_every 50
@@ -20,7 +20,6 @@ defmodule Mix.Tasks.Pleroma.Uploads do
Options:
- `--delete` - delete local uploads after migrating them to the target uploader


A list of available uploaders can be seen in config.exs
"""
def run(["migrate_local", target_uploader | args]) do


+ 1
- 1
lib/mix/tasks/pleroma/user.ex Ver fichero

@@ -5,9 +5,9 @@
defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Ecto.Changeset
alias Mix.Tasks.Pleroma.Common
alias Pleroma.Repo
alias Pleroma.User
alias Mix.Tasks.Pleroma.Common

@shortdoc "Manages Pleroma users"
@moduledoc """


+ 2
- 2
lib/pleroma/PasswordResetToken.ex Ver fichero

@@ -7,9 +7,9 @@ defmodule Pleroma.PasswordResetToken do

import Ecto.Changeset

alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.PasswordResetToken
alias Pleroma.Repo
alias Pleroma.User

schema "password_reset_tokens" do
belongs_to(:user, User, type: Pleroma.FlakeId)


+ 13
- 1
lib/pleroma/activity.ex Ver fichero

@@ -5,9 +5,9 @@
defmodule Pleroma.Activity do
use Ecto.Schema

alias Pleroma.Repo
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Repo

import Ecto.Query

@@ -107,6 +107,18 @@ defmodule Pleroma.Activity do

def get_in_reply_to_activity(_), do: nil

def delete_by_ap_id(id) when is_binary(id) do
by_object_ap_id(id)
|> Repo.delete_all(returning: true)
|> elem(1)
|> Enum.find(fn
%{data: %{"type" => "Create", "object" => %{"id" => ap_id}}} -> ap_id == id
_ -> nil
end)
end

def delete_by_ap_id(_), do: nil

for {ap_type, type} <- @mastodon_notification_types do
def mastodon_notification_type(%Activity{data: %{"type" => unquote(ap_type)}}),
do: unquote(type)


+ 10
- 10
lib/pleroma/application.ex Ver fichero

@@ -11,10 +11,10 @@ defmodule Pleroma.Application do
@repository Mix.Project.config()[:source_url]
def name, do: @name
def version, do: @version
def named_version(), do: @name <> " " <> @version
def named_version, do: @name <> " " <> @version
def repository, do: @repository

def user_agent() do
def user_agent do
info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>"
named_version() <> "; " <> info
end
@@ -48,7 +48,7 @@ defmodule Pleroma.Application do
[
:user_cache,
[
default_ttl: 25000,
default_ttl: 25_000,
ttl_interval: 1000,
limit: 2500
]
@@ -60,7 +60,7 @@ defmodule Pleroma.Application do
[
:object_cache,
[
default_ttl: 25000,
default_ttl: 25_000,
ttl_interval: 1000,
limit: 2500
]
@@ -127,7 +127,7 @@ defmodule Pleroma.Application do
Supervisor.start_link(children, opts)
end

def enabled_hackney_pools() do
def enabled_hackney_pools do
[:media] ++
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
[:federation]
@@ -142,14 +142,14 @@ defmodule Pleroma.Application do
end

if Mix.env() == :test do
defp streamer_child(), do: []
defp chat_child(), do: []
defp streamer_child, do: []
defp chat_child, do: []
else
defp streamer_child() do
defp streamer_child do
[worker(Pleroma.Web.Streamer, [])]
end

defp chat_child() do
defp chat_child do
if Pleroma.Config.get([:chat, :enabled]) do
[worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
else
@@ -158,7 +158,7 @@ defmodule Pleroma.Application do
end
end

defp hackney_pool_children() do
defp hackney_pool_children do
for pool <- enabled_hackney_pools() do
options = Pleroma.Config.get([:hackney_pools, pool])
:hackney_pool.child_spec(pool, options)


+ 3
- 3
lib/pleroma/captcha/captcha.ex Ver fichero

@@ -10,7 +10,7 @@ defmodule Pleroma.Captcha do
use GenServer

@doc false
def start_link() do
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end

@@ -22,7 +22,7 @@ defmodule Pleroma.Captcha do
@doc """
Ask the configured captcha service for a new captcha
"""
def new() do
def new do
GenServer.call(__MODULE__, :new)
end

@@ -73,7 +73,7 @@ defmodule Pleroma.Captcha do
secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")

# If the time found is less than (current_time - seconds_valid), then the time has already passed.
# 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])


+ 1
- 1
lib/pleroma/captcha/kocaptcha.ex Ver fichero

@@ -7,7 +7,7 @@ defmodule Pleroma.Captcha.Kocaptcha do
@behaviour Service

@impl Service
def new() do
def new do
endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])

case Tesla.get(endpoint <> "/new") do


+ 4
- 4
lib/pleroma/clippy.ex Ver fichero

@@ -7,13 +7,13 @@ defmodule Pleroma.Clippy do
# No software is complete until they have a Clippy implementation.
# A ballmer peak _may_ be required to change this module.

def tip() do
def tip do
tips()
|> Enum.random()
|> puts()
end

def tips() do
def tips do
host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])

[
@@ -92,8 +92,8 @@ defmodule Pleroma.Clippy do

# surrond one/five line clippy with blank lines around to not fuck up the layout
#
# yes this fix sucks but it's good enough, have you ever seen a release of windows wihtout some butched
# features anyway?
# yes this fix sucks but it's good enough, have you ever seen a release of windows
# without some butched features anyway?
lines =
if length(lines) == 1 or length(lines) == 5 do
[""] ++ lines ++ [""]


+ 1
- 1
lib/pleroma/config/deprecation_warnings.ex Ver fichero

@@ -5,7 +5,7 @@
defmodule Pleroma.Config.DeprecationWarnings do
require Logger

def check_frontend_config_mechanism() do
def check_frontend_config_mechanism do
if Pleroma.Config.get(:fe) do
Logger.warn("""
!!!DEPRECATION WARNING!!!


+ 4
- 4
lib/pleroma/emoji.ex Ver fichero

@@ -17,13 +17,13 @@ defmodule Pleroma.Emoji do
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]

@doc false
def start_link() do
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end

@doc "Reloads the emojis from disk."
@spec reload() :: :ok
def reload() do
def reload do
GenServer.call(__MODULE__, :reload)
end

@@ -38,7 +38,7 @@ defmodule Pleroma.Emoji do

@doc "Returns all the emojos!!"
@spec get_all() :: [{String.t(), String.t()}, ...]
def get_all() do
def get_all do
:ets.tab2list(@ets)
end

@@ -72,7 +72,7 @@ defmodule Pleroma.Emoji do
{:ok, state}
end

defp load() do
defp load do
emojis =
(load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++
load_from_file("config/emoji.txt") ++


+ 1
- 1
lib/pleroma/filter.ex Ver fichero

@@ -8,8 +8,8 @@ defmodule Pleroma.Filter do
import Ecto.Changeset
import Ecto.Query

alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User

schema "filters" do
belongs_to(:user, User, type: Pleroma.FlakeId)


+ 2
- 2
lib/pleroma/flake_id.ex Ver fichero

@@ -85,7 +85,7 @@ defmodule Pleroma.FlakeId do
{:ok, FlakeId.from_string(value)}
end

def autogenerate(), do: get()
def autogenerate, do: get()

# -- GenServer API
def start_link do
@@ -165,7 +165,7 @@ defmodule Pleroma.FlakeId do
1_000_000_000 * mega_seconds + seconds * 1000 + :erlang.trunc(micro_seconds / 1000)
end

defp worker_id() do
defp worker_id do
<<worker::integer-size(48)>> = :crypto.strong_rand_bytes(6)
worker
end


+ 1
- 0
lib/pleroma/formatter.ex Ver fichero

@@ -10,6 +10,7 @@ defmodule Pleroma.Formatter do

@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
@link_regex ~r{((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+}ui
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength

@auto_linker_config hashtag: true,
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,


+ 4
- 4
lib/pleroma/gopher/server.ex Ver fichero

@@ -6,7 +6,7 @@ defmodule Pleroma.Gopher.Server do
use GenServer
require Logger

def start_link() do
def start_link do
config = Pleroma.Config.get(:gopher, [])
ip = Keyword.get(config, :ip, {0, 0, 0, 0})
port = Keyword.get(config, :port, 1234)
@@ -36,12 +36,12 @@ defmodule Pleroma.Gopher.Server do
end

defmodule Pleroma.Gopher.Server.ProtocolHandler do
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Activity
alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility

def start_link(ref, socket, transport, opts) do
pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])


+ 1
- 1
lib/pleroma/html.ex Ver fichero

@@ -9,7 +9,7 @@ defmodule Pleroma.HTML do
defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]

def get_scrubbers() do
def get_scrubbers do
Pleroma.Config.get([:markup, :scrub_policy])
|> get_scrubbers
end


+ 7
- 3
lib/pleroma/http/connection.ex Ver fichero

@@ -8,8 +8,8 @@ defmodule Pleroma.HTTP.Connection do
"""

@hackney_options [
timeout: 10000,
recv_timeout: 20000,
connect_timeout: 2_000,
recv_timeout: 20_000,
follow_redirect: true,
pool: :federation
]
@@ -31,6 +31,10 @@ defmodule Pleroma.HTTP.Connection do
#
defp hackney_options(opts) do
options = Keyword.get(opts, :adapter, [])
@hackney_options ++ options
adapter_options = Pleroma.Config.get([:http, :adapter], [])

@hackney_options
|> Keyword.merge(adapter_options)
|> Keyword.merge(options)
end
end

+ 23
- 15
lib/pleroma/http/http.ex Ver fichero

@@ -27,21 +27,29 @@ defmodule Pleroma.HTTP do

"""
def request(method, url, body \\ "", headers \\ [], options \\ []) do
options =
process_request_options(options)
|> process_sni_options(url)

params = Keyword.get(options, :params, [])

%{}
|> Builder.method(method)
|> Builder.headers(headers)
|> Builder.opts(options)
|> Builder.url(url)
|> Builder.add_param(:body, :body, body)
|> Builder.add_param(:query, :query, params)
|> Enum.into([])
|> (&Tesla.request(Connection.new(), &1)).()
try do
options =
process_request_options(options)
|> process_sni_options(url)

params = Keyword.get(options, :params, [])

%{}
|> Builder.method(method)
|> Builder.headers(headers)
|> Builder.opts(options)
|> Builder.url(url)
|> Builder.add_param(:body, :body, body)
|> Builder.add_param(:query, :query, params)
|> Enum.into([])
|> (&Tesla.request(Connection.new(options), &1)).()
rescue
e ->
{:error, e}
catch
:exit, e ->
{:error, e}
end
end

defp process_sni_options(options, nil), do: options


+ 1
- 1
lib/pleroma/instances/instance.ex Ver fichero

@@ -2,8 +2,8 @@ defmodule Pleroma.Instances.Instance do
@moduledoc "Instance."

alias Pleroma.Instances
alias Pleroma.Repo
alias Pleroma.Instances.Instance
alias Pleroma.Repo

use Ecto.Schema



+ 2
- 2
lib/pleroma/notification.ex Ver fichero

@@ -5,12 +5,12 @@
defmodule Pleroma.Notification do
use Ecto.Schema

alias Pleroma.User
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Repo
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils

import Ecto.Query



+ 5
- 5
lib/pleroma/object.ex Ver fichero

@@ -5,11 +5,11 @@
defmodule Pleroma.Object do
use Ecto.Schema

alias Pleroma.Repo
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.ObjectTombstone
alias Pleroma.Repo
alias Pleroma.User

import Ecto.Query
import Ecto.Changeset
@@ -86,9 +86,9 @@ defmodule Pleroma.Object do

def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object),
Repo.delete_all(Activity.by_object_ap_id(id)),
deleted_activity = Activity.delete_by_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
{:ok, object}
{:ok, object, deleted_activity}
end
end



+ 6
- 3
lib/pleroma/plugs/http_security_plug.ex Ver fichero

@@ -34,13 +34,16 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do

defp csp_string do
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
websocket_url = String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")
static_url = Pleroma.Web.Endpoint.static_url()
websocket_url = String.replace(static_url, "http", "ws")

connect_src = "connect-src 'self' #{static_url} #{websocket_url}"

connect_src =
if Mix.env() == :dev do
"connect-src 'self' http://localhost:3035/ " <> websocket_url
connect_src <> " http://localhost:3035/"
else
"connect-src 'self' " <> websocket_url
connect_src
end

script_src =


+ 1
- 1
lib/pleroma/plugs/http_signature.ex Ver fichero

@@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
alias Pleroma.Web.HTTPSignatures
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.HTTPSignatures
import Plug.Conn
require Logger



+ 2
- 1
lib/pleroma/plugs/oauth_plug.ex Ver fichero

@@ -6,8 +6,8 @@ defmodule Pleroma.Plugs.OAuthPlug do
import Plug.Conn
import Ecto.Query

alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.OAuth.Token

@realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i")
@@ -38,6 +38,7 @@ defmodule Pleroma.Plugs.OAuthPlug do
preload: [user: user]
)

# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
with %Token{user: %{info: %{deactivated: false} = _} = user} = token_record <- Repo.one(query) do
{:ok, user, token_record}
end


+ 1
- 1
lib/pleroma/plugs/user_fetcher_plug.ex Ver fichero

@@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Plugs.UserFetcherPlug do
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User

import Plug.Conn



+ 6
- 4
lib/pleroma/reverse_proxy.ex Ver fichero

@@ -3,10 +3,12 @@
# 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)
@keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++
~w(if-unmodified-since if-none-match if-range range)
@resp_cache_headers ~w(etag date last-modified cache-control)
@keep_resp_headers @resp_cache_headers ++
~w(content-type content-disposition content-encoding content-range accept-ranges vary)
~w(content-type content-disposition content-encoding content-range) ++
~w(accept-ranges vary)
@default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304]
@max_read_duration :timer.seconds(30)
@@ -282,8 +284,8 @@ defmodule Pleroma.ReverseProxy do
headers

has_cache? ->
# There's caching header present but no cache-control -- we need to explicitely override it to public
# as Plug defaults to "max-age=0, private, must-revalidate"
# There's caching header present but no cache-control -- we need to explicitely override it
# to public as Plug defaults to "max-age=0, private, must-revalidate"
List.keystore(headers, "cache-control", 0, {"cache-control", "public"})

true ->


+ 1
- 1
lib/pleroma/stats.ex Ver fichero

@@ -4,8 +4,8 @@

defmodule Pleroma.Stats do
import Ecto.Query
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User

def start_link do
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)


+ 5
- 1
lib/pleroma/thread_mute.ex Ver fichero

@@ -4,7 +4,11 @@

defmodule Pleroma.ThreadMute do
use Ecto.Schema
alias Pleroma.{Repo, User, ThreadMute}

alias Pleroma.Repo
alias Pleroma.ThreadMute
alias Pleroma.User

require Ecto.Query

schema "thread_mutes" do


+ 5
- 3
lib/pleroma/upload.ex Ver fichero

@@ -85,6 +85,10 @@ defmodule Pleroma.Upload do
end
end

def char_unescaped?(char) do
URI.char_unreserved?(char) or char == ?/
end

defp get_opts(opts) do
{size_limit, activity_type} =
case Keyword.get(opts, :type) do
@@ -218,9 +222,7 @@ defmodule Pleroma.Upload do
defp url_from_spec(base_url, {:file, path}) do
path =
path
|> URI.encode()
|> String.replace("?", "%3F")
|> String.replace(":", "%3A")
|> URI.encode(&char_unescaped?/1)

[base_url, "media", path]
|> Path.join()


+ 2
- 1
lib/pleroma/uploaders/s3.ex Ver fichero

@@ -6,7 +6,8 @@ defmodule Pleroma.Uploaders.S3 do
@behaviour Pleroma.Uploaders.Uploader
require Logger

# The file name is re-encoded with S3's constraints here to comply with previous links with less strict filenames
# The file name is re-encoded with S3's constraints here to comply with previous
# links with less strict filenames
def get_file(file) do
config = Pleroma.Config.get([__MODULE__])
bucket = Keyword.fetch!(config, :bucket)


+ 1
- 1
lib/pleroma/uploaders/swift/keystone.ex Ver fichero

@@ -17,7 +17,7 @@ defmodule Pleroma.Uploaders.Swift.Keystone do
|> Poison.decode!()
end

def get_token() do
def get_token do
settings = Pleroma.Config.get(Pleroma.Uploaders.Swift)
username = Keyword.fetch!(settings, :username)
password = Keyword.fetch!(settings, :password)


+ 0
- 1
lib/pleroma/uploaders/uploader.ex Ver fichero

@@ -29,7 +29,6 @@ defmodule Pleroma.Uploaders.Uploader do
* `{:error, String.t}` error information if the file failed to be saved to the backend.
* `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method.


"""
@type file_spec :: {:file | :url, String.t()}
@callback put_file(Pleroma.Upload.t()) ::


+ 81
- 39
lib/pleroma/user.ex Ver fichero

@@ -8,21 +8,21 @@ defmodule Pleroma.User do
import Ecto.Changeset
import Ecto.Query

alias Comeonin.Pbkdf2
alias Pleroma.Activity
alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Object
alias Pleroma.Web
alias Pleroma.Activity
alias Pleroma.Notification
alias Comeonin.Pbkdf2
alias Pleroma.Formatter
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
alias Pleroma.Web.OStatus
alias Pleroma.Web.Websub
alias Pleroma.Web.OAuth
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.OStatus
alias Pleroma.Web.RelMe
alias Pleroma.Web.Websub

require Logger

@@ -30,6 +30,7 @@ defmodule Pleroma.User do

@primary_key {:id, Pleroma.FlakeId, autogenerate: true}

# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
@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])?)*$/

@strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
@@ -285,7 +286,7 @@ defmodule Pleroma.User do
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true

def needs_update?(%User{local: false} = user) do
NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86400
NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86_400
end

def needs_update?(_), do: true
@@ -435,7 +436,8 @@ 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
# 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, "/"))
@@ -532,6 +534,10 @@ defmodule Pleroma.User do
_e ->
with [_nick, _domain] <- String.split(nickname, "@"),
{:ok, user} <- fetch_by_nickname(nickname) do
if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
{:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
end

user
else
_e -> nil
@@ -539,6 +545,17 @@ defmodule Pleroma.User do
end
end

@doc "Fetch some posts when the user has just been federated with"
def fetch_initial_posts(user) do
pages = Pleroma.Config.get!([:fetch_initial_posts, :pages])

Enum.each(
# Insert all the posts in reverse order, so they're in the right order on the timeline
Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)),
&Pleroma.Web.Federator.incoming_ap_doc/1
)
end

def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do
from(
u in User,
@@ -749,13 +766,41 @@ defmodule Pleroma.User do
Repo.all(query)
end

@spec search_for_admin(binary(), %{
@spec search_for_admin(%{
local: boolean(),
page: number(),
page_size: number()
}) :: {:ok, [Pleroma.User.t()], number()}
def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
query =
from(u in User, order_by: u.id)
|> maybe_local_user_query(local)

paginated_query =
query
|> paginate(page, page_size)

count =
query
|> Repo.aggregate(:count, :id)

{:ok, Repo.all(paginated_query), count}
end

@spec search_for_admin(%{
query: binary(),
admin: Pleroma.User.t(),
local: boolean(),
page: number(),
page_size: number()
}) :: {:ok, [Pleroma.User.t()], number()}
def search_for_admin(term, %{admin: admin, local: local, page: page, page_size: page_size}) do
def search_for_admin(%{
query: term,
admin: admin,
local: local,
page: page,
page_size: page_size
}) do
term = String.trim_leading(term, "@")

local_paginated_query =
@@ -774,21 +819,6 @@ defmodule Pleroma.User do
{:ok, do_search(search_query, admin), count}
end

@spec all_for_admin(number(), number()) :: {:ok, [Pleroma.User.t()], number()}
def all_for_admin(page, page_size) do
query = from(u in User, order_by: u.id)

paginated_query =
query
|> paginate(page, page_size)

count =
query
|> Repo.aggregate(:count, :id)

{:ok, Repo.all(paginated_query), count}
end

def search(query, resolve \\ false, for_user \\ nil) do
# Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@")
@@ -1108,24 +1138,36 @@ defmodule Pleroma.User do

def html_filter_policy(_), do: @default_scrubbers

def fetch_by_ap_id(ap_id) do
ap_try = ActivityPub.make_user_from_ap_id(ap_id)

case ap_try do
{:ok, user} ->
user

_ ->
case OStatus.make_user(ap_id) do
{:ok, user} -> user
_ -> {:error, "Could not fetch by AP id"}
end
end
end

def get_or_fetch_by_ap_id(ap_id) do
user = get_by_ap_id(ap_id)

if !is_nil(user) and !User.needs_update?(user) do
user
else
ap_try = ActivityPub.make_user_from_ap_id(ap_id)

case ap_try do
{:ok, user} ->
user
user = fetch_by_ap_id(ap_id)

_ ->
case OStatus.make_user(ap_id) do
{:ok, user} -> user
_ -> {:error, "Could not fetch by AP id"}
end
if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
with %User{} = user do
{:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
end
end

user
end
end

@@ -1300,7 +1342,7 @@ defmodule Pleroma.User do
|> Enum.map(&String.downcase(&1))
end

defp local_nickname_regex() do
defp local_nickname_regex do
if Pleroma.Config.get([:instance, :extended_nickname_format]) do
@extended_local_nickname_regex
else


+ 9
- 0
lib/pleroma/user/info.ex Ver fichero

@@ -6,6 +6,8 @@ defmodule Pleroma.User.Info do
use Ecto.Schema
import Ecto.Changeset

alias Pleroma.User.Info

embedded_schema do
field(:banner, :map, default: %{})
field(:background, :map, default: %{})
@@ -250,4 +252,11 @@ defmodule Pleroma.User.Info do

cast(info, params, [:pinned_activities])
end

def roles(%Info{is_moderator: is_moderator, is_admin: is_admin}) do
%{
admin: is_admin,
moderator: is_moderator
}
end
end

+ 2
- 2
lib/pleroma/user/welcome_message.ex Ver fichero

@@ -14,7 +14,7 @@ defmodule Pleroma.User.WelcomeMessage do
end
end

defp welcome_user() do
defp welcome_user do
with nickname when is_binary(nickname) <-
Pleroma.Config.get([:instance, :welcome_user_nickname]),
%User{local: true} = user <- User.get_cached_by_nickname(nickname) do
@@ -24,7 +24,7 @@ defmodule Pleroma.User.WelcomeMessage do
end
end

defp welcome_message() do
defp welcome_message do
Pleroma.Config.get([:instance, :welcome_message])
end
end

+ 1
- 1
lib/pleroma/user_invite_token.ex Ver fichero

@@ -7,8 +7,8 @@ defmodule Pleroma.UserInviteToken do

import Ecto.Changeset

alias Pleroma.UserInviteToken
alias Pleroma.Repo
alias Pleroma.UserInviteToken

schema "user_invite_tokens" do
field(:token, :string)


+ 24
- 21
lib/pleroma/web/activity_pub/activity_pub.ex Ver fichero

@@ -4,17 +4,17 @@

defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Activity
alias Pleroma.Repo
alias Pleroma.Instances
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Upload
alias Pleroma.User
alias Pleroma.Notification
alias Pleroma.Instances
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.MRF
alias Pleroma.Web.WebFinger
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
alias Pleroma.Web.WebFinger

import Ecto.Query
import Pleroma.Web.ActivityPub.Utils
@@ -170,7 +170,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
additional
),
{:ok, activity} <- insert(create_data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
@@ -309,17 +310,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do

def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
to = object.data["to"] || [] ++ object.data["cc"] || []

data = %{
"type" => "Delete",
"actor" => actor,
"object" => id,
"to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
}
with {:ok, _} <- Object.delete(object),
with {:ok, object, activity} <- Object.delete(object),
data <- %{
"type" => "Delete",
"actor" => actor,
"object" => id,
"to" => to,
"deleted_activity_id" => activity && activity.id
},
{:ok, activity} <- insert(data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- decrease_note_count_if_public(user, object),
:ok <- maybe_federate(activity) do
{:ok, activity}
@@ -501,7 +504,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
when is_list(tag_reject) and tag_reject != [] do
from(
activity in query,
where: fragment("(not (? #> '{\"object\",\"tag\"}') \\?| ?)", activity.data, ^tag_reject)
where: fragment(~s(\(not \(? #> '{"object","tag"}'\) \\?| ?\)), activity.data, ^tag_reject)
)
end

@@ -511,7 +514,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
when is_list(tag_all) and tag_all != [] do
from(
activity in query,
where: fragment("(? #> '{\"object\",\"tag\"}') \\?& ?", activity.data, ^tag_all)
where: fragment(~s(\(? #> '{"object","tag"}'\) \\?& ?), activity.data, ^tag_all)
)
end

@@ -520,14 +523,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
from(
activity in query,
where: fragment("(? #> '{\"object\",\"tag\"}') \\?| ?", activity.data, ^tag)
where: fragment(~s(\(? #> '{"object","tag"}'\) \\?| ?), activity.data, ^tag)
)
end

defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
from(
activity in query,
where: fragment("? <@ (? #> '{\"object\",\"tag\"}')", ^tag, activity.data)
where: fragment(~s(? <@ (? #> '{"object","tag"}'\)), ^tag, activity.data)
)
end

@@ -600,7 +603,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
from(
activity in query,
where: fragment("? <@ (? #> '{\"object\",\"likes\"}')", ^ap_id, activity.data)
where: fragment(~s(? <@ (? #> '{"object","likes"}'\)), ^ap_id, activity.data)
)
end

@@ -609,7 +612,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
from(
activity in query,
where: fragment("not (? #> '{\"object\",\"attachment\"}' = ?)", activity.data, ^[])
where: fragment(~s(not (? #> '{"object","attachment"}' = ?\)), activity.data, ^[])
)
end



+ 4
- 4
lib/pleroma/web/activity_pub/activity_pub_controller.ex Ver fichero

@@ -6,15 +6,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
use Pleroma.Web, :controller

alias Pleroma.Activity
alias Pleroma.User
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator

require Logger


+ 1
- 1
lib/pleroma/web/activity_pub/mrf.ex Ver fichero

@@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
end)
end

def get_policies() do
def get_policies do
Application.get_env(:pleroma, :instance, [])
|> Keyword.get(:rewrite_policy, [])
|> get_policies()


+ 9
- 3
lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex Ver fichero

@@ -23,15 +23,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
defp score_displayname(_), do: 0.0

defp determine_if_followbot(%User{nickname: nickname, name: displayname}) do
# nickname will always be a binary string because it's generated by Pleroma.
nick_score =
nickname
|> String.downcase()
|> score_nickname()

# displayname will either be a binary string or nil, if a displayname isn't set.
name_score =
displayname
|> String.downcase()
|> score_displayname()
if is_binary(displayname) do
displayname
|> String.downcase()
|> score_displayname()
else
0.0
end

nick_score + name_score
end


+ 8
- 7
lib/pleroma/web/activity_pub/mrf/keyword_policy.ex Ver fichero

@@ -45,13 +45,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do

defp check_replace(%{"object" => %{"content" => content, "summary" => summary}} = message) do
{content, summary} =
Enum.reduce(Pleroma.Config.get([:mrf_keyword, :replace]), {content, summary}, fn {pattern,
replacement},
{content_acc,
summary_acc} ->
{String.replace(content_acc, pattern, replacement),
String.replace(summary_acc, pattern, replacement)}
end)
Enum.reduce(
Pleroma.Config.get([:mrf_keyword, :replace]),
{content, summary},
fn {pattern, replacement}, {content_acc, summary_acc} ->
{String.replace(content_acc, pattern, replacement),
String.replace(summary_acc, pattern, replacement)}
end
)

{:ok,
message


+ 2
- 2
lib/pleroma/web/activity_pub/relay.ex Ver fichero

@@ -3,9 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.User
alias Pleroma.Object
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
require Logger



+ 10
- 8
lib/pleroma/web/activity_pub/transmogrifier.ex Ver fichero

@@ -7,9 +7,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
A module to handle coding from internal to wire ActivityPub and back.
"""
alias Pleroma.Activity
alias Pleroma.User
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
@@ -650,10 +650,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
if object = Object.normalize(id), do: {:ok, object}, else: nil
end

def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) when is_binary(inReplyTo) do
with false <- String.starts_with?(inReplyTo, "http"),
{:ok, %{data: replied_to_object}} <- get_obj_helper(inReplyTo) do
Map.put(object, "inReplyTo", replied_to_object["external_url"] || inReplyTo)
def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
with false <- String.starts_with?(in_reply_to, "http"),
{:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do
Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to)
else
_e -> object
end
@@ -736,6 +736,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def prepare_outgoing(%{"type" => _type} = data) do
data =
data
|> strip_internal_fields
|> maybe_fix_object_url
|> Map.merge(Utils.make_json_ld_header())

@@ -829,10 +830,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end

def add_attributed_to(object) do
attributedTo = object["attributedTo"] || object["actor"]
attributed_to = object["attributedTo"] || object["actor"]

object
|> Map.put("attributedTo", attributedTo)
|> Map.put("attributedTo", attributed_to)
end

def add_likes(%{"id" => id, "like_count" => likes} = object) do
@@ -870,7 +871,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"announcements",
"announcement_count",
"emoji",
"context_id"
"context_id",
"deleted_activity_id"
])
end



+ 68
- 10
lib/pleroma/web/activity_pub/utils.ex Ver fichero

@@ -3,16 +3,17 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Repo
alias Pleroma.Web
alias Pleroma.Object
alias Ecto.Changeset
alias Ecto.UUID
alias Pleroma.Activity
alias Pleroma.User
alias Pleroma.Notification
alias Pleroma.Web.Router.Helpers
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Endpoint
alias Ecto.Changeset
alias Ecto.UUID
alias Pleroma.Web.Router.Helpers

import Ecto.Query

@@ -274,13 +275,31 @@ defmodule Pleroma.Web.ActivityPub.Utils do
Repo.all(query)
end

def make_like_data(%User{ap_id: ap_id} = actor, %{data: %{"id" => id}} = object, activity_id) do
def make_like_data(
%User{ap_id: ap_id} = actor,
%{data: %{"actor" => object_actor_id, "id" => id}} = object,
activity_id
) do
object_actor = User.get_cached_by_ap_id(object_actor_id)

to =
if Visibility.is_public?(object) do
[actor.follower_address, object.data["actor"]]
else
[object.data["actor"]]
end

cc =
(object.data["to"] ++ (object.data["cc"] || []))
|> List.delete(actor.ap_id)
|> List.delete(object_actor.follower_address)

data = %{
"type" => "Like",
"actor" => ap_id,
"object" => id,
"to" => [actor.follower_address, object.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"],
"to" => to,
"cc" => cc,
"context" => object.data["context"]
}

@@ -614,4 +633,43 @@ defmodule Pleroma.Web.ActivityPub.Utils do
}
|> Map.merge(additional)
end

@doc """
Fetches the OrderedCollection/OrderedCollectionPage from `from`, limiting the amount of pages fetched after
the first one to `pages_left` pages.
If the amount of pages is higher than the collection has, it returns whatever was there.
"""
def fetch_ordered_collection(from, pages_left, acc \\ []) do
with {:ok, response} <- Tesla.get(from),
{:ok, collection} <- Poison.decode(response.body) do
case collection["type"] do
"OrderedCollection" ->
# If we've encountered the OrderedCollection and not the page,
# just call the same function on the page address
fetch_ordered_collection(collection["first"], pages_left)

"OrderedCollectionPage" ->
if pages_left > 0 do
# There are still more pages
if Map.has_key?(collection, "next") do
# There are still more pages, go deeper saving what we have into the accumulator
fetch_ordered_collection(
collection["next"],
pages_left - 1,
acc ++ collection["orderedItems"]
)
else
# No more pages left, just return whatever we already have
acc ++ collection["orderedItems"]
end
else
# Got the amount of pages needed, add them all to the accumulator
acc ++ collection["orderedItems"]
end

_ ->
{:error, "Not an OrderedCollection or OrderedCollectionPage"}
end
end
end
end

+ 4
- 4
lib/pleroma/web/activity_pub/views/user_view.ex Ver fichero

@@ -5,15 +5,15 @@
defmodule Pleroma.Web.ActivityPub.UserView do
use Pleroma.Web, :view

alias Pleroma.Web.WebFinger
alias Pleroma.Web.Salmon
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Router.Helpers
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router.Helpers
alias Pleroma.Web.Salmon
alias Pleroma.Web.WebFinger

import Ecto.Query



+ 5
- 19
lib/pleroma/web/admin_api/admin_api_controller.ex Ver fichero

@@ -8,7 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.MastodonAPI.Admin.AccountView
alias Pleroma.Web.AdminAPI.AccountView

import Pleroma.Web.ControllerHelper, only: [json_response: 3]

@@ -63,28 +63,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
do: json_response(conn, :no_content, "")
end

def list_users(conn, params) do
{page, page_size} = page_params(params)

with {:ok, users, count} <- User.all_for_admin(page, page_size),
do:
conn
|> json(
AccountView.render("index.json",
users: users,
count: count,
page_size: page_size
)
)
end

def search_users(%{assigns: %{user: admin}} = conn, %{"query" => query} = params) do
def list_users(%{assigns: %{user: admin}} = conn, params) do
{page, page_size} = page_params(params)

with {:ok, users, count} <-
User.search_for_admin(query, %{
User.search_for_admin(%{
query: params["query"],
admin: admin,
local: params["local"] == "true",
local: params["local_only"] == "true",
page: page,
page_size: page_size
}),


lib/pleroma/web/mastodon_api/views/admin/account_view.ex → lib/pleroma/web/admin_api/views/account_view.ex Ver fichero

@@ -2,10 +2,11 @@
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view

alias Pleroma.Web.MastodonAPI.Admin.AccountView
alias Pleroma.User.Info
alias Pleroma.Web.AdminAPI.AccountView

def render("index.json", %{users: users, count: count, page_size: page_size}) do
%{
@@ -19,7 +20,10 @@ defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
%{
"id" => user.id,
"nickname" => user.nickname,
"deactivated" => user.info.deactivated
"deactivated" => user.info.deactivated,
"local" => user.local,
"roles" => Info.roles(user.info),
"tags" => user.tags || []
}
end
end

+ 1
- 1
lib/pleroma/web/auth/pleroma_authenticator.ex Ver fichero

@@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Pleroma.User
alias Comeonin.Pbkdf2
alias Pleroma.User

@behaviour Pleroma.Web.Auth.Authenticator



+ 1
- 1
lib/pleroma/web/channels/user_socket.ex Ver fichero

@@ -23,7 +23,7 @@ defmodule Pleroma.Web.UserSocket do
# performing token verification on connect.
def connect(%{"token" => token}, socket) do
with true <- Pleroma.Config.get([:chat, :enabled]),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
%User{} = user <- Pleroma.Repo.get(User, user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else


+ 2
- 2
lib/pleroma/web/chat_channel.ex Ver fichero

@@ -4,8 +4,8 @@

defmodule Pleroma.Web.ChatChannel do
use Phoenix.Channel
alias Pleroma.Web.ChatChannel.ChatChannelState
alias Pleroma.User
alias Pleroma.Web.ChatChannel.ChatChannelState

def join("chat:public", _message, socket) do
send(self(), :after_join)
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.ChatChannel.ChatChannelState do
end)
end

def messages() do
def messages do
Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse() end)
end
end

+ 59
- 10
lib/pleroma/web/common_api/common_api.ex Ver fichero

@@ -3,21 +3,70 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.CommonAPI do
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Activity
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ThreadMute
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Formatter

import Pleroma.Web.CommonAPI.Utils

def follow(follower, followed) do
with {:ok, follower} <- User.maybe_direct_follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed),
{:ok, follower, followed} <-
User.wait_and_refresh(
Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
follower,
followed
) do
{:ok, follower, followed, activity}
end
end

def unfollow(follower, unfollowed) do
with {:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed),
{:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed) do
{:ok, follower}
end
end

def accept_follow_request(follower, followed) do
with {:ok, follower} <- User.maybe_follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Accept"
}) do
{:ok, follower}
end
end

def reject_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Reject"
}) do
{:ok, follower}
end
end

def delete(activity_id, user) 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"],
true <- User.superuser?(user) || user.ap_id == object.data["actor"],
{:ok, _} <- unpin(activity_id, user),
{:ok, delete} <- ActivityPub.delete(object) do
{:ok, delete}
@@ -75,8 +124,8 @@ defmodule Pleroma.Web.CommonAPI do
nil ->
"public"

inReplyTo ->
Pleroma.Web.MastodonAPI.StatusView.get_visibility(inReplyTo.data["object"])
in_reply_to ->
Pleroma.Web.MastodonAPI.StatusView.get_visibility(in_reply_to.data["object"])
end
end

@@ -88,15 +137,15 @@ defmodule Pleroma.Web.CommonAPI do

with status <- String.trim(status),
attachments <- attachments_from_ids(data),
inReplyTo <- get_replied_to_activity(data["in_reply_to_status_id"]),
in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]),
{content_html, mentions, tags} <-
make_content_html(
status,
attachments,
data
),
{to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
context <- make_context(inReplyTo),
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
context <- make_context(in_reply_to),
cw <- data["spoiler_text"],
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
length when length in 1..limit <- String.length(full_payload),
@@ -107,7 +156,7 @@ defmodule Pleroma.Web.CommonAPI do
context,
content_html,
attachments,
inReplyTo,
in_reply_to,
tags,
cw,
cc


+ 2
- 2
lib/pleroma/web/common_api/utils.ex Ver fichero

@@ -6,14 +6,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Calendar.Strftime
alias Comeonin.Pbkdf2
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Config
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.ActivityPub.Utils

# This is a hack for twidere.
def get_by_id_or_ap_id(id) do


+ 2
- 1
lib/pleroma/web/controller_helper.ex Ver fichero

@@ -6,7 +6,8 @@ defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller

def oauth_scopes(params, default) do
# Note: `scopes` is used by Mastodon — supporting it but sticking to OAuth's standard `scope` wherever we control it
# Note: `scopes` is used by Mastodon — supporting it but sticking to
# OAuth's standard `scope` wherever we control it
Pleroma.Web.OAuth.parse_scopes(params["scope"] || params["scopes"], default)
end



+ 1
- 0
lib/pleroma/web/endpoint.ex Ver fichero

@@ -26,6 +26,7 @@ defmodule Pleroma.Web.Endpoint do
from: :pleroma,
only:
~w(index.html static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc)
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
)

# Code reloading can be explicitly enabled under the


+ 8
- 8
lib/pleroma/web/federator/federator.ex Ver fichero

@@ -4,27 +4,27 @@

defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
alias Pleroma.Jobs
alias Pleroma.User
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Websub
alias Pleroma.Web.Salmon
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator.RetryQueue
alias Pleroma.Web.OStatus
alias Pleroma.Jobs
alias Pleroma.Web.Salmon
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Websub

require Logger

@websub Application.get_env(:pleroma, :websub)
@ostatus Application.get_env(:pleroma, :ostatus)

def init() do
def init do
# 1 minute
Process.sleep(1000 * 60 * 1)
Process.sleep(1000 * 60)
refresh_subscriptions()
end

@@ -58,7 +58,7 @@ defmodule Pleroma.Web.Federator do
Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
end

def refresh_subscriptions() do
def refresh_subscriptions do
Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
end



+ 5
- 5
lib/pleroma/web/federator/retry_queue.ex Ver fichero

@@ -13,7 +13,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
{:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
end

def start_link() do
def start_link do
enabled =
if Mix.env() == :test, do: true, else: Pleroma.Config.get([__MODULE__, :enabled], false)

@@ -39,11 +39,11 @@ defmodule Pleroma.Web.Federator.RetryQueue do
GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1})
end

def get_stats() do
def get_stats do
GenServer.call(__MODULE__, :get_stats)
end

def reset_stats() do
def reset_stats do
GenServer.call(__MODULE__, :reset_stats)
end

@@ -55,7 +55,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end

def get_retry_timer_interval() do
def get_retry_timer_interval do
Pleroma.Config.get([:retry_queue, :interval], 1000)
end

@@ -231,7 +231,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end

defp maybe_kickoff_timer() do
defp maybe_kickoff_timer do
GenServer.cast(__MODULE__, :kickoff_timer)
end
end

+ 62
- 0
lib/pleroma/web/mastodon_api/mastodon_api.ex Ver fichero

@@ -1 +1,63 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
import Ecto.Query
import Ecto.Changeset

alias Pleroma.Repo
alias Pleroma.User

@default_limit 20

def get_followers(user, params \\ %{}) do
user
|> User.get_followers_query()
|> paginate(params)
|> Repo.all()
end

def get_friends(user, params \\ %{}) do
user
|> User.get_friends_query()
|> paginate(params)
|> Repo.all()
end

def paginate(query, params \\ %{}) do
options = cast_params(params)

query
|> restrict(:max_id, options)
|> restrict(:since_id, options)
|> restrict(:limit, options)
|> order_by([u], fragment("? desc nulls last", u.id))
end

def cast_params(params) do
param_types = %{
max_id: :string,
since_id: :string,
limit: :integer
}

changeset = cast({%{}, param_types}, params, Map.keys(param_types))
changeset.changes
end

defp restrict(query, :max_id, %{max_id: max_id}) do
query
|> where([q], q.id < ^max_id)
end

defp restrict(query, :since_id, %{since_id: since_id}) do
query
|> where([q], q.id > ^since_id)
end

defp restrict(query, :limit, options) do
limit = Map.get(options, :limit, @default_limit)

query
|> limit(^limit)
end

defp restrict(query, _, _), do: query
end

+ 39
- 86
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex Ver fichero

@@ -4,6 +4,7 @@

defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller

alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Filter
@@ -13,21 +14,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Push
alias Push.Subscription

alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.MastodonAPI.MastodonView
alias Pleroma.Web.MastodonAPI.PushSubscriptionView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MastodonAPI.ReportView
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
@@ -134,8 +131,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, account)
end

def user(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
with %User{} = user <- Repo.get(User, id),
def user(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_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)
@@ -193,6 +190,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end

defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do
params =
conn.params
|> Map.drop(["since_id", "max_id"])
|> Map.merge(params)

last = List.last(activities)
first = List.first(activities)

@@ -292,13 +294,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end

def dm_timeline(%{assigns: %{user: user}} = conn, params) do
query =
ActivityPub.fetch_activities_query(
[user.ap_id],
Map.merge(params, %{"type" => "Create", visibility: "direct"})
)
params =
params
|> Map.put("type", "Create")
|> Map.put("blocking_user", user)
|> Map.put("user", user)
|> Map.put(:visibility, "direct")

activities = Repo.all(query)
activities =
[user.ap_id]
|> ActivityPub.fetch_activities_query(params)
|> Repo.all()

conn
|> add_link_headers(:dm_timeline, activities)
@@ -646,9 +652,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> render("index.json", %{activities: activities, for: user, as: :activity})
end

def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_followers(user) do
followers <- MastodonAPI.get_followers(user, params) do
followers =
cond do
for_user && user.id == for_user.id -> followers
@@ -657,14 +663,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end

conn
|> add_link_headers(:followers, followers, user)
|> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user})
end
end

def following(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_friends(user) do
followers <- MastodonAPI.get_friends(user, params) do
followers =
cond do
for_user && user.id == for_user.id -> followers
@@ -673,6 +680,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end

conn
|> add_link_headers(:following, followers, user)
|> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user})
end
@@ -688,16 +696,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do

def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
with %User{} = follower <- Repo.get(User, id),
{:ok, follower} <- User.maybe_follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Accept"
}) do
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
@@ -711,15 +710,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do

def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
with %User{} = follower <- Repo.get(User, id),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
actor: followed,
object: follow_activity.data["id"],
type: "Reject"
}) do
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
@@ -733,14 +724,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do

def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with %User{} = followed <- Repo.get(User, id),
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
{:ok, _activity} <- ActivityPub.follow(follower, followed),
{:ok, follower, followed} <-
User.wait_and_refresh(
Config.get([:activitypub, :follow_handshake_timeout]),
follower,
followed
) do
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
@@ -754,8 +738,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do

def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
with %User{} = followed <- Repo.get_by(User, nickname: uri),
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("account.json", %{user: followed, for: follower})
@@ -769,8 +752,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do

def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with %User{} = followed <- Repo.get(User, id),
{:ok, _activity} <- ActivityPub.unfollow(follower, followed),
{:ok, follower, _} <- User.unfollow(follower, followed) do
{:ok, follower} <- CommonAPI.unfollow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
@@ -1128,7 +1110,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
compose: %{
me: "#{user.id}",
default_privacy: user.info.default_scope,
default_sensitive: false
default_sensitive: false,
allow_content_types: Config.get([:instance, :allowed_post_formats])
},
media_attachments: %{
accept_content_types: [
@@ -1273,7 +1256,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end

defp get_or_make_app() do
defp get_or_make_app do
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
scopes = ["read", "write", "follow", "push"]

@@ -1424,37 +1407,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
end

def create_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do
true = Push.enabled()
Subscription.delete_if_exists(user, token)
{:ok, subscription} = Subscription.create(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end

def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
true = Push.enabled()
subscription = Subscription.get(user, token)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end

def update_push_subscription(
%{assigns: %{user: user, token: token}} = conn,
params
) do
true = Push.enabled()
{:ok, subscription} = Subscription.update(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end

def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
true = Push.enabled()
{:ok, _response} = Subscription.delete(user, token)
json(conn, %{})
end

# fallback action
#
def errors(conn, _) do
conn
|> put_status(500)
@@ -1483,7 +1437,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
url,
[],
adapter: [
timeout: timeout,
recv_timeout: timeout,
pool: :default
]


+ 71
- 0
lib/pleroma/web/mastodon_api/subscription_controller.ex Ver fichero

@@ -0,0 +1,71 @@
# 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.SubscriptionController do
@moduledoc "The module represents functions to manage user subscriptions."
use Pleroma.Web, :controller

alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View

action_fallback(:errors)

# Creates PushSubscription
# POST /api/v1/push/subscription
#
def create(%{assigns: %{user: user, token: token}} = conn, params) do
with true <- Push.enabled(),
{:ok, _} <- Subscription.delete_if_exists(user, token),
{:ok, subscription} <- Subscription.create(user, token, params) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end

# Gets PushSubscription
# GET /api/v1/push/subscription
#
def get(%{assigns: %{user: user, token: token}} = conn, _params) do
with true <- Push.enabled(),
{:ok, subscription} <- Subscription.get(user, token) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end

# Updates PushSubscription
# PUT /api/v1/push/subscription
#
def update(%{assigns: %{user: user, token: token}} = conn, params) do
with true <- Push.enabled(),
{:ok, subscription} <- Subscription.update(user, token, params) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end

# Deletes PushSubscription
# DELETE /api/v1/push/subscription
#
def delete(%{assigns: %{user: user, token: token}} = conn, _params) do
with true <- Push.enabled(),
{:ok, _response} <- Subscription.delete(user, token),
do: json(conn, %{})
end

# fallback action
#
def errors(conn, {:error, :not_found}) do
conn
|> put_status(404)
|> json("Not found")
end

def errors(conn, _) do
conn
|> put_status(500)
|> json("Something went wrong")
end
end

+ 2
- 3
lib/pleroma/web/mastodon_api/views/push_subscription_view.ex Ver fichero

@@ -4,6 +4,7 @@

defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
use Pleroma.Web, :view
alias Pleroma.Web.Push

def render("push_subscription.json", %{subscription: subscription}) do
%{
@@ -14,7 +15,5 @@ defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
}
end

defp server_key do
Keyword.get(Application.get_env(:web_push_encryption, :vapid_details), :public_key)
end
defp server_key, do: Keyword.get(Push.vapid_config(), :public_key)
end

+ 8
- 2
lib/pleroma/web/mastodon_api/views/status_view.ex Ver fichero

@@ -102,7 +102,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
website: nil
},
language: nil,
emojis: []
emojis: [],
pleroma: %{
local: activity.local
}
}
end

@@ -181,7 +184,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
website: nil
},
language: nil,
emojis: build_emojis(activity.data["object"]["emoji"])
emojis: build_emojis(activity.data["object"]["emoji"]),
pleroma: %{
local: activity.local
}
}
end



+ 1
- 1
lib/pleroma/web/mastodon_api/websocket_handler.ex Ver fichero

@@ -5,9 +5,9 @@
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
require Logger

alias Pleroma.Web.OAuth.Token
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.OAuth.Token

@behaviour :cowboy_websocket



+ 2
- 1
lib/pleroma/web/media_proxy/media_proxy.ex Ver fichero

@@ -19,7 +19,8 @@ defmodule Pleroma.Web.MediaProxy do
else
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]

# Must preserve `%2F` for compatibility with S3 (https://git.pleroma.social/pleroma/pleroma/issues/580)
# Must preserve `%2F` for compatibility with S3
# https://git.pleroma.social/pleroma/pleroma/issues/580
replacement = get_replacement(url, ":2F:")

# The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.


+ 1
- 1
lib/pleroma/web/metadata/opengraph.ex Ver fichero

@@ -88,7 +88,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do

# TODO: Add additional properties to objects when we have the data available.
# Also, Whatsapp only wants JPEG or PNGs. It seems that if we add a second og:image
# object when a Video or GIF is attached it will display that in the Whatsapp Rich Preview.
# object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
case media_type do
"audio" ->
[


+ 2
- 1
lib/pleroma/web/metadata/twitter_card.ex Ver fichero

@@ -97,7 +97,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
| acc
]

# TODO: Need the true width and height values here or Twitter renders an iFrame with a bad aspect ratio
# TODO: Need the true width and height values here or Twitter renders an iFrame with
# a bad aspect ratio
"video" ->
[
{:meta, [property: "twitter:card", content: "player"], []},


+ 4
- 4
lib/pleroma/web/metadata/utils.ex Ver fichero

@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
# Copyright \xc2\xa9 2017-2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.Metadata.Utils do
alias Pleroma.HTML
alias Pleroma.Formatter
alias Pleroma.HTML
alias Pleroma.Web.MediaProxy

def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
@@ -17,14 +17,14 @@ defmodule Pleroma.Web.Metadata.Utils do
|> Formatter.truncate()
end

def scrub_html_and_truncate(content) when is_binary(content) do
def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
content
# html content comes from DB already encoded, decode first and scrub after
|> HtmlEntities.decode()
|> String.replace(~r/<br\s?\/?>/, " ")
|> HTML.strip_tags()
|> Formatter.demojify()
|> Formatter.truncate()
|> Formatter.truncate(max_length)
end

def attachment_url(url) do


+ 0
- 1
lib/pleroma/web/nodeinfo/nodeinfo.ex Ver fichero

@@ -1 +0,0 @@


+ 1
- 3
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex Ver fichero

@@ -6,7 +6,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
use Pleroma.Web, :controller

alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
@@ -86,8 +85,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
end

staff_accounts =
User.moderator_user_query()
|> Repo.all()
User.all_superusers()
|> Enum.map(fn u -> u.ap_id end)

mrf_user_allowlist =


+ 2
- 2
lib/pleroma/web/oauth/authorization.ex Ver fichero

@@ -5,10 +5,10 @@
defmodule Pleroma.Web.OAuth.Authorization do
use Ecto.Schema

alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.User
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization

import Ecto.Changeset
import Ecto.Query


+ 3
- 3
lib/pleroma/web/oauth/oauth_controller.ex Ver fichero

@@ -5,12 +5,12 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller

alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Auth.Authenticator
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.OAuth.App
alias Pleroma.Repo
alias Pleroma.User

import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]



+ 2
- 2
lib/pleroma/web/oauth/token.ex Ver fichero

@@ -7,11 +7,11 @@ defmodule Pleroma.Web.OAuth.Token do

import Ecto.Query

alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Token
alias Pleroma.User
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token

schema "oauth_tokens" do
field(:token, :string)


+ 1
- 1
lib/pleroma/web/ostatus/activity_representer.ex Ver fichero

@@ -4,8 +4,8 @@

defmodule Pleroma.Web.OStatus.ActivityRepresenter do
alias Pleroma.Activity
alias Pleroma.User
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.OStatus.UserRepresenter

require Logger


+ 1
- 1
lib/pleroma/web/ostatus/feed_representer.ex Ver fichero

@@ -4,8 +4,8 @@

defmodule Pleroma.Web.OStatus.FeedRepresenter do
alias Pleroma.User
alias Pleroma.Web.OStatus
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.UserRepresenter



+ 1
- 1
lib/pleroma/web/ostatus/handlers/delete_handler.ex Ver fichero

@@ -4,9 +4,9 @@

defmodule Pleroma.Web.OStatus.DeleteHandler do
require Logger
alias Pleroma.Web.XML
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.XML

def handle_delete(entry, _doc \\ nil) do
with id <- XML.string_from_xpath("//id", entry),


+ 3
- 3
lib/pleroma/web/ostatus/handlers/follow_handler.ex Ver fichero

@@ -3,10 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.OStatus.FollowHandler do
alias Pleroma.Web.XML
alias Pleroma.Web.OStatus
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML

def handle(entry, doc) do
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),


+ 17
- 15
lib/pleroma/web/ostatus/handlers/note_handler.ex Ver fichero

@@ -4,13 +4,14 @@

defmodule Pleroma.Web.OStatus.NoteHandler do
require Logger
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML

alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML

@doc """
Get the context for this note. Uses this:
@@ -18,13 +19,13 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
2. The conversation reference in the ostatus xml
3. A newly generated context id.
"""
def get_context(entry, inReplyTo) do
def get_context(entry, in_reply_to) do
context =
(XML.string_from_xpath("//ostatus:conversation[1]", entry) ||
XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry) || "")
|> String.trim()

with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do
with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(in_reply_to) do
context
else
_e ->
@@ -87,14 +88,14 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
Map.put(note, "external_url", url)
end

def fetch_replied_to_activity(entry, inReplyTo) do
with %Activity{} = activity <- Activity.get_create_by_object_ap_id(inReplyTo) do
def fetch_replied_to_activity(entry, in_reply_to) do
with %Activity{} = activity <- Activity.get_create_by_object_ap_id(in_reply_to) do
activity
else
_e ->
with inReplyToHref when not is_nil(inReplyToHref) <-
with in_reply_to_href when not is_nil(in_reply_to_href) <-
XML.string_from_xpath("//thr:in-reply-to[1]/@href", entry),
{:ok, [activity | _]} <- OStatus.fetch_activity_from_url(inReplyToHref) do
{:ok, [activity | _]} <- OStatus.fetch_activity_from_url(in_reply_to_href) do
activity
else
_e -> nil
@@ -110,11 +111,12 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
{:ok, actor} <- OStatus.find_make_or_update_user(author),
content_html <- OStatus.get_content(entry),
cw <- OStatus.get_cw(entry),
inReplyTo <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
inReplyToActivity <- fetch_replied_to_activity(entry, inReplyTo),
inReplyTo <- (inReplyToActivity && inReplyToActivity.data["object"]["id"]) || inReplyTo,
in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
in_reply_to_activity <- fetch_replied_to_activity(entry, in_reply_to),
in_reply_to <-
(in_reply_to_activity && in_reply_to_activity.data["object"]["id"]) || in_reply_to,
attachments <- OStatus.get_attachments(entry),
context <- get_context(entry, inReplyTo),
context <- get_context(entry, in_reply_to),
tags <- OStatus.get_tags(entry),
mentions <- get_mentions(entry),
to <- make_to_list(actor, mentions),
@@ -128,7 +130,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
context,
content_html,
attachments,
inReplyToActivity,
in_reply_to_activity,
[],
cw
),
@@ -140,8 +142,8 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
# TODO: Handle this case in make_note_data
note <-
if(
inReplyTo && !inReplyToActivity,
do: note |> Map.put("inReplyTo", inReplyTo),
in_reply_to && !in_reply_to_activity,
do: note |> Map.put("inReplyTo", in_reply_to),
else: note
) do
ActivityPub.create(%{


+ 3
- 3
lib/pleroma/web/ostatus/handlers/unfollow_handler.ex Ver fichero

@@ -3,10 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.OStatus.UnfollowHandler do
alias Pleroma.Web.XML
alias Pleroma.Web.OStatus
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML

def handle(entry, doc) do
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),


+ 6
- 6
lib/pleroma/web/ostatus/ostatus.ex Ver fichero

@@ -9,19 +9,19 @@ defmodule Pleroma.Web.OStatus do
import Pleroma.Web.XML
require Logger

alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
alias Pleroma.Object
alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Websub
alias Pleroma.Web.OStatus.DeleteHandler
alias Pleroma.Web.OStatus.FollowHandler
alias Pleroma.Web.OStatus.UnfollowHandler
alias Pleroma.Web.OStatus.NoteHandler
alias Pleroma.Web.OStatus.DeleteHandler
alias Pleroma.Web.OStatus.UnfollowHandler
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Websub

def is_representable?(%Activity{data: data}) do
object = Object.normalize(data["object"])


+ 3
- 3
lib/pleroma/web/ostatus/ostatus_controller.ex Ver fichero

@@ -9,13 +9,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.XML

plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])


+ 133
- 0
lib/pleroma/web/push/impl.ex Ver fichero

@@ -0,0 +1,133 @@
# 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.Impl do
@moduledoc "The module represents implementation push web notification"

alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Metadata.Utils
alias Pleroma.Web.Push.Subscription

require Logger
import Ecto.Query

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

@doc "Performs sending notifications for user subscriptions"
@spec perform_send(Notification.t()) :: list(any)
def perform_send(
%{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} =
notif
)
when activity_type in @types do
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])

type = Activity.mastodon_notification_type(notif.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)

for subscription <- fetch_subsriptions(user_id),
get_in(subscription.data, ["alerts", type]) do
%{
title: format_title(notif),
access_token: subscription.token.token,
body: format_body(notif, actor),
notification_id: notif.id,
notification_type: type,
icon: avatar_url,
preferred_locale: "en",
pleroma: %{
activity_id: activity_id
}
}
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription)
end
end

def perform_send(_) do
Logger.warn("Unknown notification type")
:error
end

@doc "Push message to web"
def push_message(body, sub, api_key, subscription) do
case WebPushEncryption.send_web_push(body, sub, api_key) do
{:ok, %{status_code: code}} when 400 <= code and code < 500 ->
Logger.debug("Removing subscription record")
Repo.delete!(subscription)
:ok

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

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

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

@doc "Gets user subscriptions"
def fetch_subsriptions(user_id) do
Subscription
|> where(user_id: ^user_id)
|> preload(:token)
|> Repo.all()
end

def build_sub(subscription) do
%{
keys: %{
p256dh: subscription.key_p256dh,
auth: subscription.key_auth
},
endpoint: subscription.endpoint
}
end

def format_body(
%{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
actor
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end

def format_body(
%{activity: %{data: %{"type" => "Announce", "object" => activity_id}}},
actor
) do
%Activity{data: %{"object" => %{"id" => object_id}}} = Activity.get_by_ap_id(activity_id)
%Object{data: %{"content" => content}} = Object.get_by_ap_id(object_id)

"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end

def format_body(
%{activity: %{data: %{"type" => type}}},
actor
)
when type in ["Follow", "Like"] do
case type do
"Follow" -> "@#{actor.nickname} has followed you"
"Like" -> "@#{actor.nickname} has favorited your post"
end
end

def format_title(%{activity: %{data: %{"type" => type}}}) do
case type do
"Create" -> "New Mention"
"Follow" -> "New Follower"
"Announce" -> "New Repeat"
"Like" -> "New Favorite"
end
end
end

+ 22
- 97
lib/pleroma/web/push/push.ex Ver fichero

@@ -5,24 +5,23 @@
defmodule Pleroma.Web.Push do
use GenServer

alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Push.Subscription
alias Pleroma.Web.Push.Impl

require Logger
import Ecto.Query

@types ["Create", "Follow", "Announce", "Like"]
##############
# Client API #
##############

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

def vapid_config() do
def vapid_config do
Application.get_env(:web_push_encryption, :vapid_details, [])
end

def enabled() do
def enabled do
case vapid_config() do
[] -> false
list when is_list(list) -> true
@@ -30,14 +29,18 @@ defmodule Pleroma.Web.Push do
end
end

def send(notification) do
if enabled() do
GenServer.cast(Pleroma.Web.Push, {:send, notification})
end
end
def send(notification),
do: GenServer.cast(__MODULE__, {:send, notification})

####################
# Server Callbacks #
####################

@impl true
def init(:ok) do
if !enabled() do
if enabled() do
{:ok, nil}
else
Logger.warn("""
VAPID key pair is not found. If you wish to enabled web push, please run

@@ -47,93 +50,15 @@ defmodule Pleroma.Web.Push do
""")

:ignore
else
{:ok, nil}
end
end

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

type = Pleroma.Activity.mastodon_notification_type(notification.activity)

Subscription
|> where(user_id: ^user_id)
|> preload(:token)
|> Repo.all()
|> Enum.filter(fn subscription ->
get_in(subscription.data, ["alerts", type]) || false
end)
|> Enum.each(fn subscription ->
sub = %{
keys: %{
p256dh: subscription.key_p256dh,
auth: subscription.key_auth
},
endpoint: subscription.endpoint
}

body =
Jason.encode!(%{
title: format_title(notification),
access_token: subscription.token.token,
body: format_body(notification, actor),
notification_id: notification.id,
notification_type: type,
icon: User.avatar_url(actor),
preferred_locale: "en"
})

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

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

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

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

{:noreply, state}
end

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

defp format_title(%{activity: %{data: %{"type" => type}}}) do
case type do
"Create" -> "New Mention"
"Follow" -> "New Follower"
"Announce" -> "New Repeat"
"Like" -> "New Favorite"
@impl true
def handle_cast({:send, notification}, state) do
if enabled() do
Impl.perform_send(notification)
end
end

defp format_body(%{activity: %{data: %{"type" => type}}}, actor) do
case type do
"Create" -> "@#{actor.nickname} has mentioned you"
"Follow" -> "@#{actor.nickname} has followed you"
"Announce" -> "@#{actor.nickname} has repeated your post"
"Like" -> "@#{actor.nickname} has favorited your post"
end
{:noreply, state}
end
end

+ 19
- 9
lib/pleroma/web/push/subscription.ex Ver fichero

@@ -12,6 +12,8 @@ defmodule Pleroma.Web.Push.Subscription do
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Push.Subscription

@type t :: %__MODULE__{}

schema "push_subscriptions" do
belongs_to(:user, User, type: Pleroma.FlakeId)
belongs_to(:token, Token)
@@ -50,30 +52,38 @@ defmodule Pleroma.Web.Push.Subscription do
})
end

@doc "Gets subsciption by user & token"
@spec get(User.t(), Token.t()) :: {:ok, t()} | {:error, :not_found}
def get(%User{id: user_id}, %Token{id: token_id}) do
Repo.get_by(Subscription, user_id: user_id, token_id: token_id)
case Repo.get_by(Subscription, user_id: user_id, token_id: token_id) do
nil -> {:error, :not_found}
subscription -> {:ok, subscription}
end
end

def update(user, token, params) do
get(user, token)
|> change(data: alerts(params))
|> Repo.update()
with {:ok, subscription} <- get(user, token) do
subscription
|> change(data: alerts(params))
|> Repo.update()
end
end

def delete(user, token) do
Repo.delete(get(user, token))
with {:ok, subscription} <- get(user, token),
do: Repo.delete(subscription)
end

def delete_if_exists(user, token) do
case get(user, token) do
nil -> {:ok, nil}
sub -> Repo.delete(sub)
{:error, _} -> {:ok, nil}
{:ok, sub} -> Repo.delete(sub)
end
end

# Some webpush clients (e.g. iOS Toot!) use an non urlsafe base64 as an encoding for the key.
# However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library we use
# requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
# However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library
# we use requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
defp ensure_base64_urlsafe(string) do
string
|> String.replace("+", "-")


+ 2
- 2
lib/pleroma/web/rel_me.ex Ver fichero

@@ -5,7 +5,6 @@
defmodule Pleroma.Web.RelMe do
@hackney_options [
pool: :media,
timeout: 2_000,
recv_timeout: 2_000,
max_body: 2_000_000
]
@@ -28,7 +27,8 @@ defmodule Pleroma.Web.RelMe do
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)

data =
Floki.attribute(html, "link[rel=me]", "href") ++ Floki.attribute(html, "a[rel=me]", "href")
Floki.attribute(html, "link[rel~=me]", "href") ++
Floki.attribute(html, "a[rel~=me]", "href")

{:ok, data}
rescue


+ 15
- 1
lib/pleroma/web/rich_media/helpers.ex Ver fichero

@@ -4,14 +4,28 @@

defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.HTML
alias Pleroma.Object
alias Pleroma.Web.RichMedia.Parser

defp validate_page_url(page_url) when is_binary(page_url) do
if AutoLinker.Parser.is_url?(page_url, true) do
URI.parse(page_url) |> validate_page_url
else
:error
end
end

defp validate_page_url(%URI{authority: nil}), do: :error
defp validate_page_url(%URI{scheme: nil}), do: :error
defp validate_page_url(%URI{}), do: :ok
defp validate_page_url(_), do: :error

def fetch_data_for_activity(%Activity{} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]),
%Object{} = object <- Object.normalize(activity.data["object"]),
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
:ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do
%{page_url: page_url, rich_media: rich_media}
else


+ 0
- 1
lib/pleroma/web/rich_media/parser.ex Ver fichero

@@ -11,7 +11,6 @@ defmodule Pleroma.Web.RichMedia.Parser do

@hackney_options [
pool: :media,
timeout: 2_000,
recv_timeout: 2_000,
max_body: 2_000_000
]


+ 5
- 6
lib/pleroma/web/router.ex Ver fichero

@@ -140,7 +140,6 @@ defmodule Pleroma.Web.Router do
pipe_through([:admin_api, :oauth_write])

get("/users", AdminAPIController, :list_users)
get("/users/search", AdminAPIController, :search_users)
delete("/user", AdminAPIController, :user_delete)
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
post("/user", AdminAPIController, :user_create)
@@ -304,10 +303,10 @@ defmodule Pleroma.Web.Router do
scope [] do
pipe_through(:oauth_push)

post("/push/subscription", MastodonAPIController, :create_push_subscription)
get("/push/subscription", MastodonAPIController, :get_push_subscription)
put("/push/subscription", MastodonAPIController, :update_push_subscription)
delete("/push/subscription", MastodonAPIController, :delete_push_subscription)
post("/push/subscription", SubscriptionController, :create)
get("/push/subscription", SubscriptionController, :get)
put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", SubscriptionController, :delete)
end
end

@@ -632,8 +631,8 @@ end

defmodule Fallback.RedirectController do
use Pleroma.Web, :controller
alias Pleroma.Web.Metadata
alias Pleroma.User
alias Pleroma.Web.Metadata

def redirector(conn, _params, code \\ 200) do
conn


+ 3
- 3
lib/pleroma/web/salmon/salmon.ex Ver fichero

@@ -9,8 +9,8 @@ defmodule Pleroma.Web.Salmon do

alias Pleroma.Instances
alias Pleroma.User
alias Pleroma.Web.XML
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.XML

require Logger

@@ -86,10 +86,10 @@ defmodule Pleroma.Web.Salmon do
# Native generation of RSA keys is only available since OTP 20+ and in default build conditions
# We try at compile time to generate natively an RSA key otherwise we fallback on the old way.
try do
_ = :public_key.generate_key({:rsa, 2048, 65537})
_ = :public_key.generate_key({:rsa, 2048, 65_537})

def generate_rsa_pem do
key = :public_key.generate_key({:rsa, 2048, 65537})
key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
{:ok, pem}


+ 13
- 6
lib/pleroma/web/streamer.ex Ver fichero

@@ -5,11 +5,11 @@
defmodule Pleroma.Web.Streamer do
use GenServer
require Logger
alias Pleroma.User
alias Pleroma.Notification
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Visibility

@keepalive_interval :timer.seconds(30)
@@ -197,10 +197,12 @@ defmodule Pleroma.Web.Streamer do
if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || []
mutes = user.info.mutes || []

parent = Object.normalize(item.data["object"])

unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do
unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
parent.data["actor"] in blocks or parent.data["actor"] in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
else
@@ -209,23 +211,28 @@ defmodule Pleroma.Web.Streamer do
end)
end

def push_to_socket(topics, topic, %Activity{id: id, data: %{"type" => "Delete"}}) do
def push_to_socket(topics, topic, %Activity{
data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id}
}) do
Enum.each(topics[topic] || [], fn socket ->
send(
socket.transport_pid,
{:text, %{event: "delete", payload: to_string(id)} |> Jason.encode!()}
{:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()}
)
end)
end

def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop

def push_to_socket(topics, topic, item) do
Enum.each(topics[topic] || [], fn socket ->
# Get the current user so we have up-to-date blocks etc.
if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || []
mutes = user.info.mutes || []

unless item.actor in blocks do
unless item.actor in blocks or item.actor in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
else


+ 111
- 29
lib/pleroma/web/templates/layout/app.html.eex Ver fichero

@@ -8,75 +8,145 @@
</title>
<style>
body {
background-color: #282c37;
background-color: #121a24;
font-family: sans-serif;
color:white;
color: #b9b9ba;
text-align: center;
}

.container {
margin: 50px auto;
max-width: 320px;
padding: 0;
padding: 40px 40px 40px 40px;
background-color: #313543;
max-width: 420px;
padding: 20px;
background-color: #182230;
border-radius: 4px;
margin: auto;
margin-top: 10vh;
box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5);
}

h1 {
margin: 0;
font-size: 24px;
}

h2 {
color: #9baec8;
color: #b9b9ba;
font-weight: normal;
font-size: 20px;
margin-bottom: 40px;
font-size: 18px;
margin-bottom: 20px;
}

form {
width: 100%;
}

.input {
text-align: left;
color: #89898a;
display: flex;
flex-direction: column;
}

input {
box-sizing: border-box;
width: 100%;
box-sizing: content-box;
padding: 10px;
margin-top: 20px;
background-color: rgba(0,0,0,.1);
color: white;
margin-top: 5px;
margin-bottom: 10px;
background-color: #121a24;
color: #b9b9ba;
border: 0;
border-bottom: 2px solid #9baec8;
transition-property: border-bottom;
transition-duration: 0.35s;
border-bottom: 2px solid #2a384a;
font-size: 14px;
}

input:focus {
border-bottom: 2px solid #4b8ed8;
.scopes-input {
display: flex;
margin-top: 1em;
text-align: left;
color: #89898a;
}

.scopes-input label:first-child {
flex-basis: 40%;
}

input[type="checkbox"] {
width: auto;
.scopes {
display: flex;
flex-wrap: wrap;
text-align: left;
color: #b9b9ba;
}

.scope {
flex-basis: 100%;
display: flex;
height: 2em;
align-items: center;
}

[type="checkbox"] + label {
margin: 0.5em;
}

[type="checkbox"] {
display: none;
}

[type="checkbox"] + label:before {
display: inline-block;
color: white;
background-color: #121a24;
border: 4px solid #121a24;
box-sizing: border-box;
width: 1.2em;
height: 1.2em;
margin-right: 1.0em;
content: "";
transition-property: background-color;
transition-duration: 0.35s;
color: #121a24;
margin-bottom: -0.2em;
border-radius: 2px;
}

[type="checkbox"]:checked + label:before {
background-color: #d8a070;
}

input:focus {
outline: none;
border-bottom: 2px solid #d8a070;
}

button {
box-sizing: border-box;
width: 100%;
color: white;
background-color: #419bdd;
background-color: #1c2a3a;
color: #b9b9ba;
border-radius: 4px;
border: none;
padding: 10px;
margin-top: 30px;
text-transform: uppercase;
font-weight: 500;
font-size: 16px;
box-shadow: 0px 0px 2px 0px black,
0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
}

button:hover {
cursor: pointer;
box-shadow: 0px 0px 0px 1px #d8a070,
0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
}

.alert-danger {
box-sizing: border-box;
width: 100%;
color: #D8000C;
background-color: #FFD2D2;
background-color: #931014;
border-radius: 4px;
border: none;
padding: 10px;
@@ -88,20 +158,32 @@
.alert-info {
box-sizing: border-box;
width: 100%;
color: #00529B;
background-color: #BDE5F8;
border-radius: 4px;
border: none;
border: 1px solid #7d796a;
padding: 10px;
margin-top: 20px;
font-weight: 500;
font-size: 16px;
}

@media all and (max-width: 440px) {
.container {
margin-top: 0
}

.scopes-input {
flex-direction: column;
}

.scope {
flex-basis: 50%;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Pleroma</h1>
<h1><%= Application.get_env(:pleroma, :instance)[:name] %></h1>
<%= render @view_module, @view_template, assigns %>
</div>
</body>


+ 19
- 16
lib/pleroma/web/templates/o_auth/o_auth/show.html.eex Ver fichero

@@ -6,23 +6,26 @@
<% end %>
<h2>OAuth Authorization</h2>
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
<%= label f, :name, "Name or email" %>
<%= text_input f, :name %>
<br>
<br>
<%= label f, :password, "Password" %>
<%= password_input f, :password %>
<br>
<br>
<div class="input">
<%= label f, :name, "Name or email" %>
<%= text_input f, :name %>
</div>
<div class="input">
<%= label f, :password, "Password" %>
<%= password_input f, :password %>
</div>
<div class="scopes-input">
<%= label f, :scope, "Permissions" %>
<br>
<%= for scope <- @available_scopes do %>
<%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
<%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
<%= label f, :"scope_#{scope}", String.capitalize(scope) %>
<br>
<% end %>
<div class="scopes">
<%= for scope <- @available_scopes do %>
<%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
<div class="scope">
<%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
<%= label f, :"scope_#{scope}", String.capitalize(scope) %>
</div>
<% end %>
</div>
</div>

<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :response_type, value: @response_type %>


+ 2
- 2
lib/pleroma/web/twitter_api/controllers/util_controller.ex Ver fichero

@@ -10,13 +10,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Comeonin.Pbkdf2
alias Pleroma.Emoji
alias Pleroma.PasswordResetToken
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OStatus
alias Pleroma.Web.WebFinger
alias Pleroma.Web.ActivityPub.ActivityPub

def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio

Cargando…
Cancelar
Guardar