Skip to content

Commit

Permalink
Support undefined
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmach committed Feb 29, 2024
1 parent fae27c4 commit 30cd3e4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 52 deletions.
20 changes: 16 additions & 4 deletions src/hex_core.erl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
%%
%% * `repo_verify_origin' - If `true' will verify the repository signature origin,
%% requires protobuf messages as of hex_core v0.4.0 (default: `true').
%%
%% * `tarball_max_size' - Maximum size of package tarball, defaults to
%% `8_388_608' (8 MiB). Set to `undefined' to not enforce the limit.
%%
%% * `tarball_max_uncompressed_size' - Maximum size of uncompressed package tarball, defaults to
%% `67_108_864' (64 MiB). Set to `undefined' to not enforce the limit.
%%
%% * `docs_tarball_max_size' - Maximum size of docs tarball, defaults to
%% `16_777_216' (16 MiB). Set to `undefined' to not enforce the limit.
%%
%% * `docs_tarball_max_uncompressed_size' - Maximum size of uncompressed docs tarball, defaults to
%% `134_217_728' (128 MiB). Set to `undefined' to not enforce the limit.

-module(hex_core).
-export([default_config/0]).
Expand Down Expand Up @@ -81,10 +93,10 @@
repo_organization => binary() | undefined,
repo_verify => boolean(),
repo_verify_origin => boolean(),
tarball_max_size => pos_integer(),
tarball_max_uncompressed_size => pos_integer(),
docs_tarball_max_size => pos_integer(),
docs_tarball_max_uncompressed_size => pos_integer()
tarball_max_size => pos_integer() | undefined,
tarball_max_uncompressed_size => pos_integer() | undefined,
docs_tarball_max_size => pos_integer() | undefined,
docs_tarball_max_uncompressed_size => pos_integer() | undefined
}.

-spec default_config() -> config().
Expand Down
116 changes: 68 additions & 48 deletions src/hex_tarball.erl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
}}
| {error, term()}.
create(Metadata, Files, Config) ->
#{
tarball_max_size := TarballMaxSize,
tarball_max_uncompressed_size := TarballMaxUncompressedSize
} = Config,

MetadataBinary = encode_metadata(Metadata),
ContentsTarball = create_memory_tarball(Files),
ContentsTarballCompressed = gzip(ContentsTarball),
Expand All @@ -73,20 +78,23 @@ create(Metadata, Files, Config) ->
{"contents.tar.gz", ContentsTarballCompressed}
],

Tarball = create_memory_tarball(OuterFiles),
OuterChecksum = checksum(Tarball),

UncompressedSize = byte_size(ContentsTarball),

case {(byte_size(Tarball) > TarballMaxSize), (UncompressedSize > TarballMaxUncompressedSize)} of
{_, true} ->
{error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}};
{true, _} ->
{error, {tarball, {too_big_compressed, TarballMaxSize}}};
{false, false} ->
{ok, #{
tarball => Tarball, outer_checksum => OuterChecksum, inner_checksum => InnerChecksum
}}
case valid_size(ContentsTarball, TarballMaxUncompressedSize) of
true ->
Tarball = create_memory_tarball(OuterFiles),
OuterChecksum = checksum(Tarball),

case valid_size(Tarball, TarballMaxSize) of
true ->
{ok, #{
tarball => Tarball,
outer_checksum => OuterChecksum,
inner_checksum => InnerChecksum
}};
false ->
{error, {tarball, {too_big_compressed, TarballMaxSize}}}
end;
false ->
{error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
end.

-spec create(metadata(), files()) ->
Expand All @@ -111,22 +119,26 @@ create(Metadata, Files) ->
%% '''
%% @end
-spec create_docs(files(), hex_core:config()) -> {ok, tarball()} | {error, term()}.
create_docs(Files, #{
docs_tarball_max_size := TarballMaxSize,
docs_tarball_max_uncompressed_size := TarballMaxUncompressedSize
}) ->
create_docs(Files, Config) ->
#{
docs_tarball_max_size := TarballMaxSize,
docs_tarball_max_uncompressed_size := TarballMaxUncompressedSize
} = Config,

UncompressedTarball = create_memory_tarball(Files),
UncompressedSize = byte_size(UncompressedTarball),
Tarball = gzip(UncompressedTarball),
Size = byte_size(Tarball),

case {(Size > TarballMaxSize), (UncompressedSize > TarballMaxUncompressedSize)} of
{_, true} ->
{error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}};
{true, _} ->
{error, {tarball, {too_big_compressed, TarballMaxSize}}};
{false, false} ->
{ok, Tarball}

case valid_size(UncompressedTarball, TarballMaxUncompressedSize) of
true ->
Tarball = gzip(UncompressedTarball),

case valid_size(Tarball, TarballMaxSize) of
true ->
{ok, Tarball};
false ->
{error, {tarball, {too_big_compressed, TarballMaxSize}}}
end;
false ->
{error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
end.

-spec create_docs(files()) -> {ok, tarball()}.
Expand Down Expand Up @@ -167,19 +179,20 @@ create_docs(Files) ->
metadata => metadata()
}}
| {error, term()}.
unpack(Tarball, _, #{tarball_max_size := TarballMaxSize}) when
byte_size(Tarball) > TarballMaxSize
->
{error, {tarball, too_big}};
unpack(Tarball, Output, _Config) ->
case hex_erl_tar:extract({binary, Tarball}, [memory]) of
{ok, []} ->
{error, {tarball, empty}};
{ok, FileList} ->
OuterChecksum = crypto:hash(sha256, Tarball),
do_unpack(maps:from_list(FileList), OuterChecksum, Output);
{error, Reason} ->
{error, {tarball, Reason}}
unpack(Tarball, Output, Config) ->
case valid_size(Tarball, maps:get(tarball_max_size, Config)) of
true ->
case hex_erl_tar:extract({binary, Tarball}, [memory]) of
{ok, []} ->
{error, {tarball, empty}};
{ok, FileList} ->
OuterChecksum = crypto:hash(sha256, Tarball),
do_unpack(maps:from_list(FileList), OuterChecksum, Output);
{error, Reason} ->
{error, {tarball, Reason}}
end;
false ->
{error, {tarball, too_big}}
end.

%% @doc
Expand Down Expand Up @@ -220,12 +233,13 @@ unpack(Tarball, Output) ->
-spec unpack_docs
(tarball(), memory, hex_core:config()) -> {ok, contents()} | {error, term()};
(tarball(), filename(), hex_core:config()) -> ok | {error, term()}.
unpack_docs(Tarball, _, #{docs_tarball_max_size := TarballMaxSize}) when
byte_size(Tarball) > TarballMaxSize
->
{error, {tarball, too_big}};
unpack_docs(Tarball, Output, _Config) ->
unpack_tarball(Tarball, Output).
unpack_docs(Tarball, Output, Config) ->
case valid_size(Tarball, maps:get(docs_tarball_max_size, Config)) of
true ->
unpack_tarball(Tarball, Output);
false ->
{error, {tarball, too_big}}
end.

-spec unpack_docs
(tarball(), memory) -> {ok, contents()} | {error, term()};
Expand Down Expand Up @@ -602,6 +616,12 @@ gzip_no_header(Uncompressed) ->
%% Helpers
%%====================================================================

%% @private
valid_size(Binary, undefined) when is_binary(Binary) ->
true;
valid_size(Binary, Limit) when is_binary(Binary) ->
byte_size(Binary) =< Limit.

%% @private
binarify(Binary) when is_binary(Binary) -> Binary;
binarify(Number) when is_number(Number) -> Number;
Expand Down

0 comments on commit 30cd3e4

Please sign in to comment.