Browse Source

Merge branch 'develop' into gun

debug-remote-ip
Alexander Strizhakov 4 years ago
parent
commit
f0651730bd
No known key found for this signature in database GPG Key ID: 22896A53AEF1381
100 changed files with 986 additions and 509 deletions
  1. +4
    -0
      CHANGELOG.md
  2. +0
    -2
      config/benchmark.exs
  3. +0
    -4
      config/config.exs
  4. +0
    -51
      config/description.exs
  5. +2
    -0
      config/test.exs
  6. +1
    -1
      docs/API/differences_in_mastoapi_responses.md
  7. +2
    -1
      docs/API/pleroma_api.md
  8. +1
    -1
      docs/clients.md
  9. +0
    -8
      docs/configuration/cheatsheet.md
  10. +0
    -2
      installation/pleroma.nginx
  11. +1
    -1
      lib/pleroma/activity/ir/topics.ex
  12. +256
    -0
      lib/pleroma/earmark_renderer.ex
  13. +17
    -2
      lib/pleroma/plugs/ensure_authenticated_plug.ex
  14. +12
    -6
      lib/pleroma/plugs/federating_plug.ex
  15. +16
    -11
      lib/pleroma/plugs/rate_limiter/rate_limiter.ex
  16. +5
    -2
      lib/pleroma/plugs/remote_ip.ex
  17. +4
    -1
      lib/pleroma/plugs/static_fe_plug.ex
  18. +6
    -1
      lib/pleroma/plugs/uploaded_media.ex
  19. +9
    -11
      lib/pleroma/reverse_proxy/reverse_proxy.ex
  20. +25
    -31
      lib/pleroma/user.ex
  21. +64
    -41
      lib/pleroma/web/activity_pub/activity_pub_controller.ex
  22. +0
    -39
      lib/pleroma/web/activity_pub/utils.ex
  23. +1
    -6
      lib/pleroma/web/activity_pub/views/user_view.ex
  24. +2
    -2
      lib/pleroma/web/admin_api/admin_api_controller.ex
  25. +2
    -2
      lib/pleroma/web/admin_api/views/account_view.ex
  26. +1
    -1
      lib/pleroma/web/common_api/utils.ex
  27. +1
    -1
      lib/pleroma/web/endpoint.ex
  28. +6
    -1
      lib/pleroma/web/feed/user_controller.ex
  29. +1
    -1
      lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
  30. +4
    -15
      lib/pleroma/web/mastodon_api/views/account_view.ex
  31. +7
    -3
      lib/pleroma/web/ostatus/ostatus_controller.ex
  32. +25
    -8
      lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
  33. +4
    -2
      lib/pleroma/web/router.ex
  34. +22
    -11
      lib/pleroma/web/static_fe/static_fe_controller.ex
  35. +2
    -0
      lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
  36. +2
    -0
      lib/pleroma/web/twitter_api/controllers/util_controller.ex
  37. +0
    -4
      lib/pleroma/workers/background_worker.ex
  38. +1
    -1
      mix.exs
  39. +2
    -1
      mix.lock
  40. +10
    -0
      priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs
  41. +10
    -0
      priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs
  42. +0
    -0
      priv/static/adminfe/chunk-0d8f.650c8e81.css
  43. +0
    -0
      priv/static/adminfe/chunk-136a.3936457d.css
  44. +0
    -0
      priv/static/adminfe/chunk-15fa.5a5f973d.css
  45. +0
    -0
      priv/static/adminfe/chunk-46cf.a43e9415.css
  46. +0
    -0
      priv/static/adminfe/chunk-46ef.d45db7be.css
  47. +1
    -1
      priv/static/adminfe/chunk-4e7d.7aace723.css
  48. +0
    -0
      priv/static/adminfe/chunk-4ffb.dd09fe2e.css
  49. +0
    -0
      priv/static/adminfe/chunk-876c.90dffac4.css
  50. +1
    -1
      priv/static/adminfe/chunk-87b3.2affd602.css
  51. +1
    -1
      priv/static/adminfe/chunk-cf57.4d39576f.css
  52. +0
    -0
      priv/static/adminfe/chunk-e5cf.cba3ae06.css
  53. +1
    -1
      priv/static/adminfe/index.html
  54. +0
    -2
      priv/static/adminfe/static/js/app.55df3157.js
  55. +0
    -1
      priv/static/adminfe/static/js/app.55df3157.js.map
  56. +2
    -0
      priv/static/adminfe/static/js/app.d2c3c6b3.js
  57. +1
    -0
      priv/static/adminfe/static/js/app.d2c3c6b3.js.map
  58. +0
    -2
      priv/static/adminfe/static/js/chunk-03b0.7a203856.js
  59. +0
    -1
      priv/static/adminfe/static/js/chunk-03b0.7a203856.js.map
  60. +2
    -2
      priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js
  61. +1
    -1
      priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js.map
  62. +2
    -2
      priv/static/adminfe/static/js/chunk-136a.142aa42a.js
  63. +1
    -1
      priv/static/adminfe/static/js/chunk-136a.142aa42a.js.map
  64. +1
    -1
      priv/static/adminfe/static/js/chunk-15fa.34070731.js
  65. +1
    -1
      priv/static/adminfe/static/js/chunk-15fa.34070731.js.map
  66. +0
    -2
      priv/static/adminfe/static/js/chunk-293a.a728de01.js
  67. +0
    -1
      priv/static/adminfe/static/js/chunk-293a.a728de01.js.map
  68. +1
    -1
      priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js
  69. +1
    -1
      priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js.map
  70. +2
    -2
      priv/static/adminfe/static/js/chunk-46ef.215af110.js
  71. +1
    -1
      priv/static/adminfe/static/js/chunk-46ef.215af110.js.map
  72. +2
    -0
      priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js
  73. +1
    -0
      priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js.map
  74. +2
    -2
      priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js
  75. +1
    -1
      priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js.map
  76. +2
    -2
      priv/static/adminfe/static/js/chunk-876c.e4ceccca.js
  77. +1
    -1
      priv/static/adminfe/static/js/chunk-876c.e4ceccca.js.map
  78. +2
    -0
      priv/static/adminfe/static/js/chunk-87b3.4704cadf.js
  79. +1
    -0
      priv/static/adminfe/static/js/chunk-87b3.4704cadf.js.map
  80. +2
    -0
      priv/static/adminfe/static/js/chunk-cf57.42b96339.js
  81. +1
    -0
      priv/static/adminfe/static/js/chunk-cf57.42b96339.js.map
  82. +0
    -2
      priv/static/adminfe/static/js/chunk-cf58.e52693b3.js
  83. +0
    -1
      priv/static/adminfe/static/js/chunk-cf58.e52693b3.js.map
  84. +2
    -2
      priv/static/adminfe/static/js/chunk-e5cf.501d7902.js
  85. +1
    -1
      priv/static/adminfe/static/js/chunk-e5cf.501d7902.js.map
  86. +0
    -2
      priv/static/adminfe/static/js/runtime.ae93ea9f.js
  87. +2
    -0
      priv/static/adminfe/static/js/runtime.fa19e5d1.js
  88. +1
    -1
      priv/static/adminfe/static/js/runtime.fa19e5d1.js.map
  89. +4
    -4
      test/activity/ir/topics_test.exs
  90. +79
    -0
      test/earmark_renderer_test.exs
  91. +1
    -1
      test/plugs/cache_control_test.exs
  92. +52
    -14
      test/plugs/ensure_authenticated_plug_test.exs
  93. +1
    -1
      test/plugs/oauth_plug_test.exs
  94. +28
    -48
      test/plugs/rate_limiter_test.exs
  95. +1
    -12
      test/reverse_proxy/reverse_proxy_test.exs
  96. +24
    -0
      test/support/conn_case.ex
  97. +215
    -44
      test/web/activity_pub/activity_pub_controller_test.exs
  98. +4
    -0
      test/web/activity_pub/publisher_test.exs
  99. +0
    -65
      test/web/activity_pub/utils_test.exs
  100. +8
    -4
      test/web/admin_api/admin_api_controller_test.exs

+ 4
- 0
CHANGELOG.md View File

@@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [unreleased]
### Changed
- **Breaking:** BBCode and Markdown formatters will no longer return any `\n` and only use `<br/>` for newlines

## [2.0.0] - 2019-03-08
### Security
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.


+ 0
- 2
config/benchmark.exs View File

@@ -61,8 +61,6 @@ config :web_push_encryption, :vapid_details,

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

config :pleroma_job_queue, disabled: true

config :pleroma, Pleroma.ScheduledActivity,
daily_user_limit: 2,
total_user_limit: 3,


+ 0
- 4
config/config.exs View File

@@ -482,10 +482,6 @@ config :pleroma, :workers,
federator_outgoing: 5
]

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

config :auto_linker,
opts: [
extra: true,


+ 0
- 51
config/description.exs View File

@@ -1781,25 +1781,6 @@ config :pleroma, :config_description, [
]
},
%{
group: :pleroma_job_queue,
key: :queues,
type: :group,
description: "[Deprecated] Replaced with `Oban`/`:queues` (keeping the same format)"
},
%{
group: :pleroma,
key: Pleroma.Web.Federator.RetryQueue,
type: :group,
description: "[Deprecated] See `Oban` and `:workers` sections for configuration notes",
children: [
%{
key: :max_retries,
type: :integer,
description: "[Deprecated] Replaced as `Oban`/`:queues`/`:outgoing_federation` value"
}
]
},
%{
group: :pleroma,
key: Oban,
type: :group,
@@ -2008,25 +1989,6 @@ config :pleroma, :config_description, [
]
},
%{
group: :pleroma,
key: :fetch_initial_posts,
type: :group,
description: "Fetching initial posts settings",
children: [
%{
key: :enabled,
type: :boolean,
description: "Fetch posts when a new user is federated with"
},
%{
key: :pages,
type: :integer,
description: "The amount of pages to fetch",
suggestions: [5]
}
]
},
%{
group: :auto_linker,
key: :opts,
type: :group,
@@ -2597,19 +2559,6 @@ config :pleroma, :config_description, [
]
},
%{
group: :tesla,
type: :group,
description: "Tesla settings",
children: [
%{
key: :adapter,
type: :module,
description: "Tesla adapter",
suggestions: [Tesla.Adapter.Hackney, Tesla.Adapter.Gun]
}
]
},
%{
group: :pleroma,
key: :chat,
type: :group,


+ 2
- 0
config/test.exs View File

@@ -94,6 +94,8 @@ config :pleroma, Pleroma.Gun, Pleroma.GunMock

config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true

config :pleroma, Pleroma.Plugs.RemoteIp, enabled: false

if File.exists?("./config/test.secret.exs") do
import_config "test.secret.exs"
else


+ 1
- 1
docs/API/differences_in_mastoapi_responses.md View File

@@ -180,7 +180,7 @@ Post here request with grant_type=refresh_token to obtain new access token. Retu
## Account Registration
`POST /api/v1/accounts`

Has theses additionnal parameters (which are the same as in Pleroma-API):
Has theses additional parameters (which are the same as in Pleroma-API):
* `fullname`: optional
* `bio`: optional
* `captcha_solution`: optional, contains provider-specific captcha solution,


+ 2
- 1
docs/API/pleroma_api.md View File

@@ -288,10 +288,11 @@ Pleroma Conversations have the same general structure that Mastodon Conversation
2. Pleroma Conversations statuses can be requested by Conversation id.
3. Pleroma Conversations can be replied to.

Conversations have the additional field "recipients" under the "pleroma" key. This holds a list of all the accounts that will receive a message in this conversation.
Conversations have the additional field `recipients` under the `pleroma` key. This holds a list of all the accounts that will receive a message in this conversation.

The status posting endpoint takes an additional parameter, `in_reply_to_conversation_id`, which, when set, will set the visiblity to direct and address only the people who are the recipients of that Conversation.

⚠ Conversation IDs can be found in direct messages with the `pleroma.direct_conversation_id` key, do not confuse it with `pleroma.conversation_id`.

## `GET /api/v1/pleroma/conversations/:id/statuses`
### Timeline for a given conversation


+ 1
- 1
docs/clients.md View File

@@ -1,5 +1,5 @@
# Pleroma Clients
Note: Additionnal clients may be working but theses are officially supporting Pleroma.
Note: Additional clients may be working but theses are officially supporting Pleroma.
Feel free to contact us to be added to this list!

## Desktop


+ 0
- 8
docs/configuration/cheatsheet.md View File

@@ -151,14 +151,6 @@ config :pleroma, :mrf_user_allowlist,
* `sign_object_fetches`: Sign object fetches with HTTP signatures
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches

### :fetch_initial_posts

!!! warning
Be careful with this setting, fetching posts may lead to new users being discovered whose posts will then also be fetched. This can lead to serious load on your instance and database.

* `enabled`: If enabled, when a new user is discovered by your instance, fetch some of their latest posts.
* `pages`: The amount of pages to fetch

## Pleroma.ScheduledActivity

* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`)


+ 0
- 2
installation/pleroma.nginx View File

@@ -90,8 +90,6 @@ server {
proxy_ignore_client_abort on;
proxy_buffering on;
chunked_transfer_encoding on;
proxy_ignore_headers Cache-Control;
proxy_hide_header Cache-Control;
proxy_pass http://127.0.0.1:4000;
}
}

+ 1
- 1
lib/pleroma/activity/ir/topics.ex View File

@@ -39,7 +39,7 @@ defmodule Pleroma.Activity.Ir.Topics do
end
end

defp item_creation_tags(tags, %{data: %{"type" => "Create"}} = object, activity) do
defp item_creation_tags(tags, object, %{data: %{"type" => "Create"}} = activity) do
tags ++ hashtags_to_topics(object) ++ attachment_topics(object, activity)
end



+ 256
- 0
lib/pleroma/earmark_renderer.ex View File

@@ -0,0 +1,256 @@
# Pleroma: A lightweight social networking server
# Copyright © 2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
#
# This file is derived from Earmark, under the following copyright:
# Copyright © 2014 Dave Thomas, The Pragmatic Programmers
# SPDX-License-Identifier: Apache-2.0
# Upstream: https://github.com/pragdave/earmark/blob/master/lib/earmark/html_renderer.ex
defmodule Pleroma.EarmarkRenderer do
@moduledoc false

alias Earmark.Block
alias Earmark.Context
alias Earmark.HtmlRenderer
alias Earmark.Options

import Earmark.Inline, only: [convert: 3]
import Earmark.Helpers.HtmlHelpers
import Earmark.Message, only: [add_messages_from: 2, get_messages: 1, set_messages: 2]
import Earmark.Context, only: [append: 2, set_value: 2]
import Earmark.Options, only: [get_mapper: 1]

@doc false
def render(blocks, %Context{options: %Options{}} = context) do
messages = get_messages(context)

{contexts, html} =
get_mapper(context.options).(
blocks,
&render_block(&1, put_in(context.options.messages, []))
)
|> Enum.unzip()

all_messages =
contexts
|> Enum.reduce(messages, fn ctx, messages1 -> messages1 ++ get_messages(ctx) end)

{put_in(context.options.messages, all_messages), html |> IO.iodata_to_binary()}
end

#############
# Paragraph #
#############
defp render_block(%Block.Para{lnb: lnb, lines: lines, attrs: attrs}, context) do
lines = convert(lines, lnb, context)
add_attrs(lines, "<p>#{lines.value}</p>", attrs, [], lnb)
end

########
# Html #
########
defp render_block(%Block.Html{html: html}, context) do
{context, html}
end

defp render_block(%Block.HtmlComment{lines: lines}, context) do
{context, lines}
end

defp render_block(%Block.HtmlOneline{html: html}, context) do
{context, html}
end

#########
# Ruler #
#########
defp render_block(%Block.Ruler{lnb: lnb, attrs: attrs}, context) do
add_attrs(context, "<hr />", attrs, [], lnb)
end

###########
# Heading #
###########
defp render_block(
%Block.Heading{lnb: lnb, level: level, content: content, attrs: attrs},
context
) do
converted = convert(content, lnb, context)
html = "<h#{level}>#{converted.value}</h#{level}>"
add_attrs(converted, html, attrs, [], lnb)
end

##############
# Blockquote #
##############

defp render_block(%Block.BlockQuote{lnb: lnb, blocks: blocks, attrs: attrs}, context) do
{context1, body} = render(blocks, context)
html = "<blockquote>#{body}</blockquote>"
add_attrs(context1, html, attrs, [], lnb)
end

#########
# Table #
#########

defp render_block(
%Block.Table{lnb: lnb, header: header, rows: rows, alignments: aligns, attrs: attrs},
context
) do
{context1, html} = add_attrs(context, "<table>", attrs, [], lnb)
context2 = set_value(context1, html)

context3 =
if header do
append(add_trs(append(context2, "<thead>"), [header], "th", aligns, lnb), "</thead>")
else
# Maybe an error, needed append(context, html)
context2
end

context4 = append(add_trs(append(context3, "<tbody>"), rows, "td", aligns, lnb), "</tbody>")

{context4, [context4.value, "</table>"]}
end

########
# Code #
########

defp render_block(
%Block.Code{lnb: lnb, language: language, attrs: attrs} = block,
%Context{options: options} = context
) do
class =
if language, do: ~s{ class="#{code_classes(language, options.code_class_prefix)}"}, else: ""

tag = ~s[<pre><code#{class}>]
lines = options.render_code.(block)
html = ~s[#{tag}#{lines}</code></pre>]
add_attrs(context, html, attrs, [], lnb)
end

#########
# Lists #
#########

defp render_block(
%Block.List{lnb: lnb, type: type, blocks: items, attrs: attrs, start: start},
context
) do
{context1, content} = render(items, context)
html = "<#{type}#{start}>#{content}</#{type}>"
add_attrs(context1, html, attrs, [], lnb)
end

# format a single paragraph list item, and remove the para tags
defp render_block(
%Block.ListItem{lnb: lnb, blocks: blocks, spaced: false, attrs: attrs},
context
)
when length(blocks) == 1 do
{context1, content} = render(blocks, context)
content = Regex.replace(~r{</?p>}, content, "")
html = "<li>#{content}</li>"
add_attrs(context1, html, attrs, [], lnb)
end

# format a spaced list item
defp render_block(%Block.ListItem{lnb: lnb, blocks: blocks, attrs: attrs}, context) do
{context1, content} = render(blocks, context)
html = "<li>#{content}</li>"
add_attrs(context1, html, attrs, [], lnb)
end

##################
# Footnote Block #
##################

defp render_block(%Block.FnList{blocks: footnotes}, context) do
items =
Enum.map(footnotes, fn note ->
blocks = append_footnote_link(note)
%Block.ListItem{attrs: "#fn:#{note.number}", type: :ol, blocks: blocks}
end)

{context1, html} = render_block(%Block.List{type: :ol, blocks: items}, context)
{context1, Enum.join([~s[<div class="footnotes">], "<hr />", html, "</div>"])}
end

#######################################
# Isolated IALs are rendered as paras #
#######################################

defp render_block(%Block.Ial{verbatim: verbatim}, context) do
{context, "<p>{:#{verbatim}}</p>"}
end

####################
# IDDef is ignored #
####################

defp render_block(%Block.IdDef{}, context), do: {context, ""}

#####################################
# And here are the inline renderers #
#####################################

defdelegate br, to: HtmlRenderer
defdelegate codespan(text), to: HtmlRenderer
defdelegate em(text), to: HtmlRenderer
defdelegate strong(text), to: HtmlRenderer
defdelegate strikethrough(text), to: HtmlRenderer

defdelegate link(url, text), to: HtmlRenderer
defdelegate link(url, text, title), to: HtmlRenderer

defdelegate image(path, alt, title), to: HtmlRenderer

defdelegate footnote_link(ref, backref, number), to: HtmlRenderer

# Table rows
defp add_trs(context, rows, tag, aligns, lnb) do
numbered_rows =
rows
|> Enum.zip(Stream.iterate(lnb, &(&1 + 1)))

numbered_rows
|> Enum.reduce(context, fn {row, lnb}, ctx ->
append(add_tds(append(ctx, "<tr>"), row, tag, aligns, lnb), "</tr>")
end)
end

defp add_tds(context, row, tag, aligns, lnb) do
Enum.reduce(1..length(row), context, add_td_fn(row, tag, aligns, lnb))
end

defp add_td_fn(row, tag, aligns, lnb) do
fn n, ctx ->
style =
case Enum.at(aligns, n - 1, :default) do
:default -> ""
align -> " style=\"text-align: #{align}\""
end

col = Enum.at(row, n - 1)
converted = convert(col, lnb, set_messages(ctx, []))
append(add_messages_from(ctx, converted), "<#{tag}#{style}>#{converted.value}</#{tag}>")
end
end

###############################
# Append Footnote Return Link #
###############################

defdelegate append_footnote_link(note), to: HtmlRenderer
defdelegate append_footnote_link(note, fnlink), to: HtmlRenderer

defdelegate render_code(lines), to: HtmlRenderer

defp code_classes(language, prefix) do
["" | String.split(prefix || "")]
|> Enum.map(fn pfx -> "#{pfx}#{language}" end)
|> Enum.join(" ")
end
end

+ 17
- 2
lib/pleroma/plugs/ensure_authenticated_plug.ex View File

@@ -15,9 +15,24 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do
conn
end

def call(conn, _) do
def call(conn, options) do
perform =
cond do
options[:if_func] -> options[:if_func].()
options[:unless_func] -> !options[:unless_func].()
true -> true
end

if perform do
fail(conn)
else
conn
end
end

def fail(conn) do
conn
|> render_error(:forbidden, "Invalid credentials.")
|> halt
|> halt()
end
end

+ 12
- 6
lib/pleroma/plugs/federating_plug.ex View File

@@ -10,14 +10,20 @@ defmodule Pleroma.Web.FederatingPlug do
end

def call(conn, _opts) do
if Pleroma.Config.get([:instance, :federating]) do
if federating?() do
conn
else
conn
|> put_status(404)
|> Phoenix.Controller.put_view(Pleroma.Web.ErrorView)
|> Phoenix.Controller.render("404.json")
|> halt()
fail(conn)
end
end

def federating?, do: Pleroma.Config.get([:instance, :federating])

defp fail(conn) do
conn
|> put_status(404)
|> Phoenix.Controller.put_view(Pleroma.Web.ErrorView)
|> Phoenix.Controller.render("404.json")
|> halt()
end
end

+ 16
- 11
lib/pleroma/plugs/rate_limiter/rate_limiter.ex View File

@@ -78,7 +78,7 @@ defmodule Pleroma.Plugs.RateLimiter do
end

def call(conn, plug_opts) do
if disabled?() do
if disabled?(conn) do
handle_disabled(conn)
else
action_settings = action_settings(plug_opts)
@@ -87,9 +87,9 @@ defmodule Pleroma.Plugs.RateLimiter do
end

defp handle_disabled(conn) do
if Config.get(:env) == :prod do
Logger.warn("Rate limiter is disabled for localhost/socket")
end
Logger.warn(
"Rate limiter disabled due to forwarded IP not being found. Please ensure your reverse proxy is providing the X-Forwarded-For header or disable the RemoteIP plug/rate limiter."
)

conn
end
@@ -109,16 +109,21 @@ defmodule Pleroma.Plugs.RateLimiter do
end
end

def disabled? do
def disabled?(conn) do
localhost_or_socket =
Config.get([Pleroma.Web.Endpoint, :http, :ip])
|> Tuple.to_list()
|> Enum.join(".")
|> String.match?(~r/^local|^127.0.0.1/)
case Config.get([Pleroma.Web.Endpoint, :http, :ip]) do
{127, 0, 0, 1} -> true
{0, 0, 0, 0, 0, 0, 0, 1} -> true
{:local, _} -> true
_ -> false
end

remote_ip_disabled = not Config.get([Pleroma.Plugs.RemoteIp, :enabled])
remote_ip_not_found =
if Map.has_key?(conn.assigns, :remote_ip_found),
do: !conn.assigns.remote_ip_found,
else: false

localhost_or_socket and remote_ip_disabled
localhost_or_socket and remote_ip_not_found
end

@inspect_bucket_not_found {:error, :not_found}


+ 5
- 2
lib/pleroma/plugs/remote_ip.ex View File

@@ -7,6 +7,8 @@ defmodule Pleroma.Plugs.RemoteIp do
This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
"""

import Plug.Conn

@behaviour Plug

@headers ~w[
@@ -26,11 +28,12 @@ defmodule Pleroma.Plugs.RemoteIp do

def init(_), do: nil

def call(conn, _) do
def call(%{remote_ip: original_remote_ip} = conn, _) do
config = Pleroma.Config.get(__MODULE__, [])

if Keyword.get(config, :enabled, false) do
RemoteIp.call(conn, remote_ip_opts(config))
%{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts(config))
assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip)
else
conn
end


+ 4
- 1
lib/pleroma/plugs/static_fe_plug.ex View File

@@ -21,6 +21,9 @@ defmodule Pleroma.Plugs.StaticFEPlug do
defp enabled?, do: Pleroma.Config.get([:static_fe, :enabled], false)

defp accepts_html?(conn) do
conn |> get_req_header("accept") |> List.first() |> String.contains?("text/html")
case get_req_header(conn, "accept") do
[accept | _] -> String.contains?(accept, "text/html")
_ -> false
end
end
end

+ 6
- 1
lib/pleroma/plugs/uploaded_media.ex View File

@@ -14,9 +14,14 @@ defmodule Pleroma.Plugs.UploadedMedia do
# no slashes
@path "media"

@default_cache_control_header "public, max-age=1209600"

def init(_opts) do
static_plug_opts =
[]
[
headers: %{"cache-control" => @default_cache_control_header},
cache_control_for_etags: @default_cache_control_header
]
|> Keyword.put(:from, "__unconfigured_media_plug")
|> Keyword.put(:at, "/__unconfigured_media_plug")
|> Plug.Static.init()


+ 9
- 11
lib/pleroma/reverse_proxy/reverse_proxy.ex View File

@@ -5,7 +5,7 @@
defmodule Pleroma.ReverseProxy do
@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)
@keep_resp_headers @resp_cache_headers ++
~w(content-type content-disposition content-encoding content-range) ++
~w(accept-ranges vary)
@@ -32,9 +32,6 @@ defmodule Pleroma.ReverseProxy do
* request: `#{inspect(@keep_req_headers)}`
* response: `#{inspect(@keep_resp_headers)}`

If no caching headers (`#{inspect(@resp_cache_headers)}`) are returned by upstream, `cache-control` will be
set to `#{inspect(@default_cache_control_header)}`.

Options:

* `redirect_on_failure` (default `false`). Redirects the client to the real remote URL if there's any HTTP
@@ -291,16 +288,17 @@ defmodule Pleroma.ReverseProxy do

defp build_resp_cache_headers(headers, _opts) do
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
has_cache_control? = List.keymember?(headers, "cache-control", 0)

cond do
has_cache? && has_cache_control? ->
headers

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

true ->
List.keystore(


+ 25
- 31
lib/pleroma/user.ex View File

@@ -16,6 +16,7 @@ defmodule Pleroma.User do
alias Pleroma.Conversation.Participation
alias Pleroma.Delivery
alias Pleroma.FollowingRelationship
alias Pleroma.HTML
alias Pleroma.Keys
alias Pleroma.Notification
alias Pleroma.Object
@@ -839,10 +840,6 @@ defmodule Pleroma.User do
_e ->
with [_nick, _domain] <- String.split(nickname, "@"),
{:ok, user} <- fetch_by_nickname(nickname) do
if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
fetch_initial_posts(user)
end

{:ok, user}
else
_e -> {:error, "not found " <> nickname}
@@ -850,11 +847,6 @@ defmodule Pleroma.User do
end
end

@doc "Fetch some posts when the user has just been federated with"
def fetch_initial_posts(user) do
BackgroundWorker.enqueue("fetch_initial_posts", %{"user_id" => user.id})
end

@spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
def get_followers_query(%User{} = user, nil) do
User.Query.build(%{followers: user, deactivated: false})
@@ -1320,16 +1312,6 @@ defmodule Pleroma.User do
Repo.delete(user)
end

def perform(:fetch_initial_posts, %User{} = user) do
pages = Pleroma.Config.get!([:fetch_initial_posts, :pages])

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

def perform(:deactivate_async, user, status), do: deactivate(user, status)

@spec perform(atom(), User.t(), list()) :: list() | {:error, any()}
@@ -1458,18 +1440,7 @@ defmodule Pleroma.User do
if !is_nil(user) and !needs_update?(user) do
{:ok, user}
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])

resp = fetch_by_ap_id(ap_id)

if should_fetch_initial do
with {:ok, %User{} = user} <- resp do
fetch_initial_posts(user)
end
end

resp
fetch_by_ap_id(ap_id)
end
end

@@ -2062,4 +2033,27 @@ defmodule Pleroma.User do
|> validate_required([:invisible])
|> update_and_set_cache()
end

def sanitize_html(%User{} = user) do
sanitize_html(user, nil)
end

# User data that mastodon isn't filtering (treated as plaintext):
# - field name
# - display name
def sanitize_html(%User{} = user, filter) do
fields =
user
|> User.fields()
|> Enum.map(fn %{"name" => name, "value" => value} ->
%{
"name" => name,
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
}
end)

user
|> Map.put(:bio, HTML.filter_tags(user.bio, filter))
|> Map.put(:fields, fields)
end
end

+ 64
- 41
lib/pleroma/web/activity_pub/activity_pub_controller.ex View File

@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Delivery
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.Plugs.EnsureAuthenticatedPlug
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.InternalFetchActor
@@ -18,23 +19,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.FederatingPlug
alias Pleroma.Web.Federator

require Logger

action_fallback(:errors)

@federating_only_actions [:internal_fetch, :relay, :relay_following, :relay_followers]

plug(FederatingPlug when action in @federating_only_actions)

plug(
EnsureAuthenticatedPlug,
[unless_func: &FederatingPlug.federating?/0] when action not in @federating_only_actions
)

plug(
EnsureAuthenticatedPlug
when action in [:read_inbox, :update_outbox, :whoami, :upload_media, :following, :followers]
)

plug(
Pleroma.Plugs.Cache,
[query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2]
when action in [:activity, :object]
)

plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])
plug(:set_requester_reachable when action in [:inbox])
plug(:relay_active? when action in [:relay])

def relay_active?(conn, _) do
defp relay_active?(conn, _) do
if Pleroma.Config.get([:instance, :allow_relay]) do
conn
else
@@ -127,11 +142,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end

# GET /relay/following
def following(%{assigns: %{relay: true}} = conn, _params) do
conn
|> put_resp_content_type("application/activity+json")
|> put_view(UserView)
|> render("following.json", %{user: Relay.get_actor()})
def relay_following(conn, _params) do
with %{halted: false} = conn <- FederatingPlug.call(conn, []) do
conn
|> put_resp_content_type("application/activity+json")
|> put_view(UserView)
|> render("following.json", %{user: Relay.get_actor()})
end
end

def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do
@@ -164,11 +181,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end

# GET /relay/followers
def followers(%{assigns: %{relay: true}} = conn, _params) do
conn
|> put_resp_content_type("application/activity+json")
|> put_view(UserView)
|> render("followers.json", %{user: Relay.get_actor()})
def relay_followers(conn, _params) do
with %{halted: false} = conn <- FederatingPlug.call(conn, []) do
conn
|> put_resp_content_type("application/activity+json")
|> put_view(UserView)
|> render("followers.json", %{user: Relay.get_actor()})
end
end

def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do
@@ -200,13 +219,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end

def outbox(conn, %{"nickname" => nickname, "page" => page?} = params)
def outbox(
%{assigns: %{user: for_user}} = conn,
%{"nickname" => nickname, "page" => page?} = params
)
when page? in [true, "true"] do
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- User.ensure_keys_present(user) do
activities =
if params["max_id"] do
ActivityPub.fetch_user_activities(user, nil, %{
ActivityPub.fetch_user_activities(user, for_user, %{
"max_id" => params["max_id"],
# This is a hack because postgres generates inefficient queries when filtering by
# 'Answer', poll votes will be hidden by the visibility filter in this case anyway
@@ -214,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
"limit" => 10
})
else
ActivityPub.fetch_user_activities(user, nil, %{
ActivityPub.fetch_user_activities(user, for_user, %{
"limit" => 10,
"include_poll_votes" => true
})
@@ -255,8 +277,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, "ok")
end

# only accept relayed Creates
def inbox(conn, %{"type" => "Create"} = params) do
# POST /relay/inbox -or- POST /internal/fetch/inbox
def inbox(conn, params) do
if params["type"] == "Create" && FederatingPlug.federating?() do
post_inbox_relayed_create(conn, params)
else
post_inbox_fallback(conn, params)
end
end

defp post_inbox_relayed_create(conn, params) do
Logger.debug(
"Signature missing or not from author, relayed Create message, fetching object from source"
)
@@ -266,10 +296,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, "ok")
end

def inbox(conn, params) do
defp post_inbox_fallback(conn, params) do
headers = Enum.into(conn.req_headers, %{})

if String.contains?(headers["signature"], params["actor"]) do
if headers["signature"] && params["actor"] &&
String.contains?(headers["signature"], params["actor"]) do
Logger.debug(
"Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"
)
@@ -277,7 +308,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
Logger.debug(inspect(conn.req_headers))
end

json(conn, dgettext("errors", "error"))
conn
|> put_status(:bad_request)
|> json(dgettext("errors", "error"))
end

defp represent_service_actor(%User{} = user, conn) do
@@ -311,10 +344,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> render("user.json", %{user: user})
end

def whoami(_conn, _params), do: {:error, :not_found}

def read_inbox(
%{assigns: %{user: %{nickname: nickname} = user}} = conn,
%{assigns: %{user: %User{nickname: nickname} = user}} = conn,
%{"nickname" => nickname, "page" => page?} = params
)
when page? in [true, "true"] do
@@ -337,7 +368,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
})
end

def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{
def read_inbox(%{assigns: %{user: %User{nickname: nickname} = user}} = conn, %{
"nickname" => nickname
}) do
with {:ok, user} <- User.ensure_keys_present(user) do
@@ -348,15 +379,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end

def read_inbox(%{assigns: %{user: nil}} = conn, %{"nickname" => nickname}) do
err = dgettext("errors", "can't read inbox of %{nickname}", nickname: nickname)

conn
|> put_status(:forbidden)
|> json(err)
end

def read_inbox(%{assigns: %{user: %{nickname: as_nickname}}} = conn, %{
def read_inbox(%{assigns: %{user: %User{nickname: as_nickname}}} = conn, %{
"nickname" => nickname
}) do
err =
@@ -370,7 +393,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(err)
end

def handle_user_activity(user, %{"type" => "Create"} = params) do
defp handle_user_activity(%User{} = user, %{"type" => "Create"} = params) do
object =
params["object"]
|> Map.merge(Map.take(params, ["to", "cc"]))
@@ -386,7 +409,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
})
end

def handle_user_activity(user, %{"type" => "Delete"} = params) do
defp handle_user_activity(%User{} = user, %{"type" => "Delete"} = params) do
with %Object{} = object <- Object.normalize(params["object"]),
true <- user.is_moderator || user.ap_id == object.data["actor"],
{:ok, delete} <- ActivityPub.delete(object) do
@@ -396,7 +419,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end

def handle_user_activity(user, %{"type" => "Like"} = params) do
defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do
with %Object{} = object <- Object.normalize(params["object"]),
{:ok, activity, _object} <- ActivityPub.like(user, object) do
{:ok, activity}
@@ -405,7 +428,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end

def handle_user_activity(_, _) do
defp handle_user_activity(_, _) do
{:error, dgettext("errors", "Unhandled activity type")}
end

@@ -434,7 +457,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end

def update_outbox(%{assigns: %{user: user}} = conn, %{"nickname" => nickname} = _) do
def update_outbox(%{assigns: %{user: %User{} = user}} = conn, %{"nickname" => nickname}) do
err =
dgettext("errors", "can't update outbox of %{nickname} as %{as_nickname}",
nickname: nickname,
@@ -446,13 +469,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(err)
end

def errors(conn, {:error, :not_found}) do
defp errors(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> json(dgettext("errors", "Not found"))
end

def errors(conn, _e) do
defp errors(conn, _e) do
conn
|> put_status(:internal_server_error)
|> json(dgettext("errors", "error"))
@@ -492,7 +515,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
- HTTP Code: 201 Created
- HTTP Body: ActivityPub object to be inserted into another's `attachment` field
"""
def upload_media(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do
with {:ok, object} <-
ActivityPub.upload(
file,


+ 0
- 39
lib/pleroma/web/activity_pub/utils.ex View File

@@ -784,45 +784,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do

defp build_flag_object(_), do: []

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

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

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

#### Report-related helpers
def get_reports(params, page, page_size) do
params =


+ 1
- 6
lib/pleroma/web/activity_pub/views/user_view.ex View File

@@ -73,6 +73,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
{:ok, _, public_key} = Keys.keys_from_pem(user.keys)
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key])
user = User.sanitize_html(user)

endpoints = render("endpoints.json", %{user: user})

@@ -81,12 +82,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do
fields =
user
|> User.fields()
|> Enum.map(fn %{"name" => name, "value" => value} ->
%{
"name" => Pleroma.HTML.strip_tags(name),
"value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
}
end)
|> Enum.map(&Map.put(&1, "type", "PropertyValue"))

%{


+ 2
- 2
lib/pleroma/web/admin_api/admin_api_controller.ex View File

@@ -745,14 +745,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end

def list_statuses(%{assigns: %{user: admin}} = conn, params) do
def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
godmode = params["godmode"] == "true" || params["godmode"] == true
local_only = params["local_only"] == "true" || params["local_only"] == true
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
{page, page_size} = page_params(params)

activities =
ActivityPub.fetch_statuses(admin, %{
ActivityPub.fetch_statuses(nil, %{
"godmode" => godmode,
"local_only" => local_only,
"limit" => page_size,


+ 2
- 2
lib/pleroma/web/admin_api/views/account_view.ex View File

@@ -5,7 +5,6 @@
defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view

alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.MediaProxy
@@ -26,7 +25,8 @@ defmodule Pleroma.Web.AdminAPI.AccountView do

def render("show.json", %{user: user}) do
avatar = User.avatar_url(user) |> MediaProxy.url()
display_name = HTML.strip_tags(user.name || user.nickname)
display_name = Pleroma.HTML.strip_tags(user.name || user.nickname)
user = User.sanitize_html(user, FastSanitize.Sanitizer.StripTags)

%{
"id" => user.id,


+ 1
- 1
lib/pleroma/web/common_api/utils.ex View File

@@ -331,7 +331,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def format_input(text, "text/markdown", options) do
text
|> Formatter.mentions_escape(options)
|> Earmark.as_html!()
|> Earmark.as_html!(%Earmark.Options{renderer: Pleroma.EarmarkRenderer})
|> Formatter.linkify(options)
|> Formatter.html_escape("text/html")
end


+ 1
- 1
lib/pleroma/web/endpoint.ex View File

@@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Plugs.HTTPSecurityPlug)
plug(Pleroma.Plugs.UploadedMedia)

@static_cache_control "public max-age=86400 must-revalidate"
@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


+ 6
- 1
lib/pleroma/web/feed/user_controller.ex View File

@@ -25,7 +25,12 @@ defmodule Pleroma.Web.Feed.UserController do

def feed_redirect(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :user)
with %{halted: false} = conn <-
Pleroma.Plugs.EnsureAuthenticatedPlug.call(conn,
unless_func: &Pleroma.Web.FederatingPlug.federating?/0
) do
ActivityPubController.call(conn, :user)
end
end

def feed_redirect(conn, %{"nickname" => nickname}) do


+ 1
- 1
lib/pleroma/web/mastodon_api/controllers/auth_controller.ex View File

@@ -86,6 +86,6 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
@spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
defp get_or_make_app do
%{client_name: @local_mastodon_name, redirect_uris: "."}
|> App.get_or_make(["read", "write", "follow", "push"])
|> App.get_or_make(["read", "write", "follow", "push", "admin"])
end
end

+ 4
- 15
lib/pleroma/web/mastodon_api/views/account_view.ex View File

@@ -5,7 +5,6 @@
defmodule Pleroma.Web.MastodonAPI.AccountView do
use Pleroma.Web, :view

alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
@@ -67,6 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end

defp do_render("show.json", %{user: user} = opts) do
user = User.sanitize_html(user, User.html_filter_policy(opts[:for]))
display_name = user.name || user.nickname

image = User.avatar_url(user) |> MediaProxy.url()
@@ -100,17 +100,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
}
end)

fields =
user
|> User.fields()
|> Enum.map(fn %{"name" => name, "value" => value} ->
%{
"name" => name,
"value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
}
end)

bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
relationship = render("relationship.json", %{user: opts[:for], target: user})

%{
@@ -123,17 +112,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
followers_count: followers_count,
following_count: following_count,
statuses_count: user.note_count,
note: bio || "",
note: user.bio || "",
url: User.profile_url(user),
avatar: image,
avatar_static: image,
header: header,
header_static: header,
emojis: emojis,
fields: fields,
fields: user.fields,
bot: bot,
source: %{
note: HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
note: Pleroma.HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
sensitive: false,
fields: user.raw_fields,
pleroma: %{


+ 7
- 3
lib/pleroma/web/ostatus/ostatus_controller.ex View File

@@ -16,6 +16,10 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Web.Metadata.PlayerView
alias Pleroma.Web.Router

plug(Pleroma.Plugs.EnsureAuthenticatedPlug,
unless_func: &Pleroma.Web.FederatingPlug.federating?/0
)

plug(
RateLimiter,
[name: :ap_routes, params: ["uuid"]] when action in [:object, :activity]
@@ -135,13 +139,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end
end

def errors(conn, {:error, :not_found}) do
defp errors(conn, {:error, :not_found}) do
render_error(conn, :not_found, "Not found")
end

def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})

def errors(conn, _) do
defp errors(conn, _) do
render_error(conn, :internal_server_error, "Something went wrong")
end
end

+ 25
- 8
lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex View File

@@ -101,6 +101,11 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
else
_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end

@@ -108,9 +113,9 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
%{assigns: %{user: user}} = conn,
%{"id" => participation_id} = params
) do
participation = Participation.get(participation_id, preload: [:conversation])
if user.id == participation.user_id do
with %Participation{} = participation <-
Participation.get(participation_id, preload: [:conversation]),
true <- user.id == participation.user_id do
params =
params
|> Map.put("blocking_user", user)
@@ -126,6 +131,11 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
else
_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end

@@ -133,15 +143,22 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
%{assigns: %{user: user}} = conn,
%{"id" => participation_id, "recipients" => recipients}
) do
participation =
participation_id
|> Participation.get()

with true <- user.id == participation.user_id,
with %Participation{} = participation <- Participation.get(participation_id),
true <- user.id == participation.user_id,
{:ok, participation} <- Participation.set_recipients(participation, recipients) do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
else
{:error, message} ->
conn
|> put_status(:bad_request)
|> json(%{"error" => message})

_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end



+ 4
- 2
lib/pleroma/web/router.ex View File

@@ -541,6 +541,7 @@ defmodule Pleroma.Web.Router do
get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)
end

# Server to Server (S2S) AP interactions
pipeline :activitypub do
plug(:accepts, ["activity+json", "json"])
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
@@ -554,6 +555,7 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/outbox", ActivityPubController, :outbox)
end

# Client to Server (C2S) AP interactions
pipeline :activitypub_client do
plug(:accepts, ["activity+json", "json"])
plug(:fetch_session)
@@ -597,8 +599,8 @@ defmodule Pleroma.Web.Router do
post("/inbox", ActivityPubController, :inbox)
end

get("/following", ActivityPubController, :following, assigns: %{relay: true})
get("/followers", ActivityPubController, :followers, assigns: %{relay: true})
get("/following", ActivityPubController, :relay_following)
get("/followers", ActivityPubController, :relay_followers)
end

scope "/internal/fetch", Pleroma.Web.ActivityPub do


+ 22
- 11
lib/pleroma/web/static_fe/static_fe_controller.ex View File

@@ -17,6 +17,10 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
plug(:put_view, Pleroma.Web.StaticFE.StaticFEView)
plug(:assign_id)

plug(Pleroma.Plugs.EnsureAuthenticatedPlug,
unless_func: &Pleroma.Web.FederatingPlug.federating?/0
)

@page_keys ["max_id", "min_id", "limit", "since_id", "order"]

defp get_title(%Object{data: %{"name" => name}}) when is_binary(name),
@@ -33,7 +37,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
|> render("error.html", %{message: message, meta: ""})
end

def get_counts(%Activity{} = activity) do
defp get_counts(%Activity{} = activity) do
%Object{data: data} = Object.normalize(activity)

%{
@@ -43,9 +47,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
}
end

def represent(%Activity{} = activity), do: represent(activity, false)
defp represent(%Activity{} = activity), do: represent(activity, false)

def represent(%Activity{object: %Object{data: data}} = activity, selected) do
defp represent(%Activity{object: %Object{data: data}} = activity, selected) do
{:ok, user} = User.get_or_fetch(activity.object.data["actor"])

link =
@@ -54,10 +58,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
_ -> data["url"] || data["external_url"] || data["id"]
end

content =
if data["content"] do
Pleroma.HTML.filter_tags(data["content"])
else
nil
end

%{
user: user,
user: User.sanitize_html(user),
title: get_title(activity.object),
content: data["content"] || nil,
content: content,
attachment: data["attachment"],
link: link,
published: data["published"],
@@ -109,7 +120,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
next_page_id = List.last(timeline) && List.last(timeline).id

render(conn, "profile.html", %{
user: user,
user: User.sanitize_html(user),
timeline: timeline,
prev_page_id: prev_page_id,
next_page_id: next_page_id,
@@ -147,17 +158,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
end
end

def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts),
defp assign_id(%{path_info: ["notice", notice_id]} = conn, _opts),
do: assign(conn, :notice_id, notice_id)

def assign_id(%{path_info: ["users", user_id]} = conn, _opts),
defp assign_id(%{path_info: ["users", user_id]} = conn, _opts),
do: assign(conn, :username_or_id, user_id)

def assign_id(%{path_info: ["objects", object_id]} = conn, _opts),
defp assign_id(%{path_info: ["objects", object_id]} = conn, _opts),
do: assign(conn, :object_id, object_id)

def assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),
defp assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),
do: assign(conn, :activity_id, activity_id)

def assign_id(conn, _opts), do: conn
defp assign_id(conn, _opts), do: conn
end

+ 2
- 0
lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex View File

@@ -16,6 +16,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do

@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]

plug(Pleroma.Web.FederatingPlug)

# Note: follower can submit the form (with password auth) not being signed in (having no token)
plug(
OAuthScopesPlug,


+ 2
- 0
lib/pleroma/web/twitter_api/controllers/util_controller.ex View File

@@ -17,6 +17,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.WebFinger

plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe)

plug(
OAuthScopesPlug,
%{scopes: ["follow", "write:follows"]}


+ 0
- 4
lib/pleroma/workers/background_worker.ex View File

@@ -10,10 +10,6 @@ defmodule Pleroma.Workers.BackgroundWorker do
use Pleroma.Workers.WorkerHelper, queue: "background"

@impl Oban.Worker
def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do
user = User.get_cached_by_id(user_id)
User.perform(:fetch_initial_posts, user)
end

def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}, _job) do
user = User.get_cached_by_id(user_id)


+ 1
- 1
mix.exs View File

@@ -134,7 +134,7 @@ defmodule Pleroma.Mixfile do
{:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.6.6"},
{:earmark, "~> 1.3"},
{:bbcode, "~> 0.1.1"},
{:bbcode_pleroma, "~> 0.2.0"},
{:ex_machina, "~> 2.3", only: :test},
{:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
{:mock, "~> 0.3.3", only: :test},


+ 2
- 1
mix.lock View File

@@ -3,7 +3,8 @@
"auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]},
"base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"bbcode": {:hex, :bbcode, "0.1.1", "0023e2c7814119b2e620b7add67182e3f6019f92bfec9a22da7e99821aceba70", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5a981b98ac7d366a9b6bf40eac389aaf4d6e623c631e6b6f8a6b571efaafd338"},
"bbcode": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/bbcode.git", "f2d267675e9a7e1ad1ea9beb4cc23382762b66c2", [ref: "v0.2.0"]},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
"benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"cachex": {:hex, :cachex, "3.2.0", "a596476c781b0646e6cb5cd9751af2e2974c3e0d5498a8cab71807618b74fe2f", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "aef93694067a43697ae0531727e097754a9e992a1e7946296f5969d6dd9ac986"},


+ 10
- 0
priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs View File

@@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.ConfigRemoveFetchInitialPosts do
use Ecto.Migration

def change do
execute(
"delete from config where config.key = ':fetch_initial_posts' and config.group = ':pleroma';",
""
)
end
end

+ 10
- 0
priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs View File

@@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.DeleteFetchInitialPostsJobs do
use Ecto.Migration

def change do
execute(
"delete from oban_jobs where worker = 'Pleroma.Workers.BackgroundWorker' and args->>'op' = 'fetch_initial_posts';",
""
)
end
end

priv/static/adminfe/chunk-17a5.edcdbe30.css → priv/static/adminfe/chunk-0d8f.650c8e81.css View File


priv/static/adminfe/chunk-2b8b.0f1ee211.css → priv/static/adminfe/chunk-136a.3936457d.css View File


priv/static/adminfe/chunk-15fa.dc3643e6.css → priv/static/adminfe/chunk-15fa.5a5f973d.css View File


priv/static/adminfe/chunk-46cf.6dd5bbb7.css → priv/static/adminfe/chunk-46cf.a43e9415.css View File


priv/static/adminfe/chunk-453a.bbab87da.css → priv/static/adminfe/chunk-46ef.d45db7be.css View File


priv/static/adminfe/chunk-4e7d.7aace723.css
File diff suppressed because it is too large
View File


priv/static/adminfe/chunk-4e46.ad5e9ff3.css → priv/static/adminfe/chunk-4ffb.dd09fe2e.css View File


priv/static/adminfe/chunk-6dd6.85f319f7.css → priv/static/adminfe/chunk-876c.90dffac4.css View File


priv/static/adminfe/chunk-87b3.2affd602.css
File diff suppressed because it is too large
View File


priv/static/adminfe/chunk-cf58.80435fa1.css → priv/static/adminfe/chunk-cf57.4d39576f.css View File

@@ -1 +1 @@
.actions-button[data-v-3850612b]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-3850612b]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-3850612b]{float:right}.el-icon-edit[data-v-3850612b]{margin-right:5px}.tag-container[data-v-3850612b]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-3850612b]{padding-right:20px}.no-hover[data-v-3850612b]:hover{color:#606266;background-color:#fff;cursor:auto}.status-card{margin-bottom:10px}.status-card .account{text-decoration:underline;line-height:26px;font-size:13px}.status-card .image{width:20%}.status-card .image img{width:100%}.status-card .show-more-button{margin-left:5px}.status-card .status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-card .status-avatar-img{display:inline-block;width:15px;height:15px;margin-right:5px}.status-card .status-account-name{display:inline-block;margin:0;height:22px}.status-card .status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-card .status-checkbox{margin-right:7px}.status-card .status-content{font-size:15px;line-height:26px}.status-card .status-deleted{font-style:italic;margin-top:3px}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.status-card .status-without-content{font-style:italic}@media only screen and (max-width:480px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.statuses-container{padding:0 15px}.statuses-container .status-container{margin:0 0 10px}.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 0 15px}.select-instance{width:350px}.statuses-pagination{padding:15px 0;text-align:center}h1{margin:22px 0 0}@media only screen and (max-width:480px){.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:10px 0}.select-field{width:100%;margin-bottom:5px}.select-instance{width:100%}}
.actions-button[data-v-3850612b]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-3850612b]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-3850612b]{float:right}.el-icon-edit[data-v-3850612b]{margin-right:5px}.tag-container[data-v-3850612b]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-3850612b]{padding-right:20px}.no-hover[data-v-3850612b]:hover{color:#606266;background-color:#fff;cursor:auto}.status-card{margin-bottom:10px}.status-card .account{text-decoration:underline;line-height:26px;font-size:13px}.status-card .image{width:20%}.status-card .image img{width:100%}.status-card .show-more-button{margin-left:5px}.status-card .status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-card .status-avatar-img{display:inline-block;width:15px;height:15px;margin-right:5px}.status-card .status-account-name{display:inline-block;margin:0;height:22px}.status-card .status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-card .status-checkbox{margin-right:7px}.status-card .status-content{font-size:15px;line-height:26px}.status-card .status-deleted{font-style:italic;margin-top:3px}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.status-card .status-without-content{font-style:italic}@media only screen and (max-width:480px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.statuses-container{padding:0 15px}.statuses-container .status-container{margin:0 0 10px}.checkbox-container{margin-bottom:15px}.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 0 15px}.select-instance{width:350px}.statuses-pagination{padding:15px 0;text-align:center}h1{margin:22px 0 0}@media only screen and (max-width:480px){.checkbox-container{margin-bottom:10px}.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:10px 0}.select-field{width:100%;margin-bottom:5px}.select-instance{width:100%}}

priv/static/adminfe/chunk-560d.802cfba1.css → priv/static/adminfe/chunk-e5cf.cba3ae06.css View File


+ 1
- 1
priv/static/adminfe/index.html View File

@@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.1abbc9b8.css rel=stylesheet><link href=chunk-libs.686b5876.css rel=stylesheet><link href=app.c836e084.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.ae93ea9f.js></script><script type=text/javascript src=static/js/chunk-elementUI.fba0efec.js></script><script type=text/javascript src=static/js/chunk-libs.b8c453ab.js></script><script type=text/javascript src=static/js/app.55df3157.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.1abbc9b8.css rel=stylesheet><link href=chunk-libs.686b5876.css rel=stylesheet><link href=app.c836e084.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.fa19e5d1.js></script><script type=text/javascript src=static/js/chunk-elementUI.fba0efec.js></script><script type=text/javascript src=static/js/chunk-libs.b8c453ab.js></script><script type=text/javascript src=static/js/app.d2c3c6b3.js></script></body></html>

+ 0
- 2
priv/static/adminfe/static/js/app.55df3157.js
File diff suppressed because it is too large
View File


+ 0
- 1
priv/static/adminfe/static/js/app.55df3157.js.map
File diff suppressed because it is too large
View File


+ 2
- 0
priv/static/adminfe/static/js/app.d2c3c6b3.js
File diff suppressed because it is too large
View File


+ 1
- 0
priv/static/adminfe/static/js/app.d2c3c6b3.js.map
File diff suppressed because it is too large
View File


+ 0
- 2
priv/static/adminfe/static/js/chunk-03b0.7a203856.js
File diff suppressed because it is too large
View File


+ 0
- 1
priv/static/adminfe/static/js/chunk-03b0.7a203856.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-0d8f.a85e3222.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-136a.142aa42a.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-136a.142aa42a.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-15fa.34070731.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-15fa.34070731.js.map
File diff suppressed because it is too large
View File


+ 0
- 2
priv/static/adminfe/static/js/chunk-293a.a728de01.js
File diff suppressed because it is too large
View File


+ 0
- 1
priv/static/adminfe/static/js/chunk-293a.a728de01.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-46cf.3bd3567a.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-46ef.215af110.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-46ef.215af110.js.map
File diff suppressed because it is too large
View File


+ 2
- 0
priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js
File diff suppressed because it is too large
View File


+ 1
- 0
priv/static/adminfe/static/js/chunk-4e7d.a40ad735.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-4e46.d257e435.js → priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-4e46"],{BF41:function(t,a,i){},"UUO+":function(t,a,i){"use strict";i.r(a);var e=i("zGwZ"),s=i.n(e),r={name:"Page401",data:function(){return{errGif:s.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=(i("UrVv"),i("KHd+")),l=Object(n.a)(r,function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("返回")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("Oops!")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("回首页")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},[],!1,null,"ab9be52c",null);l.options.__file="401.vue";a.default=l.exports},UrVv:function(t,a,i){"use strict";var e=i("BF41");i.n(e).a},zGwZ:function(t,a,i){t.exports=i.p+"static/img/401.089007e.gif"}}]);
//# sourceMappingURL=chunk-4e46.d257e435.js.map
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-4ffb"],{BF41:function(t,a,i){},"UUO+":function(t,a,i){"use strict";i.r(a);var s=i("zGwZ"),e=i.n(s),r={name:"Page401",data:function(){return{errGif:e.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=(i("UrVv"),i("KHd+")),l=Object(n.a)(r,function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("返回")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("Oops!")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("回首页")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},[],!1,null,"ab9be52c",null);l.options.__file="401.vue";a.default=l.exports},UrVv:function(t,a,i){"use strict";var s=i("BF41");i.n(s).a},zGwZ:function(t,a,i){t.exports=i.p+"static/img/401.089007e.gif"}}]);
//# sourceMappingURL=chunk-4ffb.0e8f3772.js.map

priv/static/adminfe/static/js/chunk-4ffb.0e8f3772.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-876c.e4ceccca.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-876c.e4ceccca.js.map
File diff suppressed because it is too large
View File


+ 2
- 0
priv/static/adminfe/static/js/chunk-87b3.4704cadf.js
File diff suppressed because it is too large
View File


+ 1
- 0
priv/static/adminfe/static/js/chunk-87b3.4704cadf.js.map
File diff suppressed because it is too large
View File


+ 2
- 0
priv/static/adminfe/static/js/chunk-cf57.42b96339.js
File diff suppressed because it is too large
View File


+ 1
- 0
priv/static/adminfe/static/js/chunk-cf57.42b96339.js.map
File diff suppressed because it is too large
View File


+ 0
- 2
priv/static/adminfe/static/js/chunk-cf58.e52693b3.js
File diff suppressed because it is too large
View File


+ 0
- 1
priv/static/adminfe/static/js/chunk-cf58.e52693b3.js.map
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-e5cf.501d7902.js
File diff suppressed because it is too large
View File


priv/static/adminfe/static/js/chunk-e5cf.501d7902.js.map
File diff suppressed because it is too large
View File


+ 0
- 2
priv/static/adminfe/static/js/runtime.ae93ea9f.js View File

@@ -1,2 +0,0 @@
!function(e){function n(n){for(var r,c,o=n[0],f=n[1],i=n[2],d=0,l=[];d<o.length;d++)c=o[d],u[c]&&l.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);for(h&&h(n);l.length;)l.shift()();return a.push.apply(a,i||[]),t()}function t(){for(var e,n=0;n<a.length;n++){for(var t=a[n],r=!0,c=1;c<t.length;c++){var f=t[c];0!==u[f]&&(r=!1)}r&&(a.splice(n--,1),e=o(o.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=[];c[e]?n.push(c[e]):0!==c[e]&&{"chunk-17a5":1,"chunk-15fa":1,"chunk-2b8b":1,"chunk-453a":1,"chunk-4e46":1,"chunk-03b0":1,"chunk-560d":1,"chunk-293a":1,"chunk-46cf":1,"chunk-cf58":1,"chunk-6dd6":1}[e]&&n.push(c[e]=new Promise(function(n,t){for(var r=({}[e]||e)+"."+{"7zzA":"31d6cfe0",JEtC:"31d6cfe0",ZhIB:"31d6cfe0","chunk-17a5":"edcdbe30","chunk-15fa":"dc3643e6","chunk-2b8b":"0f1ee211","chunk-453a":"bbab87da","chunk-4e46":"ad5e9ff3","chunk-7f9e":"31d6cfe0","chunk-03b0":"49362218","chunk-df62":"31d6cfe0","chunk-560d":"802cfba1","chunk-293a":"a8b5ee5b","chunk-46cf":"6dd5bbb7","chunk-cf58":"80435fa1",oAJy:"31d6cfe0","chunk-16d0":"31d6cfe0","chunk-6dd6":"85f319f7"}[e]+".css",c=o.p+r,u=document.getElementsByTagName("link"),a=0;a<u.length;a++){var f=(d=u[a]).getAttribute("data-href")||d.getAttribute("href");if("stylesheet"===d.rel&&(f===r||f===c))return n()}var i=document.getElementsByTagName("style");for(a=0;a<i.length;a++){var d;if((f=(d=i[a]).getAttribute("data-href"))===r||f===c)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||c,u=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");u.request=r,t(u)},h.href=c,document.getElementsByTagName("head")[0].appendChild(h)}).then(function(){c[e]=0}));var t=u[e];if(0!==t)if(t)n.push(t[2]);else{var r=new Promise(function(n,r){t=u[e]=[n,r]});n.push(t[2]=r);var a,f=document.createElement("script");f.charset="utf-8",f.timeout=120,o.nc&&f.setAttribute("nonce",o.nc),f.src=function(e){return o.p+"static/js/"+({}[e]||e)+"."+{"7zzA":"e1ae1c94",JEtC:"f9ba4594",ZhIB:"861df339","chunk-17a5":"13b13757","chunk-15fa":"15303f3a","chunk-2b8b":"e3daf966","chunk-453a":"2fcd7192","chunk-4e46":"d257e435","chunk-7f9e":"c49aa694","chunk-03b0":"7a203856","chunk-df62":"6c5105a6","chunk-560d":"a8bb8682","chunk-293a":"a728de01","chunk-46cf":"104380a9","chunk-cf58":"e52693b3",oAJy:"840fb1c2","chunk-16d0":"6ce78978","chunk-6dd6":"6c139a9c"}[e]+".js"}(e),a=function(n){f.onerror=f.onload=null,clearTimeout(i);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,t[1](a)}u[e]=void 0}};var i=setTimeout(function(){a({type:"timeout",target:f})},12e4);f.onerror=f.onload=a,document.head.appendChild(f)}return Promise.all(n)},o.m=e,o.c=r,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="",o.oe=function(e){throw console.error(e),e};var f=window.webpackJsonp=window.webpackJsonp||[],i=f.push.bind(f);f.push=n,f=f.slice();for(var d=0;d<f.length;d++)n(f[d]);var h=i;t()}([]);
//# sourceMappingURL=runtime.ae93ea9f.js.map

+ 2
- 0
priv/static/adminfe/static/js/runtime.fa19e5d1.js View File

@@ -0,0 +1,2 @@
!function(e){function n(n){for(var r,c,f=n[0],o=n[1],i=n[2],h=0,l=[];h<f.length;h++)c=f[h],u[c]&&l.push(u[c][0]),u[c]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(e[r]=o[r]);for(d&&d(n);l.length;)l.shift()();return a.push.apply(a,i||[]),t()}function t(){for(var e,n=0;n<a.length;n++){for(var t=a[n],r=!0,c=1;c<t.length;c++){var o=t[c];0!==u[o]&&(r=!1)}r&&(a.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[];c[e]?n.push(c[e]):0!==c[e]&&{"chunk-0d8f":1,"chunk-136a":1,"chunk-15fa":1,"chunk-46ef":1,"chunk-4ffb":1,"chunk-87b3":1,"chunk-e5cf":1,"chunk-46cf":1,"chunk-4e7d":1,"chunk-cf57":1,"chunk-876c":1}[e]&&n.push(c[e]=new Promise(function(n,t){for(var r=({}[e]||e)+"."+{"7zzA":"31d6cfe0",JEtC:"31d6cfe0",ZhIB:"31d6cfe0","chunk-0d8f":"650c8e81","chunk-136a":"3936457d","chunk-15fa":"5a5f973d","chunk-46ef":"d45db7be","chunk-4ffb":"dd09fe2e","chunk-7f9e":"31d6cfe0","chunk-87b3":"2affd602","chunk-df62":"31d6cfe0","chunk-e5cf":"cba3ae06","chunk-46cf":"a43e9415","chunk-4e7d":"7aace723","chunk-cf57":"4d39576f",oAJy:"31d6cfe0","chunk-16d0":"31d6cfe0","chunk-876c":"90dffac4"}[e]+".css",c=f.p+r,u=document.getElementsByTagName("link"),a=0;a<u.length;a++){var o=(h=u[a]).getAttribute("data-href")||h.getAttribute("href");if("stylesheet"===h.rel&&(o===r||o===c))return n()}var i=document.getElementsByTagName("style");for(a=0;a<i.length;a++){var h;if((o=(h=i[a]).getAttribute("data-href"))===r||o===c)return n()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=n,d.onerror=function(n){var r=n&&n.target&&n.target.src||c,u=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");u.request=r,t(u)},d.href=c,document.getElementsByTagName("head")[0].appendChild(d)}).then(function(){c[e]=0}));var t=u[e];if(0!==t)if(t)n.push(t[2]);else{var r=new Promise(function(n,r){t=u[e]=[n,r]});n.push(t[2]=r);var a,o=document.createElement("script");o.charset="utf-8",o.timeout=120,f.nc&&o.setAttribute("nonce",f.nc),o.src=function(e){return f.p+"static/js/"+({}[e]||e)+"."+{"7zzA":"e1ae1c94",JEtC:"f9ba4594",ZhIB:"861df339","chunk-0d8f":"a85e3222","chunk-136a":"142aa42a","chunk-15fa":"34070731","chunk-46ef":"215af110","chunk-4ffb":"0e8f3772","chunk-7f9e":"c49aa694","chunk-87b3":"4704cadf","chunk-df62":"6c5105a6","chunk-e5cf":"501d7902","chunk-46cf":"3bd3567a","chunk-4e7d":"a40ad735","chunk-cf57":"42b96339",oAJy:"840fb1c2","chunk-16d0":"6ce78978","chunk-876c":"e4ceccca"}[e]+".js"}(e),a=function(n){o.onerror=o.onload=null,clearTimeout(i);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,t[1](a)}u[e]=void 0}};var i=setTimeout(function(){a({type:"timeout",target:o})},12e4);o.onerror=o.onload=a,document.head.appendChild(o)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var o=window.webpackJsonp=window.webpackJsonp||[],i=o.push.bind(o);o.push=n,o=o.slice();for(var h=0;h<o.length;h++)n(o[h]);var d=i;t()}([]);
//# sourceMappingURL=runtime.fa19e5d1.js.map

priv/static/adminfe/static/js/runtime.fa19e5d1.js.map
File diff suppressed because it is too large
View File


+ 4
- 4
test/activity/ir/topics_test.exs View File

@@ -59,8 +59,8 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
describe "public visibility create events" do
setup do
activity = %Activity{
object: %Object{data: %{"type" => "Create", "attachment" => []}},
data: %{"to" => [Pleroma.Constants.as_public()]}
object: %Object{data: %{"attachment" => []}},
data: %{"type" => "Create", "to" => [Pleroma.Constants.as_public()]}
}

{:ok, activity: activity}
@@ -98,8 +98,8 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
describe "public visibility create events with attachments" do
setup do
activity = %Activity{
object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}},
data: %{"to" => [Pleroma.Constants.as_public()]}
object: %Object{data: %{"attachment" => ["foo"]}},
data: %{"type" => "Create", "to" => [Pleroma.Constants.as_public()]}
}

{:ok, activity: activity}


+ 79
- 0
test/earmark_renderer_test.exs View File

@@ -0,0 +1,79 @@
# Pleroma: A lightweight social networking server
# Copyright © 2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.EarmarkRendererTest do
use ExUnit.Case

test "Paragraph" do
code = ~s[Hello\n\nWorld!]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<p>Hello</p><p>World!</p>"
end

test "raw HTML" do
code = ~s[<a href="http://example.org/">OwO</a><!-- what's this?-->]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<p>#{code}</p>"
end

test "rulers" do
code = ~s[before\n\n-----\n\nafter]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<p>before</p><hr /><p>after</p>"
end

test "headings" do
code = ~s[# h1\n## h2\n### h3\n]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<h1>h1</h1><h2>h2</h2><h3>h3</h3>]
end

test "blockquote" do
code = ~s[> whoms't are you quoting?]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<blockquote><p>whoms’t are you quoting?</p></blockquote>"
end

test "code" do
code = ~s[`mix`]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<p><code class="inline">mix</code></p>]

code = ~s[``mix``]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<p><code class="inline">mix</code></p>]

code = ~s[```\nputs "Hello World"\n```]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<pre><code class="">puts &quot;Hello World&quot;</code></pre>]
end

test "lists" do
code = ~s[- one\n- two\n- three\n- four]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>"

code = ~s[1. one\n2. two\n3. three\n4. four\n]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>"
end

test "delegated renderers" do
code = ~s[a<br/>b]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == "<p>#{code}</p>"

code = ~s[*aaaa~*]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<p><em>aaaa~</em></p>]

code = ~s[**aaaa~**]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<p><strong>aaaa~</strong></p>]

# strikethrought
code = ~s[<del>aaaa~</del>]
result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
assert result == ~s[<p><del>aaaa~</del></p>]
end
end

+ 1
- 1
test/plugs/cache_control_test.exs View File

@@ -9,7 +9,7 @@ defmodule Pleroma.Web.CacheControlTest do
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 max-age=86400 must-revalidate"]
assert Conn.get_resp_header(conn, "cache-control") == ["public, no-cache"]
end

test "Verify Cache-Control header on the API", %{conn: conn} do


+ 52
- 14
test/plugs/ensure_authenticated_plug_test.exs View File

@@ -8,24 +8,62 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do
alias Pleroma.Plugs.EnsureAuthenticatedPlug
alias Pleroma.User

test "it halts if no user is assigned", %{conn: conn} do
conn =
conn
|> EnsureAuthenticatedPlug.call(%{})
describe "without :if_func / :unless_func options" do
test "it halts if user is NOT assigned", %{conn: conn} do
conn = EnsureAuthenticatedPlug.call(conn, %{})

assert conn.status == 403
assert conn.halted == true
assert conn.status == 403
assert conn.halted == true
end

test "it continues if a user is assigned", %{conn: conn} do
conn = assign(conn, :user, %User{})
ret_conn = EnsureAuthenticatedPlug.call(conn, %{})

assert ret_conn == conn
end
end

test "it continues if a user is assigned", %{conn: conn} do
conn =
conn
|> assign(:user, %User{})
describe "with :if_func / :unless_func options" do
setup do
%{
true_fn: fn -> true end,
false_fn: fn -> false end
}
end

test "it continues if a user is assigned", %{conn: conn, true_fn: true_fn, false_fn: false_fn} do
conn = assign(conn, :user, %User{})
assert EnsureAuthenticatedPlug.call(conn, if_func: true_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn
assert EnsureAuthenticatedPlug.call(conn, unless_func: false_fn) == conn
end

test "it continues if a user is NOT assigned but :if_func evaluates to `false`",
%{conn: conn, false_fn: false_fn} do
assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn
end

test "it continues if a user is NOT assigned but :unless_func evaluates to `true`",
%{conn: conn, true_fn: true_fn} do
assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn
end

test "it halts if a user is NOT assigned and :if_func evaluates to `true`",
%{conn: conn, true_fn: true_fn} do
conn = EnsureAuthenticatedPlug.call(conn, if_func: true_fn)

assert conn.status == 403
assert conn.halted == true
end

ret_conn =
conn
|> EnsureAuthenticatedPlug.call(%{})
test "it halts if a user is NOT assigned and :unless_func evaluates to `false`",
%{conn: conn, false_fn: false_fn} do
conn = EnsureAuthenticatedPlug.call(conn, unless_func: false_fn)

assert ret_conn == conn
assert conn.status == 403
assert conn.halted == true
end
end
end

+ 1
- 1
test/plugs/oauth_plug_test.exs View File

@@ -38,7 +38,7 @@ defmodule Pleroma.Plugs.OAuthPlugTest do
assert conn.assigns[:user] == opts[:user]
end

test "with valid token(downcase) in url parameters, it assings the user", opts do
test "with valid token(downcase) in url parameters, it assigns the user", opts do
conn =
:get
|> build_conn("/?access_token=#{opts[:token]}")


+ 28
- 48
test/plugs/rate_limiter_test.exs View File

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

defmodule Pleroma.Plugs.RateLimiterTest do
use ExUnit.Case, async: true
use Plug.Test
use Pleroma.Web.ConnCase

alias Pleroma.Config
alias Pleroma.Plugs.RateLimiter
@@ -36,63 +35,44 @@ defmodule Pleroma.Plugs.RateLimiterTest do
|> RateLimiter.init()
|> RateLimiter.action_settings()
end
end

test "it is disabled for localhost" do
Config.put([:rate_limit, @limiter_name], {1, 1})
Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)

assert RateLimiter.disabled?() == true
end
test "it is disabled if it remote ip plug is enabled but no remote ip is found" do
Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
assert RateLimiter.disabled?(Plug.Conn.assign(build_conn(), :remote_ip_found, false))
end

test "it is disabled for socket" do
Config.put([:rate_limit, @limiter_name], {1, 1})
Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)
test "it restricts based on config values" do
limiter_name = :test_plug_opts
scale = 80
limit = 5

assert RateLimiter.disabled?() == true
end
Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
Config.put([:rate_limit, limiter_name], {scale, limit})

test "it is enabled for socket when remote ip is enabled" do
Config.put([:rate_limit, @limiter_name], {1, 1})
Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
plug_opts = RateLimiter.init(name: limiter_name)
conn = conn(:get, "/")

assert RateLimiter.disabled?() == false
for i <- 1..5 do
conn = RateLimiter.call(conn, plug_opts)
assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
Process.sleep(10)
end

test "it restricts based on config values" do
limiter_name = :test_plug_opts
scale = 80
limit = 5

Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
Config.put([:rate_limit, limiter_name], {scale, limit})

plug_opts = RateLimiter.init(name: limiter_name)
conn = conn(:get, "/")

for i <- 1..5 do
conn = RateLimiter.call(conn, plug_opts)
assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
Process.sleep(10)
end
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert conn.halted

conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
Process.sleep(50)

Process.sleep(50)
conn = conn(:get, "/")

conn = conn(:get, "/")
conn = RateLimiter.call(conn, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)

conn = RateLimiter.call(conn, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)

refute conn.status == Plug.Conn.Status.code(:too_many_requests)
refute conn.resp_body
refute conn.halted
end
refute conn.status == Plug.Conn.Status.code(:too_many_requests)
refute conn.resp_body
refute conn.halted
end

describe "options" do


+ 1
- 12
test/reverse_proxy/reverse_proxy_test.exs View File

@@ -278,17 +278,6 @@ defmodule Pleroma.ReverseProxyTest do
end

describe "cache resp headers" do
test "returns headers", %{conn: conn} do
ClientMock
|> expect(:request, fn :get, "/cache/" <> ttl, _, _, _ ->
{:ok, 200, [{"cache-control", "public, max-age=" <> ttl}], %{}}
end)
|> expect(:stream_body, fn _ -> :done end)

conn = ReverseProxy.call(conn, "/cache/10")
assert {"cache-control", "public, max-age=10"} in conn.resp_headers
end

test "add cache-control", %{conn: conn} do
ClientMock
|> expect(:request, fn :get, "/cache", _, _, _ ->
@@ -297,7 +286,7 @@ defmodule Pleroma.ReverseProxyTest do
|> expect(:stream_body, fn _ -> :done end)

conn = ReverseProxy.call(conn, "/cache")
assert {"cache-control", "public"} in conn.resp_headers
assert {"cache-control", "public, max-age=1209600"} in conn.resp_headers
end
end



+ 24
- 0
test/support/conn_case.ex View File

@@ -26,6 +26,8 @@ defmodule Pleroma.Web.ConnCase do
use Pleroma.Tests.Helpers
import Pleroma.Web.Router.Helpers

alias Pleroma.Config

# The default endpoint for testing
@endpoint Pleroma.Web.Endpoint

@@ -48,6 +50,28 @@ defmodule Pleroma.Web.ConnCase do

%{user: user, token: token, conn: conn}
end

defp ensure_federating_or_authenticated(conn, url, user) do
initial_setting = Config.get([:instance, :federating])
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)

Config.put([:instance, :federating], false)

conn
|> get(url)
|> response(403)

conn
|> assign(:user, user)
|> get(url)
|> response(200)

Config.put([:instance, :federating], true)

conn
|> get(url)
|> response(200)
end
end
end



+ 215
- 44
test/web/activity_pub/activity_pub_controller_test.exs View File

@@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

import Pleroma.Factory
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Delivery
alias Pleroma.Instances
alias Pleroma.Object
@@ -25,9 +26,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
:ok
end

clear_config_all([:instance, :federating],
do: Pleroma.Config.put([:instance, :federating], true)
)
clear_config([:instance, :federating]) do
Config.put([:instance, :federating], true)
end

describe "/relay" do
clear_config([:instance, :allow_relay])
@@ -42,12 +43,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end

test "with the relay disabled, it returns 404", %{conn: conn} do
Pleroma.Config.put([:instance, :allow_relay], false)
Config.put([:instance, :allow_relay], false)

conn
|> get(activity_pub_path(conn, :relay))
|> json_response(404)
end

test "on non-federating instance, it returns 404", %{conn: conn} do
Config.put([:instance, :federating], false)
user = insert(:user)

conn
|> assign(:user, user)
|> get(activity_pub_path(conn, :relay))
|> json_response(404)
|> assert
end
end

@@ -60,6 +70,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

assert res["id"] =~ "/fetch"
end

test "on non-federating instance, it returns 404", %{conn: conn} do
Config.put([:instance, :federating], false)
user = insert(:user)

conn
|> assign(:user, user)
|> get(activity_pub_path(conn, :internal_fetch))
|> json_response(404)
end
end

describe "/users/:nickname" do
@@ -123,9 +143,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

assert json_response(conn, 404)
end

test "it returns error when user is not found", %{conn: conn} do
response =
conn
|> put_req_header("accept", "application/json")
|> get("/users/jimm")
|> json_response(404)

assert response == "Not found"
end

test "it requires authentication if instance is NOT federating", %{
conn: conn
} do
user = insert(:user)

conn =
put_req_header(
conn,
"accept",
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
)

ensure_federating_or_authenticated(conn, "/users/#{user.nickname}.json", user)
end
end

describe "/object/:uuid" do
describe "/objects/:uuid" do
test "it returns a json representation of the object with accept application/json", %{
conn: conn
} do
@@ -236,6 +281,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

assert "Not found" == json_response(conn2, :not_found)
end

test "it requires authentication if instance is NOT federating", %{
conn: conn
} do
user = insert(:user)
note = insert(:note)
uuid = String.split(note.data["id"], "/") |> List.last()

conn = put_req_header(conn, "accept", "application/activity+json")

ensure_federating_or_authenticated(conn, "/objects/#{uuid}", user)
end
end

describe "/activities/:uuid" do
@@ -307,6 +364,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

assert "Not found" == json_response(conn2, :not_found)
end

test "it requires authentication if instance is NOT federating", %{
conn: conn
} do
user = insert(:user)
activity = insert(:note_activity)
uuid = String.split(activity.data["id"], "/") |> List.last()

conn = put_req_header(conn, "accept", "application/activity+json")

ensure_federating_or_authenticated(conn, "/activities/#{uuid}", user)
end
end

describe "/inbox" do
@@ -379,6 +448,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
end

test "without valid signature, " <>
"it only accepts Create activities and requires enabled federation",
%{conn: conn} do
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()

conn = put_req_header(conn, "content-type", "application/activity+json")

Config.put([:instance, :federating], false)

conn
|> post("/inbox", data)
|> json_response(403)

conn
|> post("/inbox", non_create_data)
|> json_response(403)

Config.put([:instance, :federating], true)

ret_conn = post(conn, "/inbox", data)
assert "ok" == json_response(ret_conn, 200)

conn
|> post("/inbox", non_create_data)
|> json_response(400)
end
end

describe "/users/:nickname/inbox" do
@@ -517,22 +614,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

test "it rejects reads from other users", %{conn: conn} do
user = insert(:user)
otheruser = insert(:user)

conn =
conn
|> assign(:user, otheruser)
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/inbox")

assert json_response(conn, 403)
end

test "it doesn't crash without an authenticated user", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)

conn =
conn
|> assign(:user, other_user)
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/inbox")

@@ -613,14 +699,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
refute recipient.follower_address in activity.data["cc"]
refute recipient.follower_address in activity.data["to"]
end

test "it requires authentication", %{conn: conn} do
user = insert(:user)
conn = put_req_header(conn, "accept", "application/activity+json")

ret_conn = get(conn, "/users/#{user.nickname}/inbox")
assert json_response(ret_conn, 403)

ret_conn =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/inbox")

assert json_response(ret_conn, 200)
end
end

describe "/users/:nickname/outbox" do
test "it will not bomb when there is no activity", %{conn: conn} do
describe "GET /users/:nickname/outbox" do
test "it returns 200 even if there're no activities", %{conn: conn} do
user = insert(:user)

conn =
conn
|> assign(:user, user)
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/outbox")

@@ -635,6 +737,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

conn =
conn
|> assign(:user, user)
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/outbox?page=true")

@@ -647,24 +750,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

conn =
conn
|> assign(:user, user)
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/outbox?page=true")

assert response(conn, 200) =~ announce_activity.data["object"]
end

test "it rejects posts from other users", %{conn: conn} do
test "it requires authentication if instance is NOT federating", %{
conn: conn
} do
user = insert(:user)
conn = put_req_header(conn, "accept", "application/activity+json")

ensure_federating_or_authenticated(conn, "/users/#{user.nickname}/outbox", user)
end
end

describe "POST /users/:nickname/outbox" do
test "it rejects posts from other users / unauuthenticated users", %{conn: conn} do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
user = insert(:user)
otheruser = insert(:user)
other_user = insert(:user)
conn = put_req_header(conn, "content-type", "application/activity+json")

conn =
conn
|> assign(:user, otheruser)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
conn
|> post("/users/#{user.nickname}/outbox", data)
|> json_response(403)

assert json_response(conn, 403)
conn
|> assign(:user, other_user)
|> post("/users/#{user.nickname}/outbox", data)
|> json_response(403)
end

test "it inserts an incoming create activity into the database", %{conn: conn} do
@@ -779,24 +896,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:relay, true)
|> get("/relay/followers")
|> json_response(200)

assert result["first"]["orderedItems"] == [user.ap_id]
end

test "on non-federating instance, it returns 404", %{conn: conn} do
Config.put([:instance, :federating], false)
user = insert(:user)

conn
|> assign(:user, user)
|> get("/relay/followers")
|> json_response(404)
end
end

describe "/relay/following" do
test "it returns relay following", %{conn: conn} do
result =
conn
|> assign(:relay, true)
|> get("/relay/following")
|> json_response(200)

assert result["first"]["orderedItems"] == []
end

test "on non-federating instance, it returns 404", %{conn: conn} do
Config.put([:instance, :federating], false)
user = insert(:user)

conn
|> assign(:user, user)
|> get("/relay/following")
|> json_response(404)
end
end

describe "/users/:nickname/followers" do
@@ -807,32 +942,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user_two)
|> get("/users/#{user_two.nickname}/followers")
|> json_response(200)

assert result["first"]["orderedItems"] == [user.ap_id]
end

test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
test "it returns a uri if the user has 'hide_followers' set", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, hide_followers: true)
User.follow(user, user_two)

result =
conn
|> assign(:user, user)
|> get("/users/#{user_two.nickname}/followers")
|> json_response(200)

assert is_binary(result["first"])
end

test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is from another user",
%{conn: conn} do
user = insert(:user, hide_followers: true)
user = insert(:user)
other_user = insert(:user, hide_followers: true)

result =
conn
|> get("/users/#{user.nickname}/followers?page=1")
|> assign(:user, user)
|> get("/users/#{other_user.nickname}/followers?page=1")

assert result.status == 403
assert result.resp_body == ""
@@ -864,6 +1003,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/followers")
|> json_response(200)

@@ -873,12 +1013,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/followers?page=2")
|> json_response(200)

assert length(result["orderedItems"]) == 5
assert result["totalItems"] == 15
end

test "returns 403 if requester is not logged in", %{conn: conn} do
user = insert(:user)

conn
|> get("/users/#{user.nickname}/followers")
|> json_response(403)
end
end

describe "/users/:nickname/following" do
@@ -889,6 +1038,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/following")
|> json_response(200)

@@ -896,25 +1046,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end

test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
user = insert(:user, hide_follows: true)
user_two = insert(:user)
user = insert(:user)
user_two = insert(:user, hide_follows: true)
User.follow(user, user_two)

result =
conn
|> get("/users/#{user.nickname}/following")
|> assign(:user, user)
|> get("/users/#{user_two.nickname}/following")
|> json_response(200)

assert is_binary(result["first"])
end

test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is from another user",
%{conn: conn} do
user = insert(:user, hide_follows: true)
user = insert(:user)
user_two = insert(:user, hide_follows: true)

result =
conn
|> get("/users/#{user.nickname}/following?page=1")
|> assign(:user, user)
|> get("/users/#{user_two.nickname}/following?page=1")

assert result.status == 403
assert result.resp_body == ""
@@ -947,6 +1100,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/following")
|> json_response(200)

@@ -956,12 +1110,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do

result =
conn
|> assign(:user, user)
|> get("/users/#{user.nickname}/following?page=2")
|> json_response(200)

assert length(result["orderedItems"]) == 5
assert result["totalItems"] == 15
end

test "returns 403 if requester is not logged in", %{conn: conn} do
user = insert(:user)

conn
|> get("/users/#{user.nickname}/following")
|> json_response(403)
end
end

describe "delivery tracking" do
@@ -1046,8 +1209,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
end

describe "Additionnal ActivityPub C2S endpoints" do
test "/api/ap/whoami", %{conn: conn} do
describe "Additional ActivityPub C2S endpoints" do
test "GET /api/ap/whoami", %{conn: conn} do
user = insert(:user)

conn =
@@ -1058,12 +1221,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = User.get_cached_by_id(user.id)

assert UserView.render("user.json", %{user: user}) == json_response(conn, 200)

conn
|> get("/api/ap/whoami")
|> json_response(403)
end

clear_config([:media_proxy])
clear_config([Pleroma.Upload])

test "uploadMedia", %{conn: conn} do
test "POST /api/ap/upload_media", %{conn: conn} do
user = insert(:user)

desc = "Description of the image"
@@ -1083,6 +1250,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert object["name"] == desc
assert object["type"] == "Document"
assert object["actor"] == user.ap_id

conn
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|> json_response(403)
end
end
end

+ 4
- 0
test/web/activity_pub/publisher_test.exs View File

@@ -23,6 +23,10 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
:ok
end

clear_config_all([:instance, :federating]) do
Pleroma.Config.put([:instance, :federating], true)
end

describe "gather_webfinger_links/1" do
test "it returns links" do
user = insert(:user)


+ 0
- 65
test/web/activity_pub/utils_test.exs View File

@@ -177,71 +177,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
end
end

describe "fetch_ordered_collection" do
import Tesla.Mock

test "fetches the first OrderedCollectionPage when an OrderedCollection is encountered" do
mock(fn
%{method: :get, url: "http://mastodon.com/outbox"} ->
json(%{"type" => "OrderedCollection", "first" => "http://mastodon.com/outbox?page=true"})

%{method: :get, url: "http://mastodon.com/outbox?page=true"} ->
json(%{"type" => "OrderedCollectionPage", "orderedItems" => ["ok"]})
end)

assert Utils.fetch_ordered_collection("http://mastodon.com/outbox", 1) == ["ok"]
end

test "fetches several pages in the right order one after another, but only the specified amount" do
mock(fn
%{method: :get, url: "http://example.com/outbox"} ->
json(%{
"type" => "OrderedCollectionPage",
"orderedItems" => [0],
"next" => "http://example.com/outbox?page=1"
})

%{method: :get, url: "http://example.com/outbox?page=1"} ->
json(%{
"type" => "OrderedCollectionPage",
"orderedItems" => [1],
"next" => "http://example.com/outbox?page=2"
})

%{method: :get, url: "http://example.com/outbox?page=2"} ->
json(%{"type" => "OrderedCollectionPage", "orderedItems" => [2]})
end)

assert Utils.fetch_ordered_collection("http://example.com/outbox", 0) == [0]
assert Utils.fetch_ordered_collection("http://example.com/outbox", 1) == [0, 1]
end

test "returns an error if the url doesn't have an OrderedCollection/Page" do
mock(fn
%{method: :get, url: "http://example.com/not-an-outbox"} ->
json(%{"type" => "NotAnOutbox"})
end)

assert {:error, _} = Utils.fetch_ordered_collection("http://example.com/not-an-outbox", 1)
end

test "returns the what was collected if there are less pages than specified" do
mock(fn
%{method: :get, url: "http://example.com/outbox"} ->
json(%{
"type" => "OrderedCollectionPage",
"orderedItems" => [0],
"next" => "http://example.com/outbox?page=1"
})

%{method: :get, url: "http://example.com/outbox?page=1"} ->
json(%{"type" => "OrderedCollectionPage", "orderedItems" => [1]})
end)

assert Utils.fetch_ordered_collection("http://example.com/outbox", 5) == [0, 1]
end
end

test "make_json_ld_header/0" do
assert Utils.make_json_ld_header() == %{
"@context" => [


+ 8
- 4
test/web/admin_api/admin_api_controller_test.exs View File

@@ -3048,7 +3048,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end

describe "GET /api/pleroma/admin/statuses" do
test "returns all public, unlisted, and direct statuses", %{conn: conn, admin: admin} do
test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
blocked = insert(:user)
user = insert(:user)
User.block(admin, blocked)
@@ -3067,7 +3067,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|> json_response(200)

refute "private" in Enum.map(response, & &1["visibility"])
assert length(response) == 4
assert length(response) == 3
end

test "returns only local statuses with local_only on", %{conn: conn} do
@@ -3084,12 +3084,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert length(response) == 1
end

test "returns private statuses with godmode on", %{conn: conn} do
test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
user = insert(:user)

{:ok, _} =
CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})

{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
assert json_response(conn, 200) |> length() == 2
assert json_response(conn, 200) |> length() == 3
end
end



Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save