forked from AkkomaGang/akkoma
Merge branch 'develop' into frontend-switcher-9000
This commit is contained in:
commit
4c9c959bb3
33 changed files with 338 additions and 148 deletions
|
@ -4,6 +4,13 @@ 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
|
||||
|
||||
## Added
|
||||
- Nodeinfo keys for unauthenticated timeline visibility
|
||||
- Option to disable federated timeline
|
||||
- Option to make the bubble timeline publicly accessible
|
||||
|
||||
## 2023.03
|
||||
|
||||
## Fixed
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM hexpm/elixir:1.13.4-erlang-24.3.4.5-alpine-3.15.6
|
||||
FROM hexpm/elixir:1.14.3-erlang-25.3-alpine-3.17.2
|
||||
|
||||
ENV MIX_ENV=prod
|
||||
ENV ERL_EPMD_ADDRESS=127.0.0.1
|
||||
|
|
|
@ -54,6 +54,9 @@ If your platform is not supported, or you just want to be able to edit the sourc
|
|||
### Docker
|
||||
Docker installation is supported via [this setup](https://docs.akkoma.dev/stable/installation/docker_en/)
|
||||
|
||||
### Packages
|
||||
Akkoma is packaged for [YunoHost](https://yunohost.org) and can be found and installed from the [YunoHost app catalogue](https://yunohost.org/#/apps).
|
||||
|
||||
### Compilation Troubleshooting
|
||||
If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things:
|
||||
|
||||
|
|
|
@ -261,7 +261,8 @@
|
|||
privileged_staff: false,
|
||||
local_bubble: [],
|
||||
max_frontend_settings_json_chars: 100_000,
|
||||
export_prometheus_metrics: true
|
||||
export_prometheus_metrics: true,
|
||||
federated_timeline_available: true
|
||||
|
||||
config :pleroma, :welcome,
|
||||
direct_message: [
|
||||
|
@ -813,7 +814,7 @@
|
|||
private_instance? = :if_instance_is_private
|
||||
|
||||
config :pleroma, :restrict_unauthenticated,
|
||||
timelines: %{local: private_instance?, federated: private_instance?},
|
||||
timelines: %{local: private_instance?, federated: private_instance?, bubble: true},
|
||||
profiles: %{local: private_instance?, remote: private_instance?},
|
||||
activities: %{local: private_instance?, remote: private_instance?}
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
hehe, /emoji/hehe.png, Akkoma
|
||||
nothehe, /emoji/nothehe.png, Akkoma
|
|
@ -969,6 +969,12 @@
|
|||
key: :export_prometheus_metrics,
|
||||
type: :boolean,
|
||||
description: "Enable prometheus metrics (at /api/v1/akkoma/metrics)"
|
||||
},
|
||||
%{
|
||||
key: :federated_timeline_available,
|
||||
type: :boolean,
|
||||
description:
|
||||
"Let people view the 'firehose' feed of all public statuses from all instances."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2993,6 +2999,11 @@
|
|||
key: :federated,
|
||||
type: :boolean,
|
||||
description: "Disallow viewing the whole known network timeline."
|
||||
},
|
||||
%{
|
||||
key: :bubble,
|
||||
type: :boolean,
|
||||
description: "Disallow viewing the bubble timeline."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
## Required dependencies
|
||||
|
||||
* PostgreSQL 9.6+
|
||||
* Elixir 1.12+ (1.13+ recommended)
|
||||
* Erlang OTP 22.2+
|
||||
* Elixir 1.14+
|
||||
* Erlang OTP 24+
|
||||
* git
|
||||
* file / libmagic
|
||||
* gcc (clang might also work)
|
||||
|
|
9
docs/docs/installation/yunohost_en.md
Normal file
9
docs/docs/installation/yunohost_en.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Installing on Yunohost
|
||||
|
||||
[YunoHost](https://yunohost.org) is a server operating system aimed at self-hosting. The YunoHost community maintains a package of Akkoma which allows you to install Akkoma on YunoHost. You can install it via the normal way through the admin web interface, or through the CLI. More information can be found at [the repo of the package](https://github.com/YunoHost-Apps/akkoma_ynh).
|
||||
|
||||
## Questions
|
||||
|
||||
Questions and problems related to the YunoHost parts can be done through the [YunoHost channels](https://yunohost.org/en/help).
|
||||
|
||||
For questions about Akkoma, check out the [Akkoma community channels](../../#community-channels).
|
|
@ -1,2 +1,2 @@
|
|||
elixir_version=1.9.4
|
||||
erlang_version=22.3.4.1
|
||||
elixir_version=1.14.3
|
||||
erlang_version=25.3
|
||||
|
|
|
@ -82,4 +82,46 @@ def run(["user_timeline", nickname, reading_nickname]) do
|
|||
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||
|> IO.puts()
|
||||
end
|
||||
|
||||
def run(["notifications", nickname]) do
|
||||
start_pleroma()
|
||||
user = Repo.get_by!(User, nickname: nickname)
|
||||
account_ap_id = user.ap_id
|
||||
options = %{account_ap_id: user.ap_id}
|
||||
|
||||
query =
|
||||
user
|
||||
|> Pleroma.Notification.for_user_query(options)
|
||||
|> where([n, a], a.actor == ^account_ap_id)
|
||||
|> limit(20)
|
||||
|
||||
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||
|> IO.puts()
|
||||
end
|
||||
|
||||
def run(["known_network", nickname]) do
|
||||
start_pleroma()
|
||||
user = Repo.get_by!(User, nickname: nickname)
|
||||
|
||||
params =
|
||||
%{}
|
||||
|> Map.put(:type, ["Create"])
|
||||
|> Map.put(:local_only, false)
|
||||
|> Map.put(:blocking_user, user)
|
||||
|> Map.put(:muting_user, user)
|
||||
|> Map.put(:reply_filtering_user, user)
|
||||
# Restricts unfederated content to authenticated users
|
||||
|> Map.put(:includes_local_public, not is_nil(user))
|
||||
|> Map.put(:restrict_unlisted, true)
|
||||
|
||||
query =
|
||||
Pleroma.Web.ActivityPub.ActivityPub.fetch_activities_query(
|
||||
[Pleroma.Constants.as_public()],
|
||||
params
|
||||
)
|
||||
|> limit(20)
|
||||
|
||||
Ecto.Adapters.SQL.explain(Repo, :all, query, analyze: true, timeout: :infinity)
|
||||
|> IO.puts()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -277,6 +277,13 @@ def get_create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
|
|||
|
||||
def get_create_by_object_ap_id_with_object(_), do: nil
|
||||
|
||||
def get_local_create_by_object_ap_id(ap_id) when is_binary(ap_id) do
|
||||
ap_id
|
||||
|> create_by_object_ap_id()
|
||||
|> where(local: true)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
@spec create_by_id_with_object(String.t()) :: t() | nil
|
||||
def create_by_id_with_object(id) do
|
||||
get_by_id_with_opts(id, preload: [:object], filter: [type: "Create"])
|
||||
|
|
|
@ -162,7 +162,7 @@ def local do
|
|||
%Instance{
|
||||
host: Pleroma.Web.Endpoint.host(),
|
||||
favicon: Pleroma.Web.Endpoint.url() <> "/favicon.png",
|
||||
nodeinfo: Pleroma.Web.Nodeinfo.NodeinfoController.raw_nodeinfo()
|
||||
nodeinfo: Pleroma.Web.Nodeinfo.Nodeinfo.get_nodeinfo("2.1")
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -366,21 +366,21 @@ def invisible?(%User{invisible: true}), do: true
|
|||
def invisible?(_), do: false
|
||||
|
||||
def avatar_url(user, options \\ []) do
|
||||
case user.avatar do
|
||||
%{"url" => [%{"href" => href} | _]} ->
|
||||
href
|
||||
|
||||
_ ->
|
||||
unless options[:no_default] do
|
||||
Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
|
||||
end
|
||||
end
|
||||
default = Config.get([:assets, :default_user_avatar], "#{Endpoint.url()}/images/avi.png")
|
||||
do_optional_url(user.avatar, default, options)
|
||||
end
|
||||
|
||||
def banner_url(user, options \\ []) do
|
||||
case user.banner do
|
||||
%{"url" => [%{"href" => href} | _]} -> href
|
||||
_ -> !options[:no_default] && "#{Endpoint.url()}/images/banner.png"
|
||||
do_optional_url(user.banner, "#{Endpoint.url()}/images/banner.png", options)
|
||||
end
|
||||
|
||||
defp do_optional_url(field, default, options) do
|
||||
case field do
|
||||
%{"url" => [%{"href" => href} | _]} when is_binary(href) ->
|
||||
href
|
||||
|
||||
_ ->
|
||||
unless options[:no_default], do: default
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1502,13 +1502,22 @@ def fetch_activities_bounded(
|
|||
|
||||
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
|
||||
def upload(file, opts \\ []) do
|
||||
with {:ok, data} <- Upload.store(file, opts) do
|
||||
with {:ok, data} <- Upload.store(sanitize_upload_file(file), opts) do
|
||||
obj_data = Maps.put_if_present(data, "actor", opts[:actor])
|
||||
|
||||
Repo.insert(%Object{data: obj_data})
|
||||
end
|
||||
end
|
||||
|
||||
defp sanitize_upload_file(%Plug.Upload{filename: filename} = upload) when is_binary(filename) do
|
||||
%Plug.Upload{
|
||||
upload
|
||||
| filename: Path.basename(filename)
|
||||
}
|
||||
end
|
||||
|
||||
defp sanitize_upload_file(upload), do: upload
|
||||
|
||||
@spec get_actor_url(any()) :: binary() | nil
|
||||
defp get_actor_url(url) when is_binary(url), do: url
|
||||
defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
|
||||
|
|
|
@ -70,7 +70,8 @@ def public_operation do
|
|||
operationId: "TimelineController.public",
|
||||
responses: %{
|
||||
200 => Operation.response("Array of Status", "application/json", array_of_statuses()),
|
||||
401 => Operation.response("Error", "application/json", ApiError)
|
||||
401 => Operation.response("Error", "application/json", ApiError),
|
||||
404 => Operation.response("Error", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
alias Pleroma.Web.Plugs.RateLimiter
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(:skip_public_check when action in [:public, :hashtag])
|
||||
plug(:skip_public_check when action in [:public, :hashtag, :bubble])
|
||||
|
||||
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||
|
@ -28,19 +28,25 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
plug(RateLimiter, [name: :timeline, bucket_name: :list_timeline] when action == :list)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :bubble_timeline] when action == :bubble)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct, :bubble])
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
|
||||
when action in [:public, :hashtag]
|
||||
when action in [:public, :hashtag, :bubble]
|
||||
)
|
||||
|
||||
require Logger
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TimelineOperation
|
||||
|
||||
# GET /api/v1/timelines/home
|
||||
def home(%{assigns: %{user: user}} = conn, params) do
|
||||
%{nickname: nickname} = user
|
||||
|
||||
Logger.debug("TimelineController.home: #{nickname}")
|
||||
|
||||
followed_hashtags =
|
||||
user
|
||||
|> User.followed_hashtags()
|
||||
|
@ -58,11 +64,15 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
|||
|> Map.put(:followed_hashtags, followed_hashtags)
|
||||
|> Map.delete(:local)
|
||||
|
||||
Logger.debug("TimelineController.home: #{nickname} - fetching activities")
|
||||
|
||||
activities =
|
||||
[user.ap_id | User.following(user)]
|
||||
|> ActivityPub.fetch_activities(params)
|
||||
|> Enum.reverse()
|
||||
|
||||
Logger.debug("TimelineController.home: #{nickname} - rendering")
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|> render("index.json",
|
||||
|
@ -75,6 +85,8 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
|||
|
||||
# GET /api/v1/timelines/direct
|
||||
def direct(%{assigns: %{user: user}} = conn, params) do
|
||||
Logger.debug("TimelineController.direct: #{user.nickname}")
|
||||
|
||||
params =
|
||||
params
|
||||
|> Map.put(:type, "Create")
|
||||
|
@ -82,11 +94,15 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
|||
|> Map.put(:user, user)
|
||||
|> Map.put(:visibility, "direct")
|
||||
|
||||
Logger.debug("TimelineController.direct: #{user.nickname} - fetching activities")
|
||||
|
||||
activities =
|
||||
[user.ap_id]
|
||||
|> ActivityPub.fetch_activities_query(params)
|
||||
|> Pagination.fetch_paginated(params)
|
||||
|
||||
Logger.debug("TimelineController.direct: #{user.nickname} - rendering")
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|> render("index.json",
|
||||
|
@ -96,21 +112,22 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
|||
)
|
||||
end
|
||||
|
||||
defp restrict_unauthenticated?(true = _local_only) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, :local)
|
||||
end
|
||||
|
||||
defp restrict_unauthenticated?(_) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, :federated)
|
||||
defp restrict_unauthenticated?(type) do
|
||||
Config.restrict_unauthenticated_access?(:timelines, type)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/public
|
||||
def public(%{assigns: %{user: user}} = conn, params) do
|
||||
Logger.debug("TimelineController.public")
|
||||
local_only = params[:local]
|
||||
timeline_type = if local_only, do: :local, else: :federated
|
||||
|
||||
with {:enabled, true} <-
|
||||
{:enabled, local_only || Config.get([:instance, :federated_timeline_available], true)},
|
||||
{:authenticated, true} <-
|
||||
{:authenticated, !(is_nil(user) and restrict_unauthenticated?(timeline_type))} do
|
||||
Logger.debug("TimelineController.public: fetching activities")
|
||||
|
||||
if is_nil(user) and restrict_unauthenticated?(local_only) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
activities =
|
||||
params
|
||||
|> Map.put(:type, ["Create"])
|
||||
|
@ -123,6 +140,8 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
|||
|> Map.put(:includes_local_public, not is_nil(user))
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|
||||
Logger.debug("TimelineController.public: rendering")
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities, %{"local" => local_only})
|
||||
|> render("index.json",
|
||||
|
@ -131,20 +150,32 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
|||
as: :activity,
|
||||
with_muted: Map.get(params, :with_muted, false)
|
||||
)
|
||||
else
|
||||
{:enabled, false} ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Federated timeline is disabled"})
|
||||
|
||||
{:authenticated, false} ->
|
||||
fail_on_bad_auth(conn)
|
||||
end
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/bubble
|
||||
def bubble(%{assigns: %{user: user}} = conn, params) do
|
||||
Logger.debug("TimelineController.bubble")
|
||||
|
||||
if is_nil(user) and restrict_unauthenticated?(:bubble) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
bubble_instances =
|
||||
Enum.uniq(
|
||||
Config.get([:instance, :local_bubble], []) ++
|
||||
[Pleroma.Web.Endpoint.host()]
|
||||
)
|
||||
|
||||
if is_nil(user) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
Logger.debug("TimelineController.bubble: fetching activities")
|
||||
|
||||
activities =
|
||||
params
|
||||
|> Map.put(:type, ["Create"])
|
||||
|
@ -154,6 +185,8 @@ def bubble(%{assigns: %{user: user}} = conn, params) do
|
|||
|> Map.put(:instance, bubble_instances)
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|
||||
Logger.debug("TimelineController.bubble: rendering")
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|> render("index.json",
|
||||
|
@ -195,7 +228,7 @@ defp hashtag_fetching(params, user, local_only) do
|
|||
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||
local_only = params[:local]
|
||||
|
||||
if is_nil(user) and restrict_unauthenticated?(local_only) do
|
||||
if is_nil(user) and restrict_unauthenticated?(if local_only, do: :local, else: :federated) do
|
||||
fail_on_bad_auth(conn)
|
||||
else
|
||||
activities = hashtag_fetching(params, user, local_only)
|
||||
|
|
|
@ -67,6 +67,9 @@ def features do
|
|||
"pleroma:api/v1/notifications:include_types_filter",
|
||||
"quote_posting",
|
||||
"editing",
|
||||
if !Enum.empty?(Config.get([:instance, :local_bubble], [])) do
|
||||
"bubble_timeline"
|
||||
end,
|
||||
if Config.get([:media_proxy, :enabled]) do
|
||||
"media_proxy"
|
||||
end,
|
||||
|
|
|
@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.MediaProxy
|
||||
alias Pleroma.Web.PleromaAPI.EmojiReactionController
|
||||
require Logger
|
||||
|
||||
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
||||
|
||||
|
@ -87,6 +88,7 @@ defp reblogged?(activity, %User{ap_id: ap_id}) do
|
|||
defp reblogged?(_activity, _user), do: false
|
||||
|
||||
def render("index.json", opts) do
|
||||
Logger.debug("Rendering index")
|
||||
reading_user = opts[:for]
|
||||
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
||||
activities = Enum.filter(opts.activities, & &1)
|
||||
|
@ -136,8 +138,10 @@ def render("index.json", opts) do
|
|||
|
||||
def render(
|
||||
"show.json",
|
||||
%{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts
|
||||
%{activity: %{id: id, data: %{"type" => "Announce", "object" => _object}} = activity} =
|
||||
opts
|
||||
) do
|
||||
Logger.debug("Rendering reblog #{id}")
|
||||
user = CommonAPI.get_user(activity.data["actor"])
|
||||
created_at = Utils.to_masto_date(activity.data["published"])
|
||||
object = Object.normalize(activity, fetch: false)
|
||||
|
@ -209,7 +213,9 @@ def render(
|
|||
}
|
||||
end
|
||||
|
||||
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
||||
def render("show.json", %{activity: %{id: id, data: %{"object" => _object}} = activity} = opts) do
|
||||
Logger.debug("Rendering status #{id}")
|
||||
|
||||
with %Object{} = object <- Object.normalize(activity, fetch: false) do
|
||||
user = CommonAPI.get_user(activity.data["actor"])
|
||||
user_follower_address = user.follower_address
|
||||
|
@ -428,6 +434,7 @@ def render("show.json", _) do
|
|||
end
|
||||
|
||||
def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
||||
Logger.debug("Rendering history for #{activity.id}")
|
||||
object = Object.normalize(activity, fetch: false)
|
||||
|
||||
hashtags = Object.hashtags(object)
|
||||
|
@ -614,6 +621,8 @@ def render("attachment_meta.json", %{
|
|||
def render("attachment_meta.json", _), do: nil
|
||||
|
||||
def render("context.json", %{activity: activity, activities: activities, user: user}) do
|
||||
Logger.debug("Rendering context for #{activity.id}")
|
||||
|
||||
%{ancestors: ancestors, descendants: descendants} =
|
||||
activities
|
||||
|> Enum.reverse()
|
||||
|
|
|
@ -71,7 +71,15 @@ def get_nodeinfo("2.0") do
|
|||
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
|
||||
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false),
|
||||
privilegedStaff: Config.get([:instance, :privileged_staff]),
|
||||
localBubbleInstances: Config.get([:instance, :local_bubble], [])
|
||||
localBubbleInstances: Config.get([:instance, :local_bubble], []),
|
||||
publicTimelineVisibility: %{
|
||||
federated:
|
||||
!Config.restrict_unauthenticated_access?(:timelines, :federated) &&
|
||||
Config.get([:instance, :federated_timeline_available], true),
|
||||
local: !Config.restrict_unauthenticated_access?(:timelines, :local),
|
||||
bubble: !Config.restrict_unauthenticated_access?(:timelines, :bubble)
|
||||
},
|
||||
federatedTimelineAvailable: Config.get([:instance, :federated_timeline_available], true)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
alias Pleroma.Web.Federator.Publisher
|
||||
alias Pleroma.Web.MastodonAPI.InstanceView
|
||||
alias Pleroma.Web.Endpoint
|
||||
alias Pleroma.Web.Nodeinfo.Nodeinfo
|
||||
|
||||
def schemas(conn, _params) do
|
||||
response = %{
|
||||
|
@ -29,101 +30,15 @@ def schemas(conn, _params) do
|
|||
json(conn, response)
|
||||
end
|
||||
|
||||
# returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
|
||||
# under software.
|
||||
def raw_nodeinfo do
|
||||
stats = Stats.get_stats()
|
||||
|
||||
staff_accounts =
|
||||
User.all_superusers()
|
||||
|> Enum.map(fn u -> u.ap_id end)
|
||||
|> Enum.filter(fn u -> not Enum.member?(Config.get([:instance, :staff_transparency]), u) end)
|
||||
|
||||
features = InstanceView.features()
|
||||
federation = InstanceView.federation()
|
||||
|
||||
%{
|
||||
version: "2.0",
|
||||
software: %{
|
||||
name: Pleroma.Application.name() |> String.downcase(),
|
||||
version: Pleroma.Application.version()
|
||||
},
|
||||
protocols: Publisher.gather_nodeinfo_protocol_names(),
|
||||
services: %{
|
||||
inbound: [],
|
||||
outbound: []
|
||||
},
|
||||
openRegistrations: Config.get([:instance, :registrations_open]),
|
||||
usage: %{
|
||||
users: %{
|
||||
total: Map.get(stats, :user_count, 0)
|
||||
},
|
||||
localPosts: Map.get(stats, :status_count, 0)
|
||||
},
|
||||
metadata: %{
|
||||
nodeName: Config.get([:instance, :name]),
|
||||
nodeDescription: Config.get([:instance, :description]),
|
||||
private: !Config.get([:instance, :public], true),
|
||||
suggestions: %{
|
||||
enabled: false
|
||||
},
|
||||
staffAccounts: staff_accounts,
|
||||
federation: federation,
|
||||
pollLimits: Config.get([:instance, :poll_limits]),
|
||||
postFormats: Config.get([:instance, :allowed_post_formats]),
|
||||
uploadLimits: %{
|
||||
general: Config.get([:instance, :upload_limit]),
|
||||
avatar: Config.get([:instance, :avatar_upload_limit]),
|
||||
banner: Config.get([:instance, :banner_upload_limit]),
|
||||
background: Config.get([:instance, :background_upload_limit])
|
||||
},
|
||||
fieldsLimits: %{
|
||||
maxFields: Config.get([:instance, :max_account_fields]),
|
||||
maxRemoteFields: Config.get([:instance, :max_remote_account_fields]),
|
||||
nameLength: Config.get([:instance, :account_field_name_length]),
|
||||
valueLength: Config.get([:instance, :account_field_value_length])
|
||||
},
|
||||
accountActivationRequired: Config.get([:instance, :account_activation_required], false),
|
||||
invitesEnabled: Config.get([:instance, :invites_enabled], false),
|
||||
mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
|
||||
features: features,
|
||||
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
|
||||
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false),
|
||||
localBubbleInstances: Config.get([:instance, :local_bubble], [])
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
|
||||
# and https://github.com/jhass/nodeinfo/blob/master/schemas/2.1/schema.json
|
||||
def nodeinfo(conn, %{"version" => "2.0"}) do
|
||||
def nodeinfo(conn, %{"version" => version}) when version in ["2.0", "2.1"] do
|
||||
conn
|
||||
|> put_resp_header(
|
||||
"content-type",
|
||||
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
|
||||
)
|
||||
|> json(raw_nodeinfo())
|
||||
end
|
||||
|
||||
def nodeinfo(conn, %{"version" => "2.1"}) do
|
||||
raw_response = raw_nodeinfo()
|
||||
|
||||
updated_software =
|
||||
raw_response
|
||||
|> Map.get(:software)
|
||||
|> Map.put(:repository, Pleroma.Application.repository())
|
||||
|
||||
response =
|
||||
raw_response
|
||||
|> Map.put(:software, updated_software)
|
||||
|> Map.put(:version, "2.1")
|
||||
|
||||
conn
|
||||
|> put_resp_header(
|
||||
"content-type",
|
||||
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.1#; charset=utf-8"
|
||||
)
|
||||
|> json(response)
|
||||
|> json(Nodeinfo.get_nodeinfo(version))
|
||||
end
|
||||
|
||||
def nodeinfo(conn, _) do
|
||||
|
|
|
@ -36,7 +36,7 @@ def object(%{assigns: %{format: format}} = conn, _params)
|
|||
def object(conn, _params) do
|
||||
with id <- Endpoint.url() <> conn.request_path,
|
||||
{_, %Activity{} = activity} <-
|
||||
{:activity, Activity.get_create_by_object_ap_id_with_object(id)},
|
||||
{:activity, Activity.get_local_create_by_object_ap_id(id)},
|
||||
{_, true} <- {:public?, Visibility.is_public?(activity)},
|
||||
{_, false} <- {:local_public?, Visibility.is_local_public?(activity)} do
|
||||
redirect(conn, to: "/notice/#{activity.id}")
|
||||
|
|
|
@ -621,7 +621,6 @@ defmodule Pleroma.Web.Router do
|
|||
get("/timelines/home", TimelineController, :home)
|
||||
get("/timelines/direct", TimelineController, :direct)
|
||||
get("/timelines/list/:list_id", TimelineController, :list)
|
||||
get("/timelines/bubble", TimelineController, :bubble)
|
||||
|
||||
get("/announcements", AnnouncementController, :index)
|
||||
post("/announcements/:id/dismiss", AnnouncementController, :mark_read)
|
||||
|
@ -676,6 +675,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
get("/timelines/public", TimelineController, :public)
|
||||
get("/timelines/tag/:tag", TimelineController, :hashtag)
|
||||
get("/timelines/bubble", TimelineController, :bubble)
|
||||
|
||||
get("/polls/:id", PollController, :show)
|
||||
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -5,7 +5,7 @@ def project do
|
|||
[
|
||||
app: :pleroma,
|
||||
version: version("3.7.1"),
|
||||
elixir: "~> 1.12",
|
||||
elixir: "~> 1.14",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
compilers: [:phoenix] ++ Mix.compilers(),
|
||||
elixirc_options: [warnings_as_errors: warnings_as_errors()],
|
||||
|
|
14
mix.lock
14
mix.lock
|
@ -27,7 +27,7 @@
|
|||
"earmark": {:hex, :earmark, "1.4.37", "56ce845c543393aa3f9b294c818c3d783452a4a67e4ab18c4303a954a8b59363", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d86d5e12868db86d5321b00e62a4bbcb4150346e4acc9a90a041fb188a5cb106"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
|
||||
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
|
||||
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
|
||||
"ecto": {:hex, :ecto, "3.9.5", "9f0aa7ae44a1577b651c98791c6988cd1b69b21bc724e3fd67090b97f7604263", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4f3115d8cbacdc0bfa4b742865459fb1371d0715515842a1fb17fe31920b74c"},
|
||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
|
||||
|
@ -38,7 +38,7 @@
|
|||
"ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"},
|
||||
"ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"},
|
||||
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.29.2", "dfa97532ba66910b2a3016a4bbd796f41a86fc71dd5227e96f4c8581fdf0fdf0", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "6b5d7139eda18a753e3250e27e4a929f8d2c880dd0d460cb9986305dea3e03af"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.29.3", "f07444bcafb302db86e4f02d8bbcd82f2e881a0dcf4f3e4740e4b8128b9353f7", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3dc6787d7b08801ec3b51e9bd26be5e8826fbf1a17e92d1ebc252e1a1c75bfe1"},
|
||||
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
|
||||
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"},
|
||||
|
@ -86,14 +86,14 @@
|
|||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
|
||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.17", "74938b02f3c531bed3f87fe1ea39af6b5b2d26ab1405e77e76b8ef5df9ffa8a1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f4b5710e19a29b8dc93b7af4bab4739c067a3cb759af01ffc3057165453dce38"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
|
||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.4", "615f8f393135de7e0cbb4bd00ba238b1e0cd324b0d90efbaee613c2f02ca5e5c", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3971221846232021ab5e3c7489fd62ec5bfd6a2e01cae10a317ccf6fb350571c"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
|
||||
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
|
||||
"plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.2.4", "34c380ef387cc7e8d537854ddd4b7096c79a4397d53587cb80419c782b03fdbc", [:mix], [], "hexpm", "4de415f03faec94d9da9be8c12cb51e9c98cbf66d732b6df669d4562d8e91acc"},
|
||||
"plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
|
||||
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
||||
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
|
||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||
|
@ -117,7 +117,7 @@
|
|||
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
|
||||
"temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]},
|
||||
"tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"},
|
||||
"timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"},
|
||||
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
|
||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
||||
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
|
||||
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
||||
|
|
BIN
priv/static/emoji/hehe.png
Normal file
BIN
priv/static/emoji/hehe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
priv/static/emoji/nothehe.png
Normal file
BIN
priv/static/emoji/nothehe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -2509,6 +2509,16 @@ test "avatar fallback" do
|
|||
assert User.avatar_url(user, no_default: true) == nil
|
||||
end
|
||||
|
||||
test "avatar object with nil in href" do
|
||||
user = insert(:user, avatar: %{"url" => [%{"href" => nil}]})
|
||||
assert User.avatar_url(user) != nil
|
||||
end
|
||||
|
||||
test "banner object with nil in href" do
|
||||
user = insert(:user, banner: %{"url" => [%{"href" => nil}]})
|
||||
assert User.banner_url(user) != nil
|
||||
end
|
||||
|
||||
test "get_host/1" do
|
||||
user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
|
||||
assert User.get_host(user) == "lain.com"
|
||||
|
|
|
@ -1303,6 +1303,14 @@ test "returns reblogs for users for whom reblogs have not been muted" do
|
|||
%{test_file: test_file}
|
||||
end
|
||||
|
||||
test "strips / from filename", %{test_file: file} do
|
||||
file = %Plug.Upload{file | filename: "../../../../../nested/bad.jpg"}
|
||||
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||
[%{"href" => href}] = object.data["url"]
|
||||
assert Regex.match?(~r"/bad.jpg$", href)
|
||||
refute Regex.match?(~r"/nested/", href)
|
||||
end
|
||||
|
||||
test "sets a description if given", %{test_file: file} do
|
||||
{:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
|
||||
assert object.data["name"] == "a cool file"
|
||||
|
|
|
@ -124,6 +124,23 @@ test "/api/v2/media, upload_limit", %{conn: conn, user: user} do
|
|||
|
||||
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
||||
end
|
||||
|
||||
test "Do not allow nested filename", %{conn: conn, image: image} do
|
||||
image = %Plug.Upload{
|
||||
image
|
||||
| filename: "../../../../../nested/file.jpg"
|
||||
}
|
||||
|
||||
desc = "Description of the image"
|
||||
|
||||
media =
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/v1/media", %{"file" => image, "description" => desc})
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
refute Regex.match?(~r"/nested/", media["url"])
|
||||
end
|
||||
end
|
||||
|
||||
describe "Update media description" do
|
||||
|
|
|
@ -408,6 +408,26 @@ test "should not return local-only posts for anonymous users" do
|
|||
|
||||
assert [] = result
|
||||
end
|
||||
|
||||
test "should return 404 if disabled" do
|
||||
clear_config([:instance, :federated_timeline_available], false)
|
||||
|
||||
result =
|
||||
build_conn()
|
||||
|> get("/api/v1/timelines/public")
|
||||
|> json_response_and_validate_schema(404)
|
||||
|
||||
assert %{"error" => "Federated timeline is disabled"} = result
|
||||
end
|
||||
|
||||
test "should not return 404 if local is specified" do
|
||||
clear_config([:instance, :federated_timeline_available], false)
|
||||
|
||||
result =
|
||||
build_conn()
|
||||
|> get("/api/v1/timelines/public?local=true")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
end
|
||||
|
||||
defp local_and_remote_activities do
|
||||
|
@ -1036,9 +1056,8 @@ test "with `%{local: true, federated: false}`, forbids unauthenticated access to
|
|||
end
|
||||
|
||||
describe "bubble" do
|
||||
setup do: oauth_access(["read:statuses"])
|
||||
|
||||
test "filtering", %{conn: conn, user: user} do
|
||||
test "filtering" do
|
||||
%{conn: conn, user: user} = oauth_access(["read:statuses"])
|
||||
clear_config([:instance, :local_bubble], [])
|
||||
# our endpoint host has a port in it so let's set the AP ID
|
||||
local_user = insert(:user, %{ap_id: "https://localhost/users/user"})
|
||||
|
@ -1072,6 +1091,20 @@ test "filtering", %{conn: conn, user: user} do
|
|||
assert local_activity.id in two_instances
|
||||
assert remote_activity.id in two_instances
|
||||
end
|
||||
|
||||
test "restrict_unauthenticated with bubble timeline", %{conn: conn} do
|
||||
clear_config([:restrict_unauthenticated, :timelines, :bubble], true)
|
||||
|
||||
conn
|
||||
|> get("/api/v1/timelines/bubble")
|
||||
|> json_response_and_validate_schema(:unauthorized)
|
||||
|
||||
clear_config([:restrict_unauthenticated, :timelines, :bubble], false)
|
||||
|
||||
conn
|
||||
|> get("/api/v1/timelines/bubble")
|
||||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_remote_activity(user) do
|
||||
|
|
|
@ -396,6 +396,34 @@ test "updates the user's background, upload_limit, returns a HTTP 413", %{
|
|||
assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
|
||||
end
|
||||
|
||||
test "Strip / from upload files", %{user: user, conn: conn} do
|
||||
new_image = %Plug.Upload{
|
||||
content_type: "image/jpeg",
|
||||
path: Path.absname("test/fixtures/image.jpg"),
|
||||
filename: "../../../../nested/an_image.jpg"
|
||||
}
|
||||
|
||||
assert user.avatar == %{}
|
||||
|
||||
res =
|
||||
patch(conn, "/api/v1/accounts/update_credentials", %{
|
||||
"avatar" => new_image,
|
||||
"header" => new_image,
|
||||
"pleroma_background_image" => new_image
|
||||
})
|
||||
|
||||
assert user_response = json_response_and_validate_schema(res, 200)
|
||||
assert user_response["avatar"]
|
||||
assert user_response["header"]
|
||||
assert user_response["pleroma"]["background_image"]
|
||||
refute Regex.match?(~r"/nested/", user_response["avatar"])
|
||||
refute Regex.match?(~r"/nested/", user_response["header"])
|
||||
refute Regex.match?(~r"/nested/", user_response["pleroma"]["background_image"])
|
||||
|
||||
user = User.get_by_id(user.id)
|
||||
refute user.avatar == %{}
|
||||
end
|
||||
|
||||
test "requires 'write:accounts' permission" do
|
||||
token1 = insert(:oauth_token, scopes: ["read"])
|
||||
token2 = insert(:oauth_token, scopes: ["write", "follow"])
|
||||
|
|
|
@ -269,8 +269,8 @@ test "Represent a Service(bot) account" do
|
|||
}
|
||||
|
||||
with_mock(
|
||||
Pleroma.Web.Nodeinfo.NodeinfoController,
|
||||
raw_nodeinfo: fn -> %{version: "2.0"} end
|
||||
Pleroma.Web.Nodeinfo.Nodeinfo,
|
||||
get_nodeinfo: fn _ -> %{version: "2.0"} end
|
||||
) do
|
||||
assert expected ==
|
||||
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||
|
|
|
@ -292,4 +292,38 @@ test "shows extra information in the mrf_simple_info field for relevant entries"
|
|||
assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
|
||||
end
|
||||
end
|
||||
|
||||
describe "public timeline visibility" do
|
||||
test "shows public timeline visibility", %{conn: conn} do
|
||||
clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: false})
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["publicTimelineVisibility"]["local"] == true
|
||||
assert response["metadata"]["publicTimelineVisibility"]["federated"] == true
|
||||
|
||||
clear_config([:restrict_unauthenticated, :timelines], %{local: true, federated: false})
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["publicTimelineVisibility"]["local"] == false
|
||||
assert response["metadata"]["publicTimelineVisibility"]["federated"] == true
|
||||
|
||||
clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: true})
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["publicTimelineVisibility"]["local"] == true
|
||||
assert response["metadata"]["publicTimelineVisibility"]["federated"] == false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue