Merge remote-tracking branch 'origin/develop' into shigusegubu
* origin/develop: (87 commits) Add a gopher url port config option modify the migrations to use naive_datetime_usec Fix filter migration Fix migration timestamp type Ecto 3.0.5 migration Update frontend Format Use ILIKE to search users transmogrifier: upgrade: when upgrading OStatus users to AP, ensure we always use the fake collection user: properly cope with actors which do not declare a followers collection transmogrifier: when determining followers collection URI, we may need to fetch the actor test: add test for list sanitization tests: add test for as:Public issues activitypub: transmogrifier: do not allow missing lists to be interpreted as nil activitypub: transmogrifier: ensure as:Public activities are delivered to followers fix UploadTest to use new image_tmp.jpg used imageOptim to reduce size of image files Document additional pleroma changes to /api/v1/accounts/:id Check if the user has indeed not been federated with Added support for exclude_types, limit, and min_id in Mastodon notifications. ...
This commit is contained in:
commit
9bb34a12eb
392 changed files with 2149 additions and 715 deletions
12
.credo.exs
12
.credo.exs
|
|
@ -69,8 +69,8 @@
|
||||||
# You can also customize the exit_status of each check.
|
# You can also customize the exit_status of each check.
|
||||||
# If you don't want TODO comments to cause `mix credo` to fail, just
|
# If you don't want TODO comments to cause `mix credo` to fail, just
|
||||||
# set this value to 0 (zero).
|
# set this value to 0 (zero).
|
||||||
{Credo.Check.Design.TagTODO, exit_status: 2},
|
{Credo.Check.Design.TagTODO, exit_status: 0},
|
||||||
{Credo.Check.Design.TagFIXME},
|
{Credo.Check.Design.TagFIXME, exit_status: 0},
|
||||||
|
|
||||||
{Credo.Check.Readability.FunctionNames},
|
{Credo.Check.Readability.FunctionNames},
|
||||||
{Credo.Check.Readability.LargeNumbers},
|
{Credo.Check.Readability.LargeNumbers},
|
||||||
|
|
@ -81,7 +81,9 @@
|
||||||
{Credo.Check.Readability.ParenthesesOnZeroArityDefs},
|
{Credo.Check.Readability.ParenthesesOnZeroArityDefs},
|
||||||
{Credo.Check.Readability.ParenthesesInCondition},
|
{Credo.Check.Readability.ParenthesesInCondition},
|
||||||
{Credo.Check.Readability.PredicateFunctionNames},
|
{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.RedundantBlankLines},
|
||||||
{Credo.Check.Readability.StringSigils},
|
{Credo.Check.Readability.StringSigils},
|
||||||
{Credo.Check.Readability.TrailingBlankLine},
|
{Credo.Check.Readability.TrailingBlankLine},
|
||||||
|
|
@ -126,10 +128,6 @@
|
||||||
|
|
||||||
# Deprecated checks (these will be deleted after a grace period)
|
# Deprecated checks (these will be deleted after a grace period)
|
||||||
{Credo.Check.Readability.Specs, false},
|
{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`.
|
# Custom checks can be created using `mix credo.gen.check`.
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ cache:
|
||||||
stages:
|
stages:
|
||||||
- lint
|
- lint
|
||||||
- test
|
- test
|
||||||
|
- analysis
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- mix local.hex --force
|
- mix local.hex --force
|
||||||
|
|
@ -37,3 +38,8 @@ unit-testing:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- mix test --trace --preload-modules
|
- mix test --trace --preload-modules
|
||||||
|
|
||||||
|
analysis:
|
||||||
|
stage: analysis
|
||||||
|
script:
|
||||||
|
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ use Mix.Config
|
||||||
# General application configuration
|
# General application configuration
|
||||||
config :pleroma, ecto_repos: [Pleroma.Repo]
|
config :pleroma, ecto_repos: [Pleroma.Repo]
|
||||||
|
|
||||||
config :pleroma, Pleroma.Repo, types: Pleroma.PostgresTypes
|
|
||||||
|
|
||||||
config :pleroma, Pleroma.Captcha,
|
config :pleroma, Pleroma.Captcha,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
seconds_valid: 60,
|
seconds_valid: 60,
|
||||||
|
|
@ -34,7 +32,8 @@ config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.
|
||||||
# Upload configuration
|
# Upload configuration
|
||||||
config :pleroma, Pleroma.Upload,
|
config :pleroma, Pleroma.Upload,
|
||||||
uploader: Pleroma.Uploaders.Local,
|
uploader: Pleroma.Uploaders.Local,
|
||||||
filters: [],
|
filters: [Pleroma.Upload.Filter.Dedupe],
|
||||||
|
link_name: true,
|
||||||
proxy_remote: false,
|
proxy_remote: false,
|
||||||
proxy_opts: [
|
proxy_opts: [
|
||||||
redirect_on_failure: false,
|
redirect_on_failure: false,
|
||||||
|
|
@ -256,8 +255,6 @@ config :pleroma, :media_proxy,
|
||||||
|
|
||||||
config :pleroma, :chat, enabled: false
|
config :pleroma, :chat, enabled: false
|
||||||
|
|
||||||
config :ecto, json_library: Jason
|
|
||||||
|
|
||||||
config :phoenix, :format_encoders, json: Jason
|
config :phoenix, :format_encoders, json: Jason
|
||||||
|
|
||||||
config :pleroma, :gopher,
|
config :pleroma, :gopher,
|
||||||
|
|
@ -353,6 +350,17 @@ config :auto_linker,
|
||||||
rel: false
|
rel: false
|
||||||
]
|
]
|
||||||
|
|
||||||
|
config :pleroma, :ldap,
|
||||||
|
enabled: System.get_env("LDAP_ENABLED") == "true",
|
||||||
|
host: System.get_env("LDAP_HOST") || "localhost",
|
||||||
|
port: String.to_integer(System.get_env("LDAP_PORT") || "389"),
|
||||||
|
ssl: System.get_env("LDAP_SSL") == "true",
|
||||||
|
sslopts: [],
|
||||||
|
tls: System.get_env("LDAP_TLS") == "true",
|
||||||
|
tlsopts: [],
|
||||||
|
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
|
||||||
|
uid: System.get_env("LDAP_UID") || "cn"
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
# Import environment specific config. This must remain at the bottom
|
||||||
# of this file so it overrides the configuration defined above.
|
# of this file so it overrides the configuration defined above.
|
||||||
import_config "#{Mix.env()}.exs"
|
import_config "#{Mix.env()}.exs"
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ config :pleroma, Pleroma.Captcha,
|
||||||
# Print only warnings and errors during test
|
# Print only warnings and errors during test
|
||||||
config :logger, level: :warn
|
config :logger, level: :warn
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Upload, filters: [], link_name: false
|
||||||
|
|
||||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "test/uploads"
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "test/uploads"
|
||||||
|
|
||||||
config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Test
|
config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Test
|
||||||
|
|
|
||||||
18
docs/Custom-Emoji.md
Normal file
18
docs/Custom-Emoji.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Custom emoji
|
||||||
|
|
||||||
|
To add custom emoji:
|
||||||
|
* Add the image file(s) to `priv/static/emoji/custom`
|
||||||
|
* In case of conflicts: add the desired shortcode with the path to `config/custom_emoji.txt`, comma-separated and one per line
|
||||||
|
* Force recompilation (``mix clean && mix compile``)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
image files (in `/priv/static/emoji/custom`): `happy.png` and `sad.png`
|
||||||
|
|
||||||
|
content of `config/custom_emoji.txt`:
|
||||||
|
```
|
||||||
|
happy, /emoji/custom/happy.png
|
||||||
|
sad, /emoji/custom/sad.png
|
||||||
|
```
|
||||||
|
|
||||||
|
The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon.
|
||||||
|
|
@ -20,6 +20,26 @@ Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
- `local`: true if the post was made on the local instance.
|
- `local`: true if the post was made on the local instance.
|
||||||
|
|
||||||
|
## Attachments
|
||||||
|
|
||||||
|
Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
|
- `mime_type`: mime type of the attachment.
|
||||||
|
|
||||||
## Accounts
|
## 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.
|
- `/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.
|
||||||
|
|
||||||
|
Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
|
- `tags`: Lists an array of tags for the user
|
||||||
|
- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/api/entities/#relationship
|
||||||
|
- `is_moderator`: boolean, true if user is a moderator
|
||||||
|
- `is_admin`: boolean, true if user is an admin
|
||||||
|
- `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
|
- `is_seen`: true if the notification was read by the user
|
||||||
|
|
|
||||||
119
docs/Message-Rewrite-Facility-configuration.md
Normal file
119
docs/Message-Rewrite-Facility-configuration.md
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Message Rewrite Facility configuration
|
||||||
|
The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages.
|
||||||
|
|
||||||
|
Possible uses include:
|
||||||
|
|
||||||
|
* marking incoming messages with media from a given account or instance as sensitive
|
||||||
|
* rejecting messages from a specific instance
|
||||||
|
* removing/unlisting messages from the public timelines
|
||||||
|
* removing media from messages
|
||||||
|
* sending only public messages to a specific instance
|
||||||
|
|
||||||
|
The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module.
|
||||||
|
It is possible to use multiple, active MRF policies at the same time.
|
||||||
|
|
||||||
|
## Quarantine Instances
|
||||||
|
|
||||||
|
You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance.
|
||||||
|
|
||||||
|
If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes.
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
[...]
|
||||||
|
quarantined_instances: ["instance.example", "other.example"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using `SimplePolicy`
|
||||||
|
|
||||||
|
`SimplePolicy` is capable of handling most common admin tasks.
|
||||||
|
|
||||||
|
To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
[...]
|
||||||
|
rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy
|
||||||
|
```
|
||||||
|
|
||||||
|
Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are:
|
||||||
|
|
||||||
|
* `media_removal`: Servers in this group will have media stripped from incoming messages.
|
||||||
|
* `media_nsfw`: Servers in this group will have the #nsfw tag and sensitive setting injected into incoming messages which contain media.
|
||||||
|
* `reject`: Servers in this group will have their messages rejected.
|
||||||
|
* `federated_timeline_removal`: Servers in this group will have their messages unlisted from the public timelines by flipping the `to` and `cc` fields.
|
||||||
|
|
||||||
|
Servers should be configured as lists.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com` and remove messages from `spam.university` from the federated timeline:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
||||||
|
|
||||||
|
config :pleroma, :mrf_simple,
|
||||||
|
media_removal: ["illegalporn.biz"],
|
||||||
|
media_nsfw: ["porn.biz", "porn.business"],
|
||||||
|
reject: ["spam.com"],
|
||||||
|
federated_timeline_removal: ["spam.university"]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use with Care
|
||||||
|
|
||||||
|
The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance.
|
||||||
|
|
||||||
|
## Writing your own MRF Policy
|
||||||
|
|
||||||
|
As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting.
|
||||||
|
|
||||||
|
For example, here is a sample policy module which rewrites all messages to "new message content":
|
||||||
|
|
||||||
|
```!elixir
|
||||||
|
# This is a sample MRF policy which rewrites all Notes to have "new message
|
||||||
|
# content."
|
||||||
|
defmodule Site.RewritePolicy do
|
||||||
|
@behavior Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
# Catch messages which contain Note objects with actual data to filter.
|
||||||
|
# Capture the object as `object`, the message content as `content` and the
|
||||||
|
# message itself as `message`.
|
||||||
|
@impl true
|
||||||
|
def filter(%{"type" => Create", "object" => {"type" => "Note", "content" => content} = object} = message)
|
||||||
|
when is_binary(content) do
|
||||||
|
# Subject / CW is stored as summary instead of `name` like other AS2 objects
|
||||||
|
# because of Mastodon doing it that way.
|
||||||
|
summary = object["summary"]
|
||||||
|
|
||||||
|
# Message edits go here.
|
||||||
|
content = "new message content"
|
||||||
|
|
||||||
|
# Assemble the mutated object.
|
||||||
|
object =
|
||||||
|
object
|
||||||
|
|> Map.put("content", content)
|
||||||
|
|> Map.put("summary", summary)
|
||||||
|
|
||||||
|
# Assemble the mutated message.
|
||||||
|
message = Map.put(message, "object", object)
|
||||||
|
{:ok, message}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Let all other messages through without modifying them.
|
||||||
|
@impl true
|
||||||
|
def filter(message), do: {:ok, message}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
If you save this file as `lib/site/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
rewrite_policy: [
|
||||||
|
Pleroma.Web.ActivityPub.MRF.SimplePolicy,
|
||||||
|
Site.RewritePolicy
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request.
|
||||||
|
|
@ -108,3 +108,11 @@ See [Admin-API](Admin-API.md)
|
||||||
* Response: JSON string. Returns the user flavour or the default one.
|
* Response: JSON string. Returns the user flavour or the default one.
|
||||||
* Example response: "glitch"
|
* Example response: "glitch"
|
||||||
* Note: This is intended to be used only by mastofe
|
* Note: This is intended to be used only by mastofe
|
||||||
|
|
||||||
|
## `/api/pleroma/notifications/read`
|
||||||
|
### Mark a single notification as read
|
||||||
|
* Method `POST`
|
||||||
|
* Authentication: required
|
||||||
|
* Params:
|
||||||
|
* `id`: notifications's id
|
||||||
|
* Response: JSON. Returns `{"status": "success"}` if the reading was successful, otherwise returns `{"error": "error_msg"}`
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherw
|
||||||
## Pleroma.Upload
|
## Pleroma.Upload
|
||||||
* `uploader`: Select which `Pleroma.Uploaders` to use
|
* `uploader`: Select which `Pleroma.Uploaders` to use
|
||||||
* `filters`: List of `Pleroma.Upload.Filter` to use.
|
* `filters`: List of `Pleroma.Upload.Filter` to use.
|
||||||
|
* `link_name`: When enabled Pleroma will add a `name` parameter to the url of the upload, for example `https://instance.tld/media/corndog.png?name=corndog.png`. This is needed to provide the correct filename in Content-Disposition headers when using filters like `Pleroma.Upload.Filter.Dedupe`
|
||||||
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host.
|
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host.
|
||||||
* `proxy_remote`: If you\'re using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
|
* `proxy_remote`: If you\'re using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
|
||||||
* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
|
* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
|
||||||
|
|
@ -189,6 +190,7 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
|
||||||
* `enabled`: Enables the gopher interface
|
* `enabled`: Enables the gopher interface
|
||||||
* `ip`: IP address to bind to
|
* `ip`: IP address to bind to
|
||||||
* `port`: Port to bind to
|
* `port`: Port to bind to
|
||||||
|
* `dstport`: Port advertised in urls (optional, defaults to `port`)
|
||||||
|
|
||||||
## :activitypub
|
## :activitypub
|
||||||
* ``accept_blocks``: Whether to accept incoming block activities from other instances
|
* ``accept_blocks``: Whether to accept incoming block activities from other instances
|
||||||
|
|
@ -330,3 +332,26 @@ config :auto_linker,
|
||||||
rel: false
|
rel: false
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## :ldap
|
||||||
|
|
||||||
|
Use LDAP for user authentication. When a user logs in to the Pleroma
|
||||||
|
instance, the name and password will be verified by trying to authenticate
|
||||||
|
(bind) to an LDAP server. If a user exists in the LDAP directory but there
|
||||||
|
is no account with the same name yet on the Pleroma instance then a new
|
||||||
|
Pleroma account will be created with the same name as the LDAP user name.
|
||||||
|
|
||||||
|
* `enabled`: enables LDAP authentication
|
||||||
|
* `host`: LDAP server hostname
|
||||||
|
* `port`: LDAP port, e.g. 389 or 636
|
||||||
|
* `ssl`: true to use SSL, usually implies the port 636
|
||||||
|
* `sslopts`: additional SSL options
|
||||||
|
* `tls`: true to start TLS, usually implies the port 389
|
||||||
|
* `tlsopts`: additional TLS options
|
||||||
|
* `base`: LDAP base, e.g. "dc=example,dc=com"
|
||||||
|
* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
|
||||||
|
|
||||||
|
## Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
|
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
|
||||||
|
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
|
||||||
|
|
|
||||||
20
docs/static_dir.md
Normal file
20
docs/static_dir.md
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Static Directory
|
||||||
|
|
||||||
|
Static frontend files are shipped in `priv/static/` and tracked by version control in this repository. If you want to overwrite or update these without the possibility of merge conflicts, you can write your custom versions to `instance/static/`.
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
static_dir: "instance/static/",
|
||||||
|
```
|
||||||
|
|
||||||
|
You can overwrite this value in your configuration to use a different static instance directory.
|
||||||
|
|
||||||
|
## robots.txt
|
||||||
|
|
||||||
|
By default, the `robots.txt` that ships in `priv/static/` is permissive. It allows well-behaved search engines to index all of your instance's URIs.
|
||||||
|
|
||||||
|
If you want to generate a restrictive `robots.txt`, you can run the following mix task. The generated `robots.txt` will be written in your instance static directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
mix pleroma.robots_txt disallow_all
|
||||||
|
```
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Relay do
|
defmodule Mix.Tasks.Pleroma.Relay do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
|
||||||
alias Mix.Tasks.Pleroma.Common
|
alias Mix.Tasks.Pleroma.Common
|
||||||
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
|
|
||||||
@shortdoc "Manages remote relays"
|
@shortdoc "Manages remote relays"
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
|
|
|
||||||
32
lib/mix/tasks/pleroma/robotstxt.ex
Normal file
32
lib/mix/tasks/pleroma/robotstxt.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
||||||
|
use Mix.Task
|
||||||
|
|
||||||
|
@shortdoc "Generate robots.txt"
|
||||||
|
@moduledoc """
|
||||||
|
Generates robots.txt
|
||||||
|
|
||||||
|
## Overwrite robots.txt to disallow all
|
||||||
|
|
||||||
|
mix pleroma.robots_txt disallow_all
|
||||||
|
|
||||||
|
This will write a robots.txt that will hide all paths on your instance
|
||||||
|
from search engines and other robots that obey robots.txt
|
||||||
|
|
||||||
|
"""
|
||||||
|
def run(["disallow_all"]) do
|
||||||
|
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
|
||||||
|
|
||||||
|
if !File.exists?(static_dir) do
|
||||||
|
File.mkdir_p!(static_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
robots_txt_path = Path.join(static_dir, "robots.txt")
|
||||||
|
robots_txt_content = "User-Agent: *\nDisallow: /\n"
|
||||||
|
|
||||||
|
File.write!(robots_txt_path, robots_txt_content, [:write])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Uploads do
|
defmodule Mix.Tasks.Pleroma.Uploads do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
alias Mix.Tasks.Pleroma.Common
|
||||||
alias Pleroma.Upload
|
alias Pleroma.Upload
|
||||||
alias Pleroma.Uploaders.Local
|
alias Pleroma.Uploaders.Local
|
||||||
alias Mix.Tasks.Pleroma.Common
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@log_every 50
|
@log_every 50
|
||||||
|
|
@ -20,7 +20,6 @@ defmodule Mix.Tasks.Pleroma.Uploads do
|
||||||
Options:
|
Options:
|
||||||
- `--delete` - delete local uploads after migrating them to the target uploader
|
- `--delete` - delete local uploads after migrating them to the target uploader
|
||||||
|
|
||||||
|
|
||||||
A list of available uploaders can be seen in config.exs
|
A list of available uploaders can be seen in config.exs
|
||||||
"""
|
"""
|
||||||
def run(["migrate_local", target_uploader | args]) do
|
def run(["migrate_local", target_uploader | args]) do
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
defmodule Mix.Tasks.Pleroma.User do
|
defmodule Mix.Tasks.Pleroma.User do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
alias Mix.Tasks.Pleroma.Common
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Mix.Tasks.Pleroma.Common
|
|
||||||
|
|
||||||
@shortdoc "Manages Pleroma users"
|
@shortdoc "Manages Pleroma users"
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ defmodule Pleroma.PasswordResetToken do
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.PasswordResetToken
|
alias Pleroma.PasswordResetToken
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
schema "password_reset_tokens" do
|
schema "password_reset_tokens" do
|
||||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
defmodule Pleroma.Activity do
|
defmodule Pleroma.Activity do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Repo
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
|
@ -22,6 +22,10 @@ defmodule Pleroma.Activity do
|
||||||
"Like" => "favourite"
|
"Like" => "favourite"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types,
|
||||||
|
into: %{},
|
||||||
|
do: {v, k}
|
||||||
|
|
||||||
schema "activities" do
|
schema "activities" do
|
||||||
field(:data, :map)
|
field(:data, :map)
|
||||||
field(:local, :boolean, default: true)
|
field(:local, :boolean, default: true)
|
||||||
|
|
@ -109,7 +113,8 @@ defmodule Pleroma.Activity do
|
||||||
|
|
||||||
def delete_by_ap_id(id) when is_binary(id) do
|
def delete_by_ap_id(id) when is_binary(id) do
|
||||||
by_object_ap_id(id)
|
by_object_ap_id(id)
|
||||||
|> Repo.delete_all(returning: true)
|
|> select([u], u)
|
||||||
|
|> Repo.delete_all()
|
||||||
|> elem(1)
|
|> elem(1)
|
||||||
|> Enum.find(fn
|
|> Enum.find(fn
|
||||||
%{data: %{"type" => "Create", "object" => %{"id" => ap_id}}} -> ap_id == id
|
%{data: %{"type" => "Create", "object" => %{"id" => ap_id}}} -> ap_id == id
|
||||||
|
|
@ -126,6 +131,10 @@ defmodule Pleroma.Activity do
|
||||||
|
|
||||||
def mastodon_notification_type(%Activity{}), do: nil
|
def mastodon_notification_type(%Activity{}), do: nil
|
||||||
|
|
||||||
|
def from_mastodon_notification_type(type) do
|
||||||
|
Map.get(@mastodon_to_ap_notification_types, type)
|
||||||
|
end
|
||||||
|
|
||||||
def all_by_actor_and_id(actor, status_ids \\ [])
|
def all_by_actor_and_id(actor, status_ids \\ [])
|
||||||
def all_by_actor_and_id(_actor, []), do: []
|
def all_by_actor_and_id(_actor, []), do: []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ defmodule Pleroma.Application do
|
||||||
@repository Mix.Project.config()[:source_url]
|
@repository Mix.Project.config()[:source_url]
|
||||||
def name, do: @name
|
def name, do: @name
|
||||||
def version, do: @version
|
def version, do: @version
|
||||||
def named_version(), do: @name <> " " <> @version
|
def named_version, do: @name <> " " <> @version
|
||||||
def repository, do: @repository
|
def repository, do: @repository
|
||||||
|
|
||||||
def user_agent() do
|
def user_agent do
|
||||||
info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>"
|
info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>"
|
||||||
named_version() <> "; " <> info
|
named_version() <> "; " <> info
|
||||||
end
|
end
|
||||||
|
|
@ -48,7 +48,7 @@ defmodule Pleroma.Application do
|
||||||
[
|
[
|
||||||
:user_cache,
|
:user_cache,
|
||||||
[
|
[
|
||||||
default_ttl: 25000,
|
default_ttl: 25_000,
|
||||||
ttl_interval: 1000,
|
ttl_interval: 1000,
|
||||||
limit: 2500
|
limit: 2500
|
||||||
]
|
]
|
||||||
|
|
@ -60,7 +60,7 @@ defmodule Pleroma.Application do
|
||||||
[
|
[
|
||||||
:object_cache,
|
:object_cache,
|
||||||
[
|
[
|
||||||
default_ttl: 25000,
|
default_ttl: 25_000,
|
||||||
ttl_interval: 1000,
|
ttl_interval: 1000,
|
||||||
limit: 2500
|
limit: 2500
|
||||||
]
|
]
|
||||||
|
|
@ -127,7 +127,7 @@ defmodule Pleroma.Application do
|
||||||
Supervisor.start_link(children, opts)
|
Supervisor.start_link(children, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled_hackney_pools() do
|
def enabled_hackney_pools do
|
||||||
[:media] ++
|
[:media] ++
|
||||||
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
|
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
|
||||||
[:federation]
|
[:federation]
|
||||||
|
|
@ -142,14 +142,14 @@ defmodule Pleroma.Application do
|
||||||
end
|
end
|
||||||
|
|
||||||
if Mix.env() == :test do
|
if Mix.env() == :test do
|
||||||
defp streamer_child(), do: []
|
defp streamer_child, do: []
|
||||||
defp chat_child(), do: []
|
defp chat_child, do: []
|
||||||
else
|
else
|
||||||
defp streamer_child() do
|
defp streamer_child do
|
||||||
[worker(Pleroma.Web.Streamer, [])]
|
[worker(Pleroma.Web.Streamer, [])]
|
||||||
end
|
end
|
||||||
|
|
||||||
defp chat_child() do
|
defp chat_child do
|
||||||
if Pleroma.Config.get([:chat, :enabled]) do
|
if Pleroma.Config.get([:chat, :enabled]) do
|
||||||
[worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
|
[worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
|
||||||
else
|
else
|
||||||
|
|
@ -158,7 +158,7 @@ defmodule Pleroma.Application do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp hackney_pool_children() do
|
defp hackney_pool_children do
|
||||||
for pool <- enabled_hackney_pools() do
|
for pool <- enabled_hackney_pools() do
|
||||||
options = Pleroma.Config.get([:hackney_pools, pool])
|
options = Pleroma.Config.get([:hackney_pools, pool])
|
||||||
:hackney_pool.child_spec(pool, options)
|
:hackney_pool.child_spec(pool, options)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ defmodule Pleroma.Captcha do
|
||||||
use GenServer
|
use GenServer
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def start_link() do
|
def start_link do
|
||||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Captcha do
|
||||||
@doc """
|
@doc """
|
||||||
Ask the configured captcha service for a new captcha
|
Ask the configured captcha service for a new captcha
|
||||||
"""
|
"""
|
||||||
def new() do
|
def new do
|
||||||
GenServer.call(__MODULE__, :new)
|
GenServer.call(__MODULE__, :new)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ defmodule Pleroma.Captcha do
|
||||||
secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
|
secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
|
||||||
sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
|
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
|
# 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
|
# that the data is still valid and the captcha can be checked
|
||||||
seconds_valid = Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])
|
seconds_valid = Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Captcha.Kocaptcha do
|
||||||
@behaviour Service
|
@behaviour Service
|
||||||
|
|
||||||
@impl Service
|
@impl Service
|
||||||
def new() do
|
def new do
|
||||||
endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
|
endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
|
||||||
|
|
||||||
case Tesla.get(endpoint <> "/new") do
|
case Tesla.get(endpoint <> "/new") do
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ defmodule Pleroma.Clippy do
|
||||||
# No software is complete until they have a Clippy implementation.
|
# No software is complete until they have a Clippy implementation.
|
||||||
# A ballmer peak _may_ be required to change this module.
|
# A ballmer peak _may_ be required to change this module.
|
||||||
|
|
||||||
def tip() do
|
def tip do
|
||||||
tips()
|
tips()
|
||||||
|> Enum.random()
|
|> Enum.random()
|
||||||
|> puts()
|
|> puts()
|
||||||
end
|
end
|
||||||
|
|
||||||
def tips() do
|
def tips do
|
||||||
host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
|
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
|
# 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
|
# yes this fix sucks but it's good enough, have you ever seen a release of windows
|
||||||
# features anyway?
|
# without some butched features anyway?
|
||||||
lines =
|
lines =
|
||||||
if length(lines) == 1 or length(lines) == 5 do
|
if length(lines) == 1 or length(lines) == 5 do
|
||||||
[""] ++ lines ++ [""]
|
[""] ++ lines ++ [""]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Config.DeprecationWarnings do
|
defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def check_frontend_config_mechanism() do
|
def check_frontend_config_mechanism do
|
||||||
if Pleroma.Config.get(:fe) do
|
if Pleroma.Config.get(:fe) do
|
||||||
Logger.warn("""
|
Logger.warn("""
|
||||||
!!!DEPRECATION WARNING!!!
|
!!!DEPRECATION WARNING!!!
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@ defmodule Pleroma.Emoji do
|
||||||
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
|
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def start_link() do
|
def start_link do
|
||||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Reloads the emojis from disk."
|
@doc "Reloads the emojis from disk."
|
||||||
@spec reload() :: :ok
|
@spec reload() :: :ok
|
||||||
def reload() do
|
def reload do
|
||||||
GenServer.call(__MODULE__, :reload)
|
GenServer.call(__MODULE__, :reload)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ defmodule Pleroma.Emoji do
|
||||||
|
|
||||||
@doc "Returns all the emojos!!"
|
@doc "Returns all the emojos!!"
|
||||||
@spec get_all() :: [{String.t(), String.t()}, ...]
|
@spec get_all() :: [{String.t(), String.t()}, ...]
|
||||||
def get_all() do
|
def get_all do
|
||||||
:ets.tab2list(@ets)
|
:ets.tab2list(@ets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ defmodule Pleroma.Emoji do
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp load() do
|
defp load do
|
||||||
emojis =
|
emojis =
|
||||||
(load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++
|
(load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++
|
||||||
load_from_file("config/emoji.txt") ++
|
load_from_file("config/emoji.txt") ++
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ defmodule Pleroma.Filter do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
schema "filters" do
|
schema "filters" do
|
||||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ defmodule Pleroma.FlakeId do
|
||||||
{:ok, FlakeId.from_string(value)}
|
{:ok, FlakeId.from_string(value)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def autogenerate(), do: get()
|
def autogenerate, do: get()
|
||||||
|
|
||||||
# -- GenServer API
|
# -- GenServer API
|
||||||
def start_link do
|
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)
|
1_000_000_000 * mega_seconds + seconds * 1000 + :erlang.trunc(micro_seconds / 1000)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp worker_id() do
|
defp worker_id do
|
||||||
<<worker::integer-size(48)>> = :crypto.strong_rand_bytes(6)
|
<<worker::integer-size(48)>> = :crypto.strong_rand_bytes(6)
|
||||||
worker
|
worker
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Formatter do
|
||||||
|
|
||||||
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
|
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
|
||||||
@link_regex ~r{((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+}ui
|
@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,
|
@auto_linker_config hashtag: true,
|
||||||
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
|
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Gopher.Server do
|
||||||
use GenServer
|
use GenServer
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def start_link() do
|
def start_link do
|
||||||
config = Pleroma.Config.get(:gopher, [])
|
config = Pleroma.Config.get(:gopher, [])
|
||||||
ip = Keyword.get(config, :ip, {0, 0, 0, 0})
|
ip = Keyword.get(config, :ip, {0, 0, 0, 0})
|
||||||
port = Keyword.get(config, :port, 1234)
|
port = Keyword.get(config, :port, 1234)
|
||||||
|
|
@ -36,12 +36,12 @@ defmodule Pleroma.Gopher.Server do
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule Pleroma.Gopher.Server.ProtocolHandler do
|
defmodule Pleroma.Gopher.Server.ProtocolHandler do
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
|
||||||
def start_link(ref, socket, transport, opts) do
|
def start_link(ref, socket, transport, opts) do
|
||||||
pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])
|
pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])
|
||||||
|
|
@ -66,7 +66,8 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
|
||||||
def link(name, selector, type \\ 1) do
|
def link(name, selector, type \\ 1) do
|
||||||
address = Pleroma.Web.Endpoint.host()
|
address = Pleroma.Web.Endpoint.host()
|
||||||
port = Pleroma.Config.get([:gopher, :port], 1234)
|
port = Pleroma.Config.get([:gopher, :port], 1234)
|
||||||
"#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"
|
dstport = Pleroma.Config.get([:gopher, :dstport], port)
|
||||||
|
"#{type}#{name}\t#{selector}\t#{address}\t#{dstport}\r\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_activities(activities) do
|
def render_activities(activities) do
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.HTML do
|
||||||
defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
|
defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
|
||||||
defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]
|
defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]
|
||||||
|
|
||||||
def get_scrubbers() do
|
def get_scrubbers do
|
||||||
Pleroma.Config.get([:markup, :scrub_policy])
|
Pleroma.Config.get([:markup, :scrub_policy])
|
||||||
|> get_scrubbers
|
|> get_scrubbers
|
||||||
end
|
end
|
||||||
|
|
@ -95,6 +95,13 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
|
||||||
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
|
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
|
||||||
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
|
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_this_attribute_values("a", "rel", [
|
||||||
|
"tag",
|
||||||
|
"nofollow",
|
||||||
|
"noopener",
|
||||||
|
"noreferrer"
|
||||||
|
])
|
||||||
|
|
||||||
# paragraphs and linebreaks
|
# paragraphs and linebreaks
|
||||||
Meta.allow_tag_with_these_attributes("br", [])
|
Meta.allow_tag_with_these_attributes("br", [])
|
||||||
Meta.allow_tag_with_these_attributes("p", [])
|
Meta.allow_tag_with_these_attributes("p", [])
|
||||||
|
|
@ -137,6 +144,13 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
||||||
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
|
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
|
||||||
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
|
Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])
|
||||||
|
|
||||||
|
Meta.allow_tag_with_this_attribute_values("a", "rel", [
|
||||||
|
"tag",
|
||||||
|
"nofollow",
|
||||||
|
"noopener",
|
||||||
|
"noreferrer"
|
||||||
|
])
|
||||||
|
|
||||||
Meta.allow_tag_with_these_attributes("abbr", ["title"])
|
Meta.allow_tag_with_these_attributes("abbr", ["title"])
|
||||||
|
|
||||||
Meta.allow_tag_with_these_attributes("b", [])
|
Meta.allow_tag_with_these_attributes("b", [])
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ defmodule Pleroma.Instances.Instance do
|
||||||
@moduledoc "Instance."
|
@moduledoc "Instance."
|
||||||
|
|
||||||
alias Pleroma.Instances
|
alias Pleroma.Instances
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Instances.Instance
|
alias Pleroma.Instances.Instance
|
||||||
|
alias Pleroma.Repo
|
||||||
|
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ defmodule Pleroma.Instances.Instance do
|
||||||
|
|
||||||
schema "instances" do
|
schema "instances" do
|
||||||
field(:host, :string)
|
field(:host, :string)
|
||||||
field(:unreachable_since, :naive_datetime)
|
field(:unreachable_since, :naive_datetime_usec)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@
|
||||||
defmodule Pleroma.Notification do
|
defmodule Pleroma.Notification do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.CommonAPI.Utils
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
schema "notifications" do
|
schema "notifications" do
|
||||||
field(:seen, :boolean, default: false)
|
field(:seen, :boolean, default: false)
|
||||||
|
|
@ -22,36 +24,22 @@ defmodule Pleroma.Notification do
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Make generic and unify (see activity_pub.ex)
|
def changeset(%Notification{} = notification, attrs) do
|
||||||
defp restrict_max(query, %{"max_id" => max_id}) do
|
notification
|
||||||
from(activity in query, where: activity.id < ^max_id)
|
|> cast(attrs, [:seen])
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict_max(query, _), do: query
|
def for_user_query(user) do
|
||||||
|
Notification
|
||||||
defp restrict_since(query, %{"since_id" => since_id}) do
|
|> where(user_id: ^user.id)
|
||||||
from(activity in query, where: activity.id > ^since_id)
|
|> join(:inner, [n], activity in assoc(n, :activity))
|
||||||
|
|> preload(:activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict_since(query, _), do: query
|
|
||||||
|
|
||||||
def for_user(user, opts \\ %{}) do
|
def for_user(user, opts \\ %{}) do
|
||||||
query =
|
user
|
||||||
from(
|
|> for_user_query()
|
||||||
n in Notification,
|
|> Pagination.fetch_paginated(opts)
|
||||||
where: n.user_id == ^user.id,
|
|
||||||
order_by: [desc: n.id],
|
|
||||||
join: activity in assoc(n, :activity),
|
|
||||||
preload: [activity: activity],
|
|
||||||
limit: 20
|
|
||||||
)
|
|
||||||
|
|
||||||
query =
|
|
||||||
query
|
|
||||||
|> restrict_since(opts)
|
|
||||||
|> restrict_max(opts)
|
|
||||||
|
|
||||||
Repo.all(query)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_read_up_to(%{id: user_id} = _user, id) do
|
def set_read_up_to(%{id: user_id} = _user, id) do
|
||||||
|
|
@ -68,6 +56,14 @@ defmodule Pleroma.Notification do
|
||||||
Repo.update_all(query, [])
|
Repo.update_all(query, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read_one(%User{} = user, notification_id) do
|
||||||
|
with {:ok, %Notification{} = notification} <- get(user, notification_id) do
|
||||||
|
notification
|
||||||
|
|> changeset(%{seen: true})
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get(%{id: user_id} = _user, id) do
|
def get(%{id: user_id} = _user, id) do
|
||||||
query =
|
query =
|
||||||
from(
|
from(
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
defmodule Pleroma.Object do
|
defmodule Pleroma.Object do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.ObjectTombstone
|
alias Pleroma.ObjectTombstone
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
|
||||||
78
lib/pleroma/pagination.ex
Normal file
78
lib/pleroma/pagination.ex
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
defmodule Pleroma.Pagination do
|
||||||
|
@moduledoc """
|
||||||
|
Implements Mastodon-compatible pagination.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Ecto.Query
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
|
||||||
|
@default_limit 20
|
||||||
|
|
||||||
|
def fetch_paginated(query, params) do
|
||||||
|
options = cast_params(params)
|
||||||
|
|
||||||
|
query
|
||||||
|
|> paginate(options)
|
||||||
|
|> Repo.all()
|
||||||
|
|> enforce_order(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def paginate(query, options) do
|
||||||
|
query
|
||||||
|
|> restrict(:min_id, options)
|
||||||
|
|> restrict(:since_id, options)
|
||||||
|
|> restrict(:max_id, options)
|
||||||
|
|> restrict(:order, options)
|
||||||
|
|> restrict(:limit, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp cast_params(params) do
|
||||||
|
param_types = %{
|
||||||
|
min_id: :string,
|
||||||
|
since_id: :string,
|
||||||
|
max_id: :string,
|
||||||
|
limit: :integer
|
||||||
|
}
|
||||||
|
|
||||||
|
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
||||||
|
changeset.changes
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :min_id, %{min_id: min_id}) do
|
||||||
|
where(query, [q], q.id > ^min_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :since_id, %{since_id: since_id}) do
|
||||||
|
where(query, [q], q.id > ^since_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :max_id, %{max_id: max_id}) do
|
||||||
|
where(query, [q], q.id < ^max_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :order, %{min_id: _}) do
|
||||||
|
order_by(query, [u], fragment("? asc nulls last", u.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :order, _options) do
|
||||||
|
order_by(query, [u], fragment("? desc nulls last", u.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :limit, options) do
|
||||||
|
limit = Map.get(options, :limit, @default_limit)
|
||||||
|
|
||||||
|
query
|
||||||
|
|> limit(^limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict(query, _, _), do: query
|
||||||
|
|
||||||
|
defp enforce_order(result, %{min_id: _}) do
|
||||||
|
result
|
||||||
|
|> Enum.reverse()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp enforce_order(result, _), do: result
|
||||||
|
end
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
||||||
alias Pleroma.Web.HTTPSignatures
|
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
alias Pleroma.Web.HTTPSignatures
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ defmodule Pleroma.Plugs.InstanceStatic do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@only ~w(index.html static emoji packs sounds images instance favicon.png sw.js sw-pleroma.js)
|
@only ~w(index.html robots.txt static emoji packs sounds images instance favicon.png sw.js
|
||||||
|
sw-pleroma.js)
|
||||||
|
|
||||||
def init(opts) do
|
def init(opts) do
|
||||||
opts
|
opts
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ defmodule Pleroma.Plugs.OAuthPlug do
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
@realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i")
|
@realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i")
|
||||||
|
|
@ -38,6 +38,7 @@ defmodule Pleroma.Plugs.OAuthPlug do
|
||||||
preload: [user: user]
|
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
|
with %Token{user: %{info: %{deactivated: false} = _} = user} = token_record <- Repo.one(query) do
|
||||||
{:ok, user, token_record}
|
{:ok, user, token_record}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,18 @@ defmodule Pleroma.Plugs.UploadedMedia do
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
|
def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
|
||||||
|
conn =
|
||||||
|
case fetch_query_params(conn) do
|
||||||
|
%{query_params: %{"name" => name}} = conn ->
|
||||||
|
name = String.replace(name, "\"", "\\\"")
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_resp_header("content-disposition", "filename=\"#{name}\"")
|
||||||
|
|
||||||
|
conn ->
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
|
||||||
config = Pleroma.Config.get([Pleroma.Upload])
|
config = Pleroma.Config.get([Pleroma.Upload])
|
||||||
|
|
||||||
with uploader <- Keyword.fetch!(config, :uploader),
|
with uploader <- Keyword.fetch!(config, :uploader),
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Plugs.UserFetcherPlug do
|
defmodule Pleroma.Plugs.UserFetcherPlug do
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Repo do
|
defmodule Pleroma.Repo do
|
||||||
use Ecto.Repo, otp_app: :pleroma
|
use Ecto.Repo,
|
||||||
|
otp_app: :pleroma,
|
||||||
|
adapter: Ecto.Adapters.Postgres,
|
||||||
|
migration_timestamps: [type: :naive_datetime_usec]
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Dynamically loads the repository url from the
|
Dynamically loads the repository url from the
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,12 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.ReverseProxy do
|
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)
|
@resp_cache_headers ~w(etag date last-modified cache-control)
|
||||||
@keep_resp_headers @resp_cache_headers ++
|
@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"
|
@default_cache_control_header "public, max-age=1209600"
|
||||||
@valid_resp_codes [200, 206, 304]
|
@valid_resp_codes [200, 206, 304]
|
||||||
@max_read_duration :timer.seconds(30)
|
@max_read_duration :timer.seconds(30)
|
||||||
|
|
@ -282,8 +284,8 @@ defmodule Pleroma.ReverseProxy do
|
||||||
headers
|
headers
|
||||||
|
|
||||||
has_cache? ->
|
has_cache? ->
|
||||||
# There's caching header present but no cache-control -- we need to explicitely override it to public
|
# There's caching header present but no cache-control -- we need to explicitely override it
|
||||||
# as Plug defaults to "max-age=0, private, must-revalidate"
|
# to public as Plug defaults to "max-age=0, private, must-revalidate"
|
||||||
List.keystore(headers, "cache-control", 0, {"cache-control", "public"})
|
List.keystore(headers, "cache-control", 0, {"cache-control", "public"})
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
|
|
@ -309,7 +311,25 @@ defmodule Pleroma.ReverseProxy do
|
||||||
end
|
end
|
||||||
|
|
||||||
if attachment? do
|
if attachment? do
|
||||||
disposition = "attachment; filename=" <> Keyword.get(opts, :attachment_name, "attachment")
|
name =
|
||||||
|
try do
|
||||||
|
{{"content-disposition", content_disposition_string}, _} =
|
||||||
|
List.keytake(headers, "content-disposition", 0)
|
||||||
|
|
||||||
|
[name | _] =
|
||||||
|
Regex.run(
|
||||||
|
~r/filename="((?:[^"\\]|\\.)*)"/u,
|
||||||
|
content_disposition_string || "",
|
||||||
|
capture: :all_but_first
|
||||||
|
)
|
||||||
|
|
||||||
|
name
|
||||||
|
rescue
|
||||||
|
MatchError -> Keyword.get(opts, :attachment_name, "attachment")
|
||||||
|
end
|
||||||
|
|
||||||
|
disposition = "attachment; filename=\"#{name}\""
|
||||||
|
|
||||||
List.keystore(headers, "content-disposition", 0, {"content-disposition", disposition})
|
List.keystore(headers, "content-disposition", 0, {"content-disposition", disposition})
|
||||||
else
|
else
|
||||||
headers
|
headers
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Stats do
|
defmodule Pleroma.Stats do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
def start_link do
|
def start_link do
|
||||||
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
defmodule Pleroma.ThreadMute do
|
defmodule Pleroma.ThreadMute do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
alias Pleroma.{Repo, User, ThreadMute}
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.ThreadMute
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
require Ecto.Query
|
require Ecto.Query
|
||||||
|
|
||||||
schema "thread_mutes" do
|
schema "thread_mutes" do
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ defmodule Pleroma.Upload do
|
||||||
%{
|
%{
|
||||||
"type" => "Link",
|
"type" => "Link",
|
||||||
"mediaType" => upload.content_type,
|
"mediaType" => upload.content_type,
|
||||||
"href" => url_from_spec(opts.base_url, url_spec)
|
"href" => url_from_spec(upload, opts.base_url, url_spec)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name" => Map.get(opts, :description) || upload.name
|
"name" => Map.get(opts, :description) || upload.name
|
||||||
|
|
@ -219,14 +219,18 @@ defmodule Pleroma.Upload do
|
||||||
tmp_path
|
tmp_path
|
||||||
end
|
end
|
||||||
|
|
||||||
defp url_from_spec(base_url, {:file, path}) do
|
defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do
|
||||||
path =
|
path =
|
||||||
path
|
URI.encode(path, &char_unescaped?/1) <>
|
||||||
|> URI.encode(&char_unescaped?/1)
|
if Pleroma.Config.get([__MODULE__, :link_name], false) do
|
||||||
|
"?name=#{URI.encode(name, &char_unescaped?/1)}"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
[base_url, "media", path]
|
[base_url, "media", path]
|
||||||
|> Path.join()
|
|> Path.join()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp url_from_spec(_base_url, {:url, url}), do: url
|
defp url_from_spec(_upload, _base_url, {:url, url}), do: url
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ defmodule Pleroma.Uploaders.S3 do
|
||||||
@behaviour Pleroma.Uploaders.Uploader
|
@behaviour Pleroma.Uploaders.Uploader
|
||||||
require Logger
|
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
|
def get_file(file) do
|
||||||
config = Pleroma.Config.get([__MODULE__])
|
config = Pleroma.Config.get([__MODULE__])
|
||||||
bucket = Keyword.fetch!(config, :bucket)
|
bucket = Keyword.fetch!(config, :bucket)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.Uploaders.Swift.Keystone do
|
||||||
|> Poison.decode!()
|
|> Poison.decode!()
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_token() do
|
def get_token do
|
||||||
settings = Pleroma.Config.get(Pleroma.Uploaders.Swift)
|
settings = Pleroma.Config.get(Pleroma.Uploaders.Swift)
|
||||||
username = Keyword.fetch!(settings, :username)
|
username = Keyword.fetch!(settings, :username)
|
||||||
password = Keyword.fetch!(settings, :password)
|
password = Keyword.fetch!(settings, :password)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ defmodule Pleroma.Uploaders.Uploader do
|
||||||
* `{:error, String.t}` error information if the file failed to be saved to the backend.
|
* `{: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.
|
* `: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()}
|
@type file_spec :: {:file | :url, String.t()}
|
||||||
@callback put_file(Pleroma.Upload.t()) ::
|
@callback put_file(Pleroma.Upload.t()) ::
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,21 @@ defmodule Pleroma.User do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Comeonin.Pbkdf2
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Formatter
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
alias Pleroma.Activity
|
|
||||||
alias Pleroma.Notification
|
|
||||||
alias Comeonin.Pbkdf2
|
|
||||||
alias Pleroma.Formatter
|
|
||||||
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.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
|
||||||
|
alias Pleroma.Web.OAuth
|
||||||
|
alias Pleroma.Web.OStatus
|
||||||
alias Pleroma.Web.RelMe
|
alias Pleroma.Web.RelMe
|
||||||
|
alias Pleroma.Web.Websub
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
@ -30,6 +30,7 @@ defmodule Pleroma.User do
|
||||||
|
|
||||||
@primary_key {:id, Pleroma.FlakeId, autogenerate: true}
|
@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])?)*$/
|
@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]+$/
|
@strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
|
||||||
|
|
@ -51,7 +52,7 @@ defmodule Pleroma.User do
|
||||||
field(:search_rank, :float, virtual: true)
|
field(:search_rank, :float, virtual: true)
|
||||||
field(:tags, {:array, :string}, default: [])
|
field(:tags, {:array, :string}, default: [])
|
||||||
field(:bookmarks, {:array, :string}, default: [])
|
field(:bookmarks, {:array, :string}, default: [])
|
||||||
field(:last_refreshed_at, :naive_datetime)
|
field(:last_refreshed_at, :naive_datetime_usec)
|
||||||
has_many(:notifications, Notification)
|
has_many(:notifications, Notification)
|
||||||
embeds_one(:info, Pleroma.User.Info)
|
embeds_one(:info, Pleroma.User.Info)
|
||||||
|
|
||||||
|
|
@ -103,9 +104,8 @@ defmodule Pleroma.User do
|
||||||
"#{Web.base_url()}/users/#{nickname}"
|
"#{Web.base_url()}/users/#{nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def ap_followers(%User{} = user) do
|
def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa
|
||||||
"#{ap_id(user)}/followers"
|
def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers"
|
||||||
end
|
|
||||||
|
|
||||||
def user_info(%User{} = user) do
|
def user_info(%User{} = user) do
|
||||||
oneself = if user.local, do: 1, else: 0
|
oneself = if user.local, do: 1, else: 0
|
||||||
|
|
@ -285,7 +285,7 @@ defmodule Pleroma.User do
|
||||||
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
|
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
|
||||||
|
|
||||||
def needs_update?(%User{local: false} = user) do
|
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
|
end
|
||||||
|
|
||||||
def needs_update?(_), do: true
|
def needs_update?(_), do: true
|
||||||
|
|
@ -334,10 +334,11 @@ defmodule Pleroma.User do
|
||||||
^followed_addresses
|
^followed_addresses
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
select: u
|
||||||
)
|
)
|
||||||
|
|
||||||
{1, [follower]} = Repo.update_all(q, [], returning: true)
|
{1, [follower]} = Repo.update_all(q, [])
|
||||||
|
|
||||||
Enum.each(followeds, fn followed ->
|
Enum.each(followeds, fn followed ->
|
||||||
update_follower_count(followed)
|
update_follower_count(followed)
|
||||||
|
|
@ -367,10 +368,11 @@ defmodule Pleroma.User do
|
||||||
q =
|
q =
|
||||||
from(u in User,
|
from(u in User,
|
||||||
where: u.id == ^follower.id,
|
where: u.id == ^follower.id,
|
||||||
update: [push: [following: ^ap_followers]]
|
update: [push: [following: ^ap_followers]],
|
||||||
|
select: u
|
||||||
)
|
)
|
||||||
|
|
||||||
{1, [follower]} = Repo.update_all(q, [], returning: true)
|
{1, [follower]} = Repo.update_all(q, [])
|
||||||
|
|
||||||
{:ok, _} = update_follower_count(followed)
|
{:ok, _} = update_follower_count(followed)
|
||||||
|
|
||||||
|
|
@ -385,10 +387,11 @@ defmodule Pleroma.User do
|
||||||
q =
|
q =
|
||||||
from(u in User,
|
from(u in User,
|
||||||
where: u.id == ^follower.id,
|
where: u.id == ^follower.id,
|
||||||
update: [pull: [following: ^ap_followers]]
|
update: [pull: [following: ^ap_followers]],
|
||||||
|
select: u
|
||||||
)
|
)
|
||||||
|
|
||||||
{1, [follower]} = Repo.update_all(q, [], returning: true)
|
{1, [follower]} = Repo.update_all(q, [])
|
||||||
|
|
||||||
{:ok, followed} = update_follower_count(followed)
|
{:ok, followed} = update_follower_count(followed)
|
||||||
|
|
||||||
|
|
@ -435,7 +438,8 @@ defmodule Pleroma.User do
|
||||||
Repo.get_by(User, ap_id: ap_id)
|
Repo.get_by(User, ap_id: ap_id)
|
||||||
end
|
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
|
def get_by_guessed_nickname(ap_id) do
|
||||||
domain = URI.parse(ap_id).host
|
domain = URI.parse(ap_id).host
|
||||||
name = List.last(String.split(ap_id, "/"))
|
name = List.last(String.split(ap_id, "/"))
|
||||||
|
|
@ -635,7 +639,7 @@ defmodule Pleroma.User do
|
||||||
users =
|
users =
|
||||||
user
|
user
|
||||||
|> User.get_follow_requests_query()
|
|> User.get_follow_requests_query()
|
||||||
|> join(:inner, [a], u in User, a.actor == u.ap_id)
|
|> join(:inner, [a], u in User, on: a.actor == u.ap_id)
|
||||||
|> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
|
|> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
|
||||||
|> group_by([a, u], u.id)
|
|> group_by([a, u], u.id)
|
||||||
|> select([a, u], u)
|
|> select([a, u], u)
|
||||||
|
|
@ -657,7 +661,8 @@ defmodule Pleroma.User do
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|> Repo.update_all([], returning: true)
|
|> select([u], u)
|
||||||
|
|> Repo.update_all([])
|
||||||
|> case do
|
|> case do
|
||||||
{1, [user]} -> set_cache(user)
|
{1, [user]} -> set_cache(user)
|
||||||
_ -> {:error, user}
|
_ -> {:error, user}
|
||||||
|
|
@ -677,7 +682,8 @@ defmodule Pleroma.User do
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|> Repo.update_all([], returning: true)
|
|> select([u], u)
|
||||||
|
|> Repo.update_all([])
|
||||||
|> case do
|
|> case do
|
||||||
{1, [user]} -> set_cache(user)
|
{1, [user]} -> set_cache(user)
|
||||||
_ -> {:error, user}
|
_ -> {:error, user}
|
||||||
|
|
@ -723,7 +729,8 @@ defmodule Pleroma.User do
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|> Repo.update_all([], returning: true)
|
|> select([u], u)
|
||||||
|
|> Repo.update_all([])
|
||||||
|> case do
|
|> case do
|
||||||
{1, [user]} -> set_cache(user)
|
{1, [user]} -> set_cache(user)
|
||||||
_ -> {:error, user}
|
_ -> {:error, user}
|
||||||
|
|
@ -771,7 +778,7 @@ defmodule Pleroma.User do
|
||||||
}) :: {:ok, [Pleroma.User.t()], number()}
|
}) :: {:ok, [Pleroma.User.t()], number()}
|
||||||
def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
|
def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
|
||||||
query =
|
query =
|
||||||
from(u in User, order_by: u.id)
|
from(u in User, order_by: u.nickname)
|
||||||
|> maybe_local_user_query(local)
|
|> maybe_local_user_query(local)
|
||||||
|
|
||||||
paginated_query =
|
paginated_query =
|
||||||
|
|
@ -787,34 +794,27 @@ defmodule Pleroma.User do
|
||||||
|
|
||||||
@spec search_for_admin(%{
|
@spec search_for_admin(%{
|
||||||
query: binary(),
|
query: binary(),
|
||||||
admin: Pleroma.User.t(),
|
|
||||||
local: boolean(),
|
local: boolean(),
|
||||||
page: number(),
|
page: number(),
|
||||||
page_size: number()
|
page_size: number()
|
||||||
}) :: {:ok, [Pleroma.User.t()], number()}
|
}) :: {:ok, [Pleroma.User.t()], number()}
|
||||||
def search_for_admin(%{
|
def search_for_admin(%{
|
||||||
query: term,
|
query: term,
|
||||||
admin: admin,
|
|
||||||
local: local,
|
local: local,
|
||||||
page: page,
|
page: page,
|
||||||
page_size: page_size
|
page_size: page_size
|
||||||
}) do
|
}) do
|
||||||
term = String.trim_leading(term, "@")
|
maybe_local_query = User |> maybe_local_user_query(local)
|
||||||
|
|
||||||
local_paginated_query =
|
search_query = from(u in maybe_local_query, where: ilike(u.nickname, ^"%#{term}%"))
|
||||||
User
|
count = search_query |> Repo.aggregate(:count, :id)
|
||||||
|> maybe_local_user_query(local)
|
|
||||||
|
results =
|
||||||
|
search_query
|
||||||
|> paginate(page, page_size)
|
|> paginate(page, page_size)
|
||||||
|
|> Repo.all()
|
||||||
|
|
||||||
search_query = fts_search_subquery(term, local_paginated_query)
|
{:ok, results, count}
|
||||||
|
|
||||||
count =
|
|
||||||
term
|
|
||||||
|> fts_search_subquery()
|
|
||||||
|> maybe_local_user_query(local)
|
|
||||||
|> Repo.aggregate(:count, :id)
|
|
||||||
|
|
||||||
{:ok, do_search(search_query, admin), count}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def search(query, resolve \\ false, for_user \\ nil) do
|
def search(query, resolve \\ false, for_user \\ nil) do
|
||||||
|
|
@ -1157,9 +1157,12 @@ defmodule Pleroma.User do
|
||||||
if !is_nil(user) and !User.needs_update?(user) do
|
if !is_nil(user) and !User.needs_update?(user) do
|
||||||
user
|
user
|
||||||
else
|
else
|
||||||
|
# Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled)
|
||||||
|
should_fetch_initial = is_nil(user) and Pleroma.Config.get([:fetch_initial_posts, :enabled])
|
||||||
|
|
||||||
user = fetch_by_ap_id(ap_id)
|
user = fetch_by_ap_id(ap_id)
|
||||||
|
|
||||||
if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
|
if should_fetch_initial do
|
||||||
with %User{} = user do
|
with %User{} = user do
|
||||||
{:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
|
{:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
|
||||||
end
|
end
|
||||||
|
|
@ -1340,7 +1343,7 @@ defmodule Pleroma.User do
|
||||||
|> Enum.map(&String.downcase(&1))
|
|> Enum.map(&String.downcase(&1))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp local_nickname_regex() do
|
defp local_nickname_regex do
|
||||||
if Pleroma.Config.get([:instance, :extended_nickname_format]) do
|
if Pleroma.Config.get([:instance, :extended_nickname_format]) do
|
||||||
@extended_local_nickname_regex
|
@extended_local_nickname_regex
|
||||||
else
|
else
|
||||||
|
|
@ -1383,4 +1386,8 @@ defmodule Pleroma.User do
|
||||||
offset: ^((page - 1) * page_size)
|
offset: ^((page - 1) * page_size)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def showing_reblogs?(%User{} = user, %User{} = target) do
|
||||||
|
target.ap_id not in user.info.muted_reblogs
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ defmodule Pleroma.User.Info do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Pleroma.User.Info
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:banner, :map, default: %{})
|
field(:banner, :map, default: %{})
|
||||||
field(:background, :map, default: %{})
|
field(:background, :map, default: %{})
|
||||||
|
|
@ -19,6 +21,7 @@ defmodule Pleroma.User.Info do
|
||||||
field(:blocks, {:array, :string}, default: [])
|
field(:blocks, {:array, :string}, default: [])
|
||||||
field(:domain_blocks, {:array, :string}, default: [])
|
field(:domain_blocks, {:array, :string}, default: [])
|
||||||
field(:mutes, {:array, :string}, default: [])
|
field(:mutes, {:array, :string}, default: [])
|
||||||
|
field(:muted_reblogs, {:array, :string}, default: [])
|
||||||
field(:deactivated, :boolean, default: false)
|
field(:deactivated, :boolean, default: false)
|
||||||
field(:no_rich_text, :boolean, default: false)
|
field(:no_rich_text, :boolean, default: false)
|
||||||
field(:ap_enabled, :boolean, default: false)
|
field(:ap_enabled, :boolean, default: false)
|
||||||
|
|
@ -250,4 +253,23 @@ defmodule Pleroma.User.Info do
|
||||||
|
|
||||||
cast(info, params, [:pinned_activities])
|
cast(info, params, [:pinned_activities])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def roles(%Info{is_moderator: is_moderator, is_admin: is_admin}) do
|
||||||
|
%{
|
||||||
|
admin: is_admin,
|
||||||
|
moderator: is_moderator
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_reblog_mute(info, ap_id) do
|
||||||
|
params = %{muted_reblogs: info.muted_reblogs ++ [ap_id]}
|
||||||
|
|
||||||
|
cast(info, params, [:muted_reblogs])
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_reblog_mute(info, ap_id) do
|
||||||
|
params = %{muted_reblogs: List.delete(info.muted_reblogs, ap_id)}
|
||||||
|
|
||||||
|
cast(info, params, [:muted_reblogs])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ defmodule Pleroma.User.WelcomeMessage do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp welcome_user() do
|
defp welcome_user do
|
||||||
with nickname when is_binary(nickname) <-
|
with nickname when is_binary(nickname) <-
|
||||||
Pleroma.Config.get([:instance, :welcome_user_nickname]),
|
Pleroma.Config.get([:instance, :welcome_user_nickname]),
|
||||||
%User{local: true} = user <- User.get_cached_by_nickname(nickname) do
|
%User{local: true} = user <- User.get_cached_by_nickname(nickname) do
|
||||||
|
|
@ -24,7 +24,7 @@ defmodule Pleroma.User.WelcomeMessage do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp welcome_message() do
|
defp welcome_message do
|
||||||
Pleroma.Config.get([:instance, :welcome_message])
|
Pleroma.Config.get([:instance, :welcome_message])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ defmodule Pleroma.UserInviteToken do
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
alias Pleroma.UserInviteToken
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.UserInviteToken
|
||||||
|
|
||||||
schema "user_invite_tokens" do
|
schema "user_invite_tokens" do
|
||||||
field(:token, :string)
|
field(:token, :string)
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Instances
|
||||||
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Upload
|
alias Pleroma.Upload
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Notification
|
|
||||||
alias Pleroma.Instances
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
|
||||||
alias Pleroma.Web.ActivityPub.MRF
|
alias Pleroma.Web.ActivityPub.MRF
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
alias Pleroma.Web.OStatus
|
alias Pleroma.Web.OStatus
|
||||||
|
alias Pleroma.Web.WebFinger
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Pleroma.Web.ActivityPub.Utils
|
import Pleroma.Web.ActivityPub.Utils
|
||||||
|
|
@ -170,7 +170,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
additional
|
additional
|
||||||
),
|
),
|
||||||
{:ok, activity} <- insert(create_data, local),
|
{: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, _actor} <- increase_note_count_if_public(actor, activity),
|
||||||
:ok <- maybe_federate(activity) do
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
|
@ -309,7 +310,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|
|
||||||
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
|
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
to = object.data["to"] || [] ++ object.data["cc"] || []
|
to = (object.data["to"] || []) ++ (object.data["cc"] || [])
|
||||||
|
|
||||||
with {:ok, object, activity} <- Object.delete(object),
|
with {:ok, object, activity} <- Object.delete(object),
|
||||||
data <- %{
|
data <- %{
|
||||||
|
|
@ -320,7 +321,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
"deleted_activity_id" => activity && activity.id
|
"deleted_activity_id" => activity && activity.id
|
||||||
},
|
},
|
||||||
{:ok, activity} <- insert(data, local),
|
{: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, _actor} <- decrease_note_count_if_public(user, object),
|
||||||
:ok <- maybe_federate(activity) do
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
|
@ -368,20 +370,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
content: content
|
content: content
|
||||||
} = params
|
} = params
|
||||||
) do
|
) do
|
||||||
additional = params[:additional] || %{}
|
|
||||||
|
|
||||||
# only accept false as false value
|
# only accept false as false value
|
||||||
local = !(params[:local] == false)
|
local = !(params[:local] == false)
|
||||||
|
forward = !(params[:forward] == false)
|
||||||
|
|
||||||
%{
|
additional = params[:additional] || %{}
|
||||||
|
|
||||||
|
params = %{
|
||||||
actor: actor,
|
actor: actor,
|
||||||
context: context,
|
context: context,
|
||||||
account: account,
|
account: account,
|
||||||
statuses: statuses,
|
statuses: statuses,
|
||||||
content: content
|
content: content
|
||||||
}
|
}
|
||||||
|> make_flag_data(additional)
|
|
||||||
|> insert(local)
|
additional =
|
||||||
|
if forward do
|
||||||
|
Map.merge(additional, %{"to" => [], "cc" => [account.ap_id]})
|
||||||
|
else
|
||||||
|
Map.merge(additional, %{"to" => [], "cc" => []})
|
||||||
|
end
|
||||||
|
|
||||||
|
with flag_data <- make_flag_data(params, additional),
|
||||||
|
{:ok, activity} <- insert(flag_data, local),
|
||||||
|
:ok <- maybe_federate(activity) do
|
||||||
|
Enum.each(User.all_superusers(), fn superuser ->
|
||||||
|
superuser
|
||||||
|
|> Pleroma.AdminEmail.report(actor, account, statuses, content)
|
||||||
|
|> Pleroma.Mailer.deliver_async()
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, activity}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_activities_for_context(context, opts \\ %{}) do
|
def fetch_activities_for_context(context, opts \\ %{}) do
|
||||||
|
|
@ -502,7 +522,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
when is_list(tag_reject) and tag_reject != [] do
|
when is_list(tag_reject) and tag_reject != [] do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("(not (? #> '{\"object\",\"tag\"}') \\?| ?)", activity.data, ^tag_reject)
|
where: fragment(~s(\(not \(? #> '{"object","tag"}'\) \\?| ?\)), activity.data, ^tag_reject)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -512,7 +532,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
when is_list(tag_all) and tag_all != [] do
|
when is_list(tag_all) and tag_all != [] do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("(? #> '{\"object\",\"tag\"}') \\?& ?", activity.data, ^tag_all)
|
where: fragment(~s(\(? #> '{"object","tag"}'\) \\?& ?), activity.data, ^tag_all)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -521,14 +541,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
|
defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("(? #> '{\"object\",\"tag\"}') \\?| ?", activity.data, ^tag)
|
where: fragment(~s(\(? #> '{"object","tag"}'\) \\?| ?), activity.data, ^tag)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
|
defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("? <@ (? #> '{\"object\",\"tag\"}')", ^tag, activity.data)
|
where: fragment(~s(? <@ (? #> '{"object","tag"}'\)), ^tag, activity.data)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -601,7 +621,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
|
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("? <@ (? #> '{\"object\",\"likes\"}')", ^ap_id, activity.data)
|
where: fragment(~s(? <@ (? #> '{"object","likes"}'\)), ^ap_id, activity.data)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -610,7 +630,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
|
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
where: fragment("not (? #> '{\"object\",\"attachment\"}' = ?)", activity.data, ^[])
|
where: fragment(~s(not (? #> '{"object","attachment"}' = ?\)), activity.data, ^[])
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -677,6 +697,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|
|
||||||
defp restrict_pinned(query, _), do: query
|
defp restrict_pinned(query, _), do: query
|
||||||
|
|
||||||
|
defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do
|
||||||
|
muted_reblogs = info.muted_reblogs || []
|
||||||
|
|
||||||
|
from(
|
||||||
|
activity in query,
|
||||||
|
where: fragment("not ?->>'type' = 'Announce'", activity.data),
|
||||||
|
where: fragment("not ? = ANY(?)", activity.actor, ^muted_reblogs)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict_muted_reblogs(query, _), do: query
|
||||||
|
|
||||||
def fetch_activities_query(recipients, opts \\ %{}) do
|
def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
base_query =
|
base_query =
|
||||||
from(
|
from(
|
||||||
|
|
@ -704,6 +736,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|> restrict_replies(opts)
|
|> restrict_replies(opts)
|
||||||
|> restrict_reblogs(opts)
|
|> restrict_reblogs(opts)
|
||||||
|> restrict_pinned(opts)
|
|> restrict_pinned(opts)
|
||||||
|
|> restrict_muted_reblogs(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_activities(recipients, opts \\ %{}) do
|
def fetch_activities(recipients, opts \\ %{}) do
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.ActivityPub.ObjectView
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.UserView
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.ActivityPub.ObjectView
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
alias Pleroma.Web.ActivityPub.UserView
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_policies() do
|
def get_policies do
|
||||||
Application.get_env(:pleroma, :instance, [])
|
Application.get_env(:pleroma, :instance, [])
|
||||||
|> Keyword.get(:rewrite_policy, [])
|
|> Keyword.get(:rewrite_policy, [])
|
||||||
|> get_policies()
|
|> get_policies()
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
||||||
|
|
||||||
defp check_replace(%{"object" => %{"content" => content, "summary" => summary}} = message) do
|
defp check_replace(%{"object" => %{"content" => content, "summary" => summary}} = message) do
|
||||||
{content, summary} =
|
{content, summary} =
|
||||||
Enum.reduce(Pleroma.Config.get([:mrf_keyword, :replace]), {content, summary}, fn {pattern,
|
Enum.reduce(
|
||||||
replacement},
|
Pleroma.Config.get([:mrf_keyword, :replace]),
|
||||||
{content_acc,
|
{content, summary},
|
||||||
summary_acc} ->
|
fn {pattern, replacement}, {content_acc, summary_acc} ->
|
||||||
{String.replace(content_acc, pattern, replacement),
|
{String.replace(content_acc, pattern, replacement),
|
||||||
String.replace(summary_acc, pattern, replacement)}
|
String.replace(summary_acc, pattern, replacement)}
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
message
|
message
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.Relay do
|
defmodule Pleroma.Web.ActivityPub.Relay do
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
A module to handle coding from internal to wire ActivityPub and back.
|
A module to handle coding from internal to wire ActivityPub and back.
|
||||||
"""
|
"""
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
|
@ -86,11 +86,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_addressing_list(map, field) do
|
def fix_addressing_list(map, field) do
|
||||||
if is_binary(map[field]) do
|
cond do
|
||||||
map
|
is_binary(map[field]) ->
|
||||||
|> Map.put(field, [map[field]])
|
Map.put(map, field, [map[field]])
|
||||||
else
|
|
||||||
map
|
is_nil(map[field]) ->
|
||||||
|
Map.put(map, field, [])
|
||||||
|
|
||||||
|
true ->
|
||||||
|
map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -128,13 +132,42 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
|> fix_explicit_addressing(explicit_mentions)
|
|> fix_explicit_addressing(explicit_mentions)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# if as:Public is addressed, then make sure the followers collection is also addressed
|
||||||
|
# so that the activities will be delivered to local users.
|
||||||
|
def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do
|
||||||
|
recipients = to ++ cc
|
||||||
|
|
||||||
|
if followers_collection not in recipients do
|
||||||
|
cond do
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public" in cc ->
|
||||||
|
to = to ++ [followers_collection]
|
||||||
|
Map.put(object, "to", to)
|
||||||
|
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public" in to ->
|
||||||
|
cc = cc ++ [followers_collection]
|
||||||
|
Map.put(object, "cc", cc)
|
||||||
|
|
||||||
|
true ->
|
||||||
|
object
|
||||||
|
end
|
||||||
|
else
|
||||||
|
object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_implicit_addressing(object, _), do: object
|
||||||
|
|
||||||
def fix_addressing(object) do
|
def fix_addressing(object) do
|
||||||
|
%User{} = user = User.get_or_fetch_by_ap_id(object["actor"])
|
||||||
|
followers_collection = User.ap_followers(user)
|
||||||
|
|
||||||
object
|
object
|
||||||
|> fix_addressing_list("to")
|
|> fix_addressing_list("to")
|
||||||
|> fix_addressing_list("cc")
|
|> fix_addressing_list("cc")
|
||||||
|> fix_addressing_list("bto")
|
|> fix_addressing_list("bto")
|
||||||
|> fix_addressing_list("bcc")
|
|> fix_addressing_list("bcc")
|
||||||
|> fix_explicit_addressing
|
|> fix_explicit_addressing
|
||||||
|
|> fix_implicit_addressing(followers_collection)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_actor(%{"attributedTo" => actor} = object) do
|
def fix_actor(%{"attributedTo" => actor} = object) do
|
||||||
|
|
@ -355,6 +388,40 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
|
||||||
|
# with nil ID.
|
||||||
|
def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = data) do
|
||||||
|
with context <- data["context"] || Utils.generate_context_id(),
|
||||||
|
content <- data["content"] || "",
|
||||||
|
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
||||||
|
|
||||||
|
# Reduce the object list to find the reported user.
|
||||||
|
%User{} = account <-
|
||||||
|
Enum.reduce_while(objects, nil, fn ap_id, _ ->
|
||||||
|
with %User{} = user <- User.get_cached_by_ap_id(ap_id) do
|
||||||
|
{:halt, user}
|
||||||
|
else
|
||||||
|
_ -> {:cont, nil}
|
||||||
|
end
|
||||||
|
end),
|
||||||
|
|
||||||
|
# Remove the reported user from the object list.
|
||||||
|
statuses <- Enum.filter(objects, fn ap_id -> ap_id != account.ap_id end) do
|
||||||
|
params = %{
|
||||||
|
actor: actor,
|
||||||
|
context: context,
|
||||||
|
account: account,
|
||||||
|
statuses: statuses,
|
||||||
|
content: content,
|
||||||
|
additional: %{
|
||||||
|
"cc" => [account.ap_id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityPub.flag(params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# disallow objects with bogus IDs
|
# disallow objects with bogus IDs
|
||||||
def handle_incoming(%{"id" => nil}), do: :error
|
def handle_incoming(%{"id" => nil}), do: :error
|
||||||
def handle_incoming(%{"id" => ""}), do: :error
|
def handle_incoming(%{"id" => ""}), do: :error
|
||||||
|
|
@ -650,10 +717,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
if object = Object.normalize(id), do: {:ok, object}, else: nil
|
if object = Object.normalize(id), do: {:ok, object}, else: nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) when is_binary(inReplyTo) do
|
def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
|
||||||
with false <- String.starts_with?(inReplyTo, "http"),
|
with false <- String.starts_with?(in_reply_to, "http"),
|
||||||
{:ok, %{data: replied_to_object}} <- get_obj_helper(inReplyTo) do
|
{:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do
|
||||||
Map.put(object, "inReplyTo", replied_to_object["external_url"] || inReplyTo)
|
Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to)
|
||||||
else
|
else
|
||||||
_e -> object
|
_e -> object
|
||||||
end
|
end
|
||||||
|
|
@ -830,10 +897,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_attributed_to(object) do
|
def add_attributed_to(object) do
|
||||||
attributedTo = object["attributedTo"] || object["actor"]
|
attributed_to = object["attributedTo"] || object["actor"]
|
||||||
|
|
||||||
object
|
object
|
||||||
|> Map.put("attributedTo", attributedTo)
|
|> Map.put("attributedTo", attributed_to)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_likes(%{"id" => id, "like_count" => likes} = object) do
|
def add_likes(%{"id" => id, "like_count" => likes} = object) do
|
||||||
|
|
@ -888,7 +955,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
defp strip_internal_tags(object), do: object
|
defp strip_internal_tags(object), do: object
|
||||||
|
|
||||||
defp user_upgrade_task(user) do
|
defp user_upgrade_task(user) do
|
||||||
old_follower_address = User.ap_followers(user)
|
# we pass a fake user so that the followers collection is stripped away
|
||||||
|
old_follower_address = User.ap_followers(%User{nickname: user.nickname})
|
||||||
|
|
||||||
q =
|
q =
|
||||||
from(
|
from(
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.ActivityPub.Utils do
|
defmodule Pleroma.Web.ActivityPub.Utils do
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Web
|
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Activity
|
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Notification
|
|
||||||
alias Pleroma.Web.Router.Helpers
|
|
||||||
alias Pleroma.Web.Endpoint
|
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
alias Ecto.UUID
|
alias Ecto.UUID
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Router.Helpers
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
|
@ -621,7 +621,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
||||||
#### Flag-related helpers
|
#### Flag-related helpers
|
||||||
|
|
||||||
def make_flag_data(params, additional) do
|
def make_flag_data(params, additional) do
|
||||||
status_ap_ids = Enum.map(params.statuses || [], & &1.data["id"])
|
status_ap_ids =
|
||||||
|
Enum.map(params.statuses || [], fn
|
||||||
|
%Activity{} = act -> act.data["id"]
|
||||||
|
act when is_map(act) -> act["id"]
|
||||||
|
act when is_binary(act) -> act
|
||||||
|
end)
|
||||||
|
|
||||||
object = [params.account.ap_id] ++ status_ap_ids
|
object = [params.account.ap_id] ++ status_ap_ids
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,15 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.UserView do
|
defmodule Pleroma.Web.ActivityPub.UserView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
alias Pleroma.Web.WebFinger
|
|
||||||
alias Pleroma.Web.Salmon
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Router.Helpers
|
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Router.Helpers
|
||||||
|
alias Pleroma.Web.Salmon
|
||||||
|
alias Pleroma.Web.WebFinger
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.MastodonAPI.Admin.AccountView
|
alias Pleroma.Web.AdminAPI.AccountView
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
|
defmodule Pleroma.Web.AdminAPI.AccountView do
|
||||||
use Pleroma.Web, :view
|
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
|
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,
|
"id" => user.id,
|
||||||
"nickname" => user.nickname,
|
"nickname" => user.nickname,
|
||||||
"deactivated" => user.info.deactivated
|
"deactivated" => user.info.deactivated,
|
||||||
|
"local" => user.local,
|
||||||
|
"roles" => Info.roles(user.info),
|
||||||
|
"tags" => user.tags || []
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
143
lib/pleroma/web/auth/ldap_authenticator.ex
Normal file
143
lib/pleroma/web/auth/ldap_authenticator.ex
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Auth.LDAPAuthenticator do
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
|
@connection_timeout 10_000
|
||||||
|
@search_timeout 10_000
|
||||||
|
|
||||||
|
def get_user(%Plug.Conn{} = conn) do
|
||||||
|
if Pleroma.Config.get([:ldap, :enabled]) do
|
||||||
|
{name, password} =
|
||||||
|
case conn.params do
|
||||||
|
%{"authorization" => %{"name" => name, "password" => password}} ->
|
||||||
|
{name, password}
|
||||||
|
|
||||||
|
%{"grant_type" => "password", "username" => name, "password" => password} ->
|
||||||
|
{name, password}
|
||||||
|
end
|
||||||
|
|
||||||
|
case ldap_user(name, password) do
|
||||||
|
%User{} = user ->
|
||||||
|
{:ok, user}
|
||||||
|
|
||||||
|
{:error, {:ldap_connection_error, _}} ->
|
||||||
|
# When LDAP is unavailable, try default authenticator
|
||||||
|
Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
|
||||||
|
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Fall back to default authenticator
|
||||||
|
Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_error(%Plug.Conn{} = _conn, error) do
|
||||||
|
error
|
||||||
|
end
|
||||||
|
|
||||||
|
def auth_template, do: nil
|
||||||
|
|
||||||
|
defp ldap_user(name, password) do
|
||||||
|
ldap = Pleroma.Config.get(:ldap, [])
|
||||||
|
host = Keyword.get(ldap, :host, "localhost")
|
||||||
|
port = Keyword.get(ldap, :port, 389)
|
||||||
|
ssl = Keyword.get(ldap, :ssl, false)
|
||||||
|
sslopts = Keyword.get(ldap, :sslopts, [])
|
||||||
|
|
||||||
|
options =
|
||||||
|
[{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
|
||||||
|
if sslopts != [], do: [{:sslopts, sslopts}], else: []
|
||||||
|
|
||||||
|
case :eldap.open([to_charlist(host)], options) do
|
||||||
|
{:ok, connection} ->
|
||||||
|
try do
|
||||||
|
if Keyword.get(ldap, :tls, false) do
|
||||||
|
:application.ensure_all_started(:ssl)
|
||||||
|
|
||||||
|
case :eldap.start_tls(
|
||||||
|
connection,
|
||||||
|
Keyword.get(ldap, :tlsopts, []),
|
||||||
|
@connection_timeout
|
||||||
|
) do
|
||||||
|
:ok ->
|
||||||
|
:ok
|
||||||
|
|
||||||
|
error ->
|
||||||
|
Logger.error("Could not start TLS: #{inspect(error)}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
bind_user(connection, ldap, name, password)
|
||||||
|
after
|
||||||
|
:eldap.close(connection)
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, error} ->
|
||||||
|
Logger.error("Could not open LDAP connection: #{inspect(error)}")
|
||||||
|
{:error, {:ldap_connection_error, error}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp bind_user(connection, ldap, name, password) do
|
||||||
|
uid = Keyword.get(ldap, :uid, "cn")
|
||||||
|
base = Keyword.get(ldap, :base)
|
||||||
|
|
||||||
|
case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
|
||||||
|
:ok ->
|
||||||
|
case User.get_by_nickname_or_email(name) do
|
||||||
|
%User{} = user ->
|
||||||
|
user
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
register_user(connection, base, uid, name, password)
|
||||||
|
end
|
||||||
|
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp register_user(connection, base, uid, name, password) do
|
||||||
|
case :eldap.search(connection, [
|
||||||
|
{:base, to_charlist(base)},
|
||||||
|
{:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
|
||||||
|
{:scope, :eldap.wholeSubtree()},
|
||||||
|
{:attributes, ['mail', 'email']},
|
||||||
|
{:timeout, @search_timeout}
|
||||||
|
]) do
|
||||||
|
{:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} ->
|
||||||
|
with {_, [mail]} <- List.keyfind(attributes, 'mail', 0) do
|
||||||
|
params = %{
|
||||||
|
email: :erlang.list_to_binary(mail),
|
||||||
|
name: name,
|
||||||
|
nickname: name,
|
||||||
|
password: password,
|
||||||
|
password_confirmation: password
|
||||||
|
}
|
||||||
|
|
||||||
|
changeset = User.register_changeset(%User{}, params)
|
||||||
|
|
||||||
|
case User.register(changeset) do
|
||||||
|
{:ok, user} -> user
|
||||||
|
error -> error
|
||||||
|
end
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
Logger.error("Could not find LDAP attribute mail: #{inspect(attributes)}")
|
||||||
|
{:error, :ldap_registration_missing_attributes}
|
||||||
|
end
|
||||||
|
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -3,13 +3,20 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
||||||
alias Pleroma.User
|
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
@behaviour Pleroma.Web.Auth.Authenticator
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
def get_user(%Plug.Conn{} = conn) do
|
def get_user(%Plug.Conn{} = conn) do
|
||||||
%{"authorization" => %{"name" => name, "password" => password}} = conn.params
|
{name, password} =
|
||||||
|
case conn.params do
|
||||||
|
%{"authorization" => %{"name" => name, "password" => password}} ->
|
||||||
|
{name, password}
|
||||||
|
|
||||||
|
%{"grant_type" => "password", "username" => name, "password" => password} ->
|
||||||
|
{name, password}
|
||||||
|
end
|
||||||
|
|
||||||
with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
|
with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
|
||||||
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
|
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ defmodule Pleroma.Web.UserSocket do
|
||||||
# performing token verification on connect.
|
# performing token verification on connect.
|
||||||
def connect(%{"token" => token}, socket) do
|
def connect(%{"token" => token}, socket) do
|
||||||
with true <- Pleroma.Config.get([:chat, :enabled]),
|
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
|
%User{} = user <- Pleroma.Repo.get(User, user_id) do
|
||||||
{:ok, assign(socket, :user_name, user.nickname)}
|
{:ok, assign(socket, :user_name, user.nickname)}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ChatChannel do
|
defmodule Pleroma.Web.ChatChannel do
|
||||||
use Phoenix.Channel
|
use Phoenix.Channel
|
||||||
alias Pleroma.Web.ChatChannel.ChatChannelState
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ChatChannel.ChatChannelState
|
||||||
|
|
||||||
def join("chat:public", _message, socket) do
|
def join("chat:public", _message, socket) do
|
||||||
send(self(), :after_join)
|
send(self(), :after_join)
|
||||||
|
|
@ -48,7 +48,7 @@ defmodule Pleroma.Web.ChatChannel.ChatChannelState do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def messages() do
|
def messages do
|
||||||
Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse() end)
|
Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse() end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.CommonAPI do
|
defmodule Pleroma.Web.CommonAPI do
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Formatter
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Repo
|
||||||
alias Pleroma.ThreadMute
|
alias Pleroma.ThreadMute
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Formatter
|
|
||||||
|
|
||||||
import Pleroma.Web.CommonAPI.Utils
|
import Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
|
|
@ -27,6 +27,42 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
end
|
end
|
||||||
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
|
def delete(activity_id, user) do
|
||||||
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
|
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
|
||||||
%Object{} = object <- Object.normalize(object_id),
|
%Object{} = object <- Object.normalize(object_id),
|
||||||
|
|
@ -88,8 +124,8 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
nil ->
|
nil ->
|
||||||
"public"
|
"public"
|
||||||
|
|
||||||
inReplyTo ->
|
in_reply_to ->
|
||||||
Pleroma.Web.MastodonAPI.StatusView.get_visibility(inReplyTo.data["object"])
|
Pleroma.Web.MastodonAPI.StatusView.get_visibility(in_reply_to.data["object"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -101,15 +137,15 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
|
|
||||||
with status <- String.trim(status),
|
with status <- String.trim(status),
|
||||||
attachments <- attachments_from_ids(data),
|
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} <-
|
{content_html, mentions, tags} <-
|
||||||
make_content_html(
|
make_content_html(
|
||||||
status,
|
status,
|
||||||
attachments,
|
attachments,
|
||||||
data
|
data
|
||||||
),
|
),
|
||||||
{to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
|
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
|
||||||
context <- make_context(inReplyTo),
|
context <- make_context(in_reply_to),
|
||||||
cw <- data["spoiler_text"],
|
cw <- data["spoiler_text"],
|
||||||
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
|
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
|
||||||
length when length in 1..limit <- String.length(full_payload),
|
length when length in 1..limit <- String.length(full_payload),
|
||||||
|
|
@ -120,7 +156,7 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
context,
|
context,
|
||||||
content_html,
|
content_html,
|
||||||
attachments,
|
attachments,
|
||||||
inReplyTo,
|
in_reply_to,
|
||||||
tags,
|
tags,
|
||||||
cw,
|
cw,
|
||||||
cc
|
cc
|
||||||
|
|
@ -248,14 +284,9 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
actor: user,
|
actor: user,
|
||||||
account: account,
|
account: account,
|
||||||
statuses: statuses,
|
statuses: statuses,
|
||||||
content: content_html
|
content: content_html,
|
||||||
|
forward: data["forward"] || false
|
||||||
}) do
|
}) do
|
||||||
Enum.each(User.all_superusers(), fn superuser ->
|
|
||||||
superuser
|
|
||||||
|> Pleroma.AdminEmail.report(user, account, statuses, content_html)
|
|
||||||
|> Pleroma.Mailer.deliver_async()
|
|
||||||
end)
|
|
||||||
|
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
{:error, err} -> {:error, err}
|
{:error, err} -> {:error, err}
|
||||||
|
|
@ -263,4 +294,24 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
{:account, nil} -> {:error, "Account not found"}
|
{:account, nil} -> {:error, "Account not found"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hide_reblogs(user, muted) do
|
||||||
|
ap_id = muted.ap_id
|
||||||
|
|
||||||
|
if ap_id not in user.info.muted_reblogs do
|
||||||
|
info_changeset = User.Info.add_reblog_mute(user.info, ap_id)
|
||||||
|
changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
|
||||||
|
User.update_and_set_cache(changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_reblogs(user, muted) do
|
||||||
|
ap_id = muted.ap_id
|
||||||
|
|
||||||
|
if ap_id in user.info.muted_reblogs do
|
||||||
|
info_changeset = User.Info.remove_reblog_mute(user.info, ap_id)
|
||||||
|
changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
|
||||||
|
User.update_and_set_cache(changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
alias Calendar.Strftime
|
alias Calendar.Strftime
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Config
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Config
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
|
||||||
|
|
||||||
# This is a hack for twidere.
|
# This is a hack for twidere.
|
||||||
def get_by_id_or_ap_id(id) do
|
def get_by_id_or_ap_id(id) do
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ defmodule Pleroma.Web.ControllerHelper do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
def oauth_scopes(params, default) do
|
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)
|
Pleroma.Web.OAuth.parse_scopes(params["scope"] || params["scopes"], default)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ defmodule Pleroma.Web.Endpoint do
|
||||||
at: "/",
|
at: "/",
|
||||||
from: "priv_sid/static",
|
from: "priv_sid/static",
|
||||||
only:
|
only:
|
||||||
~w(index.html static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc)
|
~w(index.html robots.txt 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
|
# Code reloading can be explicitly enabled under the
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,27 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Federator do
|
defmodule Pleroma.Web.Federator do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Jobs
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.WebFinger
|
|
||||||
alias Pleroma.Web.Websub
|
|
||||||
alias Pleroma.Web.Salmon
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
alias Pleroma.Web.Federator.RetryQueue
|
alias Pleroma.Web.Federator.RetryQueue
|
||||||
alias Pleroma.Web.OStatus
|
alias Pleroma.Web.OStatus
|
||||||
alias Pleroma.Jobs
|
alias Pleroma.Web.Salmon
|
||||||
|
alias Pleroma.Web.WebFinger
|
||||||
|
alias Pleroma.Web.Websub
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@websub Application.get_env(:pleroma, :websub)
|
@websub Application.get_env(:pleroma, :websub)
|
||||||
@ostatus Application.get_env(:pleroma, :ostatus)
|
@ostatus Application.get_env(:pleroma, :ostatus)
|
||||||
|
|
||||||
def init() do
|
def init do
|
||||||
# 1 minute
|
# 1 minute
|
||||||
Process.sleep(1000 * 60 * 1)
|
Process.sleep(1000 * 60)
|
||||||
refresh_subscriptions()
|
refresh_subscriptions()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ defmodule Pleroma.Web.Federator do
|
||||||
Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
|
Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh_subscriptions() do
|
def refresh_subscriptions do
|
||||||
Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
|
Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
|
||||||
{:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
|
{:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_link() do
|
def start_link do
|
||||||
enabled =
|
enabled =
|
||||||
if Mix.env() == :test, do: true, else: Pleroma.Config.get([__MODULE__, :enabled], false)
|
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})
|
GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1})
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_stats() do
|
def get_stats do
|
||||||
GenServer.call(__MODULE__, :get_stats)
|
GenServer.call(__MODULE__, :get_stats)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_stats() do
|
def reset_stats do
|
||||||
GenServer.call(__MODULE__, :reset_stats)
|
GenServer.call(__MODULE__, :reset_stats)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_retry_timer_interval() do
|
def get_retry_timer_interval do
|
||||||
Pleroma.Config.get([:retry_queue, :interval], 1000)
|
Pleroma.Config.get([:retry_queue, :interval], 1000)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_kickoff_timer() do
|
defp maybe_kickoff_timer do
|
||||||
GenServer.cast(__MODULE__, :kickoff_timer)
|
GenServer.cast(__MODULE__, :kickoff_timer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,61 +2,49 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Repo
|
|
||||||
|
|
||||||
@default_limit 20
|
|
||||||
|
|
||||||
def get_followers(user, params \\ %{}) do
|
def get_followers(user, params \\ %{}) do
|
||||||
user
|
user
|
||||||
|> User.get_followers_query()
|
|> User.get_followers_query()
|
||||||
|> paginate(params)
|
|> Pagination.fetch_paginated(params)
|
||||||
|> Repo.all()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_friends(user, params \\ %{}) do
|
def get_friends(user, params \\ %{}) do
|
||||||
user
|
user
|
||||||
|> User.get_friends_query()
|
|> User.get_friends_query()
|
||||||
|> paginate(params)
|
|> Pagination.fetch_paginated(params)
|
||||||
|> Repo.all()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginate(query, params \\ %{}) do
|
def get_notifications(user, params \\ %{}) do
|
||||||
options = cast_params(params)
|
options = cast_params(params)
|
||||||
|
|
||||||
query
|
user
|
||||||
|> restrict(:max_id, options)
|
|> Notification.for_user_query()
|
||||||
|> restrict(:since_id, options)
|
|> restrict(:exclude_types, options)
|
||||||
|> restrict(:limit, options)
|
|> Pagination.fetch_paginated(params)
|
||||||
|> order_by([u], fragment("? desc nulls last", u.id))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_params(params) do
|
defp cast_params(params) do
|
||||||
param_types = %{
|
param_types = %{
|
||||||
max_id: :string,
|
exclude_types: {:array, :string}
|
||||||
since_id: :string,
|
|
||||||
limit: :integer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
||||||
changeset.changes
|
changeset.changes
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict(query, :max_id, %{max_id: max_id}) do
|
defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do
|
||||||
query
|
ap_types =
|
||||||
|> where([q], q.id < ^max_id)
|
mastodon_types
|
||||||
end
|
|> Enum.map(&Activity.from_mastodon_notification_type/1)
|
||||||
|
|> Enum.filter(& &1)
|
||||||
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
|
query
|
||||||
|> limit(^limit)
|
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp restrict(query, _, _), do: query
|
defp restrict(query, _, _), do: query
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Filter
|
alias Pleroma.Filter
|
||||||
|
|
@ -13,19 +14,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
alias Pleroma.Stats
|
alias Pleroma.Stats
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.MediaProxy
|
|
||||||
|
|
||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
alias Pleroma.Web.MastodonAPI.FilterView
|
alias Pleroma.Web.MastodonAPI.FilterView
|
||||||
alias Pleroma.Web.MastodonAPI.ListView
|
alias Pleroma.Web.MastodonAPI.ListView
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonView
|
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
|
||||||
alias Pleroma.Web.MastodonAPI.ReportView
|
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.MastodonAPI.MastodonView
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.MastodonAPI.ReportView
|
||||||
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
alias Pleroma.Web.MediaProxy
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
@ -502,21 +502,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def notifications(%{assigns: %{user: user}} = conn, params) do
|
def notifications(%{assigns: %{user: user}} = conn, params) do
|
||||||
notifications = Notification.for_user(user, params)
|
notifications = MastodonAPI.get_notifications(user, params)
|
||||||
|
|
||||||
result =
|
|
||||||
notifications
|
|
||||||
|> Enum.map(fn x -> render_notification(user, x) end)
|
|
||||||
|> Enum.filter(& &1)
|
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(:notifications, notifications)
|
|> add_link_headers(:notifications, notifications)
|
||||||
|> json(result)
|
|> put_view(NotificationView)
|
||||||
|
|> render("index.json", %{notifications: notifications, for: user})
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
||||||
with {:ok, notification} <- Notification.get(user, id) do
|
with {:ok, notification} <- Notification.get(user, id) do
|
||||||
json(conn, render_notification(user, notification))
|
conn
|
||||||
|
|> put_view(NotificationView)
|
||||||
|
|> render("show.json", %{notification: notification, for: user})
|
||||||
else
|
else
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
conn
|
conn
|
||||||
|
|
@ -697,16 +695,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
|
||||||
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|
||||||
with %User{} = follower <- Repo.get(User, id),
|
with %User{} = follower <- Repo.get(User, id),
|
||||||
{:ok, follower} <- User.maybe_follow(follower, followed),
|
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
|
||||||
%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
|
|
||||||
conn
|
conn
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("relationship.json", %{user: followed, target: follower})
|
|> render("relationship.json", %{user: followed, target: follower})
|
||||||
|
|
@ -720,15 +709,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
|
||||||
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|
||||||
with %User{} = follower <- Repo.get(User, id),
|
with %User{} = follower <- Repo.get(User, id),
|
||||||
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
|
||||||
{: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
|
|
||||||
conn
|
conn
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("relationship.json", %{user: followed, target: follower})
|
|> render("relationship.json", %{user: followed, target: follower})
|
||||||
|
|
@ -742,11 +723,25 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
|
||||||
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
||||||
with %User{} = followed <- Repo.get(User, id),
|
with %User{} = followed <- Repo.get(User, id),
|
||||||
|
false <- User.following?(follower, followed),
|
||||||
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
|
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
|
||||||
conn
|
conn
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("relationship.json", %{user: follower, target: followed})
|
|> render("relationship.json", %{user: follower, target: followed})
|
||||||
else
|
else
|
||||||
|
true ->
|
||||||
|
followed = User.get_cached_by_id(id)
|
||||||
|
|
||||||
|
{:ok, follower} =
|
||||||
|
case conn.params["reblogs"] do
|
||||||
|
true -> CommonAPI.show_reblogs(follower, followed)
|
||||||
|
false -> CommonAPI.hide_reblogs(follower, followed)
|
||||||
|
end
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_view(AccountView)
|
||||||
|
|> render("relationship.json", %{user: follower, target: followed})
|
||||||
|
|
||||||
{:error, message} ->
|
{:error, message} ->
|
||||||
conn
|
conn
|
||||||
|> put_resp_content_type("application/json")
|
|> put_resp_content_type("application/json")
|
||||||
|
|
@ -770,8 +765,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
|
||||||
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
||||||
with %User{} = followed <- Repo.get(User, id),
|
with %User{} = followed <- Repo.get(User, id),
|
||||||
{:ok, _activity} <- ActivityPub.unfollow(follower, followed),
|
{:ok, follower} <- CommonAPI.unfollow(follower, followed) do
|
||||||
{:ok, follower, _} <- User.unfollow(follower, followed) do
|
|
||||||
conn
|
conn
|
||||||
|> put_view(AccountView)
|
|> put_view(AccountView)
|
||||||
|> render("relationship.json", %{user: follower, target: followed})
|
|> render("relationship.json", %{user: follower, target: followed})
|
||||||
|
|
@ -1129,7 +1123,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
compose: %{
|
compose: %{
|
||||||
me: "#{user.id}",
|
me: "#{user.id}",
|
||||||
default_privacy: user.info.default_scope,
|
default_privacy: user.info.default_scope,
|
||||||
default_sensitive: false
|
default_sensitive: false,
|
||||||
|
allow_content_types: Config.get([:instance, :allowed_post_formats])
|
||||||
},
|
},
|
||||||
media_attachments: %{
|
media_attachments: %{
|
||||||
accept_content_types: [
|
accept_content_types: [
|
||||||
|
|
@ -1274,7 +1269,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_or_make_app() do
|
defp get_or_make_app do
|
||||||
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
|
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
|
||||||
scopes = ["read", "write", "follow", "push"]
|
scopes = ["read", "write", "follow", "push"]
|
||||||
|
|
||||||
|
|
@ -1327,45 +1322,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_notification(user, %{id: id, activity: activity, inserted_at: created_at} = _params) do
|
|
||||||
actor = User.get_cached_by_ap_id(activity.data["actor"])
|
|
||||||
parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
|
|
||||||
mastodon_type = Activity.mastodon_notification_type(activity)
|
|
||||||
|
|
||||||
response = %{
|
|
||||||
id: to_string(id),
|
|
||||||
type: mastodon_type,
|
|
||||||
created_at: CommonAPI.Utils.to_masto_date(created_at),
|
|
||||||
account: AccountView.render("account.json", %{user: actor, for: user})
|
|
||||||
}
|
|
||||||
|
|
||||||
case mastodon_type do
|
|
||||||
"mention" ->
|
|
||||||
response
|
|
||||||
|> Map.merge(%{
|
|
||||||
status: StatusView.render("status.json", %{activity: activity, for: user})
|
|
||||||
})
|
|
||||||
|
|
||||||
"favourite" ->
|
|
||||||
response
|
|
||||||
|> Map.merge(%{
|
|
||||||
status: StatusView.render("status.json", %{activity: parent_activity, for: user})
|
|
||||||
})
|
|
||||||
|
|
||||||
"reblog" ->
|
|
||||||
response
|
|
||||||
|> Map.merge(%{
|
|
||||||
status: StatusView.render("status.json", %{activity: parent_activity, for: user})
|
|
||||||
})
|
|
||||||
|
|
||||||
"follow" ->
|
|
||||||
response
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_filters(%{assigns: %{user: user}} = conn, _) do
|
def get_filters(%{assigns: %{user: user}} = conn, _) do
|
||||||
filters = Filter.get_filters(user)
|
filters = Filter.get_filters(user)
|
||||||
res = FilterView.render("filters.json", filters: filters)
|
res = FilterView.render("filters.json", filters: filters)
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
||||||
muting_notifications: false,
|
muting_notifications: false,
|
||||||
requested: requested,
|
requested: requested,
|
||||||
domain_blocking: false,
|
domain_blocking: false,
|
||||||
showing_reblogs: false,
|
showing_reblogs: User.showing_reblogs?(user, target),
|
||||||
endorsed: false
|
endorsed: false
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
64
lib/pleroma/web/mastodon_api/views/notification_view.ex
Normal file
64
lib/pleroma/web/mastodon_api/views/notification_view.ex
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# 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.NotificationView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
|
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||||
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
|
||||||
|
def render("index.json", %{notifications: notifications, for: user}) do
|
||||||
|
render_many(notifications, NotificationView, "show.json", %{for: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("show.json", %{
|
||||||
|
notification: %Notification{activity: activity} = notification,
|
||||||
|
for: user
|
||||||
|
}) do
|
||||||
|
actor = User.get_cached_by_ap_id(activity.data["actor"])
|
||||||
|
parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
|
||||||
|
mastodon_type = Activity.mastodon_notification_type(activity)
|
||||||
|
|
||||||
|
response = %{
|
||||||
|
id: to_string(notification.id),
|
||||||
|
type: mastodon_type,
|
||||||
|
created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at),
|
||||||
|
account: AccountView.render("account.json", %{user: actor, for: user}),
|
||||||
|
pleroma: %{
|
||||||
|
is_seen: notification.seen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case mastodon_type do
|
||||||
|
"mention" ->
|
||||||
|
response
|
||||||
|
|> Map.merge(%{
|
||||||
|
status: StatusView.render("status.json", %{activity: activity, for: user})
|
||||||
|
})
|
||||||
|
|
||||||
|
"favourite" ->
|
||||||
|
response
|
||||||
|
|> Map.merge(%{
|
||||||
|
status: StatusView.render("status.json", %{activity: parent_activity, for: user})
|
||||||
|
})
|
||||||
|
|
||||||
|
"reblog" ->
|
||||||
|
response
|
||||||
|
|> Map.merge(%{
|
||||||
|
status: StatusView.render("status.json", %{activity: parent_activity, for: user})
|
||||||
|
})
|
||||||
|
|
||||||
|
"follow" ->
|
||||||
|
response
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -257,7 +257,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
preview_url: href,
|
preview_url: href,
|
||||||
text_url: href,
|
text_url: href,
|
||||||
type: type,
|
type: type,
|
||||||
description: attachment["name"]
|
description: attachment["name"],
|
||||||
|
pleroma: %{mime_type: media_type}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
@behaviour :cowboy_websocket
|
@behaviour :cowboy_websocket
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ defmodule Pleroma.Web.MediaProxy do
|
||||||
else
|
else
|
||||||
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
|
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:")
|
replacement = get_replacement(url, ":2F:")
|
||||||
|
|
||||||
# The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
|
# The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
|
||||||
|
|
||||||
# TODO: Add additional properties to objects when we have the data available.
|
# 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
|
# 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
|
case media_type do
|
||||||
"audio" ->
|
"audio" ->
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
||||||
| acc
|
| 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" ->
|
"video" ->
|
||||||
[
|
[
|
||||||
{:meta, [property: "twitter:card", content: "player"], []},
|
{:meta, [property: "twitter:card", content: "player"], []},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# 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
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.Metadata.Utils do
|
defmodule Pleroma.Web.Metadata.Utils do
|
||||||
alias Pleroma.HTML
|
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
|
alias Pleroma.HTML
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
|
|
||||||
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
defmodule Pleroma.Web.OAuth.Authorization do
|
defmodule Pleroma.Web.OAuth.Authorization do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
|
||||||
schema "oauth_authorizations" do
|
schema "oauth_authorizations" do
|
||||||
field(:token, :string)
|
field(:token, :string)
|
||||||
field(:scopes, {:array, :string}, default: [])
|
field(:scopes, {:array, :string}, default: [])
|
||||||
field(:valid_until, :naive_datetime)
|
field(:valid_until, :naive_datetime_usec)
|
||||||
field(:used, :boolean, default: false)
|
field(:used, :boolean, default: false)
|
||||||
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
|
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
|
||||||
belongs_to(:app, App)
|
belongs_to(:app, App)
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@
|
||||||
defmodule Pleroma.Web.OAuth.OAuthController do
|
defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
alias Pleroma.Web.Auth.Authenticator
|
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Web.OAuth.App
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Comeonin.Pbkdf2
|
alias Pleroma.Web.Auth.Authenticator
|
||||||
|
alias Pleroma.Web.OAuth.App
|
||||||
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
|
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
|
||||||
|
|
||||||
|
|
@ -105,6 +104,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
fixed_token = fix_padding(params["code"]),
|
fixed_token = fix_padding(params["code"]),
|
||||||
%Authorization{} = auth <-
|
%Authorization{} = auth <-
|
||||||
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
|
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
|
||||||
|
%User{} = user <- Repo.get(User, auth.user_id),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth),
|
{:ok, token} <- Token.exchange_token(app, auth),
|
||||||
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
|
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
|
||||||
response = %{
|
response = %{
|
||||||
|
|
@ -113,7 +113,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
refresh_token: token.refresh_token,
|
refresh_token: token.refresh_token,
|
||||||
created_at: DateTime.to_unix(inserted_at),
|
created_at: DateTime.to_unix(inserted_at),
|
||||||
expires_in: 60 * 10,
|
expires_in: 60 * 10,
|
||||||
scope: Enum.join(token.scopes, " ")
|
scope: Enum.join(token.scopes, " "),
|
||||||
|
me: user.ap_id
|
||||||
}
|
}
|
||||||
|
|
||||||
json(conn, response)
|
json(conn, response)
|
||||||
|
|
@ -126,11 +127,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
|
|
||||||
def token_exchange(
|
def token_exchange(
|
||||||
conn,
|
conn,
|
||||||
%{"grant_type" => "password", "username" => name, "password" => password} = params
|
%{"grant_type" => "password"} = params
|
||||||
) do
|
) do
|
||||||
with %App{} = app <- get_app_from_request(conn, params),
|
with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)},
|
||||||
%User{} = user <- User.get_by_nickname_or_email(name),
|
%App{} = app <- get_app_from_request(conn, params),
|
||||||
true <- Pbkdf2.checkpw(password, user.password_hash),
|
|
||||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
||||||
scopes <- oauth_scopes(params, app.scopes),
|
scopes <- oauth_scopes(params, app.scopes),
|
||||||
[] <- scopes -- app.scopes,
|
[] <- scopes -- app.scopes,
|
||||||
|
|
@ -142,7 +142,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
access_token: token.token,
|
access_token: token.token,
|
||||||
refresh_token: token.refresh_token,
|
refresh_token: token.refresh_token,
|
||||||
expires_in: 60 * 10,
|
expires_in: 60 * 10,
|
||||||
scope: Enum.join(token.scopes, " ")
|
scope: Enum.join(token.scopes, " "),
|
||||||
|
me: user.ap_id
|
||||||
}
|
}
|
||||||
|
|
||||||
json(conn, response)
|
json(conn, response)
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,17 @@ defmodule Pleroma.Web.OAuth.Token do
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
schema "oauth_tokens" do
|
schema "oauth_tokens" do
|
||||||
field(:token, :string)
|
field(:token, :string)
|
||||||
field(:refresh_token, :string)
|
field(:refresh_token, :string)
|
||||||
field(:scopes, {:array, :string}, default: [])
|
field(:scopes, {:array, :string}, default: [])
|
||||||
field(:valid_until, :naive_datetime)
|
field(:valid_until, :naive_datetime_usec)
|
||||||
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
|
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
|
||||||
belongs_to(:app, App)
|
belongs_to(:app, App)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OStatus.UserRepresenter
|
alias Pleroma.Web.OStatus.UserRepresenter
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.FeedRepresenter do
|
defmodule Pleroma.Web.OStatus.FeedRepresenter do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.OStatus
|
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
|
alias Pleroma.Web.OStatus
|
||||||
alias Pleroma.Web.OStatus.ActivityRepresenter
|
alias Pleroma.Web.OStatus.ActivityRepresenter
|
||||||
alias Pleroma.Web.OStatus.UserRepresenter
|
alias Pleroma.Web.OStatus.UserRepresenter
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.DeleteHandler do
|
defmodule Pleroma.Web.OStatus.DeleteHandler do
|
||||||
require Logger
|
require Logger
|
||||||
alias Pleroma.Web.XML
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
def handle_delete(entry, _doc \\ nil) do
|
def handle_delete(entry, _doc \\ nil) do
|
||||||
with id <- XML.string_from_xpath("//id", entry),
|
with id <- XML.string_from_xpath("//id", entry),
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.FollowHandler do
|
defmodule Pleroma.Web.OStatus.FollowHandler do
|
||||||
alias Pleroma.Web.XML
|
|
||||||
alias Pleroma.Web.OStatus
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.OStatus
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
def handle(entry, doc) do
|
def handle(entry, doc) do
|
||||||
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
|
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.NoteHandler do
|
defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
require Logger
|
require Logger
|
||||||
alias Pleroma.Web.OStatus
|
|
||||||
alias Pleroma.Web.XML
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.OStatus
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Get the context for this note. Uses this:
|
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
|
2. The conversation reference in the ostatus xml
|
||||||
3. A newly generated context id.
|
3. A newly generated context id.
|
||||||
"""
|
"""
|
||||||
def get_context(entry, inReplyTo) do
|
def get_context(entry, in_reply_to) do
|
||||||
context =
|
context =
|
||||||
(XML.string_from_xpath("//ostatus:conversation[1]", entry) ||
|
(XML.string_from_xpath("//ostatus:conversation[1]", entry) ||
|
||||||
XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry) || "")
|
XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry) || "")
|
||||||
|> String.trim()
|
|> 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
|
context
|
||||||
else
|
else
|
||||||
_e ->
|
_e ->
|
||||||
|
|
@ -87,14 +88,14 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
Map.put(note, "external_url", url)
|
Map.put(note, "external_url", url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_replied_to_activity(entry, inReplyTo) do
|
def fetch_replied_to_activity(entry, in_reply_to) do
|
||||||
with %Activity{} = activity <- Activity.get_create_by_object_ap_id(inReplyTo) do
|
with %Activity{} = activity <- Activity.get_create_by_object_ap_id(in_reply_to) do
|
||||||
activity
|
activity
|
||||||
else
|
else
|
||||||
_e ->
|
_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),
|
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
|
activity
|
||||||
else
|
else
|
||||||
_e -> nil
|
_e -> nil
|
||||||
|
|
@ -110,11 +111,12 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
{:ok, actor} <- OStatus.find_make_or_update_user(author),
|
{:ok, actor} <- OStatus.find_make_or_update_user(author),
|
||||||
content_html <- OStatus.get_content(entry),
|
content_html <- OStatus.get_content(entry),
|
||||||
cw <- OStatus.get_cw(entry),
|
cw <- OStatus.get_cw(entry),
|
||||||
inReplyTo <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
|
in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
|
||||||
inReplyToActivity <- fetch_replied_to_activity(entry, inReplyTo),
|
in_reply_to_activity <- fetch_replied_to_activity(entry, in_reply_to),
|
||||||
inReplyTo <- (inReplyToActivity && inReplyToActivity.data["object"]["id"]) || inReplyTo,
|
in_reply_to <-
|
||||||
|
(in_reply_to_activity && in_reply_to_activity.data["object"]["id"]) || in_reply_to,
|
||||||
attachments <- OStatus.get_attachments(entry),
|
attachments <- OStatus.get_attachments(entry),
|
||||||
context <- get_context(entry, inReplyTo),
|
context <- get_context(entry, in_reply_to),
|
||||||
tags <- OStatus.get_tags(entry),
|
tags <- OStatus.get_tags(entry),
|
||||||
mentions <- get_mentions(entry),
|
mentions <- get_mentions(entry),
|
||||||
to <- make_to_list(actor, mentions),
|
to <- make_to_list(actor, mentions),
|
||||||
|
|
@ -128,7 +130,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
context,
|
context,
|
||||||
content_html,
|
content_html,
|
||||||
attachments,
|
attachments,
|
||||||
inReplyToActivity,
|
in_reply_to_activity,
|
||||||
[],
|
[],
|
||||||
cw
|
cw
|
||||||
),
|
),
|
||||||
|
|
@ -140,8 +142,8 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
|
||||||
# TODO: Handle this case in make_note_data
|
# TODO: Handle this case in make_note_data
|
||||||
note <-
|
note <-
|
||||||
if(
|
if(
|
||||||
inReplyTo && !inReplyToActivity,
|
in_reply_to && !in_reply_to_activity,
|
||||||
do: note |> Map.put("inReplyTo", inReplyTo),
|
do: note |> Map.put("inReplyTo", in_reply_to),
|
||||||
else: note
|
else: note
|
||||||
) do
|
) do
|
||||||
ActivityPub.create(%{
|
ActivityPub.create(%{
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.OStatus.UnfollowHandler do
|
defmodule Pleroma.Web.OStatus.UnfollowHandler do
|
||||||
alias Pleroma.Web.XML
|
|
||||||
alias Pleroma.Web.OStatus
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.OStatus
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
def handle(entry, doc) do
|
def handle(entry, doc) do
|
||||||
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
|
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,19 @@ defmodule Pleroma.Web.OStatus do
|
||||||
import Pleroma.Web.XML
|
import Pleroma.Web.XML
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Activity
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
alias Pleroma.Web.OStatus.DeleteHandler
|
||||||
|
alias Pleroma.Web.OStatus.FollowHandler
|
||||||
|
alias Pleroma.Web.OStatus.NoteHandler
|
||||||
|
alias Pleroma.Web.OStatus.UnfollowHandler
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.WebFinger
|
||||||
alias Pleroma.Web.Websub
|
alias Pleroma.Web.Websub
|
||||||
alias Pleroma.Web.OStatus.FollowHandler
|
|
||||||
alias Pleroma.Web.OStatus.UnfollowHandler
|
|
||||||
alias Pleroma.Web.OStatus.NoteHandler
|
|
||||||
alias Pleroma.Web.OStatus.DeleteHandler
|
|
||||||
|
|
||||||
def is_representable?(%Activity{data: data}) do
|
def is_representable?(%Activity{data: data}) do
|
||||||
object = Object.normalize(data["object"])
|
object = Object.normalize(data["object"])
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPubController
|
alias Pleroma.Web.ActivityPub.ActivityPubController
|
||||||
alias Pleroma.Web.ActivityPub.ObjectView
|
alias Pleroma.Web.ActivityPub.ObjectView
|
||||||
alias Pleroma.Web.OStatus.ActivityRepresenter
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
alias Pleroma.Web.OStatus.FeedRepresenter
|
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
alias Pleroma.Web.OStatus
|
alias Pleroma.Web.OStatus
|
||||||
|
alias Pleroma.Web.OStatus.ActivityRepresenter
|
||||||
|
alias Pleroma.Web.OStatus.FeedRepresenter
|
||||||
alias Pleroma.Web.XML
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
|
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
defmodule Pleroma.Web.Push.Impl do
|
defmodule Pleroma.Web.Push.Impl do
|
||||||
@moduledoc "The module represents implementation push web notification"
|
@moduledoc "The module represents implementation push web notification"
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Activity
|
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Web.Push.Subscription
|
|
||||||
alias Pleroma.Web.Metadata.Utils
|
alias Pleroma.Web.Metadata.Utils
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Web.Push.Subscription
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ defmodule Pleroma.Web.Push do
|
||||||
# Client API #
|
# Client API #
|
||||||
##############
|
##############
|
||||||
|
|
||||||
def start_link() do
|
def start_link do
|
||||||
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
|
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
def vapid_config() do
|
def vapid_config do
|
||||||
Application.get_env(:web_push_encryption, :vapid_details, [])
|
Application.get_env(:web_push_encryption, :vapid_details, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled() do
|
def enabled do
|
||||||
case vapid_config() do
|
case vapid_config() do
|
||||||
[] -> false
|
[] -> false
|
||||||
list when is_list(list) -> true
|
list when is_list(list) -> true
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ defmodule Pleroma.Web.Push.Subscription do
|
||||||
end
|
end
|
||||||
|
|
||||||
# Some webpush clients (e.g. iOS Toot!) use an non urlsafe base64 as an encoding for the key.
|
# 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
|
# However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library
|
||||||
# requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
|
# we use requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
|
||||||
defp ensure_base64_urlsafe(string) do
|
defp ensure_base64_urlsafe(string) do
|
||||||
string
|
string
|
||||||
|> String.replace("+", "-")
|
|> String.replace("+", "-")
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.RichMedia.Helpers do
|
defmodule Pleroma.Web.RichMedia.Helpers do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.RichMedia.Parser
|
alias Pleroma.Web.RichMedia.Parser
|
||||||
|
|
||||||
defp validate_page_url(page_url) when is_binary(page_url) do
|
defp validate_page_url(page_url) when is_binary(page_url) do
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,12 @@ defmodule Pleroma.Web.Router do
|
||||||
post("/blocks_import", UtilController, :blocks_import)
|
post("/blocks_import", UtilController, :blocks_import)
|
||||||
post("/follow_import", UtilController, :follow_import)
|
post("/follow_import", UtilController, :follow_import)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope [] do
|
||||||
|
pipe_through(:oauth_read)
|
||||||
|
|
||||||
|
post("/notifications/read", UtilController, :notifications_read)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/oauth", Pleroma.Web.OAuth do
|
scope "/oauth", Pleroma.Web.OAuth do
|
||||||
|
|
@ -631,8 +637,8 @@ end
|
||||||
|
|
||||||
defmodule Fallback.RedirectController do
|
defmodule Fallback.RedirectController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
alias Pleroma.Web.Metadata
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.Metadata
|
||||||
|
|
||||||
def redirector(conn, _params, code \\ 200) do
|
def redirector(conn, _params, code \\ 200) do
|
||||||
conn
|
conn
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ defmodule Pleroma.Web.Salmon do
|
||||||
|
|
||||||
alias Pleroma.Instances
|
alias Pleroma.Instances
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.XML
|
|
||||||
alias Pleroma.Web.OStatus.ActivityRepresenter
|
alias Pleroma.Web.OStatus.ActivityRepresenter
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
require Logger
|
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
|
# 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.
|
# We try at compile time to generate natively an RSA key otherwise we fallback on the old way.
|
||||||
try do
|
try do
|
||||||
_ = :public_key.generate_key({:rsa, 2048, 65537})
|
_ = :public_key.generate_key({:rsa, 2048, 65_537})
|
||||||
|
|
||||||
def generate_rsa_pem do
|
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)
|
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
|
||||||
pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
|
pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
|
||||||
{:ok, pem}
|
{:ok, pem}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,14 @@
|
||||||
defmodule Pleroma.Web.Streamer do
|
defmodule Pleroma.Web.Streamer do
|
||||||
use GenServer
|
use GenServer
|
||||||
require Logger
|
require Logger
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Notification
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||||
|
|
||||||
@keepalive_interval :timer.seconds(30)
|
@keepalive_interval :timer.seconds(30)
|
||||||
|
|
||||||
|
|
@ -106,10 +108,10 @@ defmodule Pleroma.Web.Streamer do
|
||||||
%{
|
%{
|
||||||
event: "notification",
|
event: "notification",
|
||||||
payload:
|
payload:
|
||||||
Pleroma.Web.MastodonAPI.MastodonAPIController.render_notification(
|
NotificationView.render("show.json", %{
|
||||||
socket.assigns["user"],
|
notification: item,
|
||||||
item
|
for: socket.assigns["user"]
|
||||||
)
|
})
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
}
|
}
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|
|
@ -198,10 +200,12 @@ defmodule Pleroma.Web.Streamer do
|
||||||
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
||||||
blocks = user.info.blocks || []
|
blocks = user.info.blocks || []
|
||||||
mutes = user.info.mutes || []
|
mutes = user.info.mutes || []
|
||||||
|
reblog_mutes = user.info.muted_reblogs || []
|
||||||
|
|
||||||
parent = Object.normalize(item.data["object"])
|
parent = Object.normalize(item.data["object"])
|
||||||
|
|
||||||
unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
|
unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
|
||||||
|
item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or
|
||||||
parent.data["actor"] in blocks or parent.data["actor"] in mutes do
|
parent.data["actor"] in blocks or parent.data["actor"] in mutes do
|
||||||
send(socket.transport_pid, {:text, represent_update(item, user)})
|
send(socket.transport_pid, {:text, represent_update(item, user)})
|
||||||
end
|
end
|
||||||
|
|
@ -232,7 +236,8 @@ defmodule Pleroma.Web.Streamer do
|
||||||
blocks = user.info.blocks || []
|
blocks = user.info.blocks || []
|
||||||
mutes = user.info.mutes || []
|
mutes = user.info.mutes || []
|
||||||
|
|
||||||
unless item.actor in blocks or item.actor in mutes do
|
unless item.actor in blocks or item.actor in mutes or
|
||||||
|
not ActivityPub.contain_activity(item, user) do
|
||||||
send(socket.transport_pid, {:text, represent_update(item, user)})
|
send(socket.transport_pid, {:text, represent_update(item, user)})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
||||||
|
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
alias Pleroma.Emoji
|
alias Pleroma.Emoji
|
||||||
|
alias Pleroma.Notification
|
||||||
alias Pleroma.PasswordResetToken
|
alias Pleroma.PasswordResetToken
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.OStatus
|
alias Pleroma.Web.OStatus
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.WebFinger
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
|
|
||||||
def show_password_reset(conn, %{"token" => token}) do
|
def show_password_reset(conn, %{"token" => token}) do
|
||||||
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
|
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
|
||||||
|
|
@ -142,6 +143,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
|
||||||
|
with {:ok, _} <- Notification.read_one(user, notification_id) do
|
||||||
|
json(conn, %{status: "success"})
|
||||||
|
else
|
||||||
|
{:error, message} ->
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type("application/json")
|
||||||
|
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def config(conn, _params) do
|
def config(conn, _params) do
|
||||||
instance = Pleroma.Config.get(:instance)
|
instance = Pleroma.Config.get(:instance)
|
||||||
instance_fe = Pleroma.Config.get(:fe)
|
instance_fe = Pleroma.Config.get(:fe)
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
alias Pleroma.UserInviteToken
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Repo
|
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.UserEmail
|
|
||||||
alias Pleroma.Mailer
|
alias Pleroma.Mailer
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.UserEmail
|
||||||
|
alias Pleroma.UserInviteToken
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.TwitterAPI.UserView
|
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
|
@ -35,11 +35,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
|
|
||||||
def unfollow(%User{} = follower, params) do
|
def unfollow(%User{} = follower, params) do
|
||||||
with {:ok, %User{} = unfollowed} <- get_user(params),
|
with {:ok, %User{} = unfollowed} <- get_user(params),
|
||||||
{:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed),
|
{:ok, follower} <- CommonAPI.unfollow(follower, unfollowed) do
|
||||||
{:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed) do
|
|
||||||
{:ok, follower, unfollowed}
|
{:ok, follower, unfollowed}
|
||||||
else
|
|
||||||
err -> err
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -133,7 +130,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
end
|
end
|
||||||
|
|
||||||
def register_user(params) do
|
def register_user(params) do
|
||||||
tokenString = params["token"]
|
token_string = params["token"]
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
nickname: params["nickname"],
|
nickname: params["nickname"],
|
||||||
|
|
@ -170,8 +167,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
|
|
||||||
# no need to query DB if registration is open
|
# no need to query DB if registration is open
|
||||||
token =
|
token =
|
||||||
unless registrations_open || is_nil(tokenString) do
|
unless registrations_open || is_nil(token_string) do
|
||||||
Repo.get_by(UserInviteToken, %{token: tokenString})
|
Repo.get_by(UserInviteToken, %{token: token_string})
|
||||||
end
|
end
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,20 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||||
|
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView, TokenView}
|
|
||||||
alias Pleroma.Web.CommonAPI
|
|
||||||
alias Pleroma.{Repo, Activity, Object, User, Notification}
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
|
||||||
alias Pleroma.Web.CommonAPI
|
|
||||||
alias Pleroma.Web.TwitterAPI.ActivityView
|
|
||||||
alias Pleroma.Web.TwitterAPI.NotificationView
|
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
|
||||||
alias Pleroma.Web.TwitterAPI.UserView
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Object
|
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
alias Pleroma.Web.TwitterAPI.ActivityView
|
||||||
|
alias Pleroma.Web.TwitterAPI.NotificationView
|
||||||
|
alias Pleroma.Web.TwitterAPI.TokenView
|
||||||
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
@ -590,16 +587,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
|
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
|
||||||
with followed <- conn.assigns[:user],
|
with followed <- conn.assigns[:user],
|
||||||
%User{} = follower <- Repo.get(User, uid),
|
%User{} = follower <- Repo.get(User, uid),
|
||||||
{:ok, follower} <- User.maybe_follow(follower, followed),
|
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
|
||||||
%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
|
|
||||||
conn
|
conn
|
||||||
|> put_view(UserView)
|
|> put_view(UserView)
|
||||||
|> render("show.json", %{user: follower, for: followed})
|
|> render("show.json", %{user: follower, for: followed})
|
||||||
|
|
@ -611,15 +599,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
|
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
|
||||||
with followed <- conn.assigns[:user],
|
with followed <- conn.assigns[:user],
|
||||||
%User{} = follower <- Repo.get(User, uid),
|
%User{} = follower <- Repo.get(User, uid),
|
||||||
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
|
||||||
{: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
|
|
||||||
conn
|
conn
|
||||||
|> put_view(UserView)
|
|> put_view(UserView)
|
||||||
|> render("show.json", %{user: follower, for: followed})
|
|> render("show.json", %{user: follower, for: followed})
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue