diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e6bce31..f689160e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] ### Added +- Optional SSH access mode. (Needs `erlang-ssh` package on some distributions). +- [MongooseIM](https://github.com/esl/MongooseIM) http authentication support. - LDAP authentication - External OAuth provider authentication - A [job queue](https://git.pleroma.social/pleroma/pleroma_job_queue) for federation, emails, web push, etc. @@ -39,6 +41,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Metadata: RelMe provider - OAuth: added support for refresh tokens - Emoji packs and emoji pack manager +- Object pruning (`mix pleroma.database prune_objects`) +- OAuth: added job to clean expired access tokens +- MRF: Support for rejecting reports from specific instances (`mrf_simple`) +- MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`) ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer @@ -73,6 +79,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Don't ship finmoji by default, they can be installed as an emoji pack - Hide deactivated users and their statuses - Posts which are marked sensitive or tagged nsfw no longer have link previews. +- HTTP connection timeout is now set to 10 seconds. +- Respond with a 404 Not implemented JSON error message when requested API is not implemented ### Fixed - Added an FTS index on objects. Running `vacuum analyze` and setting a larger `work_mem` is recommended. @@ -105,6 +113,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Exposing default scope of the user to anyone - Mastodon API: Make `irreversible` field default to `false` [`POST /api/v1/filters`] - User-Agent is now sent correctly for all HTTP requests. +- MRF: Simple policy now properly delists imported or relayed statuses ## Removed - Configuration: `config :pleroma, :fe` in favor of the more flexible `config :pleroma, :frontend_configurations` diff --git a/config/config.exs b/config/config.exs index 72908266d..68168b279 100644 --- a/config/config.exs +++ b/config/config.exs @@ -184,9 +184,6 @@ config :mime, :types, %{ "application/ld+json" => ["activity+json"] } -config :pleroma, :websub, Pleroma.Web.Websub -config :pleroma, :ostatus, Pleroma.Web.OStatus -config :pleroma, :httpoison, Pleroma.HTTP config :tesla, adapter: Tesla.Adapter.Hackney # Configures http settings, upstream proxy etc. @@ -239,7 +236,8 @@ config :pleroma, :instance, welcome_message: nil, max_report_comment_size: 1000, safe_dm_mentions: false, - healthcheck: false + healthcheck: false, + remote_post_retention_days: 90 config :pleroma, :app_account_creation, enabled: true, max_requests: 25, interval: 1800 @@ -313,7 +311,9 @@ config :pleroma, :mrf_simple, federated_timeline_removal: [], report_removal: [], reject: [], - accept: [] + accept: [], + avatar_removal: [], + banner_removal: [] config :pleroma, :mrf_keyword, reject: [], @@ -384,6 +384,7 @@ config :pleroma, Pleroma.User, "activities", "api", "auth", + "check_password", "dev", "friend-requests", "inbox", @@ -404,6 +405,7 @@ config :pleroma, Pleroma.User, "status", "tag", "user-search", + "user_exists", "users", "web" ] @@ -478,7 +480,9 @@ config :pleroma, Pleroma.ScheduledActivity, config :pleroma, :oauth2, token_expires_in: 600, - issue_new_refresh_token: true + issue_new_refresh_token: true, + clean_expired_tokens: false, + clean_expired_tokens_interval: 86_400_000 config :pleroma, :database, rum_enabled: false diff --git a/config/test.exs b/config/test.exs index 6100989c4..41cddb9bd 100644 --- a/config/test.exs +++ b/config/test.exs @@ -39,8 +39,6 @@ config :pleroma, Pleroma.Repo, # Reduce hash rounds for testing config :pbkdf2_elixir, rounds: 1 -config :pleroma, :websub, Pleroma.Web.WebsubMock -config :pleroma, :ostatus, Pleroma.Web.OStatusMock config :tesla, adapter: Tesla.Mock config :pleroma, :rich_media, enabled: false diff --git a/docs/config.md b/docs/config.md index 197326bbd..67b062fe9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -104,6 +104,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `max_report_comment_size`: The maximum size of the report comment (Default: `1000`) * `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). (Default: `false`) * `healthcheck`: if set to true, system data will be shown on ``/api/pleroma/healthcheck``. +* `remote_post_retention_days`: the default amount of days to retain remote posts when pruning the database ## :app_account_creation REST API for creating an account settings @@ -219,6 +220,9 @@ relates to mascots on the mastodon frontend * `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline * `reject`: List of instances to reject any activities from * `accept`: List of instances to accept any activities from +* `report_removal`: List of instances to reject reports from +* `avatar_removal`: List of instances to strip avatars from +* `banner_removal`: List of instances to strip banners from ## :mrf_rejectnonpublic * `allow_followersonly`: whether to allow followers-only posts @@ -477,7 +481,7 @@ config :esshd, password_authenticator: "Pleroma.BBS.Authenticator" ``` -Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT` +Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT` ## :auth @@ -549,6 +553,8 @@ Configure OAuth 2 provider capabilities: * `token_expires_in` - The lifetime in seconds of the access token. * `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token. +* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. +* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours). ## :emoji * `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]` diff --git a/docs/config/howto_mongooseim.md b/docs/config/howto_mongooseim.md new file mode 100644 index 000000000..a33e590a1 --- /dev/null +++ b/docs/config/howto_mongooseim.md @@ -0,0 +1,10 @@ +# Configuring MongooseIM (XMPP Server) to use Pleroma for authentication + +If you want to give your Pleroma users an XMPP (chat) account, you can configure [MongooseIM](https://github.com/esl/MongooseIM) to use your Pleroma server for user authentication, automatically giving every local user an XMPP account. + +In general, you just have to follow the configuration described at [https://mongooseim.readthedocs.io/en/latest/authentication-backends/HTTP-authentication-module/](https://mongooseim.readthedocs.io/en/latest/authentication-backends/HTTP-authentication-module/) and do these changes to your mongooseim.cfg. + +1. Set the auth_method to `{auth_method, http}`. +2. Add the http auth pool like this: `{http, global, auth, [{workers, 50}], [{server, "https://yourpleromainstance.com"}]}` + +Restart your MongooseIM server, your users should now be able to connect with their Pleroma credentials. diff --git a/installation/caddyfile-pleroma.example b/installation/caddyfile-pleroma.example index fcf76718e..7985d9c67 100644 --- a/installation/caddyfile-pleroma.example +++ b/installation/caddyfile-pleroma.example @@ -10,7 +10,9 @@ example.tld { gzip - proxy / localhost:4000 { + # this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only + # and `localhost.` resolves to [::0] on some systems: see issue #930 + proxy / 127.0.0.1:4000 { websocket transparent } diff --git a/installation/pleroma-apache.conf b/installation/pleroma-apache.conf index 2beb7c4cc..b5640ac3d 100644 --- a/installation/pleroma-apache.conf +++ b/installation/pleroma-apache.conf @@ -58,8 +58,10 @@ CustomLog ${APACHE_LOG_DIR}/access.log combined RewriteRule /(.*) ws://localhost:4000/$1 [P,L] ProxyRequests off - ProxyPass / http://localhost:4000/ - ProxyPassReverse / http://localhost:4000/ + # this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only + # and `localhost.` resolves to [::0] on some systems: see issue #930 + ProxyPass / http://127.0.0.1:4000/ + ProxyPassReverse / http://127.0.0.1:4000/ RequestHeader set Host ${servername} ProxyPreserveHost On diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx index cc75d78b2..7425da33f 100644 --- a/installation/pleroma.nginx +++ b/installation/pleroma.nginx @@ -69,7 +69,9 @@ server { proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; - proxy_pass http://localhost:4000; + # this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only + # and `localhost.` resolves to [::0] on some systems: see issue #930 + proxy_pass http://127.0.0.1:4000; client_max_body_size 16m; } diff --git a/installation/pleroma.vcl b/installation/pleroma.vcl index 92153d8ef..154747aa6 100644 --- a/installation/pleroma.vcl +++ b/installation/pleroma.vcl @@ -1,4 +1,4 @@ -vcl 4.0; +vcl 4.1; import std; backend default { @@ -35,24 +35,6 @@ sub vcl_recv { } return(purge); } - - # Pleroma MediaProxy - strip headers that will affect caching - if (req.url ~ "^/proxy/") { - unset req.http.Cookie; - unset req.http.Authorization; - unset req.http.Accept; - return (hash); - } - - # Strip headers that will affect caching from all other static content - # This also permits caching of individual toots and AP Activities - if ((req.url ~ "^/(media|static)/") || - (req.url ~ "(?i)\.(html|js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|mp4|ogg|webm|svg|swf|ttf|pdf|woff|woff2)$")) - { - unset req.http.Cookie; - unset req.http.Authorization; - return (hash); - } } sub vcl_backend_response { @@ -61,6 +43,12 @@ sub vcl_backend_response { set beresp.do_gzip = true; } + # Retry broken backend responses. + if (beresp.status == 503) { + set bereq.http.X-Varnish-Backend-503 = "1"; + return (retry); + } + # CHUNKED SUPPORT if (bereq.http.x-range ~ "bytes=" && beresp.status == 206) { set beresp.ttl = 10m; @@ -73,8 +61,6 @@ sub vcl_backend_response { return (deliver); } - # Default object caching of 86400s; - set beresp.ttl = 86400s; # Allow serving cached content for 6h in case backend goes down set beresp.grace = 6h; @@ -90,20 +76,6 @@ sub vcl_backend_response { set beresp.ttl = 30s; return (deliver); } - - # Pleroma MediaProxy internally sets headers properly - if (bereq.url ~ "^/proxy/") { - return (deliver); - } - - # Strip cache-restricting headers from Pleroma on static content that we want to cache - if (bereq.url ~ "(?i)\.(js|css|jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|mp4|ogg|webm|svg|swf|ttf|pdf|woff|woff2)$") - { - unset beresp.http.set-cookie; - unset beresp.http.Cache-Control; - unset beresp.http.x-request-id; - set beresp.http.Cache-Control = "public, max-age=86400"; - } } # The synthetic response for 301 redirects @@ -132,10 +104,32 @@ sub vcl_hash { } sub vcl_backend_fetch { + # Be more lenient for slow servers on the fediverse + if bereq.url ~ "^/proxy/" { + set bereq.first_byte_timeout = 300s; + } + # CHUNKED SUPPORT if (bereq.http.x-range) { set bereq.http.Range = bereq.http.x-range; } + + if (bereq.retries == 0) { + # Clean up the X-Varnish-Backend-503 flag that is used internally + # to mark broken backend responses that should be retried. + unset bereq.http.X-Varnish-Backend-503; + } else { + if (bereq.http.X-Varnish-Backend-503) { + if (bereq.method != "POST" && + std.healthy(bereq.backend) && + bereq.retries <= 4) { + # Flush broken backend response flag & try again. + unset bereq.http.X-Varnish-Backend-503; + } else { + return (abandon); + } + } + } } sub vcl_deliver { @@ -145,3 +139,9 @@ sub vcl_deliver { unset resp.http.CR; } } + +sub vcl_backend_error { + # Retry broken backend responses. + set bereq.http.X-Varnish-Backend-503 = "1"; + return (retry); +} diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index f650b447d..4d480ac3f 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -5,6 +5,7 @@ defmodule Mix.Tasks.Pleroma.Database do alias Mix.Tasks.Pleroma.Common alias Pleroma.Conversation + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User require Logger @@ -23,6 +24,10 @@ defmodule Mix.Tasks.Pleroma.Database do Options: - `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references + ## Prune old objects from the database + + mix pleroma.database prune_objects + ## Create a conversation for all existing DMs. Can be safely re-run. mix pleroma.database bump_all_conversations @@ -72,4 +77,46 @@ defmodule Mix.Tasks.Pleroma.Database do Enum.each(users, &User.remove_duplicated_following/1) Enum.each(users, &User.update_follower_count/1) end + + def run(["prune_objects" | args]) do + import Ecto.Query + + {options, [], []} = + OptionParser.parse( + args, + strict: [ + vacuum: :boolean + ] + ) + + Common.start_pleroma() + + deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + + Logger.info("Pruning objects older than #{deadline} days") + + time_deadline = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-(deadline * 86_400)) + + public = "https://www.w3.org/ns/activitystreams#Public" + + from(o in Object, + where: fragment("?->'to' \\? ? OR ?->'cc' \\? ?", o.data, ^public, o.data, ^public), + where: o.inserted_at < ^time_deadline, + where: + fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host()) + ) + |> Repo.delete_all(timeout: :infinity) + + if Keyword.get(options, :vacuum) do + Logger.info("Runnning VACUUM FULL") + + Repo.query!( + "vacuum full;", + [], + timeout: :infinity + ) + end + end end diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 4e54b15ba..99589590c 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Activity do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ThreadMute alias Pleroma.User import Ecto.Changeset @@ -37,6 +38,7 @@ defmodule Pleroma.Activity do field(:local, :boolean, default: true) field(:actor, :string) field(:recipients, {:array, :string}, default: []) + field(:thread_muted?, :boolean, virtual: true) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) has_many(:notifications, Notification, on_delete: :delete_all) @@ -90,6 +92,16 @@ defmodule Pleroma.Activity do def with_preloaded_bookmark(query, _), do: query + def with_set_thread_muted_field(query, %User{} = user) do + from([a] in query, + left_join: tm in ThreadMute, + on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data), + select: %Activity{a | thread_muted?: not is_nil(tm.id)} + ) + end + + def with_set_thread_muted_field(query, _), do: query + def get_by_ap_id(ap_id) do Repo.one( from( diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index eeb415084..76df3945e 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -110,6 +110,7 @@ defmodule Pleroma.Application do hackney_pool_children() ++ [ worker(Pleroma.Web.Federator.RetryQueue, []), + worker(Pleroma.Web.OAuth.Token.CleanWorker, []), worker(Pleroma.Stats, []), worker(Task, [&Pleroma.Web.Push.init/0], restart: :temporary, id: :web_push_init), worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary, id: :federator_init) @@ -131,19 +132,22 @@ defmodule Pleroma.Application do defp setup_instrumenters do require Prometheus.Registry - :ok = - :telemetry.attach( - "prometheus-ecto", - [:pleroma, :repo, :query], - &Pleroma.Repo.Instrumenter.handle_event/4, - %{} - ) + if Application.get_env(:prometheus, Pleroma.Repo.Instrumenter) do + :ok = + :telemetry.attach( + "prometheus-ecto", + [:pleroma, :repo, :query], + &Pleroma.Repo.Instrumenter.handle_event/4, + %{} + ) + + Pleroma.Repo.Instrumenter.setup() + end Prometheus.Registry.register_collector(:prometheus_process_collector) Pleroma.Web.Endpoint.MetricsExporter.setup() Pleroma.Web.Endpoint.PipelineInstrumenter.setup() Pleroma.Web.Endpoint.Instrumenter.setup() - Pleroma.Repo.Instrumenter.setup() end def enabled_hackney_pools do diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 3d7c36d21..607843a5b 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Formatter do alias Pleroma.User alias Pleroma.Web.MediaProxy - @safe_mention_regex ~r/^(\s*(?@.+?\s+)+)(?.*)/ + @safe_mention_regex ~r/^(\s*(?(@.+?\s+){1,})+)(?.*)/s @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/ diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index c0173465a..c216cdcb1 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -8,7 +8,7 @@ defmodule Pleroma.HTTP.Connection do """ @hackney_options [ - connect_timeout: 2_000, + connect_timeout: 10_000, recv_timeout: 20_000, follow_redirect: true, pool: :federation @@ -32,9 +32,11 @@ defmodule Pleroma.HTTP.Connection do defp hackney_options(opts) do options = Keyword.get(opts, :adapter, []) adapter_options = Pleroma.Config.get([:http, :adapter], []) + proxy_url = Pleroma.Config.get([:http, :proxy_url], nil) @hackney_options |> Keyword.merge(adapter_options) |> Keyword.merge(options) + |> Keyword.merge(proxy: proxy_url) end end diff --git a/lib/pleroma/keys.ex b/lib/pleroma/keys.ex new file mode 100644 index 000000000..b7bc7a4da --- /dev/null +++ b/lib/pleroma/keys.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Keys do + # Native generation of RSA keys is only available since OTP 20+ and in default build conditions + # We try at compile time to generate natively an RSA key otherwise we fallback on the old way. + try do + _ = :public_key.generate_key({:rsa, 2048, 65_537}) + + def generate_rsa_pem do + key = :public_key.generate_key({:rsa, 2048, 65_537}) + entry = :public_key.pem_entry_encode(:RSAPrivateKey, key) + pem = :public_key.pem_encode([entry]) |> String.trim_trailing() + {:ok, pem} + end + rescue + _ -> + def generate_rsa_pem do + port = Port.open({:spawn, "openssl genrsa"}, [:binary]) + + {:ok, pem} = + receive do + {^port, {:data, pem}} -> {:ok, pem} + end + + Port.close(port) + + if Regex.match?(~r/RSA PRIVATE KEY/, pem) do + {:ok, pem} + else + :error + end + end + end + + def keys_from_pem(pem) do + [private_key_code] = :public_key.pem_decode(pem) + private_key = :public_key.pem_entry_decode(private_key_code) + {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key + public_key = {:RSAPublicKey, modulus, exponent} + {:ok, private_key, public_key} + end +end diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 740d687a3..cc6fc9c5d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -130,6 +130,13 @@ defmodule Pleroma.Object do end end + def prune(%Object{data: %{"id" => id}} = object) do + with {:ok, object} <- Repo.delete(object), + {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do + {:ok, object} + end + end + def set_cache(%Object{data: %{"id" => ap_id}} = object) do Cachex.put(:object_cache, "object:#{ap_id}", object) {:ok, object} diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 8d4bcc95e..ca980c629 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -1,4 +1,5 @@ defmodule Pleroma.Object.Fetcher do + alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Object.Containment alias Pleroma.Web.ActivityPub.Transmogrifier @@ -6,7 +7,18 @@ defmodule Pleroma.Object.Fetcher do require Logger - @httpoison Application.get_env(:pleroma, :httpoison) + defp reinject_object(data) do + Logger.debug("Reinjecting object #{data["id"]}") + + with data <- Transmogrifier.fix_object(data), + {:ok, object} <- Object.create(data) do + {:ok, object} + else + e -> + Logger.error("Error while processing object: #{inspect(e)}") + {:error, e} + end + end # TODO: # This will create a Create activity, which we need internally at the moment. @@ -26,12 +38,17 @@ defmodule Pleroma.Object.Fetcher do "object" => data }, :ok <- Containment.contain_origin(id, params), - {:ok, activity} <- Transmogrifier.handle_incoming(params) do - {:ok, Object.normalize(activity, false)} + {:ok, activity} <- Transmogrifier.handle_incoming(params), + {:object, _data, %Object{} = object} <- + {:object, data, Object.normalize(activity, false)} do + {:ok, object} else {:error, {:reject, nil}} -> {:reject, nil} + {:object, data, nil} -> + reinject_object(data) + object = %Object{} -> {:ok, object} @@ -60,7 +77,7 @@ defmodule Pleroma.Object.Fetcher do with true <- String.starts_with?(id, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- - @httpoison.get( + HTTP.get( id, [{:Accept, "application/activity+json"}] ), diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index a3f177fec..6e5feb4c3 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ReverseProxy do + alias Pleroma.HTTP + @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) @@ -60,7 +62,6 @@ defmodule Pleroma.ReverseProxy do """ @hackney Application.get_env(:pleroma, :hackney, :hackney) - @httpoison Application.get_env(:pleroma, :httpoison, HTTPoison) @default_hackney_options [] @@ -97,7 +98,7 @@ defmodule Pleroma.ReverseProxy do hackney_opts = @default_hackney_options |> Keyword.merge(Keyword.get(opts, :http, [])) - |> @httpoison.process_request_options() + |> HTTP.process_request_options() req_headers = build_req_headers(conn.req_headers, opts) diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index b7ecf00a0..1a4d54c62 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -5,11 +5,10 @@ defmodule Pleroma.Signature do @behaviour HTTPSignatures.Adapter + alias Pleroma.Keys alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.Salmon - alias Pleroma.Web.WebFinger def fetch_public_key(conn) do with actor_id <- Utils.get_ap_id(conn.params["actor"]), @@ -33,8 +32,8 @@ defmodule Pleroma.Signature do end def sign(%User{} = user, headers) do - with {:ok, %{info: %{keys: keys}}} <- WebFinger.ensure_keys_present(user), - {:ok, private_key, _} <- Salmon.keys_from_pem(keys) do + with {:ok, %{info: %{keys: keys}}} <- User.ensure_keys_present(user), + {:ok, private_key, _} <- Keys.keys_from_pem(keys) do HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers) end end diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex index 190ed9f3a..237544337 100644 --- a/lib/pleroma/uploaders/mdii.ex +++ b/lib/pleroma/uploaders/mdii.ex @@ -4,11 +4,10 @@ defmodule Pleroma.Uploaders.MDII do alias Pleroma.Config + alias Pleroma.HTTP @behaviour Pleroma.Uploaders.Uploader - @httpoison Application.get_env(:pleroma, :httpoison) - # MDII-hosted images are never passed through the MediaPlug; only local media. # Delegate to Pleroma.Uploaders.Local def get_file(file) do @@ -25,7 +24,7 @@ defmodule Pleroma.Uploaders.MDII do query = "#{cgi}?#{extension}" with {:ok, %{status: 200, body: body}} <- - @httpoison.post(query, file_data, [], adapter: [pool: :default]) do + HTTP.post(query, file_data, [], adapter: [pool: :default]) do remote_file_name = String.split(body) |> List.first() public_url = "#{files}/#{remote_file_name}.#{extension}" {:ok, {:url, public_url}} diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 05fe58f7c..653dec95f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -10,6 +10,7 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity + alias Pleroma.Keys alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -1422,4 +1423,24 @@ defmodule Pleroma.User do } } end + + def ensure_keys_present(user) do + info = user.info + + if info.keys do + {:ok, user} + else + {:ok, pem} = Keys.generate_rsa_pem() + + info_cng = + info + |> User.Info.set_keys(pem) + + cng = + Ecto.Changeset.change(user) + |> Ecto.Changeset.put_embed(:info, info_cng) + + update_and_set_cache(cng) + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5c3156978..aa0229db7 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -834,6 +834,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_preloaded_bookmark(opts["user"]) end + defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query + + defp maybe_set_thread_muted_field(query, opts) do + query + |> Activity.with_set_thread_muted_field(opts["user"]) + end + defp maybe_order(query, %{order: :desc}) do query |> order_by(desc: :id) @@ -852,6 +859,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do base_query |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) + |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) |> restrict_recipients(recipients, opts["user"]) |> restrict_tag(opts) @@ -901,7 +909,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def user_data_from_user_object(data) do + defp object_to_user_data(data) do avatar = data["icon"]["url"] && %{ @@ -948,9 +956,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, user_data} end + def user_data_from_user_object(data) do + with {:ok, data} <- MRF.filter(data), + {:ok, data} <- object_to_user_data(data) do + {:ok, data} + else + e -> {:error, e} + end + end + def fetch_and_prepare_user_from_ap_id(ap_id) do - with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id) do - user_data_from_user_object(data) + with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), + {:ok, data} <- user_data_from_user_object(data) do + {:ok, data} else e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index c967ab7a9..ad2ca1e54 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def user(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("user.json", %{user: user})) @@ -106,7 +106,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def following(conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do {page, _} = Integer.parse(page) conn @@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def following(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("following.json", %{user: user})) @@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def followers(conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do {page, _} = Integer.parse(page) conn @@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def followers(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("followers.json", %{user: user})) @@ -146,7 +146,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def outbox(conn, %{"nickname" => nickname} = params) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]})) @@ -195,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def relay(conn, _params) do with %User{} = user <- Relay.get_actor(), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("user.json", %{user: user})) diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 7190652d2..433d23c5f 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -74,8 +74,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do actor_host ), user <- User.get_cached_by_ap_id(object["actor"]), - true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"], - true <- user.follower_address in object["cc"] do + true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do to = List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++ [user.follower_address] @@ -104,9 +103,29 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do defp check_report_removal(_actor_info, object), do: {:ok, object} + defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do + if actor_host in Pleroma.Config.get([:mrf_simple, :avatar_removal]) do + {:ok, Map.delete(object, "icon")} + else + {:ok, object} + end + end + + defp check_avatar_removal(_actor_info, object), do: {:ok, object} + + defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do + if actor_host in Pleroma.Config.get([:mrf_simple, :banner_removal]) do + {:ok, Map.delete(object, "image")} + else + {:ok, object} + end + end + + defp check_banner_removal(_actor_info, object), do: {:ok, object} + @impl true - def filter(object) do - actor_info = URI.parse(object["actor"]) + def filter(%{"actor" => actor} = object) do + actor_info = URI.parse(actor) with {:ok, object} <- check_accept(actor_info, object), {:ok, object} <- check_reject(actor_info, object), @@ -119,4 +138,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do _e -> {:reject, nil} end end + + def filter(%{"id" => actor, "type" => obj_type} = object) + when obj_type in ["Application", "Group", "Organization", "Person", "Service"] do + actor_info = URI.parse(actor) + + with {:ok, object} <- check_avatar_removal(actor_info, object), + {:ok, object} <- check_banner_removal(actor_info, object) do + {:ok, object} + else + _e -> {:reject, nil} + end + end + + def filter(object), do: {:ok, object} end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex index f5078d818..47663414a 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex @@ -19,10 +19,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do end @impl true - def filter(object) do - actor_info = URI.parse(object["actor"]) + def filter(%{"actor" => actor} = object) do + actor_info = URI.parse(actor) allow_list = Config.get([:mrf_user_allowlist, String.to_atom(actor_info.host)], []) filter_by_list(object, allow_list) end + + def filter(object), do: {:ok, object} end diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 11dba87de..8f1399ce6 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Activity alias Pleroma.Config + alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay @@ -16,8 +17,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do require Logger - @httpoison Application.get_env(:pleroma, :httpoison) - @moduledoc """ ActivityPub outgoing federation module. """ @@ -63,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do with {:ok, %{status: code}} when code in 200..299 <- result = - @httpoison.post( + HTTP.post( inbox, json, [ diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 1254fdf6c..327e0e05b 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do use Pleroma.Web, :view + alias Pleroma.Keys alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -12,8 +13,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Endpoint alias Pleroma.Web.Router.Helpers - alias Pleroma.Web.Salmon - alias Pleroma.Web.WebFinger import Ecto.Query @@ -34,8 +33,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do # the instance itself is not a Person, but instead an Application def render("user.json", %{user: %{nickname: nil} = user}) do - {:ok, user} = WebFinger.ensure_keys_present(user) - {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys) + {:ok, user} = User.ensure_keys_present(user) + {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) @@ -62,8 +61,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do end def render("user.json", %{user: user}) do - {:ok, user} = WebFinger.ensure_keys_present(user) - {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys) + {:ok, user} = User.ensure_keys_present(user) + {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 9ef30e885..8cd7a2270 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -16,17 +16,32 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.UploadedMedia) + @static_cache_control "public, no-cache" + # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well - plug(Pleroma.Plugs.InstanceStatic, at: "/") + # Cache-control headers are duplicated in case we turn off etags in the future + plug(Pleroma.Plugs.InstanceStatic, + at: "/", + gzip: true, + cache_control_for_etags: @static_cache_control, + headers: %{ + "cache-control" => @static_cache_control + } + ) plug( Plug.Static, at: "/", from: :pleroma, only: - ~w(index.html robots.txt 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 + gzip: true, + cache_control_for_etags: @static_cache_control, + headers: %{ + "cache-control" => @static_cache_control + } ) plug(Plug.Static.IndexHtml, at: "/pleroma/admin/") diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 169fdf4dc..f4c9fe284 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -11,14 +11,11 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue - alias Pleroma.Web.WebFinger + alias Pleroma.Web.OStatus alias Pleroma.Web.Websub require Logger - @websub Application.get_env(:pleroma, :websub) - @ostatus Application.get_env(:pleroma, :ostatus) - def init do # 1 minute Process.sleep(1000 * 60) @@ -77,9 +74,8 @@ defmodule Pleroma.Web.Federator do def perform(:publish, activity) do Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end) - with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do - {:ok, actor} = WebFinger.ensure_keys_present(actor) - + with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), + {:ok, actor} <- User.ensure_keys_present(actor) do Publisher.publish(actor, activity) end end @@ -89,12 +85,12 @@ defmodule Pleroma.Web.Federator do "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" end) - @websub.verify(websub) + Websub.verify(websub) end def perform(:incoming_doc, doc) do Logger.info("Got document, trying to parse") - @ostatus.handle_incoming(doc) + OStatus.handle_incoming(doc) end def perform(:incoming_ap_doc, params) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 1ec0f30a1..2110027c3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Filter alias Pleroma.Formatter + alias Pleroma.HTTP alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -55,7 +56,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do when action in [:account_register] ) - @httpoison Application.get_env(:pleroma, :httpoison) @local_mastodon_name "Mastodon-Local" action_fallback(:errors) @@ -1084,7 +1084,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do from([a, o] in Activity.with_preloaded_object(Activity), where: fragment("?->>'type' = 'Create'", a.data), where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, - limit: 20 + limit: 40 ) q = @@ -1691,7 +1691,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> String.replace("{{user}}", user) with {:ok, %{status: 200, body: body}} <- - @httpoison.get( + HTTP.get( url, [], adapter: [ diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 134c07b7e..b82d3319b 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -112,7 +112,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do fields: fields, bot: bot, source: %{ - note: "", + note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, pleroma: %{} }, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index c93d915e5..e55f9b96e 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -157,6 +157,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil + thread_muted? = + case activity.thread_muted? do + thread_muted? when is_boolean(thread_muted?) -> thread_muted? + nil -> CommonAPI.thread_muted?(user, activity) + end + attachment_data = object.data["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) @@ -228,7 +234,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do reblogged: reblogged?(activity, opts[:for]), favourited: present?(favorited), bookmarked: present?(bookmarked), - muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user), + muted: thread_muted? || User.mutes?(opts[:for], user), pinned: pinned?(activity, user), sensitive: sensitive, spoiler_text: summary_html, diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex new file mode 100644 index 000000000..489d5d3a5 --- /dev/null +++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MongooseIM.MongooseIMController do + use Pleroma.Web, :controller + alias Comeonin.Pbkdf2 + alias Pleroma.Repo + alias Pleroma.User + + def user_exists(conn, %{"user" => username}) do + with %User{} <- Repo.get_by(User, nickname: username, local: true) do + conn + |> json(true) + else + _ -> + conn + |> put_status(:not_found) + |> json(false) + end + end + + def check_password(conn, %{"user" => username, "pass" => password}) do + with %User{password_hash: password_hash} <- + Repo.get_by(User, nickname: username, local: true), + true <- Pbkdf2.checkpw(password, password_hash) do + conn + |> json(true) + else + false -> + conn + |> put_status(403) + |> json(false) + + _ -> + conn + |> put_status(:not_found) + |> json(false) + end + end +end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 3bf2a0fbc..45f90c579 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -12,8 +12,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.Federator.Publisher - plug(Pleroma.Web.FederatingPlug) - def schemas(conn, _params) do response = %{ links: [ diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 66c95c2e9..f412f7eb2 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.OAuth.Token do use Ecto.Schema - import Ecto.Query import Ecto.Changeset alias Pleroma.Repo @@ -13,6 +12,7 @@ defmodule Pleroma.Web.OAuth.Token do alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.OAuth.Token.Query @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) @type t :: %__MODULE__{} @@ -31,17 +31,17 @@ defmodule Pleroma.Web.OAuth.Token do @doc "Gets token for app by access token" @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} def get_by_token(%App{id: app_id} = _app, token) do - from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token) + Query.get_by_app(app_id) + |> Query.get_by_token(token) |> Repo.find_resource() end @doc "Gets token for app by refresh token" @spec get_by_refresh_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} def get_by_refresh_token(%App{id: app_id} = _app, token) do - from(t in __MODULE__, - where: t.app_id == ^app_id and t.refresh_token == ^token, - preload: [:user] - ) + Query.get_by_app(app_id) + |> Query.get_by_refresh_token(token) + |> Query.preload([:user]) |> Repo.find_resource() end @@ -97,29 +97,25 @@ defmodule Pleroma.Web.OAuth.Token do end def delete_user_tokens(%User{id: user_id}) do - from( - t in Token, - where: t.user_id == ^user_id - ) + Query.get_by_user(user_id) |> Repo.delete_all() end def delete_user_token(%User{id: user_id}, token_id) do - from( - t in Token, - where: t.user_id == ^user_id, - where: t.id == ^token_id - ) + Query.get_by_user(user_id) + |> Query.get_by_id(token_id) + |> Repo.delete_all() + end + + def delete_expired_tokens do + Query.get_expired_tokens() |> Repo.delete_all() end def get_user_tokens(%User{id: user_id}) do - from( - t in Token, - where: t.user_id == ^user_id - ) + Query.get_by_user(user_id) + |> Query.preload([:app]) |> Repo.all() - |> Repo.preload(:app) end def is_expired?(%__MODULE__{valid_until: valid_until}) do diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex new file mode 100644 index 000000000..dca852449 --- /dev/null +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Token.CleanWorker do + @moduledoc """ + The module represents functions to clean an expired oauth tokens. + """ + + # 10 seconds + @start_interval 10_000 + @interval Pleroma.Config.get( + # 24 hours + [:oauth2, :clean_expired_tokens_interval], + 86_400_000 + ) + @queue :background + + alias Pleroma.Web.OAuth.Token + + def start_link, do: GenServer.start_link(__MODULE__, nil) + + def init(_) do + if Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) do + Process.send_after(self(), :perform, @start_interval) + {:ok, nil} + else + :ignore + end + end + + @doc false + def handle_info(:perform, state) do + Process.send_after(self(), :perform, @interval) + PleromaJobQueue.enqueue(@queue, __MODULE__, [:clean]) + {:noreply, state} + end + + # Job Worker Callbacks + def perform(:clean), do: Token.delete_expired_tokens() +end diff --git a/lib/pleroma/web/oauth/token/query.ex b/lib/pleroma/web/oauth/token/query.ex new file mode 100644 index 000000000..d92e1f071 --- /dev/null +++ b/lib/pleroma/web/oauth/token/query.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Token.Query do + @moduledoc """ + Contains queries for OAuth Token. + """ + + import Ecto.Query, only: [from: 2] + + @type query :: Ecto.Queryable.t() | Token.t() + + alias Pleroma.Web.OAuth.Token + + @spec get_by_refresh_token(query, String.t()) :: query + def get_by_refresh_token(query \\ Token, refresh_token) do + from(q in query, where: q.refresh_token == ^refresh_token) + end + + @spec get_by_token(query, String.t()) :: query + def get_by_token(query \\ Token, token) do + from(q in query, where: q.token == ^token) + end + + @spec get_by_app(query, String.t()) :: query + def get_by_app(query \\ Token, app_id) do + from(q in query, where: q.app_id == ^app_id) + end + + @spec get_by_id(query, String.t()) :: query + def get_by_id(query \\ Token, id) do + from(q in query, where: q.id == ^id) + end + + @spec get_expired_tokens(query, DateTime.t() | nil) :: query + def get_expired_tokens(query \\ Token, date \\ nil) do + expired_date = date || Timex.now() + from(q in query, where: fragment("?", q.valid_until) < ^expired_date) + end + + @spec get_by_user(query, String.t()) :: query + def get_by_user(query \\ Token, user_id) do + from(q in query, where: q.user_id == ^user_id) + end + + @spec preload(query, any) :: query + def preload(query \\ Token, assoc_preload \\ []) + + def preload(query, assoc_preload) when is_list(assoc_preload) do + from(q in query, preload: ^assoc_preload) + end + + def preload(query, _assoc_preload), do: query +end diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 61515b31e..6ed089d84 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -3,13 +3,12 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus do - @httpoison Application.get_env(:pleroma, :httpoison) - import Ecto.Query import Pleroma.Web.XML require Logger alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -363,7 +362,7 @@ defmodule Pleroma.Web.OStatus do def fetch_activity_from_atom_url(url) do with true <- String.starts_with?(url, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- - @httpoison.get( + HTTP.get( url, [{:Accept, "application/atom+xml"}] ) do @@ -380,7 +379,7 @@ defmodule Pleroma.Web.OStatus do Logger.debug("Trying to fetch #{url}") with true <- String.starts_with?(url, "http"), - {:ok, %{body: body}} <- @httpoison.get(url, []), + {:ok, %{body: body}} <- HTTP.get(url, []), {:ok, atom_url} <- get_atom_url(body) do fetch_activity_from_atom_url(atom_url) else diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4c29b24eb..352268b96 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -707,9 +707,15 @@ defmodule Pleroma.Web.Router do end end + scope "/", Pleroma.Web.MongooseIM do + get("/user_exists", MongooseIMController, :user_exists) + get("/check_password", MongooseIMController, :check_password) + end + scope "/", Fallback do get("/registration/:token", RedirectController, :registration_page) get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) + get("/api*path", RedirectController, :api_not_implemented) get("/*path", RedirectController, :redirector) options("/*path", RedirectController, :empty) @@ -721,6 +727,12 @@ defmodule Fallback.RedirectController do alias Pleroma.User alias Pleroma.Web.Metadata + def api_not_implemented(conn, _params) do + conn + |> put_status(404) + |> json(%{error: "Not implemented"}) + end + def redirector(conn, _params, code \\ 200) do conn |> put_resp_content_type("text/html") diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 42709ab47..9e91a5a40 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -5,12 +5,12 @@ defmodule Pleroma.Web.Salmon do @behaviour Pleroma.Web.Federator.Publisher - @httpoison Application.get_env(:pleroma, :httpoison) - use Bitwise alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Instances + alias Pleroma.Keys alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator.Publisher @@ -89,45 +89,6 @@ defmodule Pleroma.Web.Salmon do "RSA.#{modulus_enc}.#{exponent_enc}" end - # Native generation of RSA keys is only available since OTP 20+ and in default build conditions - # We try at compile time to generate natively an RSA key otherwise we fallback on the old way. - try do - _ = :public_key.generate_key({:rsa, 2048, 65_537}) - - def generate_rsa_pem do - key = :public_key.generate_key({:rsa, 2048, 65_537}) - entry = :public_key.pem_entry_encode(:RSAPrivateKey, key) - pem = :public_key.pem_encode([entry]) |> String.trim_trailing() - {:ok, pem} - end - rescue - _ -> - def generate_rsa_pem do - port = Port.open({:spawn, "openssl genrsa"}, [:binary]) - - {:ok, pem} = - receive do - {^port, {:data, pem}} -> {:ok, pem} - end - - Port.close(port) - - if Regex.match?(~r/RSA PRIVATE KEY/, pem) do - {:ok, pem} - else - :error - end - end - end - - def keys_from_pem(pem) do - [private_key_code] = :public_key.pem_decode(pem) - private_key = :public_key.pem_entry_decode(private_key_code) - {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key - public_key = {:RSAPublicKey, modulus, exponent} - {:ok, private_key, public_key} - end - def encode(private_key, doc) do type = "application/atom+xml" encoding = "base64url" @@ -176,7 +137,7 @@ defmodule Pleroma.Web.Salmon do def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do with {:ok, %{status: code}} when code in 200..299 <- - @httpoison.post( + HTTP.post( url, feed, [{"Content-Type", "application/magic-envelope+xml"}] @@ -227,7 +188,7 @@ defmodule Pleroma.Web.Salmon do |> :xmerl.export_simple(:xmerl_xml) |> to_string - {:ok, private, _} = keys_from_pem(keys) + {:ok, private, _} = Keys.keys_from_pem(keys) {:ok, feed} = encode(private, feed) remote_users = remote_users(activity) @@ -253,7 +214,7 @@ defmodule Pleroma.Web.Salmon do def publish(%{id: id}, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) def gather_webfinger_links(%User{} = user) do - {:ok, _private, public} = keys_from_pem(user.info.keys) + {:ok, _private, public} = Keys.keys_from_pem(user.info.keys) magic_key = encode_key(public) [ diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 44bcafe0e..e84af84dc 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -284,6 +284,12 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) ) + thread_muted? = + case activity.thread_muted? do + thread_muted? when is_boolean(thread_muted?) -> thread_muted? + nil -> CommonAPI.thread_muted?(user, activity) + end + %{ "id" => activity.id, "uri" => object.data["id"], @@ -314,7 +320,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "summary" => summary, "summary_html" => summary |> Formatter.emojify(object.data["emoji"]), "card" => card, - "muted" => CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user) + "muted" => thread_muted? || User.mutes?(opts[:for], user) } end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 1239b962a..3fca72de8 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -3,12 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFinger do - @httpoison Application.get_env(:pleroma, :httpoison) - + alias Pleroma.HTTP alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.Federator.Publisher - alias Pleroma.Web.Salmon alias Pleroma.Web.XML alias Pleroma.XmlBuilder require Jason @@ -61,7 +59,7 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "JSON") do - {:ok, user} = ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) %{ "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", @@ -71,7 +69,7 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "XML") do - {:ok, user} = ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) links = gather_links(user) @@ -88,27 +86,6 @@ defmodule Pleroma.Web.WebFinger do |> XmlBuilder.to_doc() end - # This seems a better fit in Salmon - def ensure_keys_present(user) do - info = user.info - - if info.keys do - {:ok, user} - else - {:ok, pem} = Salmon.generate_rsa_pem() - - info_cng = - info - |> User.Info.set_keys(pem) - - cng = - Ecto.Changeset.change(user) - |> Ecto.Changeset.put_embed(:info, info_cng) - - User.update_and_set_cache(cng) - end - end - defp get_magic_key(magic_key) do "data:application/magic-public-key," <> magic_key = magic_key {:ok, magic_key} @@ -198,11 +175,11 @@ defmodule Pleroma.Web.WebFinger do def find_lrdd_template(domain) do with {:ok, %{status: status, body: body}} when status in 200..299 <- - @httpoison.get("http://#{domain}/.well-known/host-meta", []) do + HTTP.get("http://#{domain}/.well-known/host-meta", []) do get_template_from_xml(body) else _ -> - with {:ok, %{body: body}} <- @httpoison.get("https://#{domain}/.well-known/host-meta", []) do + with {:ok, %{body: body}} <- HTTP.get("https://#{domain}/.well-known/host-meta", []) do get_template_from_xml(body) else e -> {:error, "Can't find LRDD template: #{inspect(e)}"} @@ -231,7 +208,7 @@ defmodule Pleroma.Web.WebFinger do end with response <- - @httpoison.get( + HTTP.get( address, Accept: "application/xrd+xml,application/jrd+json" ), diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 7ad0414ab..b61f388b8 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Websub do alias Ecto.Changeset alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.Repo alias Pleroma.User @@ -24,9 +25,7 @@ defmodule Pleroma.Web.Websub do @behaviour Pleroma.Web.Federator.Publisher - @httpoison Application.get_env(:pleroma, :httpoison) - - def verify(subscription, getter \\ &@httpoison.get/3) do + def verify(subscription, getter \\ &HTTP.get/3) do challenge = Base.encode16(:crypto.strong_rand_bytes(8)) lease_seconds = NaiveDateTime.diff(subscription.valid_until, subscription.updated_at) lease_seconds = lease_seconds |> to_string @@ -207,7 +206,7 @@ defmodule Pleroma.Web.Websub do requester.(subscription) end - def gather_feed_data(topic, getter \\ &@httpoison.get/1) do + def gather_feed_data(topic, getter \\ &HTTP.get/1) do with {:ok, response} <- getter.(topic), status when status in 200..299 <- response.status, body <- response.body, @@ -236,7 +235,7 @@ defmodule Pleroma.Web.Websub do end end - def request_subscription(websub, poster \\ &@httpoison.post/3, timeout \\ 10_000) do + def request_subscription(websub, poster \\ &HTTP.post/3, timeout \\ 10_000) do data = [ "hub.mode": "subscribe", "hub.topic": websub.topic, @@ -294,7 +293,7 @@ defmodule Pleroma.Web.Websub do Logger.info(fn -> "Pushing #{topic} to #{callback}" end) with {:ok, %{status: code}} when code in 200..299 <- - @httpoison.post( + HTTP.post( callback, xml, [ diff --git a/mix.exs b/mix.exs index 95c052c34..b2017ef9b 100644 --- a/mix.exs +++ b/mix.exs @@ -42,7 +42,7 @@ defmodule Pleroma.Mixfile do def application do [ mod: {Pleroma.Application, []}, - extra_applications: [:logger, :runtime_tools, :comeonin, :esshd, :quack], + extra_applications: [:logger, :runtime_tools, :comeonin, :quack], included_applications: [:ex_syslogger] ] end @@ -66,10 +66,7 @@ defmodule Pleroma.Mixfile do {:plug_cowboy, "~> 2.0"}, {:phoenix_pubsub, "~> 1.1"}, {:phoenix_ecto, "~> 4.0"}, - {:ecto_sql, - git: "https://github.com/elixir-ecto/ecto_sql", - ref: "14cb065a74c488d737d973f7a91bc036c6245f78", - override: true}, + {:ecto_sql, "~> 3.1"}, {:postgrex, ">= 0.13.5"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, @@ -120,7 +117,7 @@ defmodule Pleroma.Mixfile do {:recon, github: "ferd/recon", tag: "2.4.0"}, {:quack, "~> 0.1.1"}, {:benchee, "~> 1.0"}, - {:esshd, "~> 0.1.0"}, + {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)}, {:ex_rated, "~> 1.2"}, {:plug_static_index_html, "~> 1.0.0"}, {:excoveralls, "~> 0.11.1", only: :test} diff --git a/mix.lock b/mix.lock index bacc09787..857bfca79 100644 --- a/mix.lock +++ b/mix.lock @@ -21,7 +21,7 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"}, "ecto": {:hex, :ecto, "3.1.4", "69d852da7a9f04ede725855a35ede48d158ca11a404fe94f8b2fb3b2162cd3c9", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, - "ecto_sql": {:git, "https://github.com/elixir-ecto/ecto_sql", "14cb065a74c488d737d973f7a91bc036c6245f78", [ref: "14cb065a74c488d737d973f7a91bc036c6245f78"]}, + "ecto_sql": {:hex, :ecto_sql, "3.1.3", "2c536139190492d9de33c5fefac7323c5eaaa82e1b9bf93482a14649042f7cd9", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, diff --git a/test/activity_test.exs b/test/activity_test.exs index 7e91d534b..15c95502a 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.ActivityTest do use Pleroma.DataCase alias Pleroma.Activity alias Pleroma.Bookmark + alias Pleroma.ThreadMute import Pleroma.Factory test "returns an activity by it's AP id" do @@ -47,6 +48,31 @@ defmodule Pleroma.ActivityTest do assert queried_activity.bookmark == bookmark3 end + test "setting thread_muted?" do + activity = insert(:note_activity) + user = insert(:user) + annoyed_user = insert(:user) + {:ok, _} = ThreadMute.add_mute(annoyed_user.id, activity.data["context"]) + + activity_with_unset_thread_muted_field = + Ecto.Query.from(Activity) + |> Repo.one() + + activity_for_user = + Ecto.Query.from(Activity) + |> Activity.with_set_thread_muted_field(user) + |> Repo.one() + + activity_for_annoyed_user = + Ecto.Query.from(Activity) + |> Activity.with_set_thread_muted_field(annoyed_user) + |> Repo.one() + + assert activity_with_unset_thread_muted_field.thread_muted? == nil + assert activity_for_user.thread_muted? == false + assert activity_for_annoyed_user.thread_muted? == true + end + describe "getting a bookmark" do test "when association is loaded" do user = insert(:user) diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 5e7011160..bfa673049 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -184,17 +184,19 @@ defmodule Pleroma.FormatterTest do test "given the 'safe_mention' option, it will only mention people in the beginning" do user = insert(:user) - _other_user = insert(:user) + other_user = insert(:user) third_user = insert(:user) - text = " @#{user.nickname} hey dude i hate @#{third_user.nickname}" + text = " @#{user.nickname} @#{other_user.nickname} hey dudes i hate @#{third_user.nickname}" {expected_text, mentions, [] = _tags} = Formatter.linkify(text, safe_mention: true) - assert mentions == [{"@#{user.nickname}", user}] + assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}] assert expected_text == "@#{user.nickname} hey dude i hate @#{user.nickname} @#{other_user.nickname} hey dudes i hate @#{third_user.nickname}" end @@ -206,6 +208,15 @@ defmodule Pleroma.FormatterTest do assert mentions == [] assert expected_text == text end + + test "given the 'safe_mention' option, it will keep text after newlines" do + user = insert(:user) + text = " @#{user.nickname}\n hey dude\n\nhow are you doing?" + + {expected_text, _, _} = Formatter.linkify(text, safe_mention: true) + + assert expected_text =~ "how are you doing?" + end end describe ".parse_tags" do diff --git a/test/keys_test.exs b/test/keys_test.exs new file mode 100644 index 000000000..776fdea6f --- /dev/null +++ b/test/keys_test.exs @@ -0,0 +1,20 @@ +defmodule Pleroma.KeysTest do + use Pleroma.DataCase + + alias Pleroma.Keys + + test "generates an RSA private key pem" do + {:ok, key} = Keys.generate_rsa_pem() + + assert is_binary(key) + assert Regex.match?(~r/RSA/, key) + end + + test "returns a public and private key from a pem" do + pem = File.read!("test/fixtures/private_key.pem") + {:ok, private, public} = Keys.keys_from_pem(pem) + + assert elem(private, 0) == :RSAPrivateKey + assert elem(public, 0) == :RSAPublicKey + end +end diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs index 72f616782..d604fd5f5 100644 --- a/test/object/fetcher_test.exs +++ b/test/object/fetcher_test.exs @@ -87,4 +87,23 @@ defmodule Pleroma.Object.FetcherTest do ) end end + + describe "pruning" do + test "it can refetch pruned objects" do + object_id = "http://mastodon.example.org/@admin/99541947525187367" + + {:ok, object} = Fetcher.fetch_object_from_id(object_id) + + assert object + + {:ok, _object} = Object.prune(object) + + refute Object.get_by_ap_id(object_id) + + {:ok, %Object{} = object_two} = Fetcher.fetch_object_from_id(object_id) + + assert object.data["id"] == object_two.data["id"] + assert object.id != object_two.id + end + end end diff --git a/test/plugs/cache_control_test.exs b/test/plugs/cache_control_test.exs new file mode 100644 index 000000000..45151b289 --- /dev/null +++ b/test/plugs/cache_control_test.exs @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.CacheControlTest do + use Pleroma.Web.ConnCase + alias Plug.Conn + + test "Verify Cache-Control header on static assets", %{conn: conn} do + conn = get(conn, "/index.html") + + assert Conn.get_resp_header(conn, "cache-control") == ["public, no-cache"] + end + + test "Verify Cache-Control header on the API", %{conn: conn} do + conn = get(conn, "/api/v1/instance") + + assert Conn.get_resp_header(conn, "cache-control") == ["max-age=0, private, must-revalidate"] + end +end diff --git a/test/support/ostatus_mock.ex b/test/support/ostatus_mock.ex deleted file mode 100644 index 9c0f2f323..000000000 --- a/test/support/ostatus_mock.ex +++ /dev/null @@ -1,11 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatusMock do - import Pleroma.Factory - - def handle_incoming(_doc) do - insert(:note_activity) - end -end diff --git a/test/support/websub_mock.ex b/test/support/websub_mock.ex deleted file mode 100644 index e3d5a5b16..000000000 --- a/test/support/websub_mock.ex +++ /dev/null @@ -1,9 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.WebsubMock do - def verify(sub) do - {:ok, sub} - end -end diff --git a/test/user_test.exs b/test/user_test.exs index 10e463ff8..019f2b56d 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -902,7 +902,7 @@ defmodule Pleroma.UserTest do assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark) - assert [activity] == + assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] == ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2}) {:ok, _user} = User.deactivate(user) @@ -1251,4 +1251,19 @@ defmodule Pleroma.UserTest do refute user.info.confirmation_token end end + + describe "ensure_keys_present" do + test "it creates keys for a user and stores them in info" do + user = insert(:user) + refute is_binary(user.info.keys) + {:ok, user} = User.ensure_keys_present(user) + assert is_binary(user.info.keys) + end + + test "it doesn't create keys if there already are some" do + user = insert(:user, %{info: %{keys: "xxx"}}) + {:ok, user} = User.ensure_keys_present(user) + assert user.info.keys == "xxx" + end + end end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index c18e0ab5f..f743f380b 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1005,7 +1005,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do describe "update" do test "it creates an update activity with the new user data" do user = insert(:user) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user}) {:ok, update} = diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs index 74af7dcde..0fd68e103 100644 --- a/test/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/web/activity_pub/mrf/simple_policy_test.exs @@ -17,7 +17,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do federated_timeline_removal: [], report_removal: [], reject: [], - accept: [] + accept: [], + avatar_removal: [], + banner_removal: [] ) on_exit(fn -> @@ -143,6 +145,24 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do assert SimplePolicy.filter(local_message) == {:ok, local_message} end + + test "has a matching host but only as:Public in to" do + {_actor, ftl_message} = build_ftl_actor_and_message() + + ftl_message_actor_host = + ftl_message + |> Map.fetch!("actor") + |> URI.parse() + |> Map.fetch!(:host) + + ftl_message = Map.put(ftl_message, "cc", []) + + Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) + + assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) + refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] + assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"] + end end defp build_ftl_actor_and_message do @@ -206,6 +226,60 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do end end + describe "when :avatar_removal" do + test "is empty" do + Config.put([:mrf_simple, :avatar_removal], []) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "is not empty but it doesn't have a matching host" do + Config.put([:mrf_simple, :avatar_removal], ["non.matching.remote"]) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "has a matching host" do + Config.put([:mrf_simple, :avatar_removal], ["remote.instance"]) + + remote_user = build_remote_user() + {:ok, filtered} = SimplePolicy.filter(remote_user) + + refute filtered["icon"] + end + end + + describe "when :banner_removal" do + test "is empty" do + Config.put([:mrf_simple, :banner_removal], []) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "is not empty but it doesn't have a matching host" do + Config.put([:mrf_simple, :banner_removal], ["non.matching.remote"]) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "has a matching host" do + Config.put([:mrf_simple, :banner_removal], ["remote.instance"]) + + remote_user = build_remote_user() + {:ok, filtered} = SimplePolicy.filter(remote_user) + + refute filtered["image"] + end + end + defp build_local_message do %{ "actor" => "#{Pleroma.Web.base_url()}/users/alice", @@ -217,4 +291,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do defp build_remote_message do %{"actor" => "https://remote.instance/users/bob"} end + + defp build_remote_user do + %{ + "id" => "https://remote.instance/users/bob", + "icon" => %{ + "url" => "http://example.com/image.jpg", + "type" => "Image" + }, + "image" => %{ + "url" => "http://example.com/image.jpg", + "type" => "Image" + }, + "type" => "Person" + } + end end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 9fb9455d2..e6483db8b 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -2,11 +2,12 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do use Pleroma.DataCase import Pleroma.Factory + alias Pleroma.User alias Pleroma.Web.ActivityPub.UserView test "Renders a user, including the public key" do user = insert(:user) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) @@ -18,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "Does not add an avatar image if the user hasn't set one" do user = insert(:user) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) refute result["icon"] @@ -32,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do } ) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) assert result["icon"]["url"] == "https://someurl" @@ -42,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do describe "endpoints" do test "local users have a usable endpoints structure" do user = insert(:user) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) @@ -58,7 +59,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "remote users have an empty endpoints structure" do user = insert(:user, local: false) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) @@ -68,7 +69,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do test "instance users do not expose oAuth endpoints" do user = insert(:user, nickname: nil, local: true) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) result = UserView.render("user.json", %{user: user}) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index ca12c7215..43dcf945a 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -397,14 +397,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do end end - test "/api/pleroma/admin/invite_token" do + test "/api/pleroma/admin/users/invite_token" do admin = insert(:user, info: %{is_admin: true}) conn = build_conn() |> assign(:user, admin) |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/invite_token") + |> get("/api/pleroma/admin/users/invite_token") assert conn.status == 200 end @@ -437,27 +437,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do user = insert(:user, local: false, tags: ["foo", "bar"]) conn = get(conn, "/api/pleroma/admin/users?page=1") + users = + [ + %{ + "deactivated" => admin.info.deactivated, + "id" => admin.id, + "nickname" => admin.nickname, + "roles" => %{"admin" => true, "moderator" => false}, + "local" => true, + "tags" => [] + }, + %{ + "deactivated" => user.info.deactivated, + "id" => user.id, + "nickname" => user.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => false, + "tags" => ["foo", "bar"] + } + ] + |> Enum.sort_by(& &1["nickname"]) + assert json_response(conn, 200) == %{ "count" => 2, "page_size" => 50, - "users" => [ - %{ - "deactivated" => admin.info.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [] - }, - %{ - "deactivated" => user.info.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => false, - "tags" => ["foo", "bar"] - } - ] + "users" => users } end @@ -659,35 +663,39 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do |> assign(:user, admin) |> get("/api/pleroma/admin/users?filters=local") + users = + [ + %{ + "deactivated" => user.info.deactivated, + "id" => user.id, + "nickname" => user.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => true, + "tags" => [] + }, + %{ + "deactivated" => admin.info.deactivated, + "id" => admin.id, + "nickname" => admin.nickname, + "roles" => %{"admin" => true, "moderator" => false}, + "local" => true, + "tags" => [] + }, + %{ + "deactivated" => false, + "id" => old_admin.id, + "local" => true, + "nickname" => old_admin.nickname, + "roles" => %{"admin" => true, "moderator" => false}, + "tags" => [] + } + ] + |> Enum.sort_by(& &1["nickname"]) + assert json_response(conn, 200) == %{ "count" => 3, "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.info.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [] - }, - %{ - "deactivated" => admin.info.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [] - }, - %{ - "deactivated" => false, - "id" => old_admin.id, - "local" => true, - "nickname" => old_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "tags" => [] - } - ] + "users" => users } end @@ -698,27 +706,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do conn = get(conn, "/api/pleroma/admin/users?filters=is_admin") + users = + [ + %{ + "deactivated" => false, + "id" => admin.id, + "nickname" => admin.nickname, + "roles" => %{"admin" => true, "moderator" => false}, + "local" => admin.local, + "tags" => [] + }, + %{ + "deactivated" => false, + "id" => second_admin.id, + "nickname" => second_admin.nickname, + "roles" => %{"admin" => true, "moderator" => false}, + "local" => second_admin.local, + "tags" => [] + } + ] + |> Enum.sort_by(& &1["nickname"]) + assert json_response(conn, 200) == %{ "count" => 2, "page_size" => 50, - "users" => [ - %{ - "deactivated" => false, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => admin.local, - "tags" => [] - }, - %{ - "deactivated" => false, - "id" => second_admin.id, - "nickname" => second_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => second_admin.local, - "tags" => [] - } - ] + "users" => users } end @@ -753,27 +765,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second") + users = + [ + %{ + "deactivated" => false, + "id" => user1.id, + "nickname" => user1.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => user1.local, + "tags" => ["first"] + }, + %{ + "deactivated" => false, + "id" => user2.id, + "nickname" => user2.nickname, + "roles" => %{"admin" => false, "moderator" => false}, + "local" => user2.local, + "tags" => ["second"] + } + ] + |> Enum.sort_by(& &1["nickname"]) + assert json_response(conn, 200) == %{ "count" => 2, "page_size" => 50, - "users" => [ - %{ - "deactivated" => false, - "id" => user1.id, - "nickname" => user1.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user1.local, - "tags" => ["first"] - }, - %{ - "deactivated" => false, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user2.local, - "tags" => ["second"] - } - ] + "users" => users } end diff --git a/test/web/fallback_test.exs b/test/web/fallback_test.exs new file mode 100644 index 000000000..cc78b3ae1 --- /dev/null +++ b/test/web/fallback_test.exs @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.FallbackTest do + use Pleroma.Web.ConnCase + import Pleroma.Factory + + test "GET /registration/:token", %{conn: conn} do + assert conn + |> get("/registration/foo") + |> html_response(200) =~ "" + end + + test "GET /:maybe_nickname_or_id", %{conn: conn} do + user = insert(:user) + + assert conn + |> get("/foo") + |> html_response(200) =~ "" + + refute conn + |> get("/" <> user.nickname) + |> html_response(200) =~ "" + end + + test "GET /api*path", %{conn: conn} do + assert conn + |> get("/api/foo") + |> json_response(404) == %{"error" => "Not implemented"} + end + + test "GET /*path", %{conn: conn} do + assert conn + |> get("/foo") + |> html_response(200) =~ "" + + assert conn + |> get("/foo/bar") + |> html_response(200) =~ "" + end + + test "OPTIONS /*path", %{conn: conn} do + assert conn + |> options("/foo") + |> response(204) == "" + + assert conn + |> options("/foo/bar") + |> response(204) == "" + end +end diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index a24f2a050..aaf2261bb 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do fields: [], bot: false, source: %{ - note: "", + note: "valid html", sensitive: false, pleroma: %{} }, @@ -120,7 +120,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do fields: [], bot: true, source: %{ - note: "", + note: user.bio, sensitive: false, pleroma: %{} }, @@ -209,7 +209,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do fields: [], bot: true, source: %{ - note: "", + note: user.bio, sensitive: false, pleroma: %{} }, diff --git a/test/web/mongooseim/mongoose_im_controller_test.exs b/test/web/mongooseim/mongoose_im_controller_test.exs new file mode 100644 index 000000000..eb83999bb --- /dev/null +++ b/test/web/mongooseim/mongoose_im_controller_test.exs @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MongooseIMController do + use Pleroma.Web.ConnCase + import Pleroma.Factory + + test "/user_exists", %{conn: conn} do + _user = insert(:user, nickname: "lain") + _remote_user = insert(:user, nickname: "alice", local: false) + + res = + conn + |> get(mongoose_im_path(conn, :user_exists), user: "lain") + |> json_response(200) + + assert res == true + + res = + conn + |> get(mongoose_im_path(conn, :user_exists), user: "alice") + |> json_response(404) + + assert res == false + + res = + conn + |> get(mongoose_im_path(conn, :user_exists), user: "bob") + |> json_response(404) + + assert res == false + end + + test "/check_password", %{conn: conn} do + user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("cool")) + + res = + conn + |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "cool") + |> json_response(200) + + assert res == true + + res = + conn + |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "uncool") + |> json_response(403) + + assert res == false + + res = + conn + |> get(mongoose_im_path(conn, :check_password), user: "nobody", pass: "cool") + |> json_response(404) + + assert res == false + end +end diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index 2fc42b7cc..be1173513 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -7,6 +7,22 @@ defmodule Pleroma.Web.NodeInfoTest do import Pleroma.Factory + test "GET /.well-known/nodeinfo", %{conn: conn} do + links = + conn + |> get("/.well-known/nodeinfo") + |> json_response(200) + |> Map.fetch!("links") + + Enum.each(links, fn link -> + href = Map.fetch!(link, "href") + + conn + |> get(href) + |> json_response(200) + end) + end + test "nodeinfo shows staff accounts", %{conn: conn} do moderator = insert(:user, %{local: true, info: %{is_moderator: true}}) admin = insert(:user, %{local: true, info: %{is_admin: true}}) @@ -32,70 +48,6 @@ defmodule Pleroma.Web.NodeInfoTest do result["metadata"]["restrictedNicknames"] end - test "returns 404 when federation is disabled", %{conn: conn} do - instance = - Application.get_env(:pleroma, :instance) - |> Keyword.put(:federating, false) - - Application.put_env(:pleroma, :instance, instance) - - conn - |> get("/.well-known/nodeinfo") - |> json_response(404) - - conn - |> get("/nodeinfo/2.1.json") - |> json_response(404) - - instance = - Application.get_env(:pleroma, :instance) - |> Keyword.put(:federating, true) - - Application.put_env(:pleroma, :instance, instance) - end - - test "returns 200 when federation is enabled", %{conn: conn} do - conn - |> get("/.well-known/nodeinfo") - |> json_response(200) - - conn - |> get("/nodeinfo/2.1.json") - |> json_response(200) - end - - test "returns 404 when federation is disabled (nodeinfo 2.0)", %{conn: conn} do - instance = - Application.get_env(:pleroma, :instance) - |> Keyword.put(:federating, false) - - Application.put_env(:pleroma, :instance, instance) - - conn - |> get("/.well-known/nodeinfo") - |> json_response(404) - - conn - |> get("/nodeinfo/2.0.json") - |> json_response(404) - - instance = - Application.get_env(:pleroma, :instance) - |> Keyword.put(:federating, true) - - Application.put_env(:pleroma, :instance, instance) - end - - test "returns 200 when federation is enabled (nodeinfo 2.0)", %{conn: conn} do - conn - |> get("/.well-known/nodeinfo") - |> json_response(200) - - conn - |> get("/nodeinfo/2.0.json") - |> json_response(200) - end - test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do conn |> get("/.well-known/nodeinfo") diff --git a/test/web/oauth/token_test.exs b/test/web/oauth/token_test.exs index ad2a49f09..3c07309b7 100644 --- a/test/web/oauth/token_test.exs +++ b/test/web/oauth/token_test.exs @@ -69,4 +69,17 @@ defmodule Pleroma.Web.OAuth.TokenTest do assert tokens == 2 end + + test "deletes expired tokens" do + insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) + insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) + t3 = insert(:oauth_token) + t4 = insert(:oauth_token, valid_until: Timex.shift(Timex.now(), minutes: 10)) + {tokens, _} = Token.delete_expired_tokens() + assert tokens == 2 + available_tokens = Pleroma.Repo.all(Token) + + token_ids = available_tokens |> Enum.map(& &1.id) + assert token_ids == [t3.id, t4.id] + end end diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index 232082779..e86e76fe9 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Keys alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.Federator.Publisher @@ -34,12 +35,6 @@ defmodule Pleroma.Web.Salmon.SalmonTest do assert Salmon.decode_and_validate(@wrong_magickey, salmon) == :error end - test "generates an RSA private key pem" do - {:ok, key} = Salmon.generate_rsa_pem() - assert is_binary(key) - assert Regex.match?(~r/RSA/, key) - end - test "it encodes a magic key from a public key" do key = Salmon.decode_key(@magickey) magic_key = Salmon.encode_key(key) @@ -51,18 +46,10 @@ defmodule Pleroma.Web.Salmon.SalmonTest do _key = Salmon.decode_key(@magickey_friendica) end - test "returns a public and private key from a pem" do - pem = File.read!("test/fixtures/private_key.pem") - {:ok, private, public} = Salmon.keys_from_pem(pem) - - assert elem(private, 0) == :RSAPrivateKey - assert elem(public, 0) == :RSAPublicKey - end - test "encodes an xml payload with a private key" do doc = File.read!("test/fixtures/incoming_note_activity.xml") pem = File.read!("test/fixtures/private_key.pem") - {:ok, private, public} = Salmon.keys_from_pem(pem) + {:ok, private, public} = Keys.keys_from_pem(pem) # Let's try a roundtrip. {:ok, salmon} = Salmon.encode(private, doc) @@ -105,7 +92,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do {:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]}) user = User.get_cached_by_ap_id(activity.data["actor"]) - {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) Salmon.publish(user, activity) diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 6b20d8d56..335c95b18 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -105,19 +105,4 @@ defmodule Pleroma.Web.WebFingerTest do assert template == "http://status.alpicola.com/main/xrd?uri={uri}" end end - - describe "ensure_keys_present" do - test "it creates keys for a user and stores them in info" do - user = insert(:user) - refute is_binary(user.info.keys) - {:ok, user} = WebFinger.ensure_keys_present(user) - assert is_binary(user.info.keys) - end - - test "it doesn't create keys if there already are some" do - user = insert(:user, %{info: %{keys: "xxx"}}) - {:ok, user} = WebFinger.ensure_keys_present(user) - assert user.info.keys == "xxx" - end - end end diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs index 1e69ed01a..f79745d58 100644 --- a/test/web/websub/websub_controller_test.exs +++ b/test/web/websub/websub_controller_test.exs @@ -5,7 +5,6 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do use Pleroma.Web.ConnCase import Pleroma.Factory - alias Pleroma.Activity alias Pleroma.Repo alias Pleroma.Web.Websub alias Pleroma.Web.Websub.WebsubClientSubscription @@ -52,7 +51,7 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do end describe "websub_incoming" do - test "handles incoming feed updates", %{conn: conn} do + test "accepts incoming feed updates", %{conn: conn} do websub = insert(:websub_client_subscription) doc = "some stuff" signature = Websub.sign(websub.secret, doc) @@ -64,8 +63,6 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do |> post("/push/subscriptions/#{websub.id}", doc) assert response(conn, 200) == "OK" - - assert length(Repo.all(Activity)) == 1 end test "rejects incoming feed updates with the wrong signature", %{conn: conn} do @@ -80,8 +77,6 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do |> post("/push/subscriptions/#{websub.id}", doc) assert response(conn, 500) == "Error" - - assert Enum.empty?(Repo.all(Activity)) end end end