diff options
Diffstat (limited to 'src/rebar_fetch.erl')
-rw-r--r-- | src/rebar_fetch.erl | 48 |
1 files changed, 37 insertions, 11 deletions
diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl index ec16089..16840eb 100644 --- a/src/rebar_fetch.erl +++ b/src/rebar_fetch.erl @@ -40,16 +40,7 @@ download_source(AppDir, Source, State) -> ok = rebar_file_utils:mv(TmpDir, filename:absname(AppDir1)), true; {tarball, File} -> - ec_file:mkdir_p(AppDir1), - {ok, Files} = erl_tar:extract(File, [memory]), - - code:del_path(filename:absname(filename:join(AppDir1, "ebin"))), - ec_file:remove(filename:absname(AppDir1), [recursive]), - - {"contents.tar.gz", Binary} = lists:keyfind("contents.tar.gz", 1, Files), - ok = erl_tar:extract({binary, Binary}, - [{cwd, filename:absname(AppDir1)}, compressed]), - true + verify_and_extract(File, Source, AppDir1, State) end catch C:T -> @@ -69,7 +60,11 @@ needs_update(AppDir, Source, State) -> end. format_error({fetch_fail, Source}) -> - io_lib:format("Failed to fetch and copy dep: ~p", [Source]). + io_lib:format("Failed to fetch and copy dep: ~p", [Source]); +format_error({bad_checksum, File}) -> + io_lib:format("Checksum mismatch against tarball in ~s", [File]); +format_error({bad_registry_checksum, File}) -> + io_lib:format("Checksum mismatch against registry in ~s", [File]). get_resource_type({Type, Location}, Resources) -> find_resource_module(Type, Location, Resources); @@ -93,3 +88,34 @@ find_resource_module(Type, Location, Resources) -> {Type, Module} -> Module end. + +verify_and_extract(File, Source, AppDir, State) -> + ec_file:mkdir_p(AppDir), + {ok, Files} = erl_tar:extract(File, [memory]), + + code:del_path(filename:absname(filename:join(AppDir, "ebin"))), + ec_file:remove(filename:absname(AppDir), [recursive]), + + {"contents.tar.gz", Contents} = lists:keyfind("contents.tar.gz", 1, Files), + {"VERSION", Version} = lists:keyfind("VERSION", 1, Files), + {"metadata.config", Meta} = lists:keyfind("metadata.config", 1, Files), + + Checksum = checksum(Contents, Version, Meta), + RegistryChecksum = rebar_packages:registry_checksum(Source, State), + {"CHECKSUM", TarChecksum} = lists:keyfind("CHECKSUM", 1, Files), + + if + Checksum =/= TarChecksum -> + ?PRV_ERROR({bad_checksum, File}); + Checksum =/= RegistryChecksum -> + ?PRV_ERROR({bad_registry_checksum, File}); + true -> + ok = erl_tar:extract({binary, Contents}, + [{cwd, filename:absname(AppDir)}, compressed]), + true + end. + +checksum(Contents, Version, Meta) -> + Blob = <<Version/binary, Meta/binary, Contents/binary>>, + <<X:256/big-unsigned-integer>> = crypto:hash(sha256, Blob), + list_to_binary(string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X])))). |