diff options
author | Bryan Paxton <39971740+starbelly@users.noreply.github.com> | 2019-03-07 10:54:01 -0600 |
---|---|---|
committer | Tristan Sloughter <t@crashfast.com> | 2019-03-07 09:54:01 -0700 |
commit | 209c02ec57c2cc3207ee0174c3af3675b8dc8f79 (patch) | |
tree | e07b25a27a2c4cc438db75d8d066179b4e57f3f7 /src/r3_hex_repo.erl | |
parent | 9e2e54afd74104ecb05c55e033803f41932eb940 (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.erl | 174 |
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. |