diff options
-rw-r--r-- | src/rebar_fetch.erl | 48 | ||||
-rw-r--r-- | src/rebar_packages.erl | 10 | ||||
-rw-r--r-- | src/rebar_prv_install_deps.erl | 16 |
3 files changed, 55 insertions, 19 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])))). diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl index 4ab5f9f..a344328 100644 --- a/src/rebar_packages.erl +++ b/src/rebar_packages.erl @@ -3,6 +3,7 @@ -export([get_packages/1 ,registry/1 ,check_registry/3 + ,registry_checksum/2 ,find_highest_matching/3]). -export_type([package/0]). @@ -66,6 +67,15 @@ check_registry(Pkg, Vsn, State) -> false end. +registry_checksum({pkg, Name, Vsn}, State) -> + {ok, Registry} = registry(State), + case ets:lookup(Registry, {Name, Vsn}) of + [{{_, _}, [_, Checksum | _]}] -> + Checksum; + [] -> + none + end. + %% Hex supports use of ~> to specify the version required for a dependency. %% Since rebar3 requires exact versions to choose from we find the highest %% available version of the dep that passes the constraint. diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index bc0a113..2570bc0 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -563,10 +563,10 @@ fetch_app(AppInfo, AppDir, State) -> ?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]), Source = rebar_app_info:source(AppInfo), case rebar_fetch:download_source(AppDir, Source, State) of - {error, Reason} -> - throw(Reason); - Result -> - Result + true -> + true; + Error -> + throw(Error) end. update_app_info(AppInfo) -> @@ -587,10 +587,10 @@ maybe_upgrade(AppInfo, AppDir, true, State) -> true -> ?INFO("Upgrading ~s", [rebar_app_info:name(AppInfo)]), case rebar_fetch:download_source(AppDir, Source, State) of - {error, Reason} -> - throw(Reason); - Result -> - Result + true -> + true; + Error -> + throw(Error) end; false -> ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]), |