Commit 52200998 authored by lain's avatar lain
Browse files

Merge branch 'develop' into feature/activitypub

parents 4a13b848 0e2ca77e
......@@ -22,7 +22,7 @@ No release has been made yet, but several servers have been online for months al
### Dependencies
* Postgresql version 9.6 or newer
* Elixir version 1.4 or newer (you will also need erlang-dev, erlang-parsetools, erlang-xmerl packages)
* Elixir version 1.5 or newer
* Build-essential tools
### Configuration
......@@ -50,3 +50,12 @@ Logs can be watched by using `journalctl -fu pleroma.service`
### Standalone/run by other means
Run `mix phx.server` in repository's root, it will output log into stdout/stderr
### Using an upstream proxy for federation
Add the following to your `dev.secret.exs` or `prod.secret.exs` if you want to proxify all http requests that pleroma makes to an upstream proxy server:
config :pleroma, :http,
proxy_url: "127.0.0.1:8123"
This is useful for running pleroma inside Tor or i2p.
......@@ -33,7 +33,7 @@
config :pleroma, :websub, Pleroma.Web.Websub
config :pleroma, :ostatus, Pleroma.Web.OStatus
config :pleroma, :httpoison, HTTPoison
config :pleroma, :httpoison, Pleroma.HTTP
version = with {version, 0} <- System.cmd("git", ["rev-parse", "HEAD"]) do
"Pleroma #{String.trim(version)}"
......@@ -41,6 +41,10 @@
_ -> "Pleroma dev"
end
# Configures http settings, upstream proxy etc.
config :pleroma, :http,
proxy_url: nil
config :pleroma, :instance,
version: version,
name: "Pleroma",
......@@ -48,6 +52,14 @@
limit: 5000,
registrations_open: true
config :pleroma, :media_proxy,
enabled: false,
redirect_on_failure: true
#base_url: "https://cache.pleroma.social"
config :pleroma, :chat,
enabled: true
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs"
firefox, /emoji/Firefox.gif
blank, /emoji/blank.png
f_00b, /emoji/f_00b.png
f_00b11b, /emoji/f_00b11b.png
f_00b33b, /emoji/f_00b33b.png
f_00h, /emoji/f_00h.png
f_00t, /emoji/f_00t.png
f_01b, /emoji/f_01b.png
f_03b, /emoji/f_03b.png
f_10b, /emoji/f_10b.png
f_11b, /emoji/f_11b.png
f_11b00b, /emoji/f_11b00b.png
f_11b22b, /emoji/f_11b22b.png
f_11h, /emoji/f_11h.png
f_11t, /emoji/f_11t.png
f_12b, /emoji/f_12b.png
f_21b, /emoji/f_21b.png
f_22b, /emoji/f_22b.png
f_22b11b, /emoji/f_22b11b.png
f_22b33b, /emoji/f_22b33b.png
f_22h, /emoji/f_22h.png
f_22t, /emoji/f_22t.png
f_23b, /emoji/f_23b.png
f_30b, /emoji/f_30b.png
f_32b, /emoji/f_32b.png
f_33b, /emoji/f_33b.png
f_33b00b, /emoji/f_33b00b.png
f_33b22b, /emoji/f_33b22b.png
f_33h, /emoji/f_33h.png
f_33t, /emoji/f_33t.png
......@@ -14,9 +14,12 @@
# manifest is generated by the mix phoenix.digest task
# which you typically run after static files are built.
config :pleroma, Pleroma.Web.Endpoint,
on_init: {Pleroma.Web.Endpoint, :load_from_system_env, []},
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
http: [port: 4000],
protocol: "http",
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: []
# Do not print debug messages in production
config :logger, level: :info
......
instance.example.com { # Your instance's domain
proxy / localhost:4000 {
websocket
}
}
proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g
inactive=720m use_temp_path=off;
server {
listen 80;
server_name example.tld;
......@@ -19,11 +22,17 @@ server {
server_name example.tld;
location / {
add_header 'Access-Control-Allow-Origin' '*';
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:4000;
}
include snippets/well-known.conf;
}
\ No newline at end of file
location /proxy {
proxy_cache pleroma_media_cache;
proxy_cache_lock on;
proxy_pass http://localhost:4000;
}
}
......@@ -8,11 +8,20 @@ def run(_) do
domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim
name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim
email = IO.gets("What's your admin email address: ") |> String.trim
mediaproxy = IO.gets("Do you want to activate the mediaproxy? (y/N): ")
|> String.trim()
|> String.downcase()
|> String.starts_with?("y")
proxy_url = if mediaproxy do
IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ") |> String.trim
else
"https://cache.example.com"
end
secret = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", [dbpass: dbpass])
result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, dbpass: dbpass])
result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, proxy_url: proxy_url, dbpass: dbpass])
IO.puts("\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs")
File.write("config/generated_config.exs", result)
......
......@@ -10,6 +10,11 @@ config :pleroma, :instance,
limit: 5000,
registrations_open: true
config :pleroma, :media_proxy,
enabled: <%= mediaproxy %>,
redirect_on_failure: true,
base_url: "<%= proxy_url %>"
# Configure your database
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
......
......@@ -20,13 +20,18 @@ def start(_type, _args) do
limit: 2500
]]),
worker(Pleroma.Web.Federator, []),
worker(Pleroma.Web.ChatChannel.ChatChannelState, []),
worker(Pleroma.Stats, []),
]
++ if Mix.env == :test, do: [], else: [worker(Pleroma.Web.Streamer, [])]
++ if !chat_enabled(), do: [], else: [worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
Supervisor.start_link(children, opts)
end
defp chat_enabled do
Application.get_env(:pleroma, :chat, []) |> Keyword.get(:enabled)
end
end
defmodule Pleroma.Formatter do
alias Pleroma.User
alias Pleroma.Web.MediaProxy
@link_regex ~r/https?:\/\/[\w\.\/?=\-#%&@~\(\)]+[\w\/]/u
def linkify(text) do
......@@ -10,7 +11,7 @@ def linkify(text) do
def parse_tags(text, data \\ %{}) do
Regex.scan(@tag_regex, text)
|> Enum.map(fn (["#" <> tag = full_tag]) -> {full_tag, String.downcase(tag)} end)
|> (fn map -> if data["sensitive"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
|> (fn map -> if data["sensitive"] in [true, "True", "true", "1"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
end
def parse_mentions(text) do
......@@ -103,13 +104,19 @@ def html_escape(text) do
{finmoji, "/finmoji/128px/#{finmoji}-128.png"}
end)
@emoji_from_file (with {:ok, file} <- File.read("config/emoji.txt") do
file
|> String.trim
|> String.split("\n")
|> Enum.map(fn(line) ->
[name, file] = String.split(line, ", ")
{name, file}
@emoji_from_file (with {:ok, default} <- File.read("config/emoji.txt") do
custom =
with {:ok, custom} <- File.read("config/custom_emoji.txt") do
custom
else
_e -> ""
end
(default <> "\n" <> custom)
|> String.trim()
|> String.split(~r/\n+/)
|> Enum.map(fn(line) ->
[name, file] = String.split(line, ~r/,\s*/)
{name, file}
end)
else
_ -> []
......@@ -125,7 +132,7 @@ def emojify(text, additional \\ nil) do
end
Enum.reduce(all_emoji, text, fn ({emoji, file}, text) ->
String.replace(text, ":#{emoji}:", "<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{file}' />")
String.replace(text, ":#{emoji}:", "<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{MediaProxy.url(file)}' />")
end)
end
......
defmodule Pleroma.HTTP do
use HTTPoison.Base
def process_request_options(options) do
config = Application.get_env(:pleroma, :http, [])
proxy = Keyword.get(config, :proxy_url, nil)
case proxy do
nil -> options
_ -> options ++ [proxy: proxy]
end
end
end
defmodule Pleroma.Stats do
import Ecto.Query
alias Pleroma.{User, Repo, Activity}
def start_link do
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
spawn(fn -> schedule_update() end)
agent
end
def get_stats do
Agent.get(__MODULE__, fn {_, stats} -> stats end)
end
def get_peers do
Agent.get(__MODULE__, fn {peers, _} -> peers end)
end
def schedule_update do
spawn(fn ->
Process.sleep(1000 * 60 * 60 * 1) # 1 hour
schedule_update()
end)
update_stats()
end
def update_stats do
peers = from(u in Pleroma.User,
select: fragment("distinct ?->'host'", u.info),
where: u.local != ^true)
|> Repo.all()
domain_count = Enum.count(peers)
status_query = from(u in User.local_user_query,
select: fragment("sum((?->>'note_count')::int)", u.info))
status_count = Repo.one(status_query) |> IO.inspect
user_count = Repo.aggregate(User.local_user_query, :count, :id)
Agent.update(__MODULE__, fn _ ->
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
end)
end
end
......@@ -9,7 +9,7 @@ def store(%Plug.Upload{} = file) do
File.cp!(file.path, result_file)
# fix content type on some image uploads
content_type = if file.content_type == "application/octet-stream" do
content_type = if file.content_type in [nil, "application/octet-stream"] do
get_content_type(file.path)
else
file.content_type
......
......@@ -29,14 +29,14 @@ defmodule Pleroma.User do
def avatar_url(user) do
case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href
_ -> "https://placehold.it/48x48"
_ -> "#{Web.base_url()}/images/avi.png"
end
end
def banner_url(user) do
case user.info["banner"] do
%{"url" => [%{"href" => href} | _]} -> href
_ -> nil
_ -> "#{Web.base_url()}/images/banner.png"
end
end
......
......@@ -5,7 +5,9 @@ defmodule Pleroma.Web.UserSocket do
## Channels
# channel "room:*", Pleroma.Web.RoomChannel
channel "chat:*", Pleroma.Web.ChatChannel
if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
channel "chat:*", Pleroma.Web.ChatChannel
end
## Transports
transport :websocket, Phoenix.Transports.WebSocket
......
......@@ -24,7 +24,6 @@ def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}}
end
defmodule Pleroma.Web.ChatChannel.ChatChannelState do
use Agent
@max_messages 20
def start_link do
......
......@@ -95,7 +95,7 @@ def add_user_links(text, mentions) do
Enum.reduce(mentions, step_one, fn ({match, %User{ap_id: ap_id}, uuid}, text) ->
short_match = String.split(match, "@") |> tl() |> hd()
String.replace(text, uuid, "<a href='#{ap_id}'>@#{short_match}</a>")
String.replace(text, uuid, "<span><a href='#{ap_id}'>@<span>#{short_match}</span></a></span>")
end)
end
......
defmodule Pleroma.Web.Endpoint do
use Phoenix.Endpoint, otp_app: :pleroma
socket "/socket", Pleroma.Web.UserSocket
if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
socket "/socket", Pleroma.Web.UserSocket
end
socket "/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket
# Serve at "/" the static files from "priv/static" directory.
......@@ -12,7 +14,7 @@ defmodule Pleroma.Web.Endpoint do
at: "/media", from: "uploads", gzip: false
plug Plug.Static,
at: "/", from: :pleroma,
only: ~w(index.html static finmoji emoji packs sounds sw.js)
only: ~w(index.html static finmoji emoji packs sounds images instance sw.js)
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
......
......@@ -41,12 +41,12 @@ def handle(:request_subscription, websub) do
def handle(:publish, activity) do
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do
Logger.debug(fn -> "Sending #{activity.data["id"]} out via websub" end)
Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)
{:ok, actor} = WebFinger.ensure_keys_present(actor)
Logger.debug(fn -> "Sending #{activity.data["id"]} out via salmon" end)
Pleroma.Web.Salmon.publish(actor, activity)
Logger.debug(fn -> "Sending #{activity.data["id"]} out via websub" end)
Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)
end
end
......
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Pleroma.{Repo, Activity, User, Notification}
alias Pleroma.{Repo, Activity, User, Notification, Stats}
alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView}
alias Pleroma.Web.ActivityPub.ActivityPub
......@@ -93,7 +93,6 @@ def user(conn, %{"id" => id}) do
@instance Application.get_env(:pleroma, :instance)
def masto_instance(conn, _params) do
user_count = Repo.aggregate(User.local_user_query, :count, :id)
response = %{
uri: Web.base_url,
title: Keyword.get(@instance, :name),
......@@ -103,17 +102,18 @@ def masto_instance(conn, _params) do
urls: %{
streaming_api: String.replace(Web.base_url, ["http","https"], "wss")
},
stats: %{
status_count: 2,
user_count: user_count,
domain_count: 3
},
stats: Stats.get_stats,
thumbnail: Web.base_url <> "/instance/thumbnail.jpeg",
max_toot_chars: Keyword.get(@instance, :limit)
}
json(conn, response)
end
def peers(conn, _params) do
json(conn, Stats.get_peers)
end
defp mastodonized_emoji do
Pleroma.Formatter.get_custom_emoji()
|> Enum.map(fn {shortcode, relative_url} ->
......@@ -162,7 +162,7 @@ def home_timeline(%{assigns: %{user: user}} = conn, params) do
def public_timeline(%{assigns: %{user: user}} = conn, params) do
params = params
|> Map.put("type", ["Create", "Announce"])
|> Map.put("local_only", !!params["local"])
|> Map.put("local_only", params["local"] in [true, "True", "true", "1"])
|> Map.put("blocking_user", user)
activities = ActivityPub.fetch_public_activities(params)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment