...
 
Commits (4)
......@@ -9,33 +9,42 @@ Pleroma is an OStatus and Activity Pub-compatible social networking server writt
For clients it supports both the [GNU Social API with Qvitter extensions](https://twitter-api.readthedocs.io/en/latest/index.html) and the [Mastodon client API](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md).
Mobile clients that are known to work well:
Client applications that are committed to supporting Pleroma:
* Twidere
* Tusky
* Pawoo (Android + iOS)
* Subway Tooter
* Mastalab (Android)
* Tusky (Android)
* Twidere (Android)
* Mast (iOS)
* Amaroq (iOS)
Client applications that are known to work well:
* Pawoo (Android + iOS)
* Tootdon (Android + iOS)
* Tootle (iOS)
* Whalebird (Windows + Mac + Linux)
## About this package
I'm using this package as a way to learn packaging for yunohost. This package is not completely ready yet, but installation, removal and upgrade should work. Backup should work as well, but restore may have some quirks. If you have recommendations, please let me know on the fediverse at `@ilja@ilja.space`
What is not implemented:
* You need a dedicated domain or subdomain
* Changing the URL is technically impossible at this time due to the nature of federation
* There is no LDAP integration. Users on Pleroma are seperate from the yunohost users
* There is no integration with a mailbox and/or -service. This means that mails won't be sent from the application
* Changing the URL is technically impossible at this time due to the nature of federation
Extra info:
* Multiple installs are possible
* On installation you can choose to enable scopes on the Pleroma-FE
* You can choose to close regstrations on installation, but then you'll need to create invite tokens if you want others to join your instance. You can do this by accessing your yunohost server over ssh and run `cd /var/www/pleroma/pleroma/ && mix pleroma.user invite`. See: https://git.pleroma.social/pleroma/pleroma/wikis/Admin%20tasks
* On installation you'll need to chose a dedicated domain for Pleroma. You'll also be asked for a username and password for a user. This user will have admin and moderator rights.
* On installation you'll need to chose a dedicated domain for Pleroma. You'll also be asked for a username and password for a user. This user will have admin and moderator rights
* Pleroma will be listed in the admin-panel under services, so you can stop and start the service there
* Postgresql will also be listed in the admin-panel
* You can upgrade your Pleroma instance by logging in over ssh as root and run `yunohost app upgrade pleroma_ynh -u https://gitlab.com/Spctrl/pleroma_ynh`
* Your current Pleroma version and other iformation can be found on `yourdomain.tld/api/v1/instance` and `yourdomain.tld/nodeinfo/2.0.json`
* If you're not afraid of the terminal, check out https://git.pleroma.social/pleroma/pleroma/wikis/home to see what more you can do with your awesome instance!
## Contribute
If you have problems, recommendations or whatever, you can contact me at `@ilja@ilja.space`
You can also add a bug on the issue-tracker at https://gitlab.com/Spctrl/pleroma_ynh
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.Instance do
use Mix.Task
alias Mix.Tasks.Pleroma.Common
@shortdoc "Manages Pleroma instance"
@moduledoc """
Manages Pleroma instance.
## Generate a new instance config.
mix pleroma.instance gen [OPTION...]
If any options are left unspecified, you will be prompted interactively
## Options
- `-f`, `--force` - overwrite any output files
- `-o PATH`, `--output PATH` - the output file for the generated configuration
- `--output-psql PATH` - the output file for the generated PostgreSQL setup
- `--domain DOMAIN` - the domain of your instance
- `--instance-name INSTANCE_NAME` - the name of your instance
- `--admin-email ADMIN_EMAIL` - the email address of the instance admin
- `--dbhost HOSTNAME` - the hostname of the PostgreSQL database to use
- `--dbname DBNAME` - the name of the database to use
- `--dbuser DBUSER` - the user (aka role) to use for the database connection
- `--dbpass DBPASS` - the password to use for the database connection
"""
def run(["gen" | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
force: :boolean,
output: :string,
output_psql: :string,
domain: :string,
instance_name: :string,
admin_email: :string,
dbhost: :string,
dbname: :string,
dbuser: :string,
dbpass: :string
],
aliases: [
o: :output,
f: :force
]
)
paths =
[config_path, psql_path] = [
Keyword.get(options, :output, "config/generated_config.exs"),
Keyword.get(options, :output_psql, "config/setup_db.psql")
]
will_overwrite = Enum.filter(paths, &File.exists?/1)
proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
unless not proceed? do
[domain, port | _] =
String.split(
Common.get_option(
options,
:domain,
"What domain will your instance use? (e.g pleroma.soykaf.com)"
),
":"
) ++ [443]
name =
Common.get_option(
options,
:instance_name,
"What is the name of your instance? (e.g. Pleroma/Soykaf)"
)
email = Common.get_option(options, :admin_email, "What is your admin email address?")
dbhost =
Common.get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
dbname =
Common.get_option(options, :dbname, "What is the name of your database?", "pleroma_dev")
dbuser =
Common.get_option(
options,
:dbuser,
"What is the user used to connect to your database?",
"pleroma"
)
dbpass =
Common.get_option(
options,
:dbpass,
"What is the password used to connect to your database?",
:crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64),
"autogenerated"
)
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
{web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)
result_config =
EEx.eval_file(
"sample_config.eex" |> Path.expand(__DIR__),
domain: domain,
port: port,
email: email,
name: name,
dbhost: dbhost,
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass,
version: Pleroma.Mixfile.project() |> Keyword.get(:version),
secret: secret,
web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),
web_push_private_key: Base.url_encode64(web_push_private_key, padding: false)
)
result_psql =
EEx.eval_file(
"sample_psql.eex" |> Path.expand(__DIR__),
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass
)
Mix.shell().info(
"Writing config to #{config_path}. You should rename it to config/prod.secret.exs or config/dev.secret.exs."
)
File.write(config_path, result_config)
Mix.shell().info("Writing #{psql_path}.")
File.write(psql_path, result_psql)
Mix.shell().info(
"\n" <>
"""
To get started:
1. Verify the contents of the generated files.
2. Run `sudo -u postgres psql -f #{Common.escape_sh_path(psql_path)}`.
""" <>
if config_path in ["config/dev.secret.exs", "config/prod.secret.exs"] do
""
else
"3. Run `mv #{Common.escape_sh_path(config_path)} 'config/prod.secret.exs'`."
end
)
else
Mix.shell().error(
"The task would have overwritten the following files:\n" <>
(Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <>
"Rerun with `--force` to overwrite them."
)
end
end
end
defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Ecto.Changeset
alias Pleroma.{Repo, User}
alias Mix.Tasks.Pleroma.Common
@shortdoc "Manages Pleroma users"
@moduledoc """
Manages Pleroma users.
## Create a new user.
mix pleroma.user new NICKNAME EMAIL [OPTION...]
Options:
- `--name NAME` - the user's name (i.e., "Lain Iwakura")
- `--bio BIO` - the user's bio
- `--password PASSWORD` - the user's password
- `--moderator`/`--no-moderator` - whether the user is a moderator
- `--admin`/`--no-admin` - whether the user is an admin
## Generate an invite link.
mix pleroma.user invite
## Delete the user's account.
mix pleroma.user rm NICKNAME
## Deactivate or activate the user's account.
mix pleroma.user toggle_activated NICKNAME
## Unsubscribe local users from user's account and deactivate it
mix pleroma.user unsubscribe NICKNAME
## Create a password reset link.
mix pleroma.user reset_password NICKNAME
## Set the value of the given user's settings.
mix pleroma.user set NICKNAME [OPTION...]
Options:
- `--locked`/`--no-locked` - whether the user's account is locked
- `--moderator`/`--no-moderator` - whether the user is a moderator
- `--admin`/`--no-admin` - whether the user is an admin
"""
def run(["new", nickname, email | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
name: :string,
bio: :string,
password: :string,
moderator: :boolean,
admin: :boolean,
assume_yes: :boolean
]
)
name = Keyword.get(options, :name, nickname)
bio = Keyword.get(options, :bio, "")
{password, generated_password?} =
case Keyword.get(options, :password) do
nil ->
{:crypto.strong_rand_bytes(16) |> Base.encode64(), true}
password ->
{password, false}
end
moderator? = Keyword.get(options, :moderator, false)
admin? = Keyword.get(options, :admin, false)
Mix.shell().info("""
A user will be created with the following information:
- nickname: #{nickname}
- email: #{email}
- password: #{
if(generated_password?, do: "[generated; a reset link will be created]", else: password)
}
- name: #{name}
- bio: #{bio}
- moderator: #{if(moderator?, do: "true", else: "false")}
- admin: #{if(admin?, do: "true", else: "false")}
""")
proceed? = true
unless not proceed? do
Common.start_pleroma()
params = %{
nickname: nickname,
email: email,
password: password,
password_confirmation: password,
name: name,
bio: bio
}
user = User.register_changeset(%User{}, params)
Repo.insert!(user)
Mix.shell().info("User #{nickname} created")
if moderator? do
run(["set", nickname, "--moderator"])
end
if admin? do
run(["set", nickname, "--admin"])
end
if generated_password? do
run(["reset_password", nickname])
end
else
Mix.shell().info("User will not be created.")
end
end
def run(["rm", nickname]) do
Common.start_pleroma()
with %User{local: true} = user <- User.get_by_nickname(nickname) do
User.delete(user)
Mix.shell().info("User #{nickname} deleted.")
else
_ ->
Mix.shell().error("No local user #{nickname}")
end
end
def run(["toggle_activated", nickname]) do
Common.start_pleroma()
with %User{} = user <- User.get_by_nickname(nickname) do
{:ok, user} = User.deactivate(user, !user.info.deactivated)
Mix.shell().info(
"Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated"
)
else
_ ->
Mix.shell().error("No user #{nickname}")
end
end
def run(["reset_password", nickname]) do
Common.start_pleroma()
with %User{local: true} = user <- User.get_by_nickname(nickname),
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
Mix.shell().info("Generated password reset token for #{user.nickname}")
IO.puts(
"URL: #{
Pleroma.Web.Router.Helpers.util_url(
Pleroma.Web.Endpoint,
:show_password_reset,
token.token
)
}"
)
else
_ ->
Mix.shell().error("No local user #{nickname}")
end
end
def run(["unsubscribe", nickname]) do
Common.start_pleroma()
with %User{} = user <- User.get_by_nickname(nickname) do
Mix.shell().info("Deactivating #{user.nickname}")
User.deactivate(user)
{:ok, friends} = User.get_friends(user)
Enum.each(friends, fn friend ->
user = Repo.get(User, user.id)
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
User.unfollow(user, friend)
end)
:timer.sleep(500)
user = Repo.get(User, user.id)
if length(user.following) == 0 do
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
end
else
_ ->
Mix.shell().error("No user #{nickname}")
end
end
def run(["set", nickname | rest]) do
Common.start_pleroma()
{options, [], []} =
OptionParser.parse(
rest,
strict: [
moderator: :boolean,
admin: :boolean,
locked: :boolean
]
)
with %User{local: true} = user <- User.get_by_nickname(nickname) do
user =
case Keyword.get(options, :moderator) do
nil -> user
value -> set_moderator(user, value)
end
user =
case Keyword.get(options, :locked) do
nil -> user
value -> set_locked(user, value)
end
_user =
case Keyword.get(options, :admin) do
nil -> user
value -> set_admin(user, value)
end
else
_ ->
Mix.shell().error("No local user #{nickname}")
end
end
def run(["invite"]) do
Common.start_pleroma()
with {:ok, token} <- Pleroma.UserInviteToken.create_token() do
Mix.shell().info("Generated user invite token")
url =
Pleroma.Web.Router.Helpers.redirect_url(
Pleroma.Web.Endpoint,
:registration_page,
token.token
)
IO.puts(url)
else
_ ->
Mix.shell().error("Could not create invite token.")
end
end
defp set_moderator(user, value) do
info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value})
user_cng =
Ecto.Changeset.change(user)
|> put_embed(:info, info_cng)
{:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Moderator status of #{user.nickname}: #{user.info.is_moderator}")
user
end
defp set_admin(user, value) do
info_cng = User.Info.admin_api_update(user.info, %{is_admin: value})
user_cng =
Ecto.Changeset.change(user)
|> put_embed(:info, info_cng)
{:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Admin status of #{user.nickname}: #{user.info.is_admin}")
user
end
defp set_locked(user, value) do
info_cng = User.Info.user_upgrade(user.info, %{locked: value})
user_cng =
Ecto.Changeset.change(user)
|> put_embed(:info, info_cng)
{:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Locked status of #{user.nickname}: #{user.info.locked}")
user
end
end
......@@ -3,11 +3,11 @@
"id": "pleroma_ynh",
"packaging_format": 1,
"description": {
"en": "Pleroma package for YunoHost"
"en": "Pleroma is an OStatus and Activity Pub-compatible social networking server written in Elixir, compatible with GNU Social and Mastodon. It is high-performance and can run on small devices like a briqueinternet/internet cube."
},
"version": "0.9.9~ynh1",
"version": "0.9.9-beta-2~ynh1",
"url": "https://git.pleroma.social/pleroma/pleroma",
"license": "free",
"license": "AGPL-3.0-only",
"maintainer": {
"name": "Ilja",
"email": "spctrl@spectraltheorem.be",
......@@ -32,6 +32,7 @@
},
{
"name": "instance_name",
"type": "string",
"ask": {
"en": "Give a name for your instance. This will be shown on the tab of the browser"
},
......@@ -55,6 +56,7 @@
},
{
"name": "instance_user",
"type": "string",
"ask": {
"en": "A admin/moderator user will be created. Give a username for this user."
},
......@@ -78,6 +80,7 @@
},
{
"name": "instance_user_mail",
"type": "string",
"ask": {
"en": "The mailadress for the admin user. This will be the mailadres for the admin user and will also be publicly visseble"
},
......
#!/bin/bash
#=================================================
# GENERIC STARTING
#=================================================
# IMPORT GENERIC HELPERS
#=================================================
source _common.sh
source /usr/share/yunohost/helpers
#=================================================
# GIVE FAIL MESSAGE
#=================================================
ynh_die "Due to the nature of federation, changing the URL is NOT possible. You'll have to uninstall this application and install it on the new domain. You WILL loose your data!"
......@@ -79,7 +79,7 @@ ynh_app_setting_set $app db_name $db_name
ynh_print_info "Installing dependencies"
# In case https capability for apt insn't installed yet
apt-get install --yes apt-transport-https
ynh_install_app_dependencies apt-transport-https
if ! [ -e /etc/apt/sources.list.d/erlang-solutions.list ]
then
......@@ -106,17 +106,13 @@ useradd $app --home-dir=$final_path
ynh_print_info "Downloading source"
git clone --branch v0.9.9 https://git.pleroma.social/pleroma/pleroma/ $final_path/pleroma
# To only clone in one branch, we could also do
# git clone --single-branch --branch v0.9.9 https://git.pleroma.social/pleroma/pleroma/
git clone --branch 0.9.9-beta-2 https://git.pleroma.social/pleroma/pleroma/ $final_path/pleroma
# Pleroma will use tags on the master-branch. To only clone in one branch, we could do
# git clone --single-branch --branch v0.9.9 https://git.pleroma.social/pleroma/pleroma/
# And then checkout the tag
ynh_print_info "Building the Pleroma instance"
# Replace files with modified ones to make it non-interactive
# These'll be fixed with https://git.pleroma.social/pleroma/pleroma/issues/485
# and https://git.pleroma.social/pleroma/pleroma/issues/486
cp ../conf/instance.ex $final_path/pleroma/lib/mix/tasks/pleroma/instance.ex
cp ../conf/user.ex $final_path/pleroma/lib/mix/tasks/pleroma/user.ex
chown -R $app: $final_path
su - $app -c "cd $final_path/pleroma;mix local.hex --force;mix deps.get;mix local.rebar --force;mix pleroma.instance gen --domain "$domain" --instance-name "$server_name" --admin-email "$email" --dbhost localhost --dbname "$db_name" --dbuser "$app" --dbpass "$(ynh_string_random 32)";cp config/generated_config.exs config/prod.secret.exs;"
......@@ -157,10 +153,10 @@ pleroma_ynh_add_setting "config :pleroma, :instance" "registrations_open" "$(ple
ynh_print_info "Adding user to the instance"
# We have to set the the pasword for the postgresql DB-user first, otherwise the task fails.
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';"
su - postgres -c "psql -c \"ALTER USER postgres PASSWORD 'postgres';\""
ynh_print_OFF
su - $app -c "cd $final_path/pleroma; MIX_ENV=prod mix local.hex --force;MIX_ENV=prod mix pleroma.user new $instance_user $instance_user_mail --name $instance_user --bio 'admin and moderator of this instance' --password $instance_user_password --moderator --admin --assume-yes;"
su - $app -c "cd $final_path/pleroma; MIX_ENV=prod mix local.hex --force;MIX_ENV=prod mix pleroma.user new $instance_user $instance_user_mail --name $instance_user --bio 'admin and moderator of this instance' --password $instance_user_password --moderator --admin --assume-yes > /dev/null;"
ynh_print_ON
#=================================================
......@@ -224,4 +220,3 @@ systemctl reload nginx
systemctl restart $app
ynh_print_info "If you're not afraid of the terminal, check out https://git.pleroma.social/pleroma/pleroma/wikis/home to see what more you can do with your awesome instance!"
......@@ -13,8 +13,7 @@ source _common.sh
# MANAGE SCRIPT FAILURE
#=================================================
# TODO: This doesn't look like it'll always work well ^^'
#ynh_abort_if_errors
ynh_abort_if_errors
#=================================================
# LOAD SETTINGS
......@@ -24,7 +23,7 @@ app=$YNH_APP_INSTANCE_NAME
final_path=$(ynh_app_setting_get $app final_path)
domain=$(ynh_app_setting_get $app domain)
path_url=$(ynh_app_setting_get $app path_url)
path_url=$(ynh_app_setting_get $app path)
port=$(ynh_app_setting_get $app port)
db_name=$(ynh_app_setting_get $app db_name)
......@@ -32,15 +31,15 @@ db_name=$(ynh_app_setting_get $app db_name)
# CHECK IF THE APP CAN BE RESTORED
#=================================================
ynh_print_info "Checking for conflicts"
test ! -e "$final_path" || ynh_die "This path already contains a folder"
# Check web path availability
ynh_webpath_available $domain $path_url
# Register (book) web path
# ynh_webpath_register $app $domain $path_url
ynh_webpath_available $domain $path_url || ynh_die "$domain$path_url is no longer available"
# Check if port is still free
test $port = $(ynh_find_port $port) || ynh_die "Port $port is no longer available"
[ $port -eq $(ynh_find_port $port) ] || ynh_die "Port $port is no longer available"
# TODO: use different port when needed
#=================================================
......@@ -52,7 +51,7 @@ test $port = $(ynh_find_port $port) || ynh_die "Port $port is no longer availabl
ynh_print_info "Installing dependencies"
# In case https capability for apt insn't installed yet
apt-get install --yes apt-transport-https
ynh_install_app_dependencies apt-transport-https
if ! [ -e /etc/apt/sources.list.d/erlang-solutions.list ]
then
......@@ -143,3 +142,4 @@ systemctl restart $app
ynh_print_info "If you're not afraid of the terminal, check out https://git.pleroma.social/pleroma/pleroma/wikis/home to see what more you can do with your awesome instance!"
......@@ -43,15 +43,15 @@ ynh_abort_if_errors
ynh_print_info "Ensuring backwards compatibility"
# Pleroma sets the headers so we don't need to do it
# TODO: The following lines seems to break the whole thing. First make it work on install, then check this out.
## Pleroma sets the headers so we don't need to do it
#if (cat "/etc/nginx/conf.d/$domain.d/$app.conf" | grep 'add_header')
#then
# TODO: The following lines seems to break the whole thing. First make it work on install, then check this out.
#cp -rf "../conf/nginx.conf" "/etc/nginx/conf.d/$domain.d/$app.conf"
#ynh_replace_string "{APP}" "$app" "/etc/nginx/conf.d/$domain.d/$app.conf"
#ynh_replace_string "{PORT}" "$port" "/etc/nginx/conf.d/$domain.d/$app.conf"
#ynh_replace_string "add_header" "# add_header" "/etc/nginx/conf.d/$domain.conf"
#systemctl reload nginx
# cp -rf "../conf/nginx.conf" "/etc/nginx/conf.d/$domain.d/$app.conf"
# ynh_replace_string "{APP}" "$app" "/etc/nginx/conf.d/$domain.d/$app.conf"
# ynh_replace_string "{PORT}" "$port" "/etc/nginx/conf.d/$domain.d/$app.conf"
# ynh_replace_string "add_header" "# add_header" "/etc/nginx/conf.d/$domain.conf"
# systemctl reload nginx
#fi
#=================================================
......@@ -62,11 +62,13 @@ ynh_print_info "Ensuring backwards compatibility"
ynh_print_info "Doing actual upgrade"
new_branch="v0.9.9"
new_branch="0.9.9-beta-2"
systemctl stop $app
# TODO: This will have to move to the new stable branch as well
su - $app -c "cd $final_path/pleroma;git pull --no-edit;git checkout $new_branch;MIX_ENV=prod mix deps.get;MIX_ENV=prod mix ecto.migrate;"
# First we revert to the last commit, untracked files are save from this. Then we pull, I added --no-edit just to be sure.
# Then we checkout the new version and do some Pleroma magic.
# TODO: Keep track of reverted files
su - $app -c "cd $final_path/pleroma;git reset --hard;git pull --no-edit;git checkout $new_branch;MIX_ENV=prod mix deps.get;MIX_ENV=prod mix ecto.migrate;"
#=================================================
# RESTART PLEROMA
......