logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

emoji_pack_controller_test.exs (19638B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
  5. use Pleroma.Web.ConnCase
  6. import Tesla.Mock
  7. import Pleroma.Factory
  8. @emoji_path Path.join(
  9. Pleroma.Config.get!([:instance, :static_dir]),
  10. "emoji"
  11. )
  12. setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
  13. setup do: clear_config([:instance, :public], true)
  14. setup do
  15. admin = insert(:user, is_admin: true)
  16. token = insert(:oauth_admin_token, user: admin)
  17. admin_conn =
  18. build_conn()
  19. |> assign(:user, admin)
  20. |> assign(:token, token)
  21. Pleroma.Emoji.reload()
  22. {:ok, %{admin_conn: admin_conn}}
  23. end
  24. test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do
  25. Config.put([:instance, :public], false)
  26. conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
  27. end
  28. test "GET /api/pleroma/emoji/packs", %{conn: conn} do
  29. resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
  30. assert resp["count"] == 3
  31. assert resp["packs"]
  32. |> Map.keys()
  33. |> length() == 3
  34. shared = resp["packs"]["test_pack"]
  35. assert shared["files"] == %{"blank" => "blank.png", "blank2" => "blank2.png"}
  36. assert Map.has_key?(shared["pack"], "download-sha256")
  37. assert shared["pack"]["can-download"]
  38. assert shared["pack"]["share-files"]
  39. non_shared = resp["packs"]["test_pack_nonshared"]
  40. assert non_shared["pack"]["share-files"] == false
  41. assert non_shared["pack"]["can-download"] == false
  42. resp =
  43. conn
  44. |> get("/api/pleroma/emoji/packs?page_size=1")
  45. |> json_response_and_validate_schema(200)
  46. assert resp["count"] == 3
  47. packs = Map.keys(resp["packs"])
  48. assert length(packs) == 1
  49. [pack1] = packs
  50. resp =
  51. conn
  52. |> get("/api/pleroma/emoji/packs?page_size=1&page=2")
  53. |> json_response_and_validate_schema(200)
  54. assert resp["count"] == 3
  55. packs = Map.keys(resp["packs"])
  56. assert length(packs) == 1
  57. [pack2] = packs
  58. resp =
  59. conn
  60. |> get("/api/pleroma/emoji/packs?page_size=1&page=3")
  61. |> json_response_and_validate_schema(200)
  62. assert resp["count"] == 3
  63. packs = Map.keys(resp["packs"])
  64. assert length(packs) == 1
  65. [pack3] = packs
  66. assert [pack1, pack2, pack3] |> Enum.uniq() |> length() == 3
  67. end
  68. describe "GET /api/pleroma/emoji/packs/remote" do
  69. test "shareable instance", %{admin_conn: admin_conn, conn: conn} do
  70. resp =
  71. conn
  72. |> get("/api/pleroma/emoji/packs")
  73. |> json_response_and_validate_schema(200)
  74. mock(fn
  75. %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
  76. json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
  77. %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
  78. json(%{metadata: %{features: ["shareable_emoji_packs"]}})
  79. %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} ->
  80. json(resp)
  81. end)
  82. assert admin_conn
  83. |> get("/api/pleroma/emoji/packs/remote?url=https://example.com")
  84. |> json_response_and_validate_schema(200) == resp
  85. end
  86. test "non shareable instance", %{admin_conn: admin_conn} do
  87. mock(fn
  88. %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
  89. json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
  90. %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
  91. json(%{metadata: %{features: []}})
  92. end)
  93. assert admin_conn
  94. |> get("/api/pleroma/emoji/packs/remote?url=https://example.com")
  95. |> json_response_and_validate_schema(500) == %{
  96. "error" => "The requested instance does not support sharing emoji packs"
  97. }
  98. end
  99. end
  100. describe "GET /api/pleroma/emoji/packs/:name/archive" do
  101. test "download shared pack", %{conn: conn} do
  102. resp =
  103. conn
  104. |> get("/api/pleroma/emoji/packs/test_pack/archive")
  105. |> response(200)
  106. {:ok, arch} = :zip.unzip(resp, [:memory])
  107. assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end)
  108. assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end)
  109. end
  110. test "non existing pack", %{conn: conn} do
  111. assert conn
  112. |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive")
  113. |> json_response_and_validate_schema(:not_found) == %{
  114. "error" => "Pack test_pack_for_import does not exist"
  115. }
  116. end
  117. test "non downloadable pack", %{conn: conn} do
  118. assert conn
  119. |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive")
  120. |> json_response_and_validate_schema(:forbidden) == %{
  121. "error" =>
  122. "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
  123. }
  124. end
  125. end
  126. describe "POST /api/pleroma/emoji/packs/download" do
  127. test "shared pack from remote and non shared from fallback-src", %{
  128. admin_conn: admin_conn,
  129. conn: conn
  130. } do
  131. mock(fn
  132. %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
  133. json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
  134. %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
  135. json(%{metadata: %{features: ["shareable_emoji_packs"]}})
  136. %{
  137. method: :get,
  138. url: "https://example.com/api/pleroma/emoji/packs/test_pack"
  139. } ->
  140. conn
  141. |> get("/api/pleroma/emoji/packs/test_pack")
  142. |> json_response_and_validate_schema(200)
  143. |> json()
  144. %{
  145. method: :get,
  146. url: "https://example.com/api/pleroma/emoji/packs/test_pack/archive"
  147. } ->
  148. conn
  149. |> get("/api/pleroma/emoji/packs/test_pack/archive")
  150. |> response(200)
  151. |> text()
  152. %{
  153. method: :get,
  154. url: "https://example.com/api/pleroma/emoji/packs/test_pack_nonshared"
  155. } ->
  156. conn
  157. |> get("/api/pleroma/emoji/packs/test_pack_nonshared")
  158. |> json_response_and_validate_schema(200)
  159. |> json()
  160. %{
  161. method: :get,
  162. url: "https://nonshared-pack"
  163. } ->
  164. text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip"))
  165. end)
  166. assert admin_conn
  167. |> put_req_header("content-type", "multipart/form-data")
  168. |> post("/api/pleroma/emoji/packs/download", %{
  169. url: "https://example.com",
  170. name: "test_pack",
  171. as: "test_pack2"
  172. })
  173. |> json_response_and_validate_schema(200) == "ok"
  174. assert File.exists?("#{@emoji_path}/test_pack2/pack.json")
  175. assert File.exists?("#{@emoji_path}/test_pack2/blank.png")
  176. assert admin_conn
  177. |> delete("/api/pleroma/emoji/packs/test_pack2")
  178. |> json_response_and_validate_schema(200) == "ok"
  179. refute File.exists?("#{@emoji_path}/test_pack2")
  180. assert admin_conn
  181. |> put_req_header("content-type", "multipart/form-data")
  182. |> post(
  183. "/api/pleroma/emoji/packs/download",
  184. %{
  185. url: "https://example.com",
  186. name: "test_pack_nonshared",
  187. as: "test_pack_nonshared2"
  188. }
  189. )
  190. |> json_response_and_validate_schema(200) == "ok"
  191. assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json")
  192. assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png")
  193. assert admin_conn
  194. |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2")
  195. |> json_response_and_validate_schema(200) == "ok"
  196. refute File.exists?("#{@emoji_path}/test_pack_nonshared2")
  197. end
  198. test "nonshareable instance", %{admin_conn: admin_conn} do
  199. mock(fn
  200. %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} ->
  201. json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]})
  202. %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} ->
  203. json(%{metadata: %{features: []}})
  204. end)
  205. assert admin_conn
  206. |> put_req_header("content-type", "multipart/form-data")
  207. |> post(
  208. "/api/pleroma/emoji/packs/download",
  209. %{
  210. url: "https://old-instance",
  211. name: "test_pack",
  212. as: "test_pack2"
  213. }
  214. )
  215. |> json_response_and_validate_schema(500) == %{
  216. "error" => "The requested instance does not support sharing emoji packs"
  217. }
  218. end
  219. test "checksum fail", %{admin_conn: admin_conn} do
  220. mock(fn
  221. %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
  222. json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
  223. %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
  224. json(%{metadata: %{features: ["shareable_emoji_packs"]}})
  225. %{
  226. method: :get,
  227. url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha"
  228. } ->
  229. {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha")
  230. %Tesla.Env{status: 200, body: Jason.encode!(pack)}
  231. %{
  232. method: :get,
  233. url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive"
  234. } ->
  235. %Tesla.Env{
  236. status: 200,
  237. body: File.read!("test/instance_static/emoji/pack_bad_sha/pack_bad_sha.zip")
  238. }
  239. end)
  240. assert admin_conn
  241. |> put_req_header("content-type", "multipart/form-data")
  242. |> post("/api/pleroma/emoji/packs/download", %{
  243. url: "https://example.com",
  244. name: "pack_bad_sha",
  245. as: "pack_bad_sha2"
  246. })
  247. |> json_response_and_validate_schema(:internal_server_error) == %{
  248. "error" => "SHA256 for the pack doesn't match the one sent by the server"
  249. }
  250. end
  251. test "other error", %{admin_conn: admin_conn} do
  252. mock(fn
  253. %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
  254. json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
  255. %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
  256. json(%{metadata: %{features: ["shareable_emoji_packs"]}})
  257. %{
  258. method: :get,
  259. url: "https://example.com/api/pleroma/emoji/packs/test_pack"
  260. } ->
  261. {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack")
  262. %Tesla.Env{status: 200, body: Jason.encode!(pack)}
  263. end)
  264. assert admin_conn
  265. |> put_req_header("content-type", "multipart/form-data")
  266. |> post("/api/pleroma/emoji/packs/download", %{
  267. url: "https://example.com",
  268. name: "test_pack",
  269. as: "test_pack2"
  270. })
  271. |> json_response_and_validate_schema(:internal_server_error) == %{
  272. "error" =>
  273. "The pack was not set as shared and there is no fallback src to download from"
  274. }
  275. end
  276. end
  277. describe "PATCH /api/pleroma/emoji/packs/:name" do
  278. setup do
  279. pack_file = "#{@emoji_path}/test_pack/pack.json"
  280. original_content = File.read!(pack_file)
  281. on_exit(fn ->
  282. File.write!(pack_file, original_content)
  283. end)
  284. {:ok,
  285. pack_file: pack_file,
  286. new_data: %{
  287. "license" => "Test license changed",
  288. "homepage" => "https://pleroma.social",
  289. "description" => "Test description",
  290. "share-files" => false
  291. }}
  292. end
  293. test "for a pack without a fallback source", ctx do
  294. assert ctx[:admin_conn]
  295. |> put_req_header("content-type", "multipart/form-data")
  296. |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]})
  297. |> json_response_and_validate_schema(200) == ctx[:new_data]
  298. assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data]
  299. end
  300. test "for a pack with a fallback source", ctx do
  301. mock(fn
  302. %{
  303. method: :get,
  304. url: "https://nonshared-pack"
  305. } ->
  306. text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip"))
  307. end)
  308. new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
  309. new_data_with_sha =
  310. Map.put(
  311. new_data,
  312. "fallback-src-sha256",
  313. "1967BB4E42BCC34BCC12D57BE7811D3B7BE52F965BCE45C87BD377B9499CE11D"
  314. )
  315. assert ctx[:admin_conn]
  316. |> put_req_header("content-type", "multipart/form-data")
  317. |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data})
  318. |> json_response_and_validate_schema(200) == new_data_with_sha
  319. assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha
  320. end
  321. test "when the fallback source doesn't have all the files", ctx do
  322. mock(fn
  323. %{
  324. method: :get,
  325. url: "https://nonshared-pack"
  326. } ->
  327. {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory])
  328. text(empty_arch)
  329. end)
  330. new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
  331. assert ctx[:admin_conn]
  332. |> put_req_header("content-type", "multipart/form-data")
  333. |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data})
  334. |> json_response_and_validate_schema(:bad_request) == %{
  335. "error" => "The fallback archive does not have all files specified in pack.json"
  336. }
  337. end
  338. end
  339. describe "POST/DELETE /api/pleroma/emoji/packs/:name" do
  340. test "creating and deleting a pack", %{admin_conn: admin_conn} do
  341. assert admin_conn
  342. |> post("/api/pleroma/emoji/packs/test_created")
  343. |> json_response_and_validate_schema(200) == "ok"
  344. assert File.exists?("#{@emoji_path}/test_created/pack.json")
  345. assert Jason.decode!(File.read!("#{@emoji_path}/test_created/pack.json")) == %{
  346. "pack" => %{},
  347. "files" => %{},
  348. "files_count" => 0
  349. }
  350. assert admin_conn
  351. |> delete("/api/pleroma/emoji/packs/test_created")
  352. |> json_response_and_validate_schema(200) == "ok"
  353. refute File.exists?("#{@emoji_path}/test_created/pack.json")
  354. end
  355. test "if pack exists", %{admin_conn: admin_conn} do
  356. path = Path.join(@emoji_path, "test_created")
  357. File.mkdir(path)
  358. pack_file = Jason.encode!(%{files: %{}, pack: %{}})
  359. File.write!(Path.join(path, "pack.json"), pack_file)
  360. assert admin_conn
  361. |> post("/api/pleroma/emoji/packs/test_created")
  362. |> json_response_and_validate_schema(:conflict) == %{
  363. "error" => "A pack named \"test_created\" already exists"
  364. }
  365. on_exit(fn -> File.rm_rf(path) end)
  366. end
  367. test "with empty name", %{admin_conn: admin_conn} do
  368. assert admin_conn
  369. |> post("/api/pleroma/emoji/packs/ ")
  370. |> json_response_and_validate_schema(:bad_request) == %{
  371. "error" => "pack name cannot be empty"
  372. }
  373. end
  374. end
  375. test "deleting nonexisting pack", %{admin_conn: admin_conn} do
  376. assert admin_conn
  377. |> delete("/api/pleroma/emoji/packs/non_existing")
  378. |> json_response_and_validate_schema(:not_found) == %{
  379. "error" => "Pack non_existing does not exist"
  380. }
  381. end
  382. test "deleting with empty name", %{admin_conn: admin_conn} do
  383. assert admin_conn
  384. |> delete("/api/pleroma/emoji/packs/ ")
  385. |> json_response_and_validate_schema(:bad_request) == %{
  386. "error" => "pack name cannot be empty"
  387. }
  388. end
  389. test "filesystem import", %{admin_conn: admin_conn, conn: conn} do
  390. on_exit(fn ->
  391. File.rm!("#{@emoji_path}/test_pack_for_import/emoji.txt")
  392. File.rm!("#{@emoji_path}/test_pack_for_import/pack.json")
  393. end)
  394. resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
  395. refute Map.has_key?(resp["packs"], "test_pack_for_import")
  396. assert admin_conn
  397. |> get("/api/pleroma/emoji/packs/import")
  398. |> json_response_and_validate_schema(200) == ["test_pack_for_import"]
  399. resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
  400. assert resp["packs"]["test_pack_for_import"]["files"] == %{"blank" => "blank.png"}
  401. File.rm!("#{@emoji_path}/test_pack_for_import/pack.json")
  402. refute File.exists?("#{@emoji_path}/test_pack_for_import/pack.json")
  403. emoji_txt_content = """
  404. blank, blank.png, Fun
  405. blank2, blank.png
  406. foo, /emoji/test_pack_for_import/blank.png
  407. bar
  408. """
  409. File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content)
  410. assert admin_conn
  411. |> get("/api/pleroma/emoji/packs/import")
  412. |> json_response_and_validate_schema(200) == ["test_pack_for_import"]
  413. resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
  414. assert resp["packs"]["test_pack_for_import"]["files"] == %{
  415. "blank" => "blank.png",
  416. "blank2" => "blank.png",
  417. "foo" => "blank.png"
  418. }
  419. end
  420. describe "GET /api/pleroma/emoji/packs/:name" do
  421. test "shows pack.json", %{conn: conn} do
  422. assert %{
  423. "files" => files,
  424. "files_count" => 2,
  425. "pack" => %{
  426. "can-download" => true,
  427. "description" => "Test description",
  428. "download-sha256" => _,
  429. "homepage" => "https://pleroma.social",
  430. "license" => "Test license",
  431. "share-files" => true
  432. }
  433. } =
  434. conn
  435. |> get("/api/pleroma/emoji/packs/test_pack")
  436. |> json_response_and_validate_schema(200)
  437. assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"}
  438. assert %{
  439. "files" => files,
  440. "files_count" => 2
  441. } =
  442. conn
  443. |> get("/api/pleroma/emoji/packs/test_pack?page_size=1")
  444. |> json_response_and_validate_schema(200)
  445. assert files |> Map.keys() |> length() == 1
  446. assert %{
  447. "files" => files,
  448. "files_count" => 2
  449. } =
  450. conn
  451. |> get("/api/pleroma/emoji/packs/test_pack?page_size=1&page=2")
  452. |> json_response_and_validate_schema(200)
  453. assert files |> Map.keys() |> length() == 1
  454. end
  455. test "non existing pack", %{conn: conn} do
  456. assert conn
  457. |> get("/api/pleroma/emoji/packs/non_existing")
  458. |> json_response_and_validate_schema(:not_found) == %{
  459. "error" => "Pack non_existing does not exist"
  460. }
  461. end
  462. test "error name", %{conn: conn} do
  463. assert conn
  464. |> get("/api/pleroma/emoji/packs/ ")
  465. |> json_response_and_validate_schema(:bad_request) == %{
  466. "error" => "pack name cannot be empty"
  467. }
  468. end
  469. end
  470. end