Compare commits

..

4 Commits

Author SHA1 Message Date
Haelwenn (lanodan) Monnier
5fb9d5b761
Transmogrifier: Clean out unused functions 2021-07-23 07:10:16 +02:00
Haelwenn (lanodan) Monnier
def4fd9a15
Move Utils json-ld header and date to Builder 2021-07-23 07:10:14 +02:00
Haelwenn (lanodan) Monnier
bb5cc8b390
Ingestion Pipeline: Listen 2021-07-23 06:34:07 +02:00
Haelwenn (lanodan) Monnier
f5fdc5dc63
object_validator: Simplify Add/Remove 2021-07-21 21:03:40 +02:00
286 changed files with 679 additions and 1518 deletions

View File

@ -8,36 +8,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
### Added
### Fixed
### Removed
## 2.4.1 - 2021-08-29
### Changed
- Make `mix pleroma.database set_text_search_config` run concurrently and indefinitely
### Added
- AdminAPI: Missing configuration description for StealEmojiPolicy
### Fixed
- MastodonAPI: Stream out Create activities
- MRF ObjectAgePolicy: Fix pattern matching on "published"
- TwitterAPI: Make `change_password` and `change_email` require params on body instead of query
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
- AdminAPI: Fix rendering reports containing a `nil` object
- Mastodon API: Activity Search fallbacks on status fetching after a DB Timeout/Error
- Mastodon API: Fix crash in Streamer related to reblogging
- AdminAPI: List available frontends when `static/frontends` folder is missing
- Make activity search properly use language-aware GIN indexes
- AdminAPI: Fix suggestions for MRF Policies
## 2.4.0 - 2021-08-08
### Changed
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
- Support for Erlang/OTP 24
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
@ -62,8 +32,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Remote users can no longer reappear after being deleted.
- Deactivated users may now be deleted.
- Mix task `pleroma.database prune_objects`
- Fixed rendering of JSON errors on ActivityPub endpoints.
- Linkify: Parsing crash with URLs ending in unbalanced closed paren, no path separator, and no query parameters
### Removed
- **Breaking**: Remove deprecated `/api/qvitter/statuses/notifications/read` (replaced by `/api/v1/pleroma/notifications/read`)
## Unreleased (Patch)
### Fixed
- Try to save exported ConfigDB settings (migrate_from_db) in the system temp directory if default location is not writable.
- Uploading custom instance thumbnail via AdminAPI/AdminFE generated invalid URL to the image
- Applying ConcurrentLimiter settings via AdminAPI
@ -72,10 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- MRF (`SimplePolicy`): Embedded objects are now checked. If any embedded object would be rejected, its parent is rejected. This fixes Announces leaking posts from blocked domains.
- Fixed some Markdown issues, including trailing slash in links.
### Removed
- **Breaking**: Remove deprecated `/api/qvitter/statuses/notifications/read` (replaced by `/api/v1/pleroma/notifications/read`)
## [2.3.0] - 2021-03-01
## [2.3.0] - 2020-03-01
### Security
@ -176,7 +150,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: Support for expires_in/expires_at in the Filters.
</details>
## [2.2.2] - 2021-01-18
## [2.2.2] - 2020-01-18
### Fixed

View File

@ -460,7 +460,7 @@ config :pleroma, :shout,
enabled: true,
limit: 5_000
config :phoenix, :format_encoders, json: Jason, "activity+json": Jason
config :phoenix, :format_encoders, json: Jason
config :phoenix, :json_library, Jason

View File

@ -5,7 +5,7 @@ Pleroma's full text search feature is powered by PostgreSQL's native [text searc
## Setup and test the new search config
In most cases, you would need an extension installed to support parsing CJK text. Here are a few extensions you may choose from, or you are more than welcome to share additional ones you found working for you with the rest of Pleroma community.
In most cases, you would need an extension installed to support parsing CJK text. Here are a few extension you may choose from, or you are more than welcome to share additional ones you found working for you with the rest of Pleroma community.
* [a generic n-gram parser](https://github.com/huangjimmy/pg_cjk_parser) supports Simplifed/Traditional Chinese, Japanese, and Korean
* [a Korean parser](https://github.com/i0seph/textsearch_ko) based on mecab
@ -34,7 +34,7 @@ Check output of the query, and see if it matches your expectation.
mix pleroma.database set_text_search_config YOUR.CONFIG
```
Note: index update may take a while, and it can be done while the instance is up and running, so you may restart db connection as soon as you see `Recreate index` in task output.
Note: index update may take a while.
## Restart database connection
Since some changes above will only apply with a new database connection, you will have to restart either Pleroma or PostgreSQL process, or use `pg_terminate_backend` SQL command without restarting either.

View File

@ -1,7 +1,4 @@
# Installing on Alpine Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation
This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v3.10 standard image. You might miss additional dependencies if you use `netboot` instead.

View File

@ -1,7 +1,4 @@
# Installing on Arch Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.

View File

@ -1,7 +1,4 @@
# Installing on Debian Based Distributions
{! backend/installation/otp_vs_from_source_source.include !}
## Installation
This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.

View File

@ -1,7 +1,4 @@
# Installing on Gentoo GNU/Linux
{! backend/installation/otp_vs_from_source_source.include !}
## Installation
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user.

View File

@ -1,8 +1,7 @@
# Switching a from-source install to OTP releases
{! backend/installation/otp_vs_from_source.include !}
In this guide we cover how you can migrate from a from source installation to one using OTP releases.
## What are OTP releases?
OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more.
## Pre-requisites
You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`.

View File

@ -1,9 +1,5 @@
# Installing on Linux using OTP releases
{! backend/installation/otp_vs_from_source.include !}
This guide covers a installation using an OTP release. To install Pleroma from source, please check out the corresponding guide for your distro.
## Pre-requisites
* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below
* A (sub)domain pointed to the machine

View File

@ -1,3 +0,0 @@
## OTP releases vs from-source installations
There are two ways to install Pleroma. You can use OTP releases or do a from-source installation. OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more. With from source installations you install Pleroma from source, meaning you have to install certain dependencies like Erlang+Elixir and compile Pleroma yourself.

View File

@ -1,3 +0,0 @@
{! backend/installation/otp_vs_from_source.include !}
This guide covers a from-source installation. To install using OTP releases, please check out [the OTP guide](./otp_en.md).

View File

@ -209,9 +209,7 @@ defmodule Mix.Tasks.Pleroma.Database do
new.fts_content := to_tsvector(new.data->>'content');
RETURN new;
END
$$ LANGUAGE plpgsql",
[],
timeout: :infinity
$$ LANGUAGE plpgsql"
)
shell_info("Refresh RUM index")
@ -221,9 +219,7 @@ defmodule Mix.Tasks.Pleroma.Database do
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE INDEX CONCURRENTLY objects_fts ON objects USING gin(to_tsvector('#{tsconfig}', data->>'content')); ",
[],
timeout: :infinity
"CREATE INDEX objects_fts ON objects USING gin(to_tsvector('#{tsconfig}', data->>'content')); "
)
end

View File

@ -26,23 +26,19 @@ defmodule Pleroma.Activity.Search do
:plain
end
try do
Activity
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> restrict_public()
|> query_with(index_type, search_query, search_function)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_blocked(user)
|> Pagination.fetch_paginated(
%{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
:offset
)
|> maybe_fetch(user, search_query)
rescue
_ -> maybe_fetch([], user, search_query)
end
Activity
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> restrict_public()
|> query_with(index_type, search_query, search_function)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_blocked(user)
|> Pagination.fetch_paginated(
%{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
:offset
)
|> maybe_fetch(user, search_query)
end
def maybe_restrict_author(query, %User{} = author) do
@ -65,17 +61,10 @@ defmodule Pleroma.Activity.Search do
end
defp query_with(q, :gin, search_query, :plain) do
%{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"select current_setting('default_text_search_config')::regconfig::oid;"
)
from([a, o] in q,
where:
fragment(
"to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
^tsc,
"to_tsvector(?->>'content') @@ plainto_tsquery(?)",
o.data,
^search_query
)
@ -83,17 +72,10 @@ defmodule Pleroma.Activity.Search do
end
defp query_with(q, :gin, search_query, :websearch) do
%{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"select current_setting('default_text_search_config')::regconfig::oid;"
)
from([a, o] in q,
where:
fragment(
"to_tsvector(?::oid::regconfig, ?->>'content') @@ websearch_to_tsquery(?)",
^tsc,
"to_tsvector(?->>'content') @@ websearch_to_tsquery(?)",
o.data,
^search_query
)

View File

@ -34,7 +34,7 @@ defmodule Pleroma.MFA.TOTP do
defp default_digits, do: Config.get(@config_ns ++ [:digits])
defp default_issuer,
do: Config.get(@config_ns ++ [:issuer], Config.get([:instance, :host]))
do: Config.get(@config_ns ++ [:issuer], Config.get([:instance, :name]))
@doc "Creates a random Base 32 encoded string"
def generate_secret do

View File

@ -51,23 +51,6 @@ defmodule Pleroma.Object.Fetcher do
end
end
defp reinject_object(%Object{} = object, new_data) do
Logger.debug("Reinjecting object #{new_data["id"]}")
with new_data <- Transmogrifier.fix_object(new_data),
data <- maybe_reinject_internal_fields(object, new_data),
changeset <- Object.change(object, %{data: data}),
changeset <- touch_changeset(changeset),
{:ok, object} <- Repo.insert_or_update(changeset),
{:ok, object} <- Object.set_cache(object) do
{:ok, object}
else
e ->
Logger.error("Error while processing object: #{inspect(e)}")
{:error, e}
end
end
def refetch_object(%Object{data: %{"id" => id}} = object) do
with {:local, false} <- {:local, Object.local?(object)},
{:ok, new_data} <- fetch_and_contain_remote_object_from_id(id),

View File

@ -20,6 +20,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Repo
alias Pleroma.Upload
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.MRF
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.Streamer
@ -310,7 +311,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
published = params[:published]
listen_data =
make_listen_data(
Builder.listen(
%{to: to, actor: actor, published: published, context: context, object: object},
additional
)

View File

@ -120,7 +120,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"to" => recipients,
"object" => object,
"type" => "Create",
"published" => DateTime.utc_now() |> DateTime.to_iso8601()
"published" => date()
}
|> Pleroma.Maps.put_if_present("context", context), []}
end
@ -132,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"type" => "ChatMessage",
"to" => [recipient],
"content" => content,
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"published" => date(),
"emoji" => Emoji.Formatter.get_emoji_map(content)
}
@ -160,7 +160,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"name" => name,
"inReplyTo" => object.data["id"],
"context" => object.data["context"],
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"published" => date(),
"id" => Utils.generate_object_id()
}, []}
end
@ -240,7 +240,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"to" => to,
"context" => object.data["context"],
"type" => "Announce",
"published" => Utils.make_date()
"published" => date()
}, []}
end
@ -305,4 +305,33 @@ defmodule Pleroma.Web.ActivityPub.Builder do
defp pinned_url(nickname) when is_binary(nickname) do
Pleroma.Web.Router.Helpers.activity_pub_url(Pleroma.Web.Endpoint, :pinned, nickname)
end
def listen(params, additional) do
%{
"type" => "Listen",
"id" => Utils.generate_activity_id(),
"to" => params.to |> Enum.uniq(),
"actor" => params.actor.ap_id,
"object" => params.object,
"published" => params.published || date(),
"context" => params.context
}
|> Map.merge(additional)
end
def json_ld_header do
%{
"@context" => [
"https://www.w3.org/ns/activitystreams",
"#{Pleroma.Web.Endpoint.url()}/schemas/litepub-0.1.jsonld",
%{
"@language" => "und"
}
]
}
end
def date do
DateTime.utc_now() |> DateTime.to_iso8601()
end
end

View File

@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
type: [:module, {:list, :module}],
description:
"A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name.",
suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF.Policy}
suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
},
%{
key: :transparency,

View File

@ -49,8 +49,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
message
|> Map.put("to", to)
|> Map.put("cc", cc)
|> Kernel.put_in(["object", "to"], to)
|> Kernel.put_in(["object", "cc"], cc)
{:ok, message}
else
@ -72,8 +70,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
message
|> Map.put("to", to)
|> Map.put("cc", cc)
|> Kernel.put_in(["object", "to"], to)
|> Kernel.put_in(["object", "cc"], cc)
{:ok, message}
else
@ -86,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
end
@impl true
def filter(%{"type" => "Create", "object" => %{"published" => _}} = message) do
def filter(%{"type" => "Create", "published" => _} = message) do
with actions <- Config.get([:mrf_object_age, :actions]),
{:reject, _} <- check_date(message),
{:ok, message} <- check_reject(message, actions),

View File

@ -93,51 +93,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
def filter(message), do: {:ok, message}
@impl true
@spec config_description :: %{
children: [
%{
description: <<_::272, _::_*256>>,
key: :hosts | :rejected_shortcodes | :size_limit,
suggestions: [any(), ...],
type: {:list, :string} | {:list, :string} | :integer
},
...
],
description: <<_::448>>,
key: :mrf_steal_emoji,
label: <<_::80>>,
related_policy: <<_::352>>
}
def config_description do
%{
key: :mrf_steal_emoji,
related_policy: "Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy",
label: "MRF Emojis",
description: "Steals emojis from selected instances when it sees them.",
children: [
%{
key: :hosts,
type: {:list, :string},
description: "List of hosts to steal emojis from",
suggestions: [""]
},
%{
key: :rejected_shortcodes,
type: {:list, :string},
description: "Regex-list of shortcodes to reject",
suggestions: [""]
},
%{
key: :size_limit,
type: :integer,
description: "File size limit (in bytes), checked before an emoji is saved to the disk",
suggestions: ["100000"]
}
]
}
end
@impl true
def describe do
{:ok, %{}}
end

View File

@ -31,6 +31,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.EventValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ListenValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator
@ -99,6 +100,21 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
def validate(
%{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = activity,
meta
) do
with {:ok, object_data} <- cast_and_apply(object),
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
{:ok, activity} <-
activity
|> ListenValidator.cast_and_validate(meta)
|> Ecto.Changeset.apply_action(:insert) do
activity = stringify_keys(activity)
{:ok, activity, meta}
end
end
def validate(
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
@ -143,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def validate(%{"type" => type} = object, meta)
when type in ~w[Accept Reject Follow Update Like EmojiReact Announce
ChatMessage Answer] do
ChatMessage Answer Add Remove] do
validator =
case type do
"Accept" -> AcceptRejectValidator
@ -155,6 +171,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"Announce" -> AnnounceValidator
"ChatMessage" -> ChatMessageValidator
"Answer" -> AnswerValidator
"Add" -> AddRemoveValidator
"Remove" -> AddRemoveValidator
end
with {:ok, object} <-
@ -166,16 +184,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
end
def validate(%{"type" => type} = object, meta) when type in ~w(Add Remove) do
with {:ok, object} <-
object
|> AddRemoveValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
end
end
def validate(o, m), do: {:error, {:validator_not_set, {o, m}}}
def cast_and_apply(%{"type" => "ChatMessage"} = object) do

View File

@ -50,6 +50,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
# Used by Pleroma's Listen-Audio Scrobbler
field(:title, :string)
field(:artist, :string)
field(:album, :string)
field(:length, :integer)
end
def cast_and_apply(data) do

View File

@ -0,0 +1,61 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.ListenValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
import Ecto.Changeset
@primary_key false
embedded_schema do
field(:id, ObjectValidators.ObjectID, primary_key: true)
field(:type, :string)
field(:published, ObjectValidators.DateTime)
field(:object, ObjectValidators.ObjectID)
field(:actor, ObjectValidators.ObjectID)
field(:context, :string)
field(:to, ObjectValidators.Recipients, default: [])
field(:cc, ObjectValidators.Recipients, default: [])
field(:bto, ObjectValidators.Recipients, default: [])
field(:bcc, ObjectValidators.Recipients, default: [])
end
def changeset(struct, data) do
struct
|> cast(data, __schema__(:fields))
end
def cast_data(data, meta \\ []) do
data = fix(data, meta)
%__MODULE__{}
|> changeset(data)
end
def cast_and_validate(data, meta \\ []) do
data
|> cast_data(meta)
|> validate_data(meta)
end
defp fix(data, _meta) do
data
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
end
defp validate_data(data_cng, _meta) do
# TODO: Restrict to Audio objects
data_cng
|> validate_inclusion(:type, ["Listen"])
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|> CommonValidations.validate_actor_presence()
end
end

View File

@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
collection, and so on.
"""
alias Pleroma.Activity
alias Pleroma.Activity.Ir.Topics
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
alias Pleroma.FollowingRelationship
@ -224,8 +225,18 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
meta
|> add_notifications(notifications)
ap_streamer().stream_out(activity)
{:ok, activity, meta}
else
e -> Repo.rollback(e)
end
end
# Tasks this handles
# - Actually create object
# - Rollback if we couldn't create it
@impl true
def handle(%{data: %{"type" => "Listen"}} = activity, meta) do
with {:ok, _object, meta} <- handle_object_creation(meta[:object_data], meta) do
{:ok, activity, meta}
else
e -> Repo.rollback(e)
@ -246,7 +257,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
if !User.is_internal_user?(user) do
Notification.create_notifications(object)
ap_streamer().stream_out(object)
object
|> Topics.get_activity_topics()
|> Streamer.stream(object)
end
{:ok, object, meta}

View File

@ -10,7 +10,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Maps
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@ -27,73 +26,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
require Logger
require Pleroma.Constants
@doc """
Modifies an incoming AP object (mastodon format) to our internal format.
"""
def fix_object(object, options \\ []) do
object
|> strip_internal_fields()
|> fix_actor()
|> fix_url()
|> fix_attachments()
|> fix_context()
|> fix_in_reply_to(options)
|> fix_emoji()
|> fix_tag()
|> fix_content_map()
|> fix_addressing()
|> fix_summary()
end
def fix_summary(%{"summary" => nil} = object) do
Map.put(object, "summary", "")
end
def fix_summary(%{"summary" => _} = object) do
# summary is present, nothing to do
object
end
def fix_summary(object), do: Map.put(object, "summary", "")
def fix_addressing_list(map, field) do
addrs = map[field]
cond do
is_list(addrs) ->
Map.put(map, field, Enum.filter(addrs, &is_binary/1))
is_binary(addrs) ->
Map.put(map, field, [addrs])
true ->
Map.put(map, field, [])
end
end
# if directMessage flag is set to true, leave the addressing alone
def fix_explicit_addressing(%{"directMessage" => true} = object, _follower_collection),
do: object
def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, follower_collection) do
explicit_mentions =
Utils.determine_explicit_mentions(object) ++
[Pleroma.Constants.as_public(), follower_collection]
explicit_to = Enum.filter(to, fn x -> x in explicit_mentions end)
explicit_cc = Enum.filter(to, fn x -> x not in explicit_mentions end)
final_cc =
(cc ++ explicit_cc)
|> Enum.filter(& &1)
|> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end)
|> Enum.uniq()
object
|> Map.put("to", explicit_to)
|> Map.put("cc", final_cc)
end
# if as:Public is addressed, then make sure the followers collection is also addressed
# so that the activities will be delivered to local users.
def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do
@ -117,34 +49,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
def fix_addressing(object) do
{:ok, %User{follower_address: follower_collection}} =
object
|> Containment.get_actor()
|> User.get_or_fetch_by_ap_id()
object
|> fix_addressing_list("to")
|> fix_addressing_list("cc")
|> fix_addressing_list("bto")
|> fix_addressing_list("bcc")
|> fix_explicit_addressing(follower_collection)
|> fix_implicit_addressing(follower_collection)
end
def fix_actor(%{"attributedTo" => actor} = object) do
actor = Containment.get_actor(%{"actor" => actor})
# TODO: Remove actor field for Objects
object
|> Map.put("actor", actor)
|> Map.put("attributedTo", actor)
end
def fix_in_reply_to(object, options \\ [])
def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
when not is_nil(in_reply_to) do
defp fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
when not is_nil(in_reply_to) do
in_reply_to_id = prepare_in_reply_to(in_reply_to)
depth = (options[:depth] || 0) + 1
@ -165,7 +71,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
def fix_in_reply_to(object, _options), do: object
defp fix_in_reply_to(object, _options), do: object
defp prepare_in_reply_to(in_reply_to) do
cond do
@ -183,100 +89,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
def fix_context(object) do
context = object["context"] || object["conversation"] || Utils.generate_context_id()
object
|> Map.put("context", context)
|> Map.drop(["conversation"])
end
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
attachments =
Enum.map(attachment, fn data ->
url =
cond do
is_list(data["url"]) -> List.first(data["url"])
is_map(data["url"]) -> data["url"]
true -> nil
end
media_type =
cond do
is_map(url) && MIME.extensions(url["mediaType"]) != [] ->
url["mediaType"]
is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] ->
data["mediaType"]
is_bitstring(data["mimeType"]) && MIME.extensions(data["mimeType"]) != [] ->
data["mimeType"]
true ->
nil
end
href =
cond do
is_map(url) && is_binary(url["href"]) -> url["href"]
is_binary(data["url"]) -> data["url"]
is_binary(data["href"]) -> data["href"]
true -> nil
end
if href do
attachment_url =
%{
"href" => href,
"type" => Map.get(url || %{}, "type", "Link")
}
|> Maps.put_if_present("mediaType", media_type)
|> Maps.put_if_present("width", (url || %{})["width"] || data["width"])
|> Maps.put_if_present("height", (url || %{})["height"] || data["height"])
%{
"url" => [attachment_url],
"type" => data["type"] || "Document"
}
|> Maps.put_if_present("mediaType", media_type)
|> Maps.put_if_present("name", data["name"])
|> Maps.put_if_present("blurhash", data["blurhash"])
else
nil
end
end)
|> Enum.filter(& &1)
Map.put(object, "attachment", attachments)
end
def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do
object
|> Map.put("attachment", [attachment])
|> fix_attachments()
end
def fix_attachments(object), do: object
def fix_url(%{"url" => url} = object) when is_map(url) do
Map.put(object, "url", url["href"])
end
def fix_url(%{"url" => url} = object) when is_list(url) do
first_element = Enum.at(url, 0)
url_string =
cond do
is_bitstring(first_element) -> first_element
is_map(first_element) -> first_element["href"] || ""
true -> ""
end
Map.put(object, "url", url_string)
end
def fix_url(object), do: object
def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do
emoji =
tags
@ -299,26 +111,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_emoji(object), do: object
def fix_tag(%{"tag" => tag} = object) when is_list(tag) do
tags =
tag
|> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
|> Enum.map(fn
%{"name" => "#" <> hashtag} -> String.downcase(hashtag)
%{"name" => hashtag} -> String.downcase(hashtag)
end)
Map.put(object, "tag", tag ++ tags)
end
def fix_tag(%{"tag" => %{} = tag} = object) do
object
|> Map.put("tag", [tag])
|> fix_tag
end
def fix_tag(object), do: object
# content map usually only has one language so this will do for now.
def fix_content_map(%{"contentMap" => content_map} = object) do
content_groups = Map.to_list(content_map)
@ -384,37 +176,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8,
do: :error
def handle_incoming(
%{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = data,
options
) do
actor = Containment.get_actor(data)
data =
Map.put(data, "actor", actor)
|> fix_addressing
with {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
reply_depth = (options[:depth] || 0) + 1
options = Keyword.put(options, :depth, reply_depth)
object = fix_object(object, options)
params = %{
to: data["to"],
object: object,
actor: user,
context: nil,
local: false,
published: data["published"],
additional: Map.take(data, ["cc", "id"])
}
ActivityPub.listen(params)
else
_e -> :error
end
end
@misskey_reactions %{
"like" => "👍",
"love" => "❤️",
@ -429,7 +190,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"star" => ""
}
@doc "Rewrite misskey likes into EmojiReacts"
# Rewrite misskey likes into EmojiReacts
def handle_incoming(
%{
"type" => "Like",
@ -493,6 +254,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(
%{"type" => "Listen", "object" => %{"type" => "Audio"}} = data,
_options
) do
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
{:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do
{:ok, activity}
end
end
def handle_incoming(
%{"type" => "Delete"} = data,
_options
) do
@ -595,30 +367,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
@spec get_embedded_obj_helper(String.t() | Object.t(), User.t()) :: {:ok, Object.t()} | nil
def get_embedded_obj_helper(%{"attributedTo" => attributed_to, "id" => object_id} = data, %User{
ap_id: ap_id
})
when attributed_to == ap_id do
with {:ok, activity} <-
handle_incoming(%{
"type" => "Create",
"to" => data["to"],
"cc" => data["cc"],
"actor" => attributed_to,
"object" => data
}) do
{:ok, Object.normalize(activity, fetch: false)}
else
_ -> get_obj_helper(object_id)
end
end
def get_embedded_obj_helper(object_id, _) do
get_obj_helper(object_id)
end
def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
defp set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
with false <- String.starts_with?(in_reply_to, "http"),
{:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do
Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to)
@ -627,13 +376,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
def set_reply_to_uri(obj), do: obj
defp set_reply_to_uri(obj), do: obj
@doc """
Serialized Mastodon-compatible `replies` collection containing _self-replies_.
Based on Mastodon's ActivityPub::NoteSerializer#replies.
"""
def set_replies(obj_data) do
# Serialized Mastodon-compatible `replies` collection containing _self-replies_.
# Based on Mastodon's ActivityPub::NoteSerializer#replies.
defp set_replies(obj_data) do
replies_uris =
with limit when limit > 0 <-
Pleroma.Config.get([:activitypub, :note_replies_output_limit], 0),
@ -663,16 +410,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Map.merge(obj, %{"replies" => replies_collection})
end
def replies(%{"replies" => %{"first" => %{"items" => items}}}) when not is_nil(items) do
items
end
def replies(%{"replies" => %{"items" => items}}) when not is_nil(items) do
items
end
def replies(_), do: []
# Prepares the object of an outgoing create activity.
def prepare_object(object) do
object
@ -689,11 +426,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> set_type
end
# @doc
# """
# internal -> Mastodon
# """
def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data)
when activity_type in ["Create", "Listen"] do
object =
@ -705,7 +437,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data =
data
|> Map.put("object", object)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
|> Map.delete("bcc")
{:ok, data}
@ -726,7 +458,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data =
data
|> strip_internal_fields
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
|> Map.delete("bcc")
{:ok, data}
@ -746,7 +478,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data =
data
|> Map.put("object", object)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
{:ok, data}
end
@ -764,7 +496,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data =
data
|> Map.put("object", object)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
{:ok, data}
end
@ -775,7 +507,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data
|> strip_internal_fields
|> maybe_fix_object_url
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
{:ok, data}
end
@ -798,7 +530,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def maybe_fix_object_url(data), do: data
def add_hashtags(object) do
defp add_hashtags(object) do
tags =
(object["tag"] || [])
|> Enum.map(fn
@ -820,7 +552,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
# TODO These should be added on our side on insertion, it doesn't make much
# sense to regenerate these all the time
def add_mention_tags(object) do
defp add_mention_tags(object) do
to = object["to"] || []
cc = object["cc"] || []
mentioned = User.get_users_from_set(to ++ cc, local_only: false)
@ -842,7 +574,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
# TODO: we should probably send mtime instead of unix epoch time for updated
def add_emoji_tags(%{"emoji" => emoji} = object) do
defp add_emoji_tags(%{"emoji" => emoji} = object) do
tags = object["tag"] || []
out = Enum.map(emoji, &build_emoji_tag/1)
@ -850,7 +582,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Map.put(object, "tag", tags ++ out)
end
def add_emoji_tags(object), do: object
defp add_emoji_tags(object), do: object
defp build_emoji_tag({name, url}) do
%{
@ -862,25 +594,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
}
end
def set_conversation(object) do
defp set_conversation(object) do
Map.put(object, "conversation", object["context"])
end
def set_type(%{"type" => "Answer"} = object) do
defp set_type(%{"type" => "Answer"} = object) do
Map.put(object, "type", "Note")
end
def set_type(object), do: object
defp set_type(object), do: object
def add_attributed_to(object) do
defp add_attributed_to(object) do
attributed_to = object["attributedTo"] || object["actor"]
Map.put(object, "attributedTo", attributed_to)
end
# TODO: Revisit this
def prepare_attachments(%{"type" => "ChatMessage"} = object), do: object
defp prepare_attachments(%{"type" => "ChatMessage"} = object), do: object
def prepare_attachments(object) do
defp prepare_attachments(object) do
attachments =
object
|> Map.get("attachment", [])
@ -954,11 +686,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> User.update_and_set_cache()
end
def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
defp maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
Map.put(data, "url", url["href"])
end
def maybe_fix_user_url(data), do: data
defp maybe_fix_user_url(data), do: data
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
end

View File

@ -13,6 +13,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.Endpoint
@ -107,22 +108,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
end
def make_json_ld_header do
%{
"@context" => [
"https://www.w3.org/ns/activitystreams",
"#{Endpoint.url()}/schemas/litepub-0.1.jsonld",
%{
"@language" => "und"
}
]
}
end
def make_date do
DateTime.utc_now() |> DateTime.to_iso8601()
end
def generate_activity_id do
generate_id("activities")
end
@ -199,7 +184,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def lazy_put_activity_defaults(map, true) do
map
|> Map.put_new("id", "pleroma:fakeid")
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new_lazy("published", &Builder.date/0)
|> Map.put_new("context", "pleroma:fakecontext")
|> Map.put_new("context_id", -1)
|> lazy_put_object_defaults(true)
@ -210,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
map
|> Map.put_new_lazy("id", &generate_activity_id/0)
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new_lazy("published", &Builder.date/0)
|> Map.put_new("context", context)
|> Map.put_new("context_id", context_id)
|> lazy_put_object_defaults(false)
@ -224,7 +209,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
object =
map
|> Map.put_new("id", "pleroma:fake_object_id")
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new_lazy("published", &Builder.date/0)
|> Map.put_new("context", activity["context"])
|> Map.put_new("context_id", activity["context_id"])
|> Map.put_new("fake", true)
@ -237,7 +222,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
object =
map
|> Map.put_new_lazy("id", &generate_object_id/0)
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new_lazy("published", &Builder.date/0)
|> Map.put_new("context", activity["context"])
|> Map.put_new("context_id", activity["context_id"])
@ -662,7 +647,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
#### Create-related helpers
def make_create_data(params, additional) do
published = params.published || make_date()
published = params.published || Builder.date()
%{
"type" => "Create",
@ -675,21 +660,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Map.merge(additional)
end
#### Listen-related helpers
def make_listen_data(params, additional) do
published = params.published || make_date()
%{
"type" => "Listen",
"to" => params.to |> Enum.uniq(),
"actor" => params.actor.ap_id,
"object" => params.object,
"published" => published,
"context" => params.context
}
|> Map.merge(additional)
end
#### Flag-related helpers
@spec make_flag_data(map(), map()) :: map()
def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do

View File

@ -6,10 +6,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
use Pleroma.Web, :view
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Transmogrifier
def render("object.json", %{object: %Object{} = object}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
base = Builder.json_ld_header()
additional = Transmogrifier.prepare_object(object.data)
Map.merge(base, additional)
@ -17,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity})
when activity_type in ["Create", "Listen"] do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
base = Builder.json_ld_header()
object = Object.normalize(activity, fetch: false)
additional =
@ -28,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
end
def render("object.json", %{object: %Activity{} = activity}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
base = Builder.json_ld_header()
object = Object.normalize(activity, fetch: false)
additional =

View File

@ -9,9 +9,9 @@ defmodule Pleroma.Web.ActivityPub.UserView do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router.Helpers
@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"endpoints" => endpoints,
"invisible" => User.invisible?(user)
}
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
# the instance itself is not a Person, but instead an Application
@ -120,7 +120,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("following.json", %{user: user, page: page} = opts) do
@ -139,7 +139,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end
collection(following, "#{user.ap_id}/following", page, showing_items, total)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("following.json", %{user: user} = opts) do
@ -168,7 +168,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"#{user.ap_id}/following?page=1"
end
}
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("followers.json", %{user: user, page: page} = opts) do
@ -187,7 +187,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end
collection(followers, "#{user.ap_id}/followers", page, showing_items, total)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("followers.json", %{user: user} = opts) do
@ -216,7 +216,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end
}
|> maybe_put_total_items(showing_count, total)
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("activity_collection.json", %{iri: iri}) do
@ -225,7 +225,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"type" => "OrderedCollection",
"first" => "#{iri}?page=true"
}
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
def render("activity_collection_page.json", %{
@ -244,7 +244,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"partOf" => iri,
"orderedItems" => collection
}
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
|> Map.merge(pagination)
end
@ -264,7 +264,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"orderedItems" => objects,
"totalItems" => length(objects)
}
|> Map.merge(Utils.make_json_ld_header())
|> Map.merge(Builder.json_ld_header())
end
defp maybe_put_total_items(map, false, _total), do: map

View File

@ -57,7 +57,6 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
def is_list?(_), do: false
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
def visible_for_user?(%Activity{actor: ap_id}, %User{ap_id: ap_id}), do: true
def visible_for_user?(%Object{data: %{"actor" => ap_id}}, %User{ap_id: ap_id}), do: true
def visible_for_user?(nil, _), do: false

View File

@ -35,12 +35,6 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
end
defp installed do
frontend_directory = Pleroma.Frontend.dir()
if File.exists?(frontend_directory) do
File.ls!(frontend_directory)
else
[]
end
File.ls!(Pleroma.Frontend.dir())
end
end

View File

@ -13,9 +13,7 @@ defmodule Pleroma.Web.AdminAPI.Report do
account = User.get_cached_by_ap_id(account_ap_id)
statuses =
status_ap_ids
|> Enum.reject(&is_nil(&1))
|> Enum.map(fn
Enum.map(status_ap_ids, fn
act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"])
act when is_binary(act) -> Activity.get_by_ap_id_with_object(act)
end)

View File

@ -8,8 +8,6 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
import Pleroma.Web.ApiSpec.Helpers
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
@ -65,7 +63,17 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
summary: "Change account password",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_password",
requestBody: request_body("Parameters", change_password_request(), required: true),
parameters: [
Operation.parameter(:password, :query, :string, "Current password", required: true),
Operation.parameter(:new_password, :query, :string, "New password", required: true),
Operation.parameter(
:new_password_confirmation,
:query,
:string,
"New password, confirmation",
required: true
)
],
responses: %{
200 =>
Operation.response("Success", "application/json", %Schema{
@ -78,30 +86,17 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
}
end
defp change_password_request do
%Schema{
title: "ChangePasswordRequest",
description: "POST body for changing the account's passowrd",
type: :object,
required: [:password, :new_password, :new_password_confirmation],
properties: %{
password: %Schema{type: :string, description: "Current password"},
new_password: %Schema{type: :string, description: "New password"},
new_password_confirmation: %Schema{
type: :string,
description: "New password, confirmation"
}
}
}
end
def change_email_operation do
%Operation{
tags: ["Account credentials"],
summary: "Change account email",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_email",
requestBody: request_body("Parameters", change_email_request(), required: true),
parameters: [
Operation.parameter(:password, :query, :string, "Current password", required: true),
Operation.parameter(:email, :query, :string, "New email", required: true)
],
requestBody: nil,
responses: %{
200 =>
Operation.response("Success", "application/json", %Schema{
@ -114,19 +109,6 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
}
end
defp change_email_request do
%Schema{
title: "ChangeEmailRequest",
description: "POST body for changing the account's email",
type: :object,
required: [:email, :password],
properties: %{
email: %Schema{type: :string, description: "New email"},
password: %Schema{type: :string, description: "Current password"}
}
}
end
def update_notificaton_settings_operation do
%Operation{
tags: ["Accounts"],

View File

@ -412,14 +412,19 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def maybe_notify_mentioned_recipients(recipients, _), do: recipients
# Do not notify subscribers if author is making a reply
def maybe_notify_subscribers(recipients, %Activity{
object: %Object{data: %{"inReplyTo" => _ap_id}}
}) do
recipients
end
def maybe_notify_subscribers(
recipients,
%Activity{data: %{"actor" => actor, "type" => "Create"}} = activity
) do
# Do not notify subscribers if author is making a reply
with %Object{data: object} <- Object.normalize(activity, fetch: false),
nil <- object["inReplyTo"],
%User{} = user <- User.get_cached_by_ap_id(actor) do
%Activity{data: %{"actor" => actor, "type" => type}} = activity
)
when type == "Create" do
with %User{} = user <- User.get_cached_by_ap_id(actor) do
subscriber_ids =
user
|> User.subscriber_users()

View File

@ -193,9 +193,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> ActivityPub.fetch_activities_bounded(following, params)
|> Enum.reverse()
conn
|> add_link_headers(activities)
|> render("index.json",
render(conn, "index.json",
activities: activities,
for: user,
as: :activity,

View File

@ -65,19 +65,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
defp get_context_id(_), do: nil
# Check if the user reblogged this status
defp reblogged?(activity, %User{ap_id: ap_id}) do
with %Object{data: %{"announcements" => announcements}} when is_list(announcements) <-
Object.normalize(activity, fetch: false) do
ap_id in announcements
else
_ -> false
end
defp reblogged?(activity, user) do
object = Object.normalize(activity, fetch: false) || %{}
present?(user && user.ap_id in (object.data["announcements"] || []))
end
# False if the user is logged out
defp reblogged?(_activity, _user), do: false
def render("index.json", opts) do
reading_user = opts[:for]

View File

@ -41,7 +41,7 @@ defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationController do
def setup(%{assigns: %{user: user}} = conn, %{"method" => "totp"} = _params) do
with {:ok, user} <- MFA.setup_totp(user),
%{secret: secret} = _ <- user.multi_factor_authentication_settings.totp do
provisioning_uri = TOTP.provisioning_uri(secret, "#{user.ap_id}")
provisioning_uri = TOTP.provisioning_uri(secret, "#{user.email}")
json(conn, %{provisioning_uri: provisioning_uri, key: secret})
else

View File

@ -81,13 +81,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
def change_password(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
def change_password(%{assigns: %{user: user}} = conn, %{
password: password,
new_password: new_password,
new_password_confirmation: new_password_confirmation
}) do
case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
with {:ok, _user} <-
User.reset_password(user, %{
password: body_params.new_password,
password_confirmation: body_params.new_password_confirmation
password: new_password,
password_confirmation: new_password_confirmation
}) do
json(conn, %{status: "success"})
else
@ -104,10 +108,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
def change_email(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do
case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
with {:ok, _user} <- User.change_email(user, body_params.email) do
with {:ok, _user} <- User.change_email(user, email) do
json(conn, %{status: "success"})
else
{:error, changeset} ->

View File

@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
version: version("2.4.1"),
version: version("2.3.50"),
elixir: "~> 1.9",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.error-page-container[data-v-09709f1e]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.error-page-container .buttons-group[data-v-09709f1e]{margin-top:4em}.error-page-container .el-icon-warning[data-v-09709f1e]{font-size:4.2em;color:#eee;margin:0 auto}.error-page-container .error-page[data-v-09709f1e]{width:45rem;max-width:100%;margin:16rem auto;text-align:center}.error-page-container .error-title[data-v-09709f1e]{color:#eee}

View File

@ -0,0 +1 @@
.moderation-log-container[data-v-ab8fe5e2]{margin:0 15px}h1[data-v-ab8fe5e2]{margin:0}.el-timeline[data-v-ab8fe5e2]{margin:25px 45px 0 0;padding:0}.moderation-log-date-panel[data-v-ab8fe5e2]{width:350px}.moderation-log-header-container[data-v-ab8fe5e2]{-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:10px 0 15px}.moderation-log-header-container[data-v-ab8fe5e2],.moderation-log-nav-container[data-v-ab8fe5e2]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.moderation-log-search[data-v-ab8fe5e2]{width:350px}.moderation-log-user-select[data-v-ab8fe5e2]{margin:0 0 20px;width:350px}.reboot-button[data-v-ab8fe5e2]{padding:10px;margin:0;width:145px}.router-link[data-v-ab8fe5e2]{text-decoration:none}.search-container[data-v-ab8fe5e2]{text-align:right}.pagination[data-v-ab8fe5e2]{text-align:center}@media only screen and (max-width:480px){h1[data-v-ab8fe5e2]{font-size:24px}.moderation-log-date-panel[data-v-ab8fe5e2]{width:100%}.moderation-log-user-select[data-v-ab8fe5e2]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-ab8fe5e2]{width:40%}}@media only screen and (max-width:801px) and (min-width:481px){.moderation-log-date-panel[data-v-ab8fe5e2]{width:55%}.moderation-log-user-select[data-v-ab8fe5e2]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-ab8fe5e2]{width:40%}}

View File

@ -1 +0,0 @@
.error-page-container[data-v-6c40cae5]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.error-page-container .buttons-group[data-v-6c40cae5]{margin-top:4em}.error-page-container .el-icon-warning[data-v-6c40cae5]{font-size:4.2em;color:#eee;margin:0 auto}.error-page-container .error-page[data-v-6c40cae5]{width:45rem;max-width:100%;margin:16rem auto;text-align:center}.error-page-container .error-title[data-v-6c40cae5]{color:#eee}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.follow-relay{width:350px;margin-right:7px}.relays-container{margin:0 15px}.relays-header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media only screen and (max-width:480px){.follow-relay{width:75%;margin-right:5px}.follow-relay input{width:100%}.follow-relay-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin:0 5px}.relays-container{margin:0 10px}}

View File

@ -1 +0,0 @@
.router-link{text-decoration:none}.moderation-log-container[data-v-a9880f26]{margin:0 15px}h1[data-v-a9880f26]{margin:0}.el-timeline[data-v-a9880f26]{margin:25px 45px 0 0;padding:0}.moderation-log-date-panel[data-v-a9880f26]{width:350px}.moderation-log-header-container[data-v-a9880f26]{-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:10px 0 15px}.moderation-log-header-container[data-v-a9880f26],.moderation-log-nav-container[data-v-a9880f26]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.moderation-log-search[data-v-a9880f26]{width:350px}.moderation-log-user-select[data-v-a9880f26]{margin:0 0 20px;width:350px}.reboot-button[data-v-a9880f26]{padding:10px;margin:0;width:145px}.pagination[data-v-a9880f26]{text-align:center}@media only screen and (max-width:480px){h1[data-v-a9880f26]{font-size:24px}.moderation-log-date-panel[data-v-a9880f26]{width:100%}.moderation-log-user-select[data-v-a9880f26]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-a9880f26]{width:40%}}@media only screen and (max-width:801px) and (min-width:481px){.moderation-log-date-panel[data-v-a9880f26]{width:55%}.moderation-log-user-select[data-v-a9880f26]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-a9880f26]{width:40%}}

View File

@ -0,0 +1 @@
.wscn-http404-container[data-v-1d6b2d2a]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-1d6b2d2a]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-1d6b2d2a]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-1d6b2d2a]{width:100%}.wscn-http404 .pic-404__child[data-v-1d6b2d2a]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-1d6b2d2a]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-1d6b2d2a;animation-name:cloudLeft-data-v-1d6b2d2a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-1d6b2d2a]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-1d6b2d2a;animation-name:cloudMid-data-v-1d6b2d2a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-1d6b2d2a]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-1d6b2d2a;animation-name:cloudRight-data-v-1d6b2d2a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-1d6b2d2a{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-1d6b2d2a{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-1d6b2d2a{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-1d6b2d2a{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-1d6b2d2a{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-1d6b2d2a{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-1d6b2d2a]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-1d6b2d2a]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-1d6b2d2a],.wscn-http404 .bullshit__oops[data-v-1d6b2d2a]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-1d6b2d2a;animation-name:slideUp-data-v-1d6b2d2a;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-1d6b2d2a]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-1d6b2d2a]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-1d6b2d2a],.wscn-http404 .bullshit__return-home[data-v-1d6b2d2a]{opacity:0;-webkit-animation-name:slideUp-data-v-1d6b2d2a;animation-name:slideUp-data-v-1d6b2d2a;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-1d6b2d2a]{display:block;float:left;width:165px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-1d6b2d2a{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-1d6b2d2a{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}

View File

@ -0,0 +1 @@
.errPage-container[data-v-ab9be52c]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-ab9be52c]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-ab9be52c]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-ab9be52c]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-ab9be52c]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-ab9be52c]{font-size:14px}.errPage-container .list-unstyled li[data-v-ab9be52c]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-ab9be52c]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-ab9be52c]:hover{text-decoration:underline}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.invites-container .actions-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:15px}.invites-container .create-invite-token{text-align:left;width:350px;padding:10px}.invites-container .create-new-token-dialog a{margin-bottom:3px}.invites-container .create-new-token-dialog .el-card__body{padding:10px 20px}.invites-container .el-dialog__body{padding:5px 20px 0}.invites-container h1{margin:0}.invites-container .icon{margin-right:5px}.invites-container .invite-link-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.invites-container .invite-link-container button{margin-left:15px}.invites-container .invite-token-table{width:100%;margin:0 15px}.invites-container .invite-via-email{text-align:left;width:350px;padding:10px}.invites-container .invite-via-email-dialog{width:50%}.invites-container .invites-header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin:10px 15px}.invites-container .info{color:#666;font-size:13px;line-height:22px;margin:0 0 10px}.invites-container .new-token-card .el-form-item{margin:0}.invites-container .reboot-button{padding:10px;margin:0;width:145px}@media only screen and (max-width:480px){.invites-container .actions-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:15px 10px 7px}.invites-container .cell{padding:0}.invites-container .create-invite-token{width:100%}.invites-container .create-new-token-dialog{width:85%}.invites-container .el-date-editor{width:150px}.invites-container .el-dialog__body{padding:5px 15px 0}.invites-container h1{margin:0}.invites-container .invite-token-table{width:100%;margin:0 5px;font-size:12px;font-weight:500}.invites-container .invite-via-email{width:100%;margin:10px 0 0}.invites-container .invite-via-email-dialog{width:85%}.invites-container .invites-header-container{margin:0 10px}.invites-container .info{margin:0 0 10px 5px}.invites-container th .cell{padding:0}.create-invite-token,.invite-via-email{width:100%}}
.invites-container .actions-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:15px}.invites-container .create-invite-token{text-align:left;width:350px;padding:10px}.invites-container .create-new-token-dialog{width:50%}.invites-container .create-new-token-dialog a{margin-bottom:3px}.invites-container .create-new-token-dialog .el-card__body{padding:10px 20px}.invites-container .el-dialog__body{padding:5px 20px 0}.invites-container h1{margin:0}.invites-container .icon{margin-right:5px}.invites-container .invite-token-table{width:100%;margin:0 15px}.invites-container .invite-via-email{text-align:left;width:350px;padding:10px}.invites-container .invite-via-email-dialog{width:50%}.invites-container .invites-header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin:10px 15px}.invites-container .info{color:#666;font-size:13px;line-height:22px;margin:0 0 10px}.invites-container .new-token-card .el-form-item{margin:0}.invites-container .reboot-button{padding:10px;margin:0;width:145px}@media only screen and (max-width:480px){.invites-container .actions-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:15px 10px 7px}.invites-container .cell{padding:0}.invites-container .create-invite-token{width:100%}.invites-container .create-new-token-dialog{width:85%}.invites-container .el-date-editor{width:150px}.invites-container .el-dialog__body{padding:5px 15px 0}.invites-container h1{margin:0}.invites-container .invite-token-table{width:100%;margin:0 5px;font-size:12px;font-weight:500}.invites-container .invite-via-email{width:100%;margin:10px 0 0}.invites-container .invite-via-email-dialog{width:85%}.invites-container .invites-header-container{margin:0 10px}.invites-container .info{margin:0 0 10px 5px}.invites-container th .cell{padding:0}.create-invite-token,.invite-via-email{width:100%}}

View File

@ -1 +1 @@
@supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}.login-container .el-input input:first-line{color:#eee}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#eee;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container .login-button{width:100%;margin:0 0 10px}.login-container .omit-host-note{color:#596f8c;font-size:.8em;font-style:italic;margin:-20px 0 15px;padding:3px 0 0 15px}.login-container[data-v-5aafa9c0]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-5aafa9c0]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-5aafa9c0]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-5aafa9c0]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-5aafa9c0]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-5aafa9c0]{position:relative}.login-container .title-container .title[data-v-5aafa9c0]{font-size:26px;color:#eee;margin:0 auto 40px;text-align:center;font-weight:700}.login-container .title-container .set-language[data-v-5aafa9c0]{color:#fff;position:absolute;top:3px;font-size:18px;right:0;cursor:pointer}.login-container .show-pwd[data-v-5aafa9c0]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-5aafa9c0]{position:absolute;right:0;bottom:6px}
@supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}.login-container .el-input input:first-line{color:#eee}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#eee;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container .login-button{width:100%;margin:0 0 10px}.login-container .omit-host-note{color:#596f8c;font-size:.8em;font-style:italic;margin:-20px 0 15px;padding:3px 0 0 15px}.login-container[data-v-5bb13616]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-5bb13616]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-5bb13616]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-5bb13616]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-5bb13616]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-5bb13616]{position:relative}.login-container .title-container .title[data-v-5bb13616]{font-size:26px;color:#eee;margin:0 auto 40px;text-align:center;font-weight:700}.login-container .title-container .set-language[data-v-5bb13616]{color:#fff;position:absolute;top:3px;font-size:18px;right:0;cursor:pointer}.login-container .show-pwd[data-v-5bb13616]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-5bb13616]{position:absolute;right:0;bottom:6px}

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.f1f2be85.css rel=stylesheet><link href=chunk-libs.74976a6a.css rel=stylesheet><link href=app.143a1409.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.2a586239.js></script><script type=text/javascript src=static/js/chunk-elementUI.4c32a355.js></script><script type=text/javascript src=static/js/chunk-libs.55b24a78.js></script><script type=text/javascript src=static/js/app.f02f5ebc.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.f77689d7.css rel=stylesheet><link href=chunk-libs.5cf7f50a.css rel=stylesheet><link href=app.6fb984d1.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.6b30c658.js></script><script type=text/javascript src=static/js/chunk-elementUI.21957ec8.js></script><script type=text/javascript src=static/js/chunk-libs.5ca2c8e8.js></script><script type=text/javascript src=static/js/app.1428845f.js></script></body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-0c60"],{"/yZL":function(t,r,o){"use strict";var e=o("3dKJ");o.n(e).a},"3dKJ":function(t,r,o){},"UUO+":function(t,r,o){"use strict";o.r(r);var e={name:"Page401",methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/login"}):this.$router.go(-1)},login:function(){this.$router.push({path:"/login"})}}},s=(o("/yZL"),o("KHd+")),n=Object(s.a)(e,function(){var t=this,r=t.$createElement,o=t._self._c||r;return o("div",{staticClass:"error-page-container"},[o("div",{staticClass:"error-page"},[o("i",{staticClass:"el-icon-warning"}),t._v(" "),o("h1",{staticClass:"error-title"},[t._v(t._s(t.$t("errLog.error401")))]),t._v(" "),o("h2",{staticClass:"error-title"},[t._v(t._s(t.$t("errLog.unauth")))]),t._v(" "),o("div",{staticClass:"buttons-group"},[o("el-button",{on:{click:t.back}},[t._v(t._s(t.$t("errLog.back")))]),t._v(" "),o("el-button",{attrs:{type:"primary"},on:{click:t.login}},[t._v(t._s(t.$t("errLog.login")))])],1)])])},[],!1,null,"09709f1e",null);n.options.__file="401.vue";r.default=n.exports}}]);
//# sourceMappingURL=chunk-0c60.9b12ac3f.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-45ed"],{"/eX4":function(t,e,r){"use strict";r.r(e);var o={name:"Page404",methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/login"}):this.$router.go(-1)},goToHomePage:function(){this.$router.push({path:"/"})}}},s=(r("meHR"),r("KHd+")),a=Object(s.a)(o,function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("div",{staticClass:"error-page-container"},[r("div",{staticClass:"error-page"},[r("i",{staticClass:"el-icon-warning"}),t._v(" "),r("h1",{staticClass:"error-title"},[t._v(t._s(t.$t("errLog.error404")))]),t._v(" "),r("h2",{staticClass:"error-title"},[t._v(t._s(t.$t("errLog.pageNotFound")))]),t._v(" "),r("h2",{staticClass:"error-title"},[t._v(t._s(t.$t("errLog.correctUrl")))]),t._v(" "),r("div",{staticClass:"buttons-group"},[r("el-button",{on:{click:t.back}},[t._v(t._s(t.$t("errLog.back")))]),t._v(" "),r("el-button",{attrs:{type:"primary"},on:{click:t.goToHomePage}},[t._v(t._s(t.$t("errLog.homePage")))])],1)])])},[],!1,null,"6c40cae5",null);a.options.__file="404.vue";e.default=a.exports},KoUO:function(t,e,r){},meHR:function(t,e,r){"use strict";var o=r("KoUO");r.n(o).a}}]);
//# sourceMappingURL=chunk-45ed.a89b5b8d.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-4a1e"],{UR5J:function(e,t,l){"use strict";l.r(t);var n={name:"Relays",components:{RebootButton:l("rIUS").a},data:function(){return{newRelay:""}},computed:{getLabelWidth:function(){return this.isDesktop?"130px":"85px"},isDesktop:function(){return"desktop"===this.$store.state.app.device},loading:function(){return this.$store.state.relays.loading},relays:function(){return this.$store.state.relays.fetchedRelays}},mounted:function(){this.$store.dispatch("FetchRelays")},methods:{followRelay:function(){this.$store.dispatch("AddRelay",this.newRelay),this.newRelay=""},deleteRelay:function(e){this.$store.dispatch("DeleteRelay",e)}}},a=(l("p8X7"),l("KHd+")),o=Object(a.a)(n,function(){var e=this,t=e.$createElement,l=e._self._c||t;return e.loading?e._e():l("div",{staticClass:"relays-container"},[l("div",{staticClass:"relays-header-container"},[l("h1",[e._v("\n "+e._s(e.$t("relays.relays"))+"\n ")]),e._v(" "),l("reboot-button")],1),e._v(" "),l("div",{staticClass:"follow-relay-container"},[l("el-input",{staticClass:"follow-relay",attrs:{placeholder:e.$t("relays.followRelay")},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.followRelay(t)}},model:{value:e.newRelay,callback:function(t){e.newRelay=t},expression:"newRelay"}}),e._v(" "),l("el-button",{nativeOn:{click:function(t){return e.followRelay(t)}}},[e._v(e._s(e.$t("relays.follow")))])],1),e._v(" "),l("el-table",{attrs:{data:e.relays}},[l("el-table-column",{attrs:{label:e.$t("relays.instanceUrl"),prop:"actor"}}),e._v(" "),l("el-table-column",{attrs:{label:e.$t("relays.followedBack"),width:e.getLabelWidth,prop:"followed_back",align:"center"},scopedSlots:e._u([{key:"default",fn:function(e){return[l("i",{class:e.row.followed_back?"el-icon-check":"el-icon-minus"})]}}],null,!1,237257305)}),e._v(" "),l("el-table-column",{attrs:{label:e.$t("table.actions"),width:e.getLabelWidth,fixed:"right",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[l("el-button",{attrs:{type:"text",size:"small"},nativeOn:{click:function(l){return e.deleteRelay(t.row.actor)}}},[e._v("\n "+e._s(e.$t("table.unfollow"))+"\n ")])]}}],null,!1,877363589)})],1)],1)},[],!1,null,null,null);o.options.__file="index.vue";t.default=o.exports},p8X7:function(e,t,l){"use strict";var n=l("sp3N");l.n(n).a},sp3N:function(e,t,l){}}]);
//# sourceMappingURL=chunk-4a1e.0f4047c1.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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