2018-12-23 13:05:55 -07:00
# Pleroma: A lightweight social networking server
2021-01-12 23:49:20 -07:00
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
2018-12-23 13:05:55 -07:00
# SPDX-License-Identifier: AGPL-3.0-only
2018-12-02 11:18:06 -07:00
defmodule Mix.Tasks.Pleroma.Instance do
2018-06-28 18:24:51 -06:00
use Mix.Task
2019-06-19 17:05:19 -06:00
import Mix.Pleroma
2018-06-28 18:24:51 -06:00
2020-02-24 12:52:38 -07:00
alias Pleroma.Config
2018-12-02 11:18:06 -07:00
@shortdoc " Manages Pleroma instance "
2022-07-15 06:27:16 -06:00
@moduledoc File . read! ( " docs/docs/administration/CLI_tasks/instance.md " )
2018-06-28 18:24:51 -06:00
2018-12-04 11:00:45 -07:00
def run ( [ " gen " | rest ] ) do
2018-06-28 18:24:51 -06:00
{ options , [ ] , [ ] } =
OptionParser . parse (
rest ,
strict : [
force : :boolean ,
output : :string ,
output_psql : :string ,
domain : :string ,
instance_name : :string ,
admin_email : :string ,
2019-04-10 04:57:41 -06:00
notify_email : :string ,
2018-06-28 18:24:51 -06:00
dbhost : :string ,
dbname : :string ,
dbuser : :string ,
2019-04-10 04:57:41 -06:00
dbpass : :string ,
2019-06-22 03:54:16 -06:00
rum : :string ,
2019-06-14 09:45:05 -06:00
indexable : :string ,
2019-06-19 18:59:16 -06:00
db_configurable : :string ,
uploads_dir : :string ,
2019-07-09 13:57:41 -06:00
static_dir : :string ,
listen_ip : :string ,
2020-10-12 10:18:39 -06:00
listen_port : :string ,
strip_uploads : :string ,
anonymize_uploads : :string ,
2020-11-07 12:09:28 -07:00
dedupe_uploads : :string
2018-06-28 18:24:51 -06:00
] ,
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 )
2019-04-10 04:57:41 -06:00
if proceed? do
2018-12-15 03:00:54 -07:00
[ domain , port | _ ] =
String . split (
2019-06-19 17:05:19 -06:00
get_option (
2018-12-15 03:00:54 -07:00
options ,
:domain ,
2022-12-03 16:17:43 -07:00
" What domain will your instance use? (e.g akkoma.example.com) "
2018-12-15 03:00:54 -07:00
) ,
" : "
) ++ [ 443 ]
2018-06-28 18:24:51 -06:00
name =
2019-06-19 17:05:19 -06:00
get_option (
2018-12-06 10:01:28 -07:00
options ,
2018-12-29 04:43:54 -07:00
:instance_name ,
2020-02-25 14:32:34 -07:00
" What is the name of your instance? (e.g. The Corndog Emporium) " ,
2020-02-25 11:59:37 -07:00
domain
2018-12-06 10:01:28 -07:00
)
2018-06-28 18:24:51 -06:00
2019-06-19 17:05:19 -06:00
email = get_option ( options , :admin_email , " What is your admin email address? " )
2018-12-02 12:04:33 -07:00
2019-04-10 04:57:41 -06:00
notify_email =
2019-06-19 17:05:19 -06:00
get_option (
2019-04-10 04:57:41 -06:00
options ,
:notify_email ,
" What email address do you want to use for sending email notifications? " ,
email
)
2019-04-02 13:09:16 -06:00
indexable =
2019-06-19 17:05:19 -06:00
get_option (
2019-04-02 13:09:16 -06:00
options ,
:indexable ,
" Do you want search engines to index your site? (y/n) " ,
" y "
) === " y "
2019-06-14 09:45:05 -06:00
db_configurable? =
2019-06-19 17:05:19 -06:00
get_option (
2019-06-14 09:45:05 -06:00
options ,
:db_configurable ,
2019-06-19 18:59:16 -06:00
" Do you want to store the configuration in the database (allows controlling it from admin-fe)? (y/n) " ,
2019-06-20 21:42:04 -06:00
" n "
2019-06-14 09:45:05 -06:00
) === " y "
2018-12-02 12:04:33 -07:00
2019-06-19 17:05:19 -06:00
dbhost = get_option ( options , :dbhost , " What is the hostname of your database? " , " localhost " )
2018-12-02 12:04:33 -07:00
2022-07-12 10:41:30 -06:00
dbname = get_option ( options , :dbname , " What is the name of your database? " , " akkoma " )
2018-06-28 18:24:51 -06:00
dbuser =
2019-06-19 17:05:19 -06:00
get_option (
2018-12-02 12:04:33 -07:00
options ,
:dbuser ,
" What is the user used to connect to your database? " ,
2022-07-12 10:41:30 -06:00
" akkoma "
2018-12-02 12:04:33 -07:00
)
2018-06-28 18:24:51 -06:00
dbpass =
2019-06-19 17:05:19 -06:00
get_option (
2018-12-02 12:04:33 -07:00
options ,
:dbpass ,
" What is the password used to connect to your database? " ,
:crypto . strong_rand_bytes ( 64 ) |> Base . encode64 ( ) |> binary_part ( 0 , 64 ) ,
" autogenerated "
)
2018-06-28 18:24:51 -06:00
2019-06-22 03:54:16 -06:00
rum_enabled =
get_option (
options ,
:rum ,
" Would you like to use RUM indices? " ,
" n "
) === " y "
2019-07-09 13:57:41 -06:00
listen_port =
get_option (
options ,
:listen_port ,
" What port will the app listen to (leave it if you are using the default setup with nginx)? " ,
4000
)
listen_ip =
get_option (
options ,
:listen_ip ,
" What ip will the app listen to (leave it if you are using the default setup with nginx)? " ,
" 127.0.0.1 "
)
2019-06-19 18:59:16 -06:00
uploads_dir =
get_option (
options ,
2019-07-04 22:19:27 -06:00
:uploads_dir ,
2019-06-19 18:59:16 -06:00
" What directory should media uploads go in (when using the local uploader)? " ,
2020-07-09 09:53:51 -06:00
Config . get ( [ Pleroma.Uploaders.Local , :uploads ] )
2019-06-19 18:59:16 -06:00
)
2020-05-20 12:16:40 -06:00
|> Path . expand ( )
2019-06-19 18:59:16 -06:00
static_dir =
get_option (
options ,
:static_dir ,
" What directory should custom public files be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)? " ,
2020-07-09 09:53:51 -06:00
Config . get ( [ :instance , :static_dir ] )
2019-06-19 18:59:16 -06:00
)
2020-05-20 12:16:40 -06:00
|> Path . expand ( )
2019-06-19 18:59:16 -06:00
2020-12-12 10:37:14 -07:00
{ strip_uploads_message , strip_uploads_default } =
if Pleroma.Utils . command_available? ( " exiftool " ) do
{ " Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n) " ,
" y " }
else
{ " Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as not installed, please install it if you answer yes. (y/n) " ,
" n " }
end
2020-10-12 10:18:39 -06:00
strip_uploads =
get_option (
options ,
:strip_uploads ,
2020-12-12 10:37:14 -07:00
strip_uploads_message ,
strip_uploads_default
2020-10-12 10:18:39 -06:00
) === " y "
anonymize_uploads =
get_option (
options ,
:anonymize_uploads ,
" Do you want to anonymize the filenames of uploads? (y/n) " ,
" n "
) === " y "
dedupe_uploads =
get_option (
options ,
:dedupe_uploads ,
" Do you want to deduplicate uploaded files? (y/n) " ,
" n "
) === " y "
2020-02-24 12:52:38 -07:00
Config . put ( [ :instance , :static_dir ] , static_dir )
2018-06-28 18:24:51 -06:00
secret = :crypto . strong_rand_bytes ( 64 ) |> Base . encode64 ( ) |> binary_part ( 0 , 64 )
2019-04-20 06:42:19 -06:00
jwt_secret = :crypto . strong_rand_bytes ( 64 ) |> Base . encode64 ( ) |> binary_part ( 0 , 64 )
2019-01-20 17:16:41 -07:00
signing_salt = :crypto . strong_rand_bytes ( 8 ) |> Base . encode64 ( ) |> binary_part ( 0 , 8 )
2021-12-15 14:17:11 -07:00
lv_signing_salt = :crypto . strong_rand_bytes ( 8 ) |> Base . encode64 ( ) |> binary_part ( 0 , 8 )
2018-12-06 10:16:51 -07:00
{ web_push_public_key , web_push_private_key } = :crypto . generate_key ( :ecdh , :prime256v1 )
2019-06-21 10:30:25 -06:00
template_dir = Application . app_dir ( :pleroma , " priv " ) <> " /templates "
2018-06-28 18:24:51 -06:00
result_config =
EEx . eval_file (
2019-06-21 10:30:25 -06:00
template_dir <> " /sample_config.eex " ,
2018-06-28 18:24:51 -06:00
domain : domain ,
2018-12-15 03:00:54 -07:00
port : port ,
2018-06-28 18:24:51 -06:00
email : email ,
2019-04-10 04:57:41 -06:00
notify_email : notify_email ,
2018-06-28 18:24:51 -06:00
name : name ,
dbhost : dbhost ,
dbname : dbname ,
dbuser : dbuser ,
dbpass : dbpass ,
2018-12-06 10:16:51 -07:00
secret : secret ,
2019-04-20 06:42:19 -06:00
jwt_secret : jwt_secret ,
2019-01-20 17:16:41 -07:00
signing_salt : signing_salt ,
2021-12-15 14:17:11 -07:00
lv_signing_salt : lv_signing_salt ,
2018-12-06 10:16:51 -07:00
web_push_public_key : Base . url_encode64 ( web_push_public_key , padding : false ) ,
2019-06-14 09:45:05 -06:00
web_push_private_key : Base . url_encode64 ( web_push_private_key , padding : false ) ,
2019-06-19 18:59:16 -06:00
db_configurable? : db_configurable? ,
static_dir : static_dir ,
2019-06-22 03:54:16 -06:00
uploads_dir : uploads_dir ,
2019-07-09 13:57:41 -06:00
rum_enabled : rum_enabled ,
listen_ip : listen_ip ,
2020-10-12 10:18:39 -06:00
listen_port : listen_port ,
upload_filters :
upload_filters ( %{
strip : strip_uploads ,
anonymize : anonymize_uploads ,
dedupe : dedupe_uploads
} )
2018-06-28 18:24:51 -06:00
)
result_psql =
EEx . eval_file (
2019-06-21 10:30:25 -06:00
template_dir <> " /sample_psql.eex " ,
2018-06-28 18:24:51 -06:00
dbname : dbname ,
dbuser : dbuser ,
2019-06-22 03:54:16 -06:00
dbpass : dbpass ,
rum_enabled : rum_enabled
2018-06-28 18:24:51 -06:00
)
2021-01-28 02:39:53 -07:00
config_dir = Path . dirname ( config_path )
psql_dir = Path . dirname ( psql_path )
2021-01-28 03:20:25 -07:00
2023-06-21 16:58:05 -06:00
# Note: Distros requiring group read (0o750) on those directories should
# pre-create the directories.
2022-12-14 05:38:48 -07:00
to_create =
[ config_dir , psql_dir , static_dir , uploads_dir ]
|> Enum . reject ( & File . exists? / 1 )
for dir <- to_create do
File . mkdir_p! ( dir )
2023-06-21 16:58:05 -06:00
File . chmod! ( dir , 0o700 )
2022-12-14 05:38:48 -07:00
end
2021-01-28 02:39:53 -07:00
2019-06-21 17:07:05 -06:00
shell_info ( " Writing config to #{ config_path } . " )
2018-06-28 18:24:51 -06:00
2023-06-21 16:58:05 -06:00
# Sadly no fchmod(2) equivalent in Elixir…
File . touch! ( config_path )
File . chmod! ( config_path , 0o640 )
2018-06-28 18:24:51 -06:00
File . write ( config_path , result_config )
2019-06-21 17:07:05 -06:00
shell_info ( " Writing the postgres script to #{ psql_path } . " )
2018-06-28 18:24:51 -06:00
File . write ( psql_path , result_psql )
2020-05-20 12:16:40 -06:00
write_robots_txt ( static_dir , indexable , template_dir )
2019-04-02 13:09:16 -06:00
2019-06-19 17:05:19 -06:00
shell_info (
2020-02-25 12:13:08 -07:00
" \n All files successfully written! Refer to the installation instructions for your platform for next steps. "
2018-06-28 18:24:51 -06:00
)
2020-02-25 12:13:08 -07:00
if db_configurable? do
shell_info (
" Please transfer your config to the database after running database migrations. Refer to \" Transfering the config to/from the database \" section of the docs for more information. "
)
end
2018-06-28 18:24:51 -06:00
else
2019-06-19 17:05:19 -06:00
shell_error (
2018-06-28 18:24:51 -06:00
" The task would have overwritten the following files: \n " <>
2023-06-21 16:58:05 -06:00
Enum . map_join ( will_overwrite , & " - #{ &1 } \n " ) <> " Rerun with `--force` to overwrite them. "
2018-06-28 18:24:51 -06:00
)
end
end
2019-04-02 13:09:16 -06:00
2020-05-20 12:16:40 -06:00
defp write_robots_txt ( static_dir , indexable , template_dir ) do
2019-04-02 13:09:16 -06:00
robots_txt =
EEx . eval_file (
2019-06-21 10:30:25 -06:00
template_dir <> " /robots_txt.eex " ,
2019-04-02 13:09:16 -06:00
indexable : indexable
)
robots_txt_path = Path . join ( static_dir , " robots.txt " )
if File . exists? ( robots_txt_path ) do
File . cp! ( robots_txt_path , " #{ robots_txt_path } .bak " )
2019-06-19 17:05:19 -06:00
shell_info ( " Backing up existing robots.txt to #{ robots_txt_path } .bak " )
2019-04-02 13:09:16 -06:00
end
File . write ( robots_txt_path , robots_txt )
2019-06-19 17:05:19 -06:00
shell_info ( " Writing #{ robots_txt_path } . " )
2019-04-02 13:09:16 -06:00
end
2020-10-12 10:18:39 -06:00
defp upload_filters ( filters ) when is_map ( filters ) do
enabled_filters =
if filters . strip do
2020-11-14 14:27:13 -07:00
[ Pleroma.Upload.Filter.Exiftool ]
2020-10-12 10:18:39 -06:00
else
[ ]
end
enabled_filters =
if filters . anonymize do
enabled_filters ++ [ Pleroma.Upload.Filter.AnonymizeFilename ]
else
enabled_filters
end
enabled_filters =
if filters . dedupe do
enabled_filters ++ [ Pleroma.Upload.Filter.Dedupe ]
else
enabled_filters
end
enabled_filters
end
2018-06-28 18:24:51 -06:00
end