@ -1,7 +1,7 @@
% % Vendored from hex_core v0 . 5 . 1 , do not edit manually
% % Vendored from hex_core v0 . 6 . 8 , do not edit manually
- module ( r3_hex_tarball ) .
- export ( [ create / 2 , create_docs / 1 , unpack / 2 , format_checksum / 1 , format_error / 1 ] ) .
- export ( [ create / 2 , create_docs / 1 , unpack / 2 , unpack_docs / 2 , format_checksum/ 1 , format_error / 1 ] ) .
- ifdef ( TEST ) .
- export ( [ do_decode_metadata / 1 , gzip / 1 , normalize_requirements / 1 ] ) .
- endif .
@ -20,7 +20,7 @@
- type checksum ( ) : : binary ( ) .
- type contents ( ) : : #{ filename ( ) = > binary ( ) } .
- type filename ( ) : : string ( ) .
- type files ( ) : : [ filename ( ) | { filename ( ) , filename ( ) } ] | contents ( ) .
- type files ( ) : : [ { filename ( ) , filename ( ) | binary ( ) } ] .
- type metadata ( ) : : map ( ) .
- type tarball ( ) : : binary ( ) .
@ -31,34 +31,37 @@
% % @ doc
% % Creates a package tarball .
% %
% % Returns the binary of the tarball the " inner checksum " and " outer checksum " .
% % The inner checksum is deprecated in favor of the inner checksum .
% %
% % Examples :
% %
% % ` ` `
% % > Metadata = #{ < < " name " > > = > < < " foo " > > , < < " version " > > = > < < " 1.0.0 " > > } ,
% % > Files = [ { " src/foo.erl " , < < " -module(foo). " > > } ] ,
% % > { ok , { Tarball , Checksum } } = r3_hex_tarball : create ( Metadata , Files ) .
% % > Tarball .
% % < < 86 , 69 , . . . > >
% % > Checksum .
% % < < 40 , 32 , . . . > >
% % > r3_hex_tarball : create ( Metadata , Files ) .
% % { ok , #{ tarball = > < < 86 , 69 , . . . > > ,
% % outer_checksum = > < < 40 , 32 , . . . > > ,
% % inner_checksum = > < < 178 , 12 , . . . > > } }
% % '''
% % @ end
- spec create ( metadata ( ) , files ( ) ) - > { ok , { tarball ( ) , checksum ( ) } } .
- spec create ( metadata ( ) , files ( ) ) - > { ok , { tarball ( ) , checksum ( ) } } | { error , term ( ) } .
create ( Metadata , Files ) - >
MetadataBinary = encode_metadata ( Metadata ) ,
ContentsTarball = create_memory_tarball ( Files ) ,
ContentsTarballCompressed = gzip ( ContentsTarball ) ,
Checksum = checksum ( ? VERSION , MetadataBinary , ContentsTarballCompressed ) ,
ChecksumBase16 = encode_base16 ( Checksum ) ,
Inner Checksum = inner_ checksum( ? VERSION , MetadataBinary , ContentsTarballCompressed ) ,
Inner ChecksumBase16 = encode_base16 ( Inner Checksum) ,
OuterFiles = [
{ " VERSION " , ? VERSION } ,
{ " CHECKSUM " , ChecksumBase16 } ,
{ " CHECKSUM " , Inner ChecksumBase16} ,
{ " metadata.config " , MetadataBinary } ,
{ " contents.tar.gz " , ContentsTarballCompressed }
] ,
Tarball = create_memory_tarball ( OuterFiles ) ,
OuterChecksum = checksum ( Tarball ) ,
UncompressedSize = byte_size ( ContentsTarball ) ,
@ -67,7 +70,7 @@ create(Metadata, Files) ->
{ error , { tarball , too_big } } ;
false - >
{ ok , { Tarball , Checksum } }
{ ok , # {tarball = > Tarball , outer_checksum = > OuterChecksum , inner_checksum = > Inner Checksum} }
end .
% % @ doc
@ -77,19 +80,15 @@ create(Metadata, Files) ->
% %
% % ` ` `
% % > Files = [ { " doc/index.html " , < < " Docs " > > } ] ,
% % > { ok , { Tarball , Checksum } } = r3_hex_tarball : create_docs ( Files ) .
% % > Tarball .
% % % % = > < < 86 , 69 , . . . > >
% % > Checksum .
% % % % = > < < 40 , 32 , . . . > >
% % > r3_hex_tarball : create_docs ( Files ) .
% % { ok , < < 86 , 69 , . . . > > }
% % '''
% % @ end
- spec create_docs ( files ( ) ) - > { ok , { tarball ( ) , checksum ( ) } } .
- spec create_docs ( files ( ) ) - > { ok , tarball ( ) } .
create_docs ( Files ) - >
UncompressedTarball = create_memory_tarball ( Files ) ,
UncompressedSize = byte_size ( UncompressedTarball ) ,
Tarball = gzip ( UncompressedTarball ) ,
Checksum = checksum ( Tarball ) ,
Size = byte_size ( Tarball ) ,
case ( Size > ? TARBALL_MAX_SIZE ) or ( UncompressedSize > ? TARBALL_MAX_UNCOMPRESSED_SIZE ) of
@ -97,22 +96,25 @@ create_docs(Files) ->
{ error , { tarball , too_big } } ;
false - >
{ ok , { Tarball , Checksum } }
{ ok , Tarball }
end .
% % @ doc
% % Unpacks a package tarball .
% %
% % Remember to verify the outer tarball checksum against the registry checksum
% % returned from ` r3_hex_repo : get_package ( Config , Package ) ` .
% %
% % Examples :
% %
% % ` ` `
% % > r3_hex_tarball : unpack ( Tarball , memory ) .
% % { ok , #{ checksum = > < < . . . > > ,
% % { ok , #{ outer_ checksum = > < < . . . > > ,
% % contents = > [ { " src/foo.erl " , < < " -module(foo). " > > } ] ,
% % metadata = > #{ < < " name " > > = > < < " foo " > > , . . . } } }
% %
% % > r3_hex_tarball : unpack ( Tarball , " path/to/unpack " ) .
% % { ok , #{ checksum = > < < . . . > > ,
% % { ok , #{ outer_ checksum = > < < . . . > > ,
% % metadata = > #{ < < " name " > > = > < < " foo " > > , . . . } } }
% % '''
- spec unpack ( tarball ( ) , memory ) - >
@ -130,12 +132,33 @@ unpack(Tarball, Output) ->
{ error , { tarball , empty } } ;
{ ok , FileList } - >
do_unpack ( maps : from_list ( FileList ) , Output ) ;
OuterChecksum = crypto : hash ( sha256 , Tarball ) ,
do_unpack ( maps : from_list ( FileList ) , OuterChecksum , Output ) ;
{ error , Reason } - >
{ error , { tarball , Reason } }
end .
% % @ doc
% % Unpacks a documentation tarball .
% %
% % Examples :
% %
% % ` ` `
% % > r3_hex_tarball : unpack_docs ( Tarball , memory ) .
% % { ok , [ { " index.html " , < < " <!doctype> " > > } , . . . ] }
% %
% % > r3_hex_tarball : unpack_docs ( Tarball , " path/to/unpack " ) .
% % ok
% % '''
- spec unpack_docs ( tarball ( ) , memory ) - > { ok , contents ( ) } | { error , term ( ) } ;
( tarball ( ) , filename ( ) ) - > ok | { error , term ( ) } .
unpack_docs ( Tarball , _ ) when byte_size ( Tarball ) > ? TARBALL_MAX_SIZE - >
{ error , { tarball , too_big } } ;
unpack_docs ( Tarball , Output ) - >
unpack_tarball ( Tarball , Output ) .
% % @ doc
% % Returns base16 - encoded representation of checksum .
- spec format_checksum ( checksum ( ) ) - > binary ( ) .
@ -148,7 +171,6 @@ format_checksum(Checksum) ->
format_error ( { tarball , empty } ) - > " empty tarball " ;
format_error ( { tarball , too_big } ) - > " tarball is too big " ;
format_error ( { tarball , { missing_files , Files } } ) - > io_lib : format ( " missing files: ~p " , [ Files ] ) ;
format_error ( { tarball , { invalid_files , Files } } ) - > io_lib : format ( " invalid files: ~p " , [ Files ] ) ;
format_error ( { tarball , { bad_version , Vsn } } ) - > io_lib : format ( " unsupported version: ~p " , [ Vsn ] ) ;
format_error ( { tarball , invalid_checksum } ) - > " invalid tarball checksum " ;
format_error ( { tarball , Reason } ) - > " tarball error, " ++ r3_hex_erl_tar : format_error ( Reason ) ;
@ -168,13 +190,12 @@ format_error({checksum_mismatch, ExpectedChecksum, ActualChecksum}) ->
% % Internal functions
% % == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
checksum ( Version , MetadataBinary , ContentsBinary ) - >
inner_ checksum( Version , MetadataBinary , ContentsBinary ) - >
Blob = < < Version / binary , MetadataBinary / binary , ContentsBinary / binary > > ,
crypto : hash ( sha256 , Blob ) .
checksum ( ContentsBinary ) - >
Blob = < < ContentsBinary / binary > > ,
crypto : hash ( sha256 , Blob ) .
checksum ( ContentsBinary ) when is_binary ( ContentsBinary ) - >
crypto : hash ( sha256 , ContentsBinary ) .
encode_metadata ( Meta ) - >
Data = lists : map (
@ -184,9 +205,10 @@ encode_metadata(Meta) ->
end , maps : to_list ( Meta ) ) ,
iolist_to_binary ( Data ) .
do_unpack ( Files , Output ) - >
do_unpack ( Files , OuterChecksum , Out put ) - >
State = #{
checksum = > undefined ,
inner_checksum = > undefined ,
outer_checksum = > OuterChecksum ,
contents = > undefined ,
files = > Files ,
metadata = > undefined ,
@ -194,23 +216,23 @@ do_unpack(Files, Output) ->
} ,
State1 = check_files ( State ) ,
State2 = check_version ( State1 ) ,
State3 = check_checksum ( State2 ) ,
State3 = check_inner_ checksum ( State2 ) ,
State4 = decode_metadata ( State3 ) ,
finish_unpack ( State4 ) .
finish_unpack ( { error , _ } = Error ) - >
Error ;
finish_unpack ( #{ metadata : = Metadata , files : = Files , output : = Output } ) - >
true = maps : is_key ( " VERSION " , Files ) ,
Checksum = decode_base16 ( maps : get ( " CHECKSUM " , Files ) ) ,
finish_unpack ( #{ metadata : = Metadata , files : = Files , inner_checksum : = InnerChecksum , outer_checksum : = OuterChecksum , output : = Output } ) - >
_ Version = maps : get ( " VERSION " , Files ) ,
ContentsBinary = maps : get ( " contents.tar.gz " , Files ) ,
filelib : ensure_dir ( filename : join ( Output , " * " ) ) ,
case unpack_tarball ( ContentsBinary , Output ) of
ok - >
copy_metadata_config ( Output , maps : get ( " metadata.config " , Files ) ) ,
{ ok , #{ checksum = > Checksum , metadata = > Metadata } } ;
{ ok , #{ inner_ checksum = > InnerChecksum , outer_checksum = > Outer Checksum, metadata = > Metadata } } ;
{ ok , Contents } - >
{ ok , #{ checksum = > Checksum , metadata = > Metadata , contents = > Contents } } ;
{ ok , #{ inner_ checksum = > InnerChecksum , outer_checksum = > Outer Checksum, metadata = > Metadata , contents = > Contents } } ;
{ error , Reason } - >
{ error , { inner_tarball , Reason } }
@ -226,10 +248,7 @@ check_files(#{files := Files} = State) ->
State ;
{ error , { missing_keys , Keys } } - >
{ error , { tarball , { missing_files , Keys } } } ;
{ error , { unknown_keys , Keys } } - >
{ error , { tarball , { invalid_files , Keys } } }
{ error , { tarball , { missing_files , Keys } } }
end .
check_version ( { error , _ } = Error ) - >
@ -243,26 +262,27 @@ check_version(#{files := Files} = State) ->
{ error , { tarball , { bad_version , Version } } }
end .
check_checksum ( { error , _ } = Error ) - >
% Note : This checksum is deprecated
check_inner_checksum ( { error , _ } = Error ) - >
Error ;
check_checksum ( #{ files : = Files } = State ) - >
check_inner_ checksum ( #{ files : = Files } = State ) - >
ChecksumBase16 = maps : get ( " CHECKSUM " , Files ) ,
ExpectedChecksum = decode_base16 ( ChecksumBase16 ) ,
Version = maps : get ( " VERSION " , Files ) ,
MetadataBinary = maps : get ( " metadata.config " , Files ) ,
ContentsBinary = maps : get ( " contents.tar.gz " , Files ) ,
ActualChecksum = checksum ( Version , MetadataBinary , ContentsBinary ) ,
ActualChecksum = inner_ checksum( Version , MetadataBinary , ContentsBinary ) ,
if
byte_size ( ExpectedChecksum ) / = 32 - >
{ error , { tarball , invalid_checksum } } ;
{ error , { tarball , invalid_inner_ checksum } } ;
ExpectedChecksum == ActualChecksum - >
maps : put ( checksum , ExpectedChecksum , State ) ;
maps : put ( inner_ checksum, ExpectedChecksum , State ) ;
true - >
{ error , { tarball , { checksum_mismatch , ExpectedChecksum , ActualChecksum } } }
{ error , { tarball , { inner_ checksum_mismatch, ExpectedChecksum , ActualChecksum } } }
end .
decode_metadata ( { error , _ } = Error ) - >
@ -343,6 +363,7 @@ guess_build_tools(Metadata) ->
unpack_tarball ( ContentsBinary , memory ) - >
r3_hex_erl_tar : extract ( { binary , ContentsBinary } , [ memory , compressed ] ) ;
unpack_tarball ( ContentsBinary , Output ) - >
filelib : ensure_dir ( filename : join ( Output , " * " ) ) ,
case r3_hex_erl_tar : extract ( { binary , ContentsBinary } , [ { cwd , Output } , compressed ] ) of
ok - >
[ try_updating_mtime ( filename : join ( Output , Path ) ) | | Path < - filelib : wildcard ( " ** " , Output ) ] ,
@ -466,8 +487,9 @@ diff_keys(Map, RequiredKeys, OptionalKeys) ->
{ [ ] , [ ] } - >
ok ;
{ _ , [ _ | _ ] } - >
{ error , { unknown_keys , UnknownKeys } } ;
% Server should validate this but clients should not
% { _ , [ _ | _ ] } - >
% { error , { unknown_keys , UnknownKeys } } ;
_ - >
{ error , { missing_keys , MissingKeys } }