logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

instance.ex (11006B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Mix.Tasks.Pleroma.Instance do
  5. use Mix.Task
  6. import Mix.Pleroma
  7. alias Pleroma.Config
  8. @shortdoc "Manages Pleroma instance"
  9. @moduledoc File.read!("docs/administration/CLI_tasks/instance.md")
  10. def run(["gen" | rest]) do
  11. {options, [], []} =
  12. OptionParser.parse(
  13. rest,
  14. strict: [
  15. force: :boolean,
  16. output: :string,
  17. output_psql: :string,
  18. domain: :string,
  19. instance_name: :string,
  20. admin_email: :string,
  21. notify_email: :string,
  22. dbhost: :string,
  23. dbname: :string,
  24. dbuser: :string,
  25. dbpass: :string,
  26. rum: :string,
  27. indexable: :string,
  28. db_configurable: :string,
  29. uploads_dir: :string,
  30. static_dir: :string,
  31. listen_ip: :string,
  32. listen_port: :string,
  33. strip_uploads_location: :string,
  34. read_uploads_description: :string,
  35. anonymize_uploads: :string,
  36. dedupe_uploads: :string
  37. ],
  38. aliases: [
  39. o: :output,
  40. f: :force
  41. ]
  42. )
  43. paths =
  44. [config_path, psql_path] = [
  45. Keyword.get(options, :output, "config/generated_config.exs"),
  46. Keyword.get(options, :output_psql, "config/setup_db.psql")
  47. ]
  48. will_overwrite = Enum.filter(paths, &File.exists?/1)
  49. proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
  50. if proceed? do
  51. [domain, port | _] =
  52. String.split(
  53. get_option(
  54. options,
  55. :domain,
  56. "What domain will your instance use? (e.g pleroma.soykaf.com)"
  57. ),
  58. ":"
  59. ) ++ [443]
  60. name =
  61. get_option(
  62. options,
  63. :instance_name,
  64. "What is the name of your instance? (e.g. The Corndog Emporium)",
  65. domain
  66. )
  67. email = get_option(options, :admin_email, "What is your admin email address?")
  68. notify_email =
  69. get_option(
  70. options,
  71. :notify_email,
  72. "What email address do you want to use for sending email notifications?",
  73. email
  74. )
  75. indexable =
  76. get_option(
  77. options,
  78. :indexable,
  79. "Do you want search engines to index your site? (y/n)",
  80. "y"
  81. ) === "y"
  82. db_configurable? =
  83. get_option(
  84. options,
  85. :db_configurable,
  86. "Do you want to store the configuration in the database (allows controlling it from admin-fe)? (y/n)",
  87. "n"
  88. ) === "y"
  89. dbhost = get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
  90. dbname = get_option(options, :dbname, "What is the name of your database?", "pleroma")
  91. dbuser =
  92. get_option(
  93. options,
  94. :dbuser,
  95. "What is the user used to connect to your database?",
  96. "pleroma"
  97. )
  98. dbpass =
  99. get_option(
  100. options,
  101. :dbpass,
  102. "What is the password used to connect to your database?",
  103. :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64),
  104. "autogenerated"
  105. )
  106. rum_enabled =
  107. get_option(
  108. options,
  109. :rum,
  110. "Would you like to use RUM indices?",
  111. "n"
  112. ) === "y"
  113. listen_port =
  114. get_option(
  115. options,
  116. :listen_port,
  117. "What port will the app listen to (leave it if you are using the default setup with nginx)?",
  118. 4000
  119. )
  120. listen_ip =
  121. get_option(
  122. options,
  123. :listen_ip,
  124. "What ip will the app listen to (leave it if you are using the default setup with nginx)?",
  125. "127.0.0.1"
  126. )
  127. uploads_dir =
  128. get_option(
  129. options,
  130. :uploads_dir,
  131. "What directory should media uploads go in (when using the local uploader)?",
  132. Config.get([Pleroma.Uploaders.Local, :uploads])
  133. )
  134. |> Path.expand()
  135. static_dir =
  136. get_option(
  137. options,
  138. :static_dir,
  139. "What directory should custom public files be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)?",
  140. Config.get([:instance, :static_dir])
  141. )
  142. |> Path.expand()
  143. {strip_uploads_location_message, strip_uploads_location_default} =
  144. if Pleroma.Utils.command_available?("exiftool") do
  145. {"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)",
  146. "y"}
  147. else
  148. {"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)",
  149. "n"}
  150. end
  151. strip_uploads_location =
  152. get_option(
  153. options,
  154. :strip_uploads_location,
  155. strip_uploads_location_message,
  156. strip_uploads_location_default
  157. ) === "y"
  158. {read_uploads_description_message, read_uploads_description_default} =
  159. if Pleroma.Utils.command_available?("exiftool") do
  160. {"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as installed. (y/n)",
  161. "y"}
  162. else
  163. {"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as not installed, please install it if you answer yes. (y/n)",
  164. "n"}
  165. end
  166. read_uploads_description =
  167. get_option(
  168. options,
  169. :read_uploads_description,
  170. read_uploads_description_message,
  171. read_uploads_description_default
  172. ) === "y"
  173. anonymize_uploads =
  174. get_option(
  175. options,
  176. :anonymize_uploads,
  177. "Do you want to anonymize the filenames of uploads? (y/n)",
  178. "n"
  179. ) === "y"
  180. dedupe_uploads =
  181. get_option(
  182. options,
  183. :dedupe_uploads,
  184. "Do you want to deduplicate uploaded files? (y/n)",
  185. "n"
  186. ) === "y"
  187. Config.put([:instance, :static_dir], static_dir)
  188. secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
  189. jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
  190. signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
  191. lv_signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
  192. {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)
  193. template_dir = Application.app_dir(:pleroma, "priv") <> "/templates"
  194. result_config =
  195. EEx.eval_file(
  196. template_dir <> "/sample_config.eex",
  197. domain: domain,
  198. port: port,
  199. email: email,
  200. notify_email: notify_email,
  201. name: name,
  202. dbhost: dbhost,
  203. dbname: dbname,
  204. dbuser: dbuser,
  205. dbpass: dbpass,
  206. secret: secret,
  207. jwt_secret: jwt_secret,
  208. signing_salt: signing_salt,
  209. lv_signing_salt: lv_signing_salt,
  210. web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),
  211. web_push_private_key: Base.url_encode64(web_push_private_key, padding: false),
  212. db_configurable?: db_configurable?,
  213. static_dir: static_dir,
  214. uploads_dir: uploads_dir,
  215. rum_enabled: rum_enabled,
  216. listen_ip: listen_ip,
  217. listen_port: listen_port,
  218. upload_filters:
  219. upload_filters(%{
  220. strip_location: strip_uploads_location,
  221. read_description: read_uploads_description,
  222. anonymize: anonymize_uploads,
  223. dedupe: dedupe_uploads
  224. })
  225. )
  226. result_psql =
  227. EEx.eval_file(
  228. template_dir <> "/sample_psql.eex",
  229. dbname: dbname,
  230. dbuser: dbuser,
  231. dbpass: dbpass,
  232. rum_enabled: rum_enabled
  233. )
  234. config_dir = Path.dirname(config_path)
  235. psql_dir = Path.dirname(psql_path)
  236. # Note: Distros requiring group read (0o750) on those directories should
  237. # pre-create the directories.
  238. [config_dir, psql_dir, static_dir, uploads_dir]
  239. |> Enum.reject(&File.exists?/1)
  240. |> Enum.each(fn dir ->
  241. File.mkdir_p!(dir)
  242. File.chmod!(dir, 0o700)
  243. end)
  244. shell_info("Writing config to #{config_path}.")
  245. # Sadly no fchmod(2) equivalent in Elixir…
  246. File.touch!(config_path)
  247. File.chmod!(config_path, 0o640)
  248. File.write(config_path, result_config)
  249. shell_info("Writing the postgres script to #{psql_path}.")
  250. File.write(psql_path, result_psql)
  251. write_robots_txt(static_dir, indexable, template_dir)
  252. shell_info(
  253. "\n All files successfully written! Refer to the installation instructions for your platform for next steps."
  254. )
  255. if db_configurable? do
  256. shell_info(
  257. " Please transfer your config to the database after running database migrations. Refer to \"Transferring the config to/from the database\" section of the docs for more information."
  258. )
  259. end
  260. else
  261. shell_error(
  262. "The task would have overwritten the following files:\n" <>
  263. Enum.map_join(will_overwrite, &"- #{&1}\n") <> "Rerun with `--force` to overwrite them."
  264. )
  265. end
  266. end
  267. defp write_robots_txt(static_dir, indexable, template_dir) do
  268. robots_txt =
  269. EEx.eval_file(
  270. template_dir <> "/robots_txt.eex",
  271. indexable: indexable
  272. )
  273. robots_txt_path = Path.join(static_dir, "robots.txt")
  274. if File.exists?(robots_txt_path) do
  275. File.cp!(robots_txt_path, "#{robots_txt_path}.bak")
  276. shell_info("Backing up existing robots.txt to #{robots_txt_path}.bak")
  277. end
  278. File.write(robots_txt_path, robots_txt)
  279. shell_info("Writing #{robots_txt_path}.")
  280. end
  281. defp upload_filters(filters) when is_map(filters) do
  282. enabled_filters =
  283. if filters.strip_location do
  284. [Pleroma.Upload.Filter.Exiftool.StripLocation]
  285. else
  286. []
  287. end
  288. enabled_filters =
  289. if filters.read_description do
  290. enabled_filters ++ [Pleroma.Upload.Filter.Exiftool.ReadDescription]
  291. else
  292. enabled_filters
  293. end
  294. enabled_filters =
  295. if filters.anonymize do
  296. enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename]
  297. else
  298. enabled_filters
  299. end
  300. enabled_filters =
  301. if filters.dedupe do
  302. enabled_filters ++ [Pleroma.Upload.Filter.Dedupe]
  303. else
  304. enabled_filters
  305. end
  306. enabled_filters
  307. end
  308. end