summaryrefslogtreecommitdiff
path: root/src/r3_hex_repo.erl
diff options
context:
space:
mode:
authorBryan Paxton <39971740+starbelly@users.noreply.github.com>2019-03-07 10:54:01 -0600
committerTristan Sloughter <t@crashfast.com>2019-03-07 09:54:01 -0700
commit209c02ec57c2cc3207ee0174c3af3675b8dc8f79 (patch)
treee07b25a27a2c4cc438db75d8d066179b4e57f3f7 /src/r3_hex_repo.erl
parent9e2e54afd74104ecb05c55e033803f41932eb940 (diff)
Fix fetching of private packages from orgs on hex repos (#2020)
- vendor in hex_core at v0.5.0 - Change where repo_name should be the org and not the parent - Changed rebar_utils:url_append_path/2 to not explicitly add a '?', this is returned in the Query chunk by http_uri:parse/1 (e.g., "?foo=bar") - update organization_merging test to expect the sub-repo as the repo_name - Add tests for rebar_utils:url_append_path/2 - Stop referencing/setting "organization" in config and use new organization settings (api_repository and repo_organization) - Do not set (assume) the read key is valid for any/every repo - Set repo_organization and api_repository to org - Update tests to check for new config opts
Diffstat (limited to 'src/r3_hex_repo.erl')
-rw-r--r--src/r3_hex_repo.erl174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/r3_hex_repo.erl b/src/r3_hex_repo.erl
new file mode 100644
index 0000000..dd8264f
--- /dev/null
+++ b/src/r3_hex_repo.erl
@@ -0,0 +1,174 @@
+%% Vendored from hex_core v0.5.0, do not edit manually
+
+-module(r3_hex_repo).
+-export([
+ get_names/1,
+ get_versions/1,
+ get_package/2,
+ get_tarball/3
+]).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+%% @doc
+%% Gets names resource from the repository.
+%%
+%% Examples:
+%%
+%% ```
+%% > r3_hex_repo:get_names(r3_hex_core:default_config()).
+%% {ok, {200, ...,
+%% [
+%% #{name => <<"package1">>},
+%% #{name => <<"package2">>},
+%% ]}}
+%% '''
+%% @end
+get_names(Config) when is_map(Config) ->
+ Verify = maps:get(repo_verify_origin, Config, true),
+ Decoder = fun(Data) ->
+ case Verify of
+ true -> r3_hex_registry:decode_names(Data, repo_name(Config));
+ false -> r3_hex_registry:decode_names(Data, no_verify)
+ end
+ end,
+ get_protobuf(Config, <<"names">>, Decoder).
+
+%% @doc
+%% Gets versions resource from the repository.
+%%
+%% Examples:
+%%
+%% ```
+%% > r3_hex_repo:get_versions(Config).
+%% {ok, {200, ...,
+%% [
+%% #{name => <<"package1">>, retired => [],
+%% versions => [<<"1.0.0">>]},
+%% #{name => <<"package2">>, retired => [<<"0.5.0>>"],
+%% versions => [<<"0.5.0">>, <<"1.0.0">>]},
+%% ]}}
+%% '''
+%% @end
+get_versions(Config) when is_map(Config) ->
+ Verify = maps:get(repo_verify_origin, Config, true),
+ Decoder = fun(Data) ->
+ case Verify of
+ true -> r3_hex_registry:decode_versions(Data, repo_name(Config));
+ false -> r3_hex_registry:decode_versions(Data, no_verify)
+ end
+ end,
+ get_protobuf(Config, <<"versions">>, Decoder).
+
+%% @doc
+%% Gets package resource from the repository.
+%%
+%% Examples:
+%%
+%% ```
+%% > r3_hex_repo:get_package(r3_hex_core:default_config(), <<"package1">>).
+%% {ok, {200, ...,
+%% {
+%% #{checksum => ..., version => <<"0.5.0">>, dependencies => []},
+%% #{checksum => ..., version => <<"1.0.0">>, dependencies => [
+%% #{package => <<"package2">>, optional => true, requirement => <<"~> 0.1">>}
+%% ]},
+%% ]}}
+%% '''
+%% @end
+get_package(Config, Name) when is_binary(Name) and is_map(Config) ->
+ Verify = maps:get(repo_verify_origin, Config, true),
+ Decoder = fun(Data) ->
+ case Verify of
+ true -> r3_hex_registry:decode_package(Data, repo_name(Config), Name);
+ false -> r3_hex_registry:decode_package(Data, no_verify, no_verify)
+ end
+ end,
+ get_protobuf(Config, <<"packages/", Name/binary>>, Decoder).
+
+%% @doc
+%% Gets tarball from the repository.
+%%
+%% Examples:
+%%
+%% ```
+%% > {ok, {200, _, Tarball}} = r3_hex_repo:get_tarball(<<"package1">>, <<"1.0.0">>, r3_hex_core:default_config()),
+%% > {ok, #{metadata := Metadata}} = r3_hex_tarball:unpack(Tarball, memory).
+%% '''
+%% @end
+get_tarball(Config, Name, Version) ->
+ ReqHeaders = make_headers(Config),
+
+ case get(Config, tarball_url(Config, Name, Version), ReqHeaders) of
+ {ok, {200, RespHeaders, Tarball}} ->
+ {ok, {200, RespHeaders, Tarball}};
+
+ Other ->
+ Other
+ end.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
+get(Config, URI, Headers) ->
+ r3_hex_http:request(Config, get, URI, Headers, undefined).
+
+get_protobuf(Config, Path, Decoder) ->
+ PublicKey = maps:get(repo_public_key, Config),
+ ReqHeaders = make_headers(Config),
+
+ case get(Config, build_url(Config, Path), ReqHeaders) of
+ {ok, {200, RespHeaders, Compressed}} ->
+ Signed = zlib:gunzip(Compressed),
+ case decode(Signed, PublicKey, Decoder, Config) of
+ {ok, Decoded} ->
+ {ok, {200, RespHeaders, Decoded}};
+
+ {error, _} = Error ->
+ Error
+ end;
+
+ Other ->
+ Other
+ end.
+
+decode(Signed, PublicKey, Decoder, Config) ->
+ Verify = maps:get(repo_verify, Config, true),
+
+ case Verify of
+ true ->
+ case r3_hex_registry:decode_and_verify_signed(Signed, PublicKey) of
+ {ok, Payload} ->
+ Decoder(Payload);
+ Other ->
+ Other
+ end;
+ false ->
+ #{payload := Payload} = r3_hex_registry:decode_signed(Signed),
+ Decoder(Payload)
+ end.
+
+repo_name(#{repo_organization := Name}) when is_binary(Name) -> Name;
+repo_name(#{repo_name := Name}) when is_binary(Name) -> Name.
+
+tarball_url(Config, Name, Version) ->
+ Filename = tarball_filename(Name, Version),
+ build_url(Config, <<"tarballs/", Filename/binary>>).
+
+build_url(#{repo_url := URI, repo_organization := Org}, Path) when is_binary(Org) ->
+ <<URI/binary, "/repos/", Org/binary, "/", Path/binary>>;
+build_url(#{repo_url := URI, repo_organization := undefined}, Path) ->
+ <<URI/binary, "/", Path/binary>>.
+
+tarball_filename(Name, Version) ->
+ <<Name/binary, "-", Version/binary, ".tar">>.
+
+make_headers(Config) ->
+ maps:fold(fun set_header/3, #{}, Config).
+
+set_header(http_etag, ETag, Headers) when is_binary(ETag) -> maps:put(<<"if-none-match">>, ETag, Headers);
+set_header(repo_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers);
+set_header(_, _, Headers) -> Headers.