Merge develop plerom a
This commit is contained in:
commit
cb49ac86e1
87
CHANGELOG.md
87
CHANGELOG.md
|
@ -3,7 +3,18 @@ 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/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## [unreleased]
|
## unreleased-patch - ???
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Rich media failure tracking (along with `:failure_backoff` option)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Mastodon API: Search parameter `following` now correctly returns the followings rather than the followers
|
||||||
|
- Mastodon API: Timelines hanging for (`number of posts with links * rich media timeout`) in the worst case.
|
||||||
|
Reduced to just rich media timeout.
|
||||||
|
- Password resets no longer processed for deactivated accounts
|
||||||
|
|
||||||
|
## [2.1.0] - 2020-08-28
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -116,11 +127,78 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Migrations not working on OTP releases if the database was connected over ssl
|
- Migrations not working on OTP releases if the database was connected over ssl
|
||||||
- Fix relay following
|
- Fix relay following
|
||||||
|
|
||||||
## [Unreleased (patch)]
|
## [2.0.7] - 2020-06-13
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Fix potential DoSes exploiting atom leaks in rich media parser and the `UserAllowListPolicy` MRF policy
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- CSP: not allowing images/media from every host when mediaproxy is disabled
|
||||||
|
- CSP: not adding mediaproxy base url to image/media hosts
|
||||||
|
- StaticFE missing the CSS file
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
|
## [2.0.6] - 2020-06-09
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- CSP: harden `image-src` and `media-src` when MediaProxy is used
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- AP C2S: Fix pagination in inbox/outbox
|
||||||
|
- Various compilation errors on OTP 23
|
||||||
|
- Mastodon API streaming: Repeats from muted threads not being filtered
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Various database performance improvements
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
1. Run database migrations (inside Pleroma directory):
|
||||||
|
- OTP: `./bin/pleroma_ctl migrate`
|
||||||
|
- From Source: `mix ecto.migrate`
|
||||||
|
2. Restart Pleroma
|
||||||
|
|
||||||
|
## [2.0.5] - 2020-05-13
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Fix possible private status leaks in Mastodon Streaming API
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Crashes when trying to block a user if block federation is disabled
|
||||||
|
- Not being able to start the instance without `erlang-eldap` installed
|
||||||
|
- Users with bios over the limit getting rejected
|
||||||
|
- Follower counters not being updated on incoming follow accepts
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
|
## [2.0.4] - 2020-05-10
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- AP C2S: Fix a potential DoS by creating nonsensical objects that break timelines
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Peertube user lookups not working
|
||||||
|
- `InsertSkeletonsForDeletedUsers` migration failing on some instances
|
||||||
- Healthcheck reporting the number of memory currently used, rather than allocated in total
|
- Healthcheck reporting the number of memory currently used, rather than allocated in total
|
||||||
- `InsertSkeletonsForDeletedUsers` failing on some instances
|
- LDAP not being usable in OTP releases
|
||||||
|
- Default apache configuration having tls chain issues
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
|
||||||
|
#### Apache only
|
||||||
|
|
||||||
|
1. Remove the following line from your config:
|
||||||
|
```
|
||||||
|
SSLCertificateFile /etc/letsencrypt/live/${servername}/cert.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Everyone
|
||||||
|
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
## [2.0.3] - 2020-05-02
|
## [2.0.3] - 2020-05-02
|
||||||
|
|
||||||
|
@ -144,7 +222,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Follow request notifications
|
- Follow request notifications
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
|
||||||
- Admin API: `GET /api/pleroma/admin/need_reboot`.
|
- Admin API: `GET /api/pleroma/admin/need_reboot`.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -179,6 +256,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Static-FE: Fix remote posts not being sanitized
|
- Static-FE: Fix remote posts not being sanitized
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
=======
|
||||||
|
- Rate limiter crashes when there is no explicitly specified ip in the config
|
||||||
- 500 errors when no `Accept` header is present if Static-FE is enabled
|
- 500 errors when no `Accept` header is present if Static-FE is enabled
|
||||||
- Instance panel not being updated immediately due to wrong `Cache-Control` headers
|
- Instance panel not being updated immediately due to wrong `Cache-Control` headers
|
||||||
- Statuses posted with BBCode/Markdown having unncessary newlines in Pleroma-FE
|
- Statuses posted with BBCode/Markdown having unncessary newlines in Pleroma-FE
|
||||||
|
|
|
@ -412,6 +412,7 @@ config :pleroma, :rich_media,
|
||||||
Pleroma.Web.RichMedia.Parsers.TwitterCard,
|
Pleroma.Web.RichMedia.Parsers.TwitterCard,
|
||||||
Pleroma.Web.RichMedia.Parsers.OEmbed
|
Pleroma.Web.RichMedia.Parsers.OEmbed
|
||||||
],
|
],
|
||||||
|
failure_backoff: 60_000,
|
||||||
ttl_setters: [Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl]
|
ttl_setters: [Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl]
|
||||||
|
|
||||||
config :pleroma, :media_proxy,
|
config :pleroma, :media_proxy,
|
||||||
|
@ -740,19 +741,23 @@ config :pleroma, :connections_pool,
|
||||||
config :pleroma, :pools,
|
config :pleroma, :pools,
|
||||||
federation: [
|
federation: [
|
||||||
size: 50,
|
size: 50,
|
||||||
max_waiting: 10
|
max_waiting: 10,
|
||||||
|
timeout: 10_000
|
||||||
],
|
],
|
||||||
media: [
|
media: [
|
||||||
size: 50,
|
size: 50,
|
||||||
max_waiting: 10
|
max_waiting: 10,
|
||||||
|
timeout: 10_000
|
||||||
],
|
],
|
||||||
upload: [
|
upload: [
|
||||||
size: 25,
|
size: 25,
|
||||||
max_waiting: 5
|
max_waiting: 5,
|
||||||
|
timeout: 15_000
|
||||||
],
|
],
|
||||||
default: [
|
default: [
|
||||||
size: 10,
|
size: 10,
|
||||||
max_waiting: 2
|
max_waiting: 2,
|
||||||
|
timeout: 5_000
|
||||||
]
|
]
|
||||||
|
|
||||||
config :pleroma, :hackney_pools,
|
config :pleroma, :hackney_pools,
|
||||||
|
|
|
@ -2385,6 +2385,13 @@ config :pleroma, :config_description, [
|
||||||
suggestions: [
|
suggestions: [
|
||||||
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :failure_backoff,
|
||||||
|
type: :integer,
|
||||||
|
description:
|
||||||
|
"Amount of milliseconds after request failure, during which the request will not be retried.",
|
||||||
|
suggestions: [60_000]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,9 +18,10 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
|
||||||
|
|
||||||
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
||||||
2. Run `git pull`. This pulls the latest changes from upstream.
|
2. Run `git pull`. This pulls the latest changes from upstream.
|
||||||
3. Run `mix deps.get`. This pulls in any new dependencies.
|
3. Run `mix deps.get` [^1]. This pulls in any new dependencies.
|
||||||
4. Stop the Pleroma service.
|
4. Stop the Pleroma service.
|
||||||
5. Run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
|
5. Run `mix ecto.migrate` [^1] [^2]. This task performs database migrations, if there were any.
|
||||||
6. Start the Pleroma service.
|
6. Start the Pleroma service.
|
||||||
|
|
||||||
[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
[^1]: Depending on which install guide you followed (for example on Debian/Ubuntu), you want to run `mix` tasks as `pleroma` user by adding `sudo -Hu pleroma` before the command.
|
||||||
|
[^2]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
||||||
|
|
|
@ -361,6 +361,7 @@ config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Http,
|
||||||
* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`.
|
* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`.
|
||||||
* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"].
|
* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"].
|
||||||
* `parsers`: list of Rich Media parsers.
|
* `parsers`: list of Rich Media parsers.
|
||||||
|
* `failure_backoff`: Amount of milliseconds after request failure, during which the request will not be retried.
|
||||||
|
|
||||||
## HTTP server
|
## HTTP server
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ defmodule Mix.Tasks.Pleroma.Frontend do
|
||||||
|
|
||||||
fe_label = "#{frontend} (#{ref})"
|
fe_label = "#{frontend} (#{ref})"
|
||||||
|
|
||||||
tmp_dir = Path.join(dest, "tmp")
|
tmp_dir = Path.join([instance_static_dir, "frontends", "tmp"])
|
||||||
|
|
||||||
with {_, :ok} <-
|
with {_, :ok} <-
|
||||||
{:download_or_unzip, download_or_unzip(frontend_info, tmp_dir, options[:file])},
|
{:download_or_unzip, download_or_unzip(frontend_info, tmp_dir, options[:file])},
|
||||||
|
@ -124,7 +124,9 @@ defmodule Mix.Tasks.Pleroma.Frontend do
|
||||||
url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"])
|
url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"])
|
||||||
|
|
||||||
with {:ok, %{status: 200, body: zip_body}} <-
|
with {:ok, %{status: 200, body: zip_body}} <-
|
||||||
Pleroma.HTTP.get(url, [], timeout: 120_000, recv_timeout: 120_000) do
|
Pleroma.HTTP.get(url, [],
|
||||||
|
adapter: [pool: :media, timeout: 120_000, recv_timeout: 120_000]
|
||||||
|
) do
|
||||||
unzip(zip_body, dest)
|
unzip(zip_body, dest)
|
||||||
else
|
else
|
||||||
e -> {:error, e}
|
e -> {:error, e}
|
||||||
|
@ -133,6 +135,7 @@ defmodule Mix.Tasks.Pleroma.Frontend do
|
||||||
|
|
||||||
defp install_frontend(frontend_info, source, dest) do
|
defp install_frontend(frontend_info, source, dest) do
|
||||||
from = frontend_info["build_dir"] || "dist"
|
from = frontend_info["build_dir"] || "dist"
|
||||||
|
File.rm_rf!(dest)
|
||||||
File.mkdir_p!(dest)
|
File.mkdir_p!(dest)
|
||||||
File.cp_r!(Path.join([source, from]), dest)
|
File.cp_r!(Path.join([source, from]), dest)
|
||||||
:ok
|
:ok
|
||||||
|
|
|
@ -22,13 +22,18 @@ defmodule Pleroma.Application do
|
||||||
def repository, do: @repository
|
def repository, do: @repository
|
||||||
|
|
||||||
def user_agent do
|
def user_agent do
|
||||||
case Config.get([:http, :user_agent], :default) do
|
if Process.whereis(Pleroma.Web.Endpoint) do
|
||||||
:default ->
|
case Config.get([:http, :user_agent], :default) do
|
||||||
info = "#{Pleroma.Web.base_url()} <#{Config.get([:instance, :email], "")}>"
|
:default ->
|
||||||
named_version() <> "; " <> info
|
info = "#{Pleroma.Web.base_url()} <#{Config.get([:instance, :email], "")}>"
|
||||||
|
named_version() <> "; " <> info
|
||||||
|
|
||||||
custom ->
|
custom ->
|
||||||
custom
|
custom
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# fallback, if endpoint is not started yet
|
||||||
|
"Pleroma Data Loader"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,6 +44,9 @@ defmodule Pleroma.Application do
|
||||||
# every time the application is restarted, so we disable module
|
# every time the application is restarted, so we disable module
|
||||||
# conflicts at runtime
|
# conflicts at runtime
|
||||||
Code.compiler_options(ignore_module_conflict: true)
|
Code.compiler_options(ignore_module_conflict: true)
|
||||||
|
# Disable warnings_as_errors at runtime, it breaks Phoenix live reload
|
||||||
|
# due to protocol consolidation warnings
|
||||||
|
Code.compiler_options(warnings_as_errors: false)
|
||||||
Pleroma.Telemetry.Logger.attach()
|
Pleroma.Telemetry.Logger.attach()
|
||||||
Config.Holder.save_default()
|
Config.Holder.save_default()
|
||||||
Pleroma.HTML.compile_scrubbers()
|
Pleroma.HTML.compile_scrubbers()
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Emoji do
|
||||||
|
use Ecto.Type
|
||||||
|
|
||||||
|
def type, do: :map
|
||||||
|
|
||||||
|
def cast(data) when is_map(data) do
|
||||||
|
has_invalid_emoji? =
|
||||||
|
Enum.find(data, fn
|
||||||
|
{name, uri} when is_binary(name) and is_binary(uri) ->
|
||||||
|
# based on ObjectValidators.Uri.cast()
|
||||||
|
case URI.parse(uri) do
|
||||||
|
%URI{host: nil} -> true
|
||||||
|
%URI{host: ""} -> true
|
||||||
|
%URI{scheme: scheme} when scheme in ["https", "http"] -> false
|
||||||
|
_ -> true
|
||||||
|
end
|
||||||
|
|
||||||
|
{_name, _uri} ->
|
||||||
|
true
|
||||||
|
end)
|
||||||
|
|
||||||
|
if has_invalid_emoji?, do: :error, else: {:ok, data}
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast(_data), do: :error
|
||||||
|
|
||||||
|
def dump(data), do: {:ok, data}
|
||||||
|
|
||||||
|
def load(data), do: {:ok, data}
|
||||||
|
end
|
|
@ -83,17 +83,25 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{ref, state} = pop_in(state.client_monitors[client_pid])
|
{ref, state} = pop_in(state.client_monitors[client_pid])
|
||||||
Process.demonitor(ref)
|
# DOWN message can receive right after `remove_client` call and cause worker to terminate
|
||||||
|
state =
|
||||||
timer =
|
if is_nil(ref) do
|
||||||
if used_by == [] do
|
state
|
||||||
max_idle = Pleroma.Config.get([:connections_pool, :max_idle_time], 30_000)
|
|
||||||
Process.send_after(self(), :idle_close, max_idle)
|
|
||||||
else
|
else
|
||||||
nil
|
Process.demonitor(ref)
|
||||||
|
|
||||||
|
timer =
|
||||||
|
if used_by == [] do
|
||||||
|
max_idle = Pleroma.Config.get([:connections_pool, :max_idle_time], 30_000)
|
||||||
|
Process.send_after(self(), :idle_close, max_idle)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
%{state | timer: timer}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:reply, :ok, %{state | timer: timer}, :hibernate}
|
{:reply, :ok, state, :hibernate}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -103,16 +111,21 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do
|
||||||
{:stop, :normal, state}
|
{:stop, :normal, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_info({:gun_up, _pid, _protocol}, state) do
|
||||||
|
{:noreply, state, :hibernate}
|
||||||
|
end
|
||||||
|
|
||||||
# Gracefully shutdown if the connection got closed without any streams left
|
# Gracefully shutdown if the connection got closed without any streams left
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:gun_down, _pid, _protocol, _reason, []}, state) do
|
def handle_info({:gun_down, _pid, _protocol, _reason, []}, state) do
|
||||||
{:stop, :normal, state}
|
{:stop, :normal, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Otherwise, shutdown with an error
|
# Otherwise, wait for retry
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:gun_down, _pid, _protocol, _reason, _killed_streams} = down_message, state) do
|
def handle_info({:gun_down, _pid, _protocol, _reason, _killed_streams}, state) do
|
||||||
{:stop, {:error, down_message}, state}
|
{:noreply, state, :hibernate}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
|
@ -109,8 +109,9 @@ defmodule Pleroma.HTML do
|
||||||
result =
|
result =
|
||||||
content
|
content
|
||||||
|> Floki.parse_fragment!()
|
|> Floki.parse_fragment!()
|
||||||
|> Floki.filter_out("a.mention,a.hashtag,a.attachment,a[rel~=\"tag\"]")
|
|> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
|
||||||
|> Floki.attribute("a", "href")
|
|> Enum.take(1)
|
||||||
|
|> Floki.attribute("href")
|
||||||
|> Enum.at(0)
|
|> Enum.at(0)
|
||||||
|
|
||||||
{:commit, {:ok, result}}
|
{:commit, {:ok, result}}
|
||||||
|
|
|
@ -11,7 +11,6 @@ defmodule Pleroma.HTTP.AdapterHelper do
|
||||||
@type proxy_type() :: :socks4 | :socks5
|
@type proxy_type() :: :socks4 | :socks5
|
||||||
@type host() :: charlist() | :inet.ip_address()
|
@type host() :: charlist() | :inet.ip_address()
|
||||||
|
|
||||||
alias Pleroma.Config
|
|
||||||
alias Pleroma.HTTP.AdapterHelper
|
alias Pleroma.HTTP.AdapterHelper
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@ -44,27 +43,13 @@ defmodule Pleroma.HTTP.AdapterHelper do
|
||||||
@spec options(URI.t(), keyword()) :: keyword()
|
@spec options(URI.t(), keyword()) :: keyword()
|
||||||
def options(%URI{} = uri, opts \\ []) do
|
def options(%URI{} = uri, opts \\ []) do
|
||||||
@defaults
|
@defaults
|
||||||
|> put_timeout()
|
|
||||||
|> Keyword.merge(opts)
|
|> Keyword.merge(opts)
|
||||||
|> adapter_helper().options(uri)
|
|> adapter_helper().options(uri)
|
||||||
end
|
end
|
||||||
|
|
||||||
# For Hackney, this is the time a connection can stay idle in the pool.
|
@spec get_conn(URI.t(), keyword()) :: {:ok, keyword()} | {:error, atom()}
|
||||||
# For Gun, this is the timeout to receive a message from Gun.
|
|
||||||
defp put_timeout(opts) do
|
|
||||||
{config_key, default} =
|
|
||||||
if adapter() == Tesla.Adapter.Gun do
|
|
||||||
{:pools, Config.get([:pools, :default, :timeout], 5_000)}
|
|
||||||
else
|
|
||||||
{:hackney_pools, 10_000}
|
|
||||||
end
|
|
||||||
|
|
||||||
timeout = Config.get([config_key, opts[:pool], :timeout], default)
|
|
||||||
|
|
||||||
Keyword.merge(opts, timeout: timeout)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_conn(uri, opts), do: adapter_helper().get_conn(uri, opts)
|
def get_conn(uri, opts), do: adapter_helper().get_conn(uri, opts)
|
||||||
|
|
||||||
defp adapter, do: Application.get_env(:tesla, :adapter)
|
defp adapter, do: Application.get_env(:tesla, :adapter)
|
||||||
|
|
||||||
defp adapter_helper do
|
defp adapter_helper do
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
||||||
@behaviour Pleroma.HTTP.AdapterHelper
|
@behaviour Pleroma.HTTP.AdapterHelper
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
alias Pleroma.Gun.ConnectionPool
|
alias Pleroma.Gun.ConnectionPool
|
||||||
alias Pleroma.HTTP.AdapterHelper
|
alias Pleroma.HTTP.AdapterHelper
|
||||||
|
|
||||||
|
@ -14,31 +15,46 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
||||||
connect_timeout: 5_000,
|
connect_timeout: 5_000,
|
||||||
domain_lookup_timeout: 5_000,
|
domain_lookup_timeout: 5_000,
|
||||||
tls_handshake_timeout: 5_000,
|
tls_handshake_timeout: 5_000,
|
||||||
retry: 0,
|
retry: 1,
|
||||||
retry_timeout: 1000,
|
retry_timeout: 1000,
|
||||||
await_up_timeout: 5_000
|
await_up_timeout: 5_000
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@type pool() :: :federation | :upload | :media | :default
|
||||||
|
|
||||||
@spec options(keyword(), URI.t()) :: keyword()
|
@spec options(keyword(), URI.t()) :: keyword()
|
||||||
def options(incoming_opts \\ [], %URI{} = uri) do
|
def options(incoming_opts \\ [], %URI{} = uri) do
|
||||||
proxy =
|
proxy =
|
||||||
Pleroma.Config.get([:http, :proxy_url])
|
[:http, :proxy_url]
|
||||||
|
|> Config.get()
|
||||||
|> AdapterHelper.format_proxy()
|
|> AdapterHelper.format_proxy()
|
||||||
|
|
||||||
config_opts = Pleroma.Config.get([:http, :adapter], [])
|
config_opts = Config.get([:http, :adapter], [])
|
||||||
|
|
||||||
@defaults
|
@defaults
|
||||||
|> Keyword.merge(config_opts)
|
|> Keyword.merge(config_opts)
|
||||||
|> add_scheme_opts(uri)
|
|> add_scheme_opts(uri)
|
||||||
|> AdapterHelper.maybe_add_proxy(proxy)
|
|> AdapterHelper.maybe_add_proxy(proxy)
|
||||||
|> Keyword.merge(incoming_opts)
|
|> Keyword.merge(incoming_opts)
|
||||||
|
|> put_timeout()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_scheme_opts(opts, %{scheme: "http"}), do: opts
|
defp add_scheme_opts(opts, %{scheme: "http"}), do: opts
|
||||||
|
|
||||||
defp add_scheme_opts(opts, %{scheme: "https"}) do
|
defp add_scheme_opts(opts, %{scheme: "https"}) do
|
||||||
opts
|
Keyword.put(opts, :certificates_verification, true)
|
||||||
|> Keyword.put(:certificates_verification, true)
|
end
|
||||||
|
|
||||||
|
defp put_timeout(opts) do
|
||||||
|
# this is the timeout to receive a message from Gun
|
||||||
|
Keyword.put_new(opts, :timeout, pool_timeout(opts[:pool]))
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec pool_timeout(pool()) :: non_neg_integer()
|
||||||
|
def pool_timeout(pool) do
|
||||||
|
default = Config.get([:pools, :default, :timeout], 5_000)
|
||||||
|
|
||||||
|
Config.get([:pools, pool, :timeout], default)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_conn(URI.t(), keyword()) :: {:ok, keyword()} | {:error, atom()}
|
@spec get_conn(URI.t(), keyword()) :: {:ok, keyword()} | {:error, atom()}
|
||||||
|
@ -51,11 +67,11 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
||||||
|
|
||||||
@prefix Pleroma.Gun.ConnectionPool
|
@prefix Pleroma.Gun.ConnectionPool
|
||||||
def limiter_setup do
|
def limiter_setup do
|
||||||
wait = Pleroma.Config.get([:connections_pool, :connection_acquisition_wait])
|
wait = Config.get([:connections_pool, :connection_acquisition_wait])
|
||||||
retries = Pleroma.Config.get([:connections_pool, :connection_acquisition_retries])
|
retries = Config.get([:connections_pool, :connection_acquisition_retries])
|
||||||
|
|
||||||
:pools
|
:pools
|
||||||
|> Pleroma.Config.get([])
|
|> Config.get([])
|
||||||
|> Enum.each(fn {name, opts} ->
|
|> Enum.each(fn {name, opts} ->
|
||||||
max_running = Keyword.get(opts, :size, 50)
|
max_running = Keyword.get(opts, :size, 50)
|
||||||
max_waiting = Keyword.get(opts, :max_waiting, 10)
|
max_waiting = Keyword.get(opts, :max_waiting, 10)
|
||||||
|
@ -69,7 +85,6 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
||||||
case result do
|
case result do
|
||||||
:ok -> :ok
|
:ok -> :ok
|
||||||
{:error, :existing} -> :ok
|
{:error, :existing} -> :ok
|
||||||
e -> raise e
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ defmodule Pleroma.HTTP.ExAws do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def request(method, url, body \\ "", headers \\ [], http_opts \\ []) do
|
def request(method, url, body \\ "", headers \\ [], http_opts \\ []) do
|
||||||
|
http_opts = Keyword.put_new(http_opts, :adapter, pool: :upload)
|
||||||
|
|
||||||
case HTTP.request(method, url, body, headers, http_opts) do
|
case HTTP.request(method, url, body, headers, http_opts) do
|
||||||
{:ok, env} ->
|
{:ok, env} ->
|
||||||
{:ok, %{status_code: env.status, headers: env.headers, body: env.body}}
|
{:ok, %{status_code: env.status, headers: env.headers, body: env.body}}
|
||||||
|
|
|
@ -11,6 +11,8 @@ defmodule Pleroma.HTTP.Tzdata do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def get(url, headers, options) do
|
def get(url, headers, options) do
|
||||||
|
options = Keyword.put_new(options, :adapter, pool: :default)
|
||||||
|
|
||||||
with {:ok, %Tesla.Env{} = env} <- HTTP.get(url, headers, options) do
|
with {:ok, %Tesla.Env{} = env} <- HTTP.get(url, headers, options) do
|
||||||
{:ok, {env.status, env.headers, env.body}}
|
{:ok, {env.status, env.headers, env.body}}
|
||||||
end
|
end
|
||||||
|
@ -18,6 +20,8 @@ defmodule Pleroma.HTTP.Tzdata do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def head(url, headers, options) do
|
def head(url, headers, options) do
|
||||||
|
options = Keyword.put_new(options, :adapter, pool: :default)
|
||||||
|
|
||||||
with {:ok, %Tesla.Env{} = env} <- HTTP.head(url, headers, options) do
|
with {:ok, %Tesla.Env{} = env} <- HTTP.head(url, headers, options) do
|
||||||
{:ok, {env.status, env.headers}}
|
{:ok, {env.status, env.headers}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -150,7 +150,9 @@ defmodule Pleroma.Instances.Instance do
|
||||||
defp scrape_favicon(%URI{} = instance_uri) do
|
defp scrape_favicon(%URI{} = instance_uri) do
|
||||||
try do
|
try do
|
||||||
with {:ok, %Tesla.Env{body: html}} <-
|
with {:ok, %Tesla.Env{body: html}} <-
|
||||||
Pleroma.HTTP.get(to_string(instance_uri), [{:Accept, "text/html"}]),
|
Pleroma.HTTP.get(to_string(instance_uri), [{"accept", "text/html"}],
|
||||||
|
adapter: [pool: :media]
|
||||||
|
),
|
||||||
favicon_rel <-
|
favicon_rel <-
|
||||||
html
|
html
|
||||||
|> Floki.parse_document!()
|
|> Floki.parse_document!()
|
||||||
|
|
|
@ -648,4 +648,16 @@ defmodule Pleroma.Notification do
|
||||||
)
|
)
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec mark_context_as_read(User.t(), String.t()) :: {integer(), nil | [term()]}
|
||||||
|
def mark_context_as_read(%User{id: id}, context) do
|
||||||
|
from(
|
||||||
|
n in Notification,
|
||||||
|
join: a in assoc(n, :activity),
|
||||||
|
where: n.user_id == ^id,
|
||||||
|
where: n.seen == false,
|
||||||
|
where: fragment("?->>'context'", a.data) == ^context
|
||||||
|
)
|
||||||
|
|> Repo.update_all(set: [seen: true])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,8 +36,7 @@ defmodule Pleroma.Object.Fetcher do
|
||||||
defp reinject_object(%Object{data: %{"type" => "Question"}} = object, new_data) do
|
defp reinject_object(%Object{data: %{"type" => "Question"}} = object, new_data) do
|
||||||
Logger.debug("Reinjecting object #{new_data["id"]}")
|
Logger.debug("Reinjecting object #{new_data["id"]}")
|
||||||
|
|
||||||
with new_data <- Transmogrifier.fix_object(new_data),
|
with data <- maybe_reinject_internal_fields(object, new_data),
|
||||||
data <- maybe_reinject_internal_fields(object, new_data),
|
|
||||||
{:ok, data, _} <- ObjectValidator.validate(data, %{}),
|
{:ok, data, _} <- ObjectValidator.validate(data, %{}),
|
||||||
changeset <- Object.change(object, %{data: data}),
|
changeset <- Object.change(object, %{data: data}),
|
||||||
changeset <- touch_changeset(changeset),
|
changeset <- touch_changeset(changeset),
|
||||||
|
@ -164,12 +163,12 @@ defmodule Pleroma.Object.Fetcher do
|
||||||
date: date
|
date: date
|
||||||
})
|
})
|
||||||
|
|
||||||
[{"signature", signature}]
|
{"signature", signature}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp sign_fetch(headers, id, date) do
|
defp sign_fetch(headers, id, date) do
|
||||||
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
||||||
headers ++ make_signature(id, date)
|
[make_signature(id, date) | headers]
|
||||||
else
|
else
|
||||||
headers
|
headers
|
||||||
end
|
end
|
||||||
|
@ -177,7 +176,7 @@ defmodule Pleroma.Object.Fetcher do
|
||||||
|
|
||||||
defp maybe_date_fetch(headers, date) do
|
defp maybe_date_fetch(headers, date) do
|
||||||
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
||||||
headers ++ [{"date", date}]
|
[{"date", date} | headers]
|
||||||
else
|
else
|
||||||
headers
|
headers
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,12 +46,23 @@ defmodule Pleroma.Uploaders.S3 do
|
||||||
|
|
||||||
op =
|
op =
|
||||||
if streaming do
|
if streaming do
|
||||||
upload.tempfile
|
op =
|
||||||
|> ExAws.S3.Upload.stream_file()
|
upload.tempfile
|
||||||
|> ExAws.S3.upload(bucket, s3_name, [
|
|> ExAws.S3.Upload.stream_file()
|
||||||
{:acl, :public_read},
|
|> ExAws.S3.upload(bucket, s3_name, [
|
||||||
{:content_type, upload.content_type}
|
{:acl, :public_read},
|
||||||
])
|
{:content_type, upload.content_type}
|
||||||
|
])
|
||||||
|
|
||||||
|
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun do
|
||||||
|
# set s3 upload timeout to respect :upload pool timeout
|
||||||
|
# timeout should be slightly larger, so s3 can retry upload on fail
|
||||||
|
timeout = Pleroma.HTTP.AdapterHelper.Gun.pool_timeout(:upload) + 1_000
|
||||||
|
opts = Keyword.put(op.opts, :timeout, timeout)
|
||||||
|
Map.put(op, :opts, opts)
|
||||||
|
else
|
||||||
|
op
|
||||||
|
end
|
||||||
else
|
else
|
||||||
{:ok, file_data} = File.read(upload.tempfile)
|
{:ok, file_data} = File.read(upload.tempfile)
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ defmodule Pleroma.User do
|
||||||
]
|
]
|
||||||
|
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field(:bio, :string)
|
field(:bio, :string, default: "")
|
||||||
field(:raw_bio, :string)
|
field(:raw_bio, :string)
|
||||||
field(:email, :string)
|
field(:email, :string)
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
|
@ -1587,7 +1587,7 @@ defmodule Pleroma.User do
|
||||||
# "Right to be forgotten"
|
# "Right to be forgotten"
|
||||||
# https://gdpr.eu/right-to-be-forgotten/
|
# https://gdpr.eu/right-to-be-forgotten/
|
||||||
change(user, %{
|
change(user, %{
|
||||||
bio: nil,
|
bio: "",
|
||||||
raw_bio: nil,
|
raw_bio: nil,
|
||||||
email: nil,
|
email: nil,
|
||||||
name: nil,
|
name: nil,
|
||||||
|
|
|
@ -116,7 +116,7 @@ defmodule Pleroma.User.Search do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp base_query(_user, false), do: User
|
defp base_query(_user, false), do: User
|
||||||
defp base_query(user, true), do: User.get_followers_query(user)
|
defp base_query(user, true), do: User.get_friends_query(user)
|
||||||
|
|
||||||
defp filter_invisible_users(query) do
|
defp filter_invisible_users(query) do
|
||||||
from(q in query, where: q.invisible == false)
|
from(q in query, where: q.invisible == false)
|
||||||
|
|
|
@ -1224,7 +1224,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
name: data["name"],
|
name: data["name"],
|
||||||
follower_address: data["followers"],
|
follower_address: data["followers"],
|
||||||
following_address: data["following"],
|
following_address: data["following"],
|
||||||
bio: data["summary"],
|
bio: data["summary"] || "",
|
||||||
actor_type: actor_type,
|
actor_type: actor_type,
|
||||||
also_known_as: Map.get(data, "alsoKnownAs", []),
|
also_known_as: Map.get(data, "alsoKnownAs", []),
|
||||||
public_key: public_key,
|
public_key: public_key,
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@ -33,8 +34,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
field(:summary, :string)
|
field(:summary, :string)
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
# TODO: Write type
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
field(:emoji, :map, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
field(:sensitive, :boolean, default: false)
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
embeds_many(:attachment, AttachmentValidator)
|
||||||
field(:replies_count, :integer, default: 0)
|
field(:replies_count, :integer, default: 0)
|
||||||
|
@ -83,6 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
data
|
data
|
||||||
|> CommonFixes.fix_defaults()
|
|> CommonFixes.fix_defaults()
|
||||||
|> CommonFixes.fix_attribution()
|
|> CommonFixes.fix_attribution()
|
||||||
|
|> Transmogrifier.fix_emoji()
|
||||||
|> fix_url()
|
|> fix_url()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
|
||||||
field(:content, ObjectValidators.SafeText)
|
field(:content, ObjectValidators.SafeText)
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
field(:emoji, :map, default: %{})
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
|
|
||||||
embeds_one(:attachment, AttachmentValidator)
|
embeds_one(:attachment, AttachmentValidator)
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,8 +11,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
||||||
Utils.create_context(data["context"] || data["conversation"])
|
Utils.create_context(data["context"] || data["conversation"])
|
||||||
|
|
||||||
data
|
data
|
||||||
|> Map.put_new("context", context)
|
|> Map.put("context", context)
|
||||||
|> Map.put_new("context_id", context_id)
|
|> Map.put("context_id", context_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_attribution(data) do
|
def fix_attribution(data) do
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@ -39,8 +40,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
|
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
# TODO: Write type
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
field(:emoji, :map, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
field(:sensitive, :boolean, default: false)
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
embeds_many(:attachment, AttachmentValidator)
|
||||||
field(:replies_count, :integer, default: 0)
|
field(:replies_count, :integer, default: 0)
|
||||||
|
@ -74,6 +74,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
data
|
data
|
||||||
|> CommonFixes.fix_defaults()
|
|> CommonFixes.fix_defaults()
|
||||||
|> CommonFixes.fix_attribution()
|
|> CommonFixes.fix_attribution()
|
||||||
|
|> Transmogrifier.fix_emoji()
|
||||||
end
|
end
|
||||||
|
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@ -32,8 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
# TODO: Write type
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
field(:emoji, :map, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
field(:sensitive, :boolean, default: false)
|
||||||
# TODO: Write type
|
# TODO: Write type
|
||||||
field(:attachment, {:array, :map}, default: [])
|
field(:attachment, {:array, :map}, default: [])
|
||||||
|
@ -53,7 +53,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
|
||||||
|> validate_data()
|
|> validate_data()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp fix(data) do
|
||||||
|
data
|
||||||
|
|> Transmogrifier.fix_emoji()
|
||||||
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
data = fix(data)
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> cast(data, __schema__(:fields))
|
|> cast(data, __schema__(:fields))
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@ -35,8 +36,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
field(:summary, :string)
|
field(:summary, :string)
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
# TODO: Write type
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
field(:emoji, :map, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
field(:sensitive, :boolean, default: false)
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
embeds_many(:attachment, AttachmentValidator)
|
||||||
field(:replies_count, :integer, default: 0)
|
field(:replies_count, :integer, default: 0)
|
||||||
|
@ -85,6 +85,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
data
|
data
|
||||||
|> CommonFixes.fix_defaults()
|
|> CommonFixes.fix_defaults()
|
||||||
|> CommonFixes.fix_attribution()
|
|> CommonFixes.fix_attribution()
|
||||||
|
|> Transmogrifier.fix_emoji()
|
||||||
|> fix_closed()
|
|> fix_closed()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -318,9 +318,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
Map.put(mapping, name, data["icon"]["url"])
|
Map.put(mapping, name, data["icon"]["url"])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
# we merge mastodon and pleroma emoji into a single mapping, to allow for both wire formats
|
|
||||||
emoji = Map.merge(object["emoji"] || %{}, emoji)
|
|
||||||
|
|
||||||
Map.put(object, "emoji", emoji)
|
Map.put(object, "emoji", emoji)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
|
||||||
description: "Add accounts to the given list.",
|
description: "Add accounts to the given list.",
|
||||||
operationId: "ListController.add_to_list",
|
operationId: "ListController.add_to_list",
|
||||||
parameters: [id_param()],
|
parameters: [id_param()],
|
||||||
requestBody: add_remove_accounts_request(),
|
requestBody: add_remove_accounts_request(true),
|
||||||
security: [%{"oAuth" => ["write:lists"]}],
|
security: [%{"oAuth" => ["write:lists"]}],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
|
@ -127,8 +127,16 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
|
||||||
tags: ["Lists"],
|
tags: ["Lists"],
|
||||||
summary: "Remove accounts from list",
|
summary: "Remove accounts from list",
|
||||||
operationId: "ListController.remove_from_list",
|
operationId: "ListController.remove_from_list",
|
||||||
parameters: [id_param()],
|
parameters: [
|
||||||
requestBody: add_remove_accounts_request(),
|
id_param(),
|
||||||
|
Operation.parameter(
|
||||||
|
:account_ids,
|
||||||
|
:query,
|
||||||
|
%Schema{type: :array, items: %Schema{type: :string}},
|
||||||
|
"Array of account IDs"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
requestBody: add_remove_accounts_request(false),
|
||||||
security: [%{"oAuth" => ["write:lists"]}],
|
security: [%{"oAuth" => ["write:lists"]}],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
|
@ -171,7 +179,7 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_remove_accounts_request do
|
defp add_remove_accounts_request(required) when is_boolean(required) do
|
||||||
request_body(
|
request_body(
|
||||||
"Parameters",
|
"Parameters",
|
||||||
%Schema{
|
%Schema{
|
||||||
|
@ -180,9 +188,9 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
|
||||||
properties: %{
|
properties: %{
|
||||||
account_ids: %Schema{type: :array, description: "Array of account IDs", items: FlakeID}
|
account_ids: %Schema{type: :array, description: "Array of account IDs", items: FlakeID}
|
||||||
},
|
},
|
||||||
required: [:account_ids]
|
required: required && [:account_ids]
|
||||||
},
|
},
|
||||||
required: true
|
required: required
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,7 +68,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
||||||
nickname = value([registration_attrs["nickname"], Registration.nickname(registration)])
|
nickname = value([registration_attrs["nickname"], Registration.nickname(registration)])
|
||||||
email = value([registration_attrs["email"], Registration.email(registration)])
|
email = value([registration_attrs["email"], Registration.email(registration)])
|
||||||
name = value([registration_attrs["name"], Registration.name(registration)]) || nickname
|
name = value([registration_attrs["name"], Registration.name(registration)]) || nickname
|
||||||
bio = value([registration_attrs["bio"], Registration.description(registration)])
|
bio = value([registration_attrs["bio"], Registration.description(registration)]) || ""
|
||||||
|
|
||||||
random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
|
random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
|
||||||
|
|
||||||
|
|
|
@ -452,7 +452,8 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_mute(user, activity) do
|
def add_mute(user, activity) do
|
||||||
with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]) do
|
with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]),
|
||||||
|
_ <- Pleroma.Notification.mark_context_as_read(user, activity.data["context"]) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
{:error, _} -> {:error, dgettext("errors", "conversation is already muted")}
|
{:error, _} -> {:error, dgettext("errors", "conversation is already muted")}
|
||||||
|
|
|
@ -59,17 +59,11 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
|
||||||
def password_reset(conn, params) do
|
def password_reset(conn, params) do
|
||||||
nickname_or_email = params["email"] || params["nickname"]
|
nickname_or_email = params["email"] || params["nickname"]
|
||||||
|
|
||||||
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
TwitterAPI.password_reset(nickname_or_email)
|
||||||
conn
|
|
||||||
|> put_status(:no_content)
|
|
||||||
|> json("")
|
|
||||||
else
|
|
||||||
{:error, "unknown user"} ->
|
|
||||||
send_resp(conn, :not_found, "")
|
|
||||||
|
|
||||||
{:error, _} ->
|
conn
|
||||||
send_resp(conn, :bad_request, "")
|
|> put_status(:no_content)
|
||||||
end
|
|> json("")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp local_mastodon_root_path(conn) do
|
defp local_mastodon_root_path(conn) do
|
||||||
|
|
|
@ -74,7 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
|
||||||
|
|
||||||
# DELETE /api/v1/lists/:id/accounts
|
# DELETE /api/v1/lists/:id/accounts
|
||||||
def remove_from_list(
|
def remove_from_list(
|
||||||
%{assigns: %{list: list}, body_params: %{account_ids: account_ids}} = conn,
|
%{assigns: %{list: list}, params: %{account_ids: account_ids}} = conn,
|
||||||
_
|
_
|
||||||
) do
|
) do
|
||||||
Enum.each(account_ids, fn account_id ->
|
Enum.each(account_ids, fn account_id ->
|
||||||
|
@ -86,6 +86,10 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
|
||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_from_list(%{body_params: params} = conn, _) do
|
||||||
|
remove_from_list(%{conn | params: params}, %{})
|
||||||
|
end
|
||||||
|
|
||||||
defp list_by_id_and_user(%{assigns: %{user: user}, params: %{id: id}} = conn, _) do
|
defp list_by_id_and_user(%{assigns: %{user: user}, params: %{id: id}} = conn, _) do
|
||||||
case Pleroma.List.get(id, user) do
|
case Pleroma.List.get(id, user) do
|
||||||
%Pleroma.List{} = list -> assign(conn, :list, list)
|
%Pleroma.List{} = list -> assign(conn, :list, list)
|
||||||
|
|
|
@ -245,7 +245,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
||||||
followers_count: followers_count,
|
followers_count: followers_count,
|
||||||
following_count: following_count,
|
following_count: following_count,
|
||||||
statuses_count: user.note_count,
|
statuses_count: user.note_count,
|
||||||
note: user.bio || "",
|
note: user.bio,
|
||||||
url: user.uri || user.ap_id,
|
url: user.uri || user.ap_id,
|
||||||
avatar: image,
|
avatar: image,
|
||||||
avatar_static: image,
|
avatar_static: image,
|
||||||
|
|
|
@ -23,6 +23,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
|
|
||||||
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
||||||
|
|
||||||
|
# This is a naive way to do this, just spawning a process per activity
|
||||||
|
# to fetch the preview. However it should be fine considering
|
||||||
|
# pagination is restricted to 40 activities at a time
|
||||||
|
defp fetch_rich_media_for_activities(activities) do
|
||||||
|
Enum.each(activities, fn activity ->
|
||||||
|
spawn(fn ->
|
||||||
|
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: Add cached version.
|
# TODO: Add cached version.
|
||||||
defp get_replied_to_activities([]), do: %{}
|
defp get_replied_to_activities([]), do: %{}
|
||||||
|
|
||||||
|
@ -80,6 +91,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
|
|
||||||
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
||||||
activities = Enum.filter(opts.activities, & &1)
|
activities = Enum.filter(opts.activities, & &1)
|
||||||
|
|
||||||
|
# Start fetching rich media before doing anything else, so that later calls to get the cards
|
||||||
|
# only block for timeout in the worst case, as opposed to
|
||||||
|
# length(activities_with_links) * timeout
|
||||||
|
fetch_rich_media_for_activities(activities)
|
||||||
replied_to_activities = get_replied_to_activities(activities)
|
replied_to_activities = get_replied_to_activities(activities)
|
||||||
|
|
||||||
parent_activities =
|
parent_activities =
|
||||||
|
|
|
@ -61,7 +61,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
|
||||||
|
|
||||||
@impl Provider
|
@impl Provider
|
||||||
def build_tags(%{user: user}) do
|
def build_tags(%{user: user}) do
|
||||||
with truncated_bio = Utils.scrub_html_and_truncate(user.bio || "") do
|
with truncated_bio = Utils.scrub_html_and_truncate(user.bio) do
|
||||||
[
|
[
|
||||||
{:meta,
|
{:meta,
|
||||||
[
|
[
|
||||||
|
|
|
@ -40,7 +40,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
||||||
|
|
||||||
@impl Provider
|
@impl Provider
|
||||||
def build_tags(%{user: user}) do
|
def build_tags(%{user: user}) do
|
||||||
with truncated_bio = Utils.scrub_html_and_truncate(user.bio || "") do
|
with truncated_bio = Utils.scrub_html_and_truncate(user.bio) do
|
||||||
[
|
[
|
||||||
title_tag(user),
|
title_tag(user),
|
||||||
{:meta, [property: "twitter:description", content: truncated_bio], []},
|
{:meta, [property: "twitter:description", content: truncated_bio], []},
|
||||||
|
|
|
@ -149,9 +149,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
|
||||||
from(c in Chat,
|
from(c in Chat,
|
||||||
where: c.user_id == ^user_id,
|
where: c.user_id == ^user_id,
|
||||||
where: c.recipient not in ^blocked_ap_ids,
|
where: c.recipient not in ^blocked_ap_ids,
|
||||||
order_by: [desc: c.updated_at],
|
order_by: [desc: c.updated_at]
|
||||||
inner_join: u in User,
|
|
||||||
on: u.ap_id == c.recipient
|
|
||||||
)
|
)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do
|
||||||
@rich_media_options
|
@rich_media_options
|
||||||
end
|
end
|
||||||
|
|
||||||
Pleroma.HTTP.get(url, headers, options)
|
Pleroma.HTTP.get(url, headers, adapter: options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.RichMedia.Parser do
|
defmodule Pleroma.Web.RichMedia.Parser do
|
||||||
|
require Logger
|
||||||
|
|
||||||
defp parsers do
|
defp parsers do
|
||||||
Pleroma.Config.get([:rich_media, :parsers])
|
Pleroma.Config.get([:rich_media, :parsers])
|
||||||
end
|
end
|
||||||
|
@ -10,17 +12,29 @@ defmodule Pleroma.Web.RichMedia.Parser do
|
||||||
def parse(nil), do: {:error, "No URL provided"}
|
def parse(nil), do: {:error, "No URL provided"}
|
||||||
|
|
||||||
if Pleroma.Config.get(:env) == :test do
|
if Pleroma.Config.get(:env) == :test do
|
||||||
|
@spec parse(String.t()) :: {:ok, map()} | {:error, any()}
|
||||||
def parse(url), do: parse_url(url)
|
def parse(url), do: parse_url(url)
|
||||||
else
|
else
|
||||||
|
@spec parse(String.t()) :: {:ok, map()} | {:error, any()}
|
||||||
def parse(url) do
|
def parse(url) do
|
||||||
try do
|
with {:ok, data} <- get_cached_or_parse(url),
|
||||||
Cachex.fetch!(:rich_media_cache, url, fn _ ->
|
{:ok, _} <- set_ttl_based_on_image(data, url) do
|
||||||
{:commit, parse_url(url)}
|
{:ok, data}
|
||||||
end)
|
else
|
||||||
|> set_ttl_based_on_image(url)
|
error ->
|
||||||
rescue
|
Logger.error(fn -> "Rich media error: #{inspect(error)}" end)
|
||||||
e ->
|
end
|
||||||
{:error, "Cachex error: #{inspect(e)}"}
|
end
|
||||||
|
|
||||||
|
defp get_cached_or_parse(url) do
|
||||||
|
case Cachex.fetch!(:rich_media_cache, url, fn _ -> {:commit, parse_url(url)} end) do
|
||||||
|
{:ok, _data} = res ->
|
||||||
|
res
|
||||||
|
|
||||||
|
{:error, _} = e ->
|
||||||
|
ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
|
||||||
|
Cachex.expire(:rich_media_cache, url, ttl)
|
||||||
|
e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,19 +61,26 @@ defmodule Pleroma.Web.RichMedia.Parser do
|
||||||
config :pleroma, :rich_media,
|
config :pleroma, :rich_media,
|
||||||
ttl_setters: [MyModule]
|
ttl_setters: [MyModule]
|
||||||
"""
|
"""
|
||||||
def set_ttl_based_on_image({:ok, data}, url) do
|
@spec set_ttl_based_on_image(map(), String.t()) ::
|
||||||
with {:ok, nil} <- Cachex.ttl(:rich_media_cache, url),
|
{:ok, Integer.t() | :noop} | {:error, :no_key}
|
||||||
ttl when is_number(ttl) <- get_ttl_from_image(data, url) do
|
def set_ttl_based_on_image(data, url) do
|
||||||
Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
|
case get_ttl_from_image(data, url) do
|
||||||
{:ok, data}
|
{:ok, ttl} when is_number(ttl) ->
|
||||||
else
|
ttl = ttl * 1000
|
||||||
|
|
||||||
|
case Cachex.expire_at(:rich_media_cache, url, ttl) do
|
||||||
|
{:ok, true} -> {:ok, ttl}
|
||||||
|
{:ok, false} -> {:error, :no_key}
|
||||||
|
end
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{:ok, data}
|
{:ok, :noop}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_ttl_from_image(data, url) do
|
defp get_ttl_from_image(data, url) do
|
||||||
Pleroma.Config.get([:rich_media, :ttl_setters])
|
[:rich_media, :ttl_setters]
|
||||||
|
|> Pleroma.Config.get()
|
||||||
|> Enum.reduce({:ok, nil}, fn
|
|> Enum.reduce({:ok, nil}, fn
|
||||||
module, {:ok, _ttl} ->
|
module, {:ok, _ttl} ->
|
||||||
module.ttl(data, url)
|
module.ttl(data, url)
|
||||||
|
@ -70,23 +91,16 @@ defmodule Pleroma.Web.RichMedia.Parser do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_url(url) do
|
defp parse_url(url) do
|
||||||
try do
|
with {:ok, %Tesla.Env{body: html}} <- Pleroma.Web.RichMedia.Helpers.rich_media_get(url),
|
||||||
{:ok, %Tesla.Env{body: html}} = Pleroma.Web.RichMedia.Helpers.rich_media_get(url)
|
{:ok, html} <- Floki.parse_document(html) do
|
||||||
|
|
||||||
html
|
html
|
||||||
|> parse_html()
|
|
||||||
|> maybe_parse()
|
|> maybe_parse()
|
||||||
|> Map.put("url", url)
|
|> Map.put("url", url)
|
||||||
|> clean_parsed_data()
|
|> clean_parsed_data()
|
||||||
|> check_parsed_data()
|
|> check_parsed_data()
|
||||||
rescue
|
|
||||||
e ->
|
|
||||||
{:error, "Parsing error: #{inspect(e)} #{inspect(__STACKTRACE__)}"}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_html(html), do: Floki.parse_document!(html)
|
|
||||||
|
|
||||||
defp maybe_parse(html) do
|
defp maybe_parse(html) do
|
||||||
Enum.reduce_while(parsers(), %{}, fn parser, acc ->
|
Enum.reduce_while(parsers(), %{}, fn parser, acc ->
|
||||||
case parser.parse(html, acc) do
|
case parser.parse(html, acc) do
|
||||||
|
|
|
@ -10,20 +10,15 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
|
||||||
|> parse_query_params()
|
|> parse_query_params()
|
||||||
|> format_query_params()
|
|> format_query_params()
|
||||||
|> get_expiration_timestamp()
|
|> get_expiration_timestamp()
|
||||||
|
else
|
||||||
|
{:error, "Not aws signed url #{inspect(image)}"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_aws_signed_url(""), do: nil
|
defp is_aws_signed_url(image) when is_binary(image) and image != "" do
|
||||||
defp is_aws_signed_url(nil), do: nil
|
|
||||||
|
|
||||||
defp is_aws_signed_url(image) when is_binary(image) do
|
|
||||||
%URI{host: host, query: query} = URI.parse(image)
|
%URI{host: host, query: query} = URI.parse(image)
|
||||||
|
|
||||||
if String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") do
|
String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires")
|
||||||
image
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_aws_signed_url(_), do: nil
|
defp is_aws_signed_url(_), do: nil
|
||||||
|
@ -46,6 +41,6 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
|
||||||
|> Map.get("X-Amz-Date")
|
|> Map.get("X-Amz-Date")
|
||||||
|> Timex.parse("{ISO:Basic:Z}")
|
|> Timex.parse("{ISO:Basic:Z}")
|
||||||
|
|
||||||
Timex.to_unix(date) + String.to_integer(Map.get(params, "X-Amz-Expires"))
|
{:ok, Timex.to_unix(date) + String.to_integer(Map.get(params, "X-Amz-Expires"))}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,7 +72,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
|
|
||||||
def password_reset(nickname_or_email) do
|
def password_reset(nickname_or_email) do
|
||||||
with true <- is_binary(nickname_or_email),
|
with true <- is_binary(nickname_or_email),
|
||||||
%User{local: true, email: email} = user when is_binary(email) <-
|
%User{local: true, email: email, deactivated: false} = user when is_binary(email) <-
|
||||||
User.get_by_nickname_or_email(nickname_or_email),
|
User.get_by_nickname_or_email(nickname_or_email),
|
||||||
{:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
|
{:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||||
user
|
user
|
||||||
|
@ -81,17 +81,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
||||||
|
|
||||||
{:ok, :enqueued}
|
{:ok, :enqueued}
|
||||||
else
|
else
|
||||||
false ->
|
_ ->
|
||||||
{:error, "bad user identifier"}
|
|
||||||
|
|
||||||
%User{local: true, email: nil} ->
|
|
||||||
{:ok, :noop}
|
{:ok, :noop}
|
||||||
|
|
||||||
%User{local: false} ->
|
|
||||||
{:error, "remote user"}
|
|
||||||
|
|
||||||
nil ->
|
|
||||||
{:error, "unknown user"}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -136,12 +136,12 @@ defmodule Pleroma.Web.WebFinger do
|
||||||
|
|
||||||
def find_lrdd_template(domain) do
|
def find_lrdd_template(domain) do
|
||||||
with {:ok, %{status: status, body: body}} when status in 200..299 <-
|
with {:ok, %{status: status, body: body}} when status in 200..299 <-
|
||||||
HTTP.get("http://#{domain}/.well-known/host-meta", []) do
|
HTTP.get("http://#{domain}/.well-known/host-meta") do
|
||||||
get_template_from_xml(body)
|
get_template_from_xml(body)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
with {:ok, %{body: body, status: status}} when status in 200..299 <-
|
with {:ok, %{body: body, status: status}} when status in 200..299 <-
|
||||||
HTTP.get("https://#{domain}/.well-known/host-meta", []) do
|
HTTP.get("https://#{domain}/.well-known/host-meta") do
|
||||||
get_template_from_xml(body)
|
get_template_from_xml(body)
|
||||||
else
|
else
|
||||||
e -> {:error, "Can't find LRDD template: #{inspect(e)}"}
|
e -> {:error, "Can't find LRDD template: #{inspect(e)}"}
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("2.0.50"),
|
version: version("2.1.50"),
|
||||||
elixir: "~> 1.9",
|
elixir: "~> 1.9",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||||
|
|
4
mix.lock
4
mix.lock
|
@ -42,8 +42,8 @@
|
||||||
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [: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", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
|
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [: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", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
|
||||||
"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"},
|
"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.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
|
"excoveralls": {:hex, :excoveralls, "0.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
|
||||||
"fast_html": {:hex, :fast_html, "2.0.2", "1fabc408b2baa965cf6399a48796326f2721b21b397a3c667bb3bb88fb9559a4", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "f077e2c1597a6e2678e6cacc64f456a6c6024eb4240092c46d4212496dc59aba"},
|
"fast_html": {:hex, :fast_html, "2.0.3", "27289dea6c3a22952191a2d4e07f546c0de8a351484782c2e797dbae06a5dc8a", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "17d41fa8afe4e912ffe74e13b87ddb085382cd2b7393636d338495c9a8a7b518"},
|
||||||
"fast_sanitize": {:hex, :fast_sanitize, "0.2.1", "3302421a988992b6cae08e68f77069e167ff116444183f3302e3c36017a50558", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bcd2c54e328128515edd1a8fb032fdea7e5581672ba161fc5962d21ecee92502"},
|
"fast_sanitize": {:hex, :fast_sanitize, "0.2.2", "3cbbaebaea6043865dfb5b4ecb0f1af066ad410a51470e353714b10c42007b81", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "69f204db9250afa94a0d559d9110139850f57de2b081719fbafa1e9a89e94466"},
|
||||||
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
||||||
"floki": {:hex, :floki, "0.27.0", "6b29a14283f1e2e8fad824bc930eaa9477c462022075df6bea8f0ad811c13599", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "583b8c13697c37179f1f82443bcc7ad2f76fbc0bf4c186606eebd658f7f2631b"},
|
"floki": {:hex, :floki, "0.27.0", "6b29a14283f1e2e8fad824bc930eaa9477c462022075df6bea8f0ad811c13599", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "583b8c13697c37179f1f82443bcc7ad2f76fbc0bf4c186606eebd658f7f2631b"},
|
||||||
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
|
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.ChatConstraints do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
remove_orphans = """
|
||||||
|
delete from chats where not exists(select id from users where ap_id = chats.recipient);
|
||||||
|
"""
|
||||||
|
|
||||||
|
execute(remove_orphans)
|
||||||
|
|
||||||
|
drop(constraint(:chats, "chats_user_id_fkey"))
|
||||||
|
|
||||||
|
alter table(:chats) do
|
||||||
|
modify(:user_id, references(:users, type: :uuid, on_delete: :delete_all))
|
||||||
|
|
||||||
|
modify(
|
||||||
|
:recipient,
|
||||||
|
references(:users, column: :ap_id, type: :string, on_delete: :delete_all)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,7 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.EnsureBioIsString do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
execute("update users set bio = '' where bio is null", "")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,10 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.BioSetNotNull do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
execute(
|
||||||
|
"alter table users alter column bio set not null",
|
||||||
|
"alter table users alter column bio drop not null"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
.actions-button[data-v-2d9f3c5e]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-2d9f3c5e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-2d9f3c5e]{float:right}.el-icon-edit[data-v-2d9f3c5e]{margin-right:5px}.tag-container[data-v-2d9f3c5e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-2d9f3c5e]{padding-right:20px}.no-hover[data-v-2d9f3c5e]:hover{color:#606266;background-color:#fff;cursor:auto}
|
|
@ -0,0 +1 @@
|
||||||
|
.select-field[data-v-06df454a]{width:350px}@media only screen and (max-width:480px){.select-field[data-v-06df454a]{width:100%;margin-bottom:5px}}.el-dialog__body{padding:20px}.create-account-form-item{margin-bottom:20px}.create-account-form-item-without-margin{margin-bottom:0}@media only screen and (max-width:480px){.create-user-dialog{width:85%}.create-account-form-item{margin-bottom:20px}.el-dialog__body{padding:20px}}.moderate-user-button{text-align:left;width:350px;padding:10px}.moderate-user-button-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media only screen and (max-width:480px){.moderate-user-button{width:100%}}.actions-button{text-align:left;width:350px;padding:10px}.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:0 15px 10px}.actions-container .el-dropdown{margin-left:10px}.active-tag{color:#409eff;font-weight:700}.active-tag .el-icon-check{color:#409eff;float:right;margin:7px 0 0 15px}.el-dropdown-link:hover{cursor:pointer;color:#409eff}.create-account>.el-icon-plus{margin-right:5px}.password-reset-token{margin:0 0 14px}.password-reset-token-dialog{width:50%}.reset-password-link{text-decoration:underline}.users-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}.users-container h1{margin:10px 0 0 15px;height:40px}.users-container .el-table__row:hover{cursor:pointer}.users-container .pagination{margin:25px 0;text-align:center}.users-container .reboot-button{margin:0 15px 0 0;padding:10px;width:145px}.users-container .search{width:350px;float:right;margin-left:10px}.users-container .filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:15px}.users-container .user-count{color:grey;font-size:28px}@media only screen and (max-width:480px){.password-reset-token-dialog{width:85%}.users-container h1{margin:0}.users-container .actions-button{width:100%}.users-container .actions-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px 7px}.users-container .el-icon-arrow-down{font-size:12px}.users-container .search{width:100%;margin-left:0}.users-container .filter-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;margin:0 10px}.users-container .el-table__row .el-tag{width:30px;display:inline-block;margin-bottom:4px;font-weight:700}.users-container .el-table__row .el-tag.el-tag--danger,.users-container .el-table__row .el-tag.el-tag--success{padding-left:8px}.users-container .reboot-button{margin:0}.users-container .users-header-container{margin:7px 10px 12px}.users-container .user-count{color:grey;font-size:22px}}@media only screen and (max-width:801px) and (min-width:481px){.actions-button,.search{width:49%}}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
h1[data-v-8208195e]{margin:0}.expl[data-v-8208195e]{color:#666;font-size:13px;line-height:22px;margin:5px 0 0;overflow-wrap:break-word;overflow:hidden;text-overflow:ellipsis}.banned-urls-table[data-v-8208195e]{margin-top:15px;margin-bottom:15px}.evict-button[data-v-8208195e]{margin-left:15px}.media-proxy-cache-header[data-v-8208195e]{margin-left:15px;margin-top:22px;font-weight:500}.media-proxy-cache-header-container[data-v-8208195e]{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}.remove-url-button[data-v-8208195e]{width:150px}.url-input[data-v-8208195e]{margin-right:15px}.url-input-container[data-v-8208195e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;margin:15px 15px 5px}.url-input-expl[data-v-8208195e]{margin-left:15px}@media only screen and (max-width:480px){.url-input[data-v-8208195e]{width:100%;margin-bottom:5px}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
.status-card{margin-bottom:10px;cursor:pointer}.status-card .account{line-height:26px;font-size:13px;color:#606266}.status-card .account:hover{text-decoration:underline}.status-card .deactivated{color:grey;line-height:28px;vertical-align:middle}.status-card .image{width:20%}.status-card .image img{width:100%}.status-card .router-link{text-decoration:none}.status-card .show-more-button{margin-left:5px}.status-card .status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-card .status-avatar-img{display:inline-block;width:15px;height:15px;margin-right:5px}.status-card .status-account-name{display:inline-block;margin:0;font-size:15px;font-weight:500}.status-card .status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-card .status-card-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-card .status-checkbox{margin-right:7px}.status-card .status-content{font-size:15px;line-height:26px}.status-card .status-created-at{font-size:13px;color:#606266}.status-card .status-deleted{font-style:italic;margin-top:3px}.status-card .status-footer,.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-card .status-tags{display:inline}.status-card .status-without-content{font-style:italic}@media only screen and (max-width:480px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.status-card .status-footer{margin-top:10px}.status-card .status-footer,.status-card .status-header{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex}}.statuses-container{padding:0 15px}.statuses-container h1{margin:10px 0 15px}.statuses-container .status-container{margin:0 0 10px}.statuses-header-container .el-button.is-plain:focus,.statuses-header-container .el-button.is-plain:hover{border-color:#dcdfe6;color:#606266;cursor:default}.checkbox-container{margin-bottom:15px}.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 0 15px}.reboot-button{padding:10px;margin:0;width:145px}.select-instance{width:396px}.statuses-header,.statuses-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}.statuses-pagination{padding:15px 0;text-align:center}@media only screen and (max-width:480px){.checkbox-container{margin-bottom:10px}.filter-container{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:10px 0}.select-field{width:100%;margin-bottom:5px}.select-instance{width:100%}.statuses-header-container{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.statuses-header-container .el-button-group{width:100%}.statuses-header-container .el-button{padding:10px 6.5px;width:50%}.statuses-header-container .el-button-group>.el-button:first-child{border-bottom-left-radius:0}.statuses-header-container .el-button-group>.el-button:not(:first-child):not(:last-child).private-button{border-top-right-radius:4px}.statuses-header-container .el-button-group>.el-button:not(:first-child):not(:last-child).public-button{border-bottom-left-radius:4px;border-top:#fff}.statuses-header-container .el-button-group>.el-button:last-child{border-top-right-radius:0;border-top:#fff}.statuses-header-container .reboot-button{margin:10px 0 0}}
|
|
@ -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}}
|
|
@ -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}
|
|
@ -0,0 +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{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%}}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +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-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}
|
|
@ -0,0 +1 @@
|
||||||
|
.router-link{text-decoration:none}.moderation-log-container[data-v-60b585cf]{margin:0 15px}h1[data-v-60b585cf]{margin:0}.el-timeline[data-v-60b585cf]{margin:25px 45px 0 0;padding:0}.moderation-log-date-panel[data-v-60b585cf]{width:350px}.moderation-log-header-container[data-v-60b585cf]{-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:10px 0 15px}.moderation-log-header-container[data-v-60b585cf],.moderation-log-nav-container[data-v-60b585cf]{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-60b585cf]{width:350px}.moderation-log-user-select[data-v-60b585cf]{margin:0 0 20px;width:350px}.reboot-button[data-v-60b585cf]{padding:10px;margin:0;width:145px}.search-container[data-v-60b585cf]{text-align:right}.pagination[data-v-60b585cf]{text-align:center}@media only screen and (max-width:480px){h1[data-v-60b585cf]{font-size:24px}.moderation-log-date-panel[data-v-60b585cf]{width:100%}.moderation-log-user-select[data-v-60b585cf]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-60b585cf]{width:40%}}@media only screen and (max-width:801px) and (min-width:481px){.moderation-log-date-panel[data-v-60b585cf]{width:55%}.moderation-log-user-select[data-v-60b585cf]{margin:0 0 10px;width:55%}.moderation-log-search[data-v-60b585cf]{width:40%}}
|
|
@ -1 +1 @@
|
||||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.1abbc9b8.css rel=stylesheet><link href=chunk-libs.5cf7f50a.css rel=stylesheet><link href=app.61bb0915.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.aaeb14f8.js></script><script type=text/javascript src=static/js/chunk-elementUI.2de79b84.js></script><script type=text/javascript src=static/js/chunk-libs.76802be9.js></script><script type=text/javascript src=static/js/app.ad6a566b.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.40545a1f.css rel=stylesheet><link href=chunk-libs.0380664d.css rel=stylesheet><link href=app.07a1f8db.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/runtime.04c4fa2f.js></script><script type=text/javascript src=static/js/chunk-elementUI.8e5c404c.js></script><script type=text/javascript src=static/js/chunk-libs.f842b12e.js></script><script type=text/javascript src=static/js/app.1df22cde.js></script></body></html>
|
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
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
|
@ -1,2 +1,6 @@
|
||||||
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-6e81"],{BF41:function(t,a,i){},"UUO+":function(t,a,i){"use strict";i.r(a);var e=i("zGwZ"),s=i.n(e),r={name:"Page401",data:function(){return{errGif:s.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=(i("UrVv"),i("KHd+")),l=Object(n.a)(r,function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("返回")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("Oops!")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("回首页")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},[],!1,null,"ab9be52c",null);l.options.__file="401.vue";a.default=l.exports},UrVv:function(t,a,i){"use strict";var e=i("BF41");i.n(e).a},zGwZ:function(t,a,i){t.exports=i.p+"static/img/401.089007e.gif"}}]);
|
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-6e81"],{BF41:function(t,a,i){},"UUO+":function(t,a,i){"use strict";i.r(a);var e=i("zGwZ"),s=i.n(e),r={name:"Page401",data:function(){return{errGif:s.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=(i("UrVv"),i("KHd+")),l=Object(n.a)(r,function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("返回")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("Oops!")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("回首页")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},[],!1,null,"ab9be52c",null);l.options.__file="401.vue";a.default=l.exports},UrVv:function(t,a,i){"use strict";var e=i("BF41");i.n(e).a},zGwZ:function(t,a,i){t.exports=i.p+"static/img/401.089007e.gif"}}]);
|
||||||
//# sourceMappingURL=chunk-6e81.b4ee7cf5.js.map
|
<<<<<<< HEAD:priv/static/adminfe/static/js/chunk-6e81.b4ee7cf5.js
|
||||||
|
//# sourceMappingURL=chunk-6e81.b4ee7cf5.js.map
|
||||||
|
=======
|
||||||
|
//# sourceMappingURL=chunk-6e81.6043af74.js.map
|
||||||
|
>>>>>>> 9433311923d4b41b057ce6cb1632ff27d46919b4:priv/static/adminfe/static/js/chunk-6e81.6043af74.js
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue