A feature for shareable emoji packs, use it in download_from & tests

This commit is contained in:
Ekaterina Vaartis 2019-09-11 22:58:55 +03:00
parent 74fb6d8647
commit 36f2275dc9
3 changed files with 88 additions and 50 deletions

View file

@ -153,64 +153,79 @@ def download_shared(conn, %{"name" => name}) do
from that instance, otherwise it will be downloaded from the fallback source, if there is one. from that instance, otherwise it will be downloaded from the fallback source, if there is one.
""" """
def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do
full_pack = shareable_packs_available =
"#{address}/api/pleroma/emoji/packs/list" "#{address}/nodeinfo/2.1.json"
|> Tesla.get!() |> Tesla.get!()
|> Map.get(:body) |> Map.get(:body)
|> Jason.decode!() |> Jason.decode!()
|> Map.get(name) |> Map.get("features")
|> Enum.member?("shareable_emoji_packs")
pack_info_res = if shareable_packs_available do
case full_pack["pack"] do full_pack =
%{"share-files" => true, "can-download" => true, "download-sha256" => sha} -> "#{address}/api/pleroma/emoji/packs/list"
{:ok, |> Tesla.get!()
%{ |> Map.get(:body)
sha: sha, |> Jason.decode!()
uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}" |> Map.get(name)
}}
%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) -> pack_info_res =
{:ok, case full_pack["pack"] do
%{ %{"share-files" => true, "can-download" => true, "download-sha256" => sha} ->
sha: sha, {:ok,
uri: src, %{
fallback: true sha: sha,
}} uri: "#{address}/api/pleroma/emoji/packs/download_shared/#{name}"
}}
_ -> %{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) ->
{:error, "The pack was not set as shared and there is no fallback src to download from"} {:ok,
%{
sha: sha,
uri: src,
fallback: true
}}
_ ->
{:error,
"The pack was not set as shared and there is no fallback src to download from"}
end
with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res,
%{body: emoji_archive} <- Tesla.get!(uri),
{_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do
local_name = data["as"] || name
pack_dir = Path.join(@emoji_dir_path, local_name)
File.mkdir_p!(pack_dir)
files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files
{:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files)
# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256
# in it to depend on itself
if pinfo[:fallback] do
pack_file_path = Path.join(pack_dir, "pack.json")
File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true))
end
json(conn, "ok")
else
{:error, e} ->
conn |> put_status(:internal_server_error) |> json(%{error: e})
{:checksum, _} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"})
end end
with {:ok, %{sha: sha, uri: uri} = pinfo} <- pack_info_res,
%{body: emoji_archive} <- Tesla.get!(uri),
{_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do
local_name = data["as"] || name
pack_dir = Path.join(@emoji_dir_path, local_name)
File.mkdir_p!(pack_dir)
files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
files = if pinfo[:fallback], do: files, else: ['pack.json'] ++ files
{:ok, _} = :zip.unzip(emoji_archive, cwd: to_charlist(pack_dir), file_list: files)
# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256
# in it to depend on itself
if pinfo[:fallback] do
pack_file_path = Path.join(pack_dir, "pack.json")
File.write!(pack_file_path, Jason.encode!(full_pack, pretty: true))
end
json(conn, "ok")
else else
{:error, e} -> conn
conn |> put_status(:internal_server_error) |> json(%{error: e}) |> put_status(:internal_server_error)
|> json(%{error: "The requested instance does not support sharing emoji packs"})
{:checksum, _} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"})
end end
end end

View file

@ -57,6 +57,7 @@ def raw_nodeinfo do
"mastodon_api_streaming", "mastodon_api_streaming",
"polls", "polls",
"pleroma_explicit_addressing", "pleroma_explicit_addressing",
"shareable_emoji_packs",
if Config.get([:media_proxy, :enabled]) do if Config.get([:media_proxy, :enabled]) do
"media_proxy" "media_proxy"
end, end,

View file

@ -54,6 +54,12 @@ test "downloading shared & unshared packs from another instance via download_fro
end) end)
mock(fn mock(fn
%{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} ->
json(%{features: []})
%{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
json(%{features: ["shareable_emoji_packs"]})
%{ %{
method: :get, method: :get,
url: "https://example.com/api/pleroma/emoji/packs/list" url: "https://example.com/api/pleroma/emoji/packs/list"
@ -87,6 +93,22 @@ test "downloading shared & unshared packs from another instance via download_fro
conn = build_conn() |> assign(:user, admin) conn = build_conn() |> assign(:user, admin)
assert (conn
|> put_req_header("content-type", "application/json")
|> post(
emoji_api_path(
conn,
:download_from
),
%{
instance_address: "https://old-instance",
pack_name: "test_pack",
as: "test_pack2"
}
|> Jason.encode!()
)
|> json_response(500))["error"] =~ "does not support"
assert conn assert conn
|> put_req_header("content-type", "application/json") |> put_req_header("content-type", "application/json")
|> post( |> post(