Skip to content

Commit

Permalink
Merge pull request #29 from phulien/main
Browse files Browse the repository at this point in the history
Support generate presigned URL with tagging
  • Loading branch information
onno-vos-dev authored Jan 15, 2025
2 parents 0429920 + f608b12 commit a4ec790
Showing 1 changed file with 55 additions and 3 deletions.
58 changes: 55 additions & 3 deletions src/aws_signature.erl
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,14 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
%% a fixed digest value, such as "UNSIGNED-PAYLOAD", when sending requests without
%% signing the body, <strong>which is expected for S3</strong>.
%% </dd>
%% <dt>`tags'</dt>
%% <dd>
%% Optional tagging of the object when generating a pre-signed URL.
%% The value of `tags' is a binary() in the format, for example:
%% `<<"key1=value1&key2=value2">>'. The actual request to put or get the object
%% must use the exact `tags' value to ensure the signature is calculated
%% correctly.
%% </dd>
%% </dl>
-spec sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Options) -> FinalURL
when AccessKeyID :: binary(),
Expand All @@ -239,7 +247,8 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
| {session_token, binary()}
| {ttl, non_neg_integer()}
| {body, binary()}
| {body_digest, binary()},
| {body_digest, binary()}
| {tags, binary()},
FinalURL :: binary().
sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Options)
when is_binary(AccessKeyID),
Expand All @@ -253,6 +262,7 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
URIEncodePath = proplists:get_value(uri_encode_path, Options, true),
TimeToLive = proplists:get_value(ttl, Options, 86400),
SessionToken = proplists:get_value(session_token, Options, undefined),
Tags = proplists:get_value(tags, Options, undefined),
BodyDigest =
case proplists:get_value(body_digest, Options, undefined) of
undefined ->
Expand All @@ -263,7 +273,13 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
end,
BaseParams =
[{<<"X-Amz-Algorithm">>, <<"AWS4-HMAC-SHA256">>},
{<<"X-Amz-SignedHeaders">>, <<"host">>}],
{<<"X-Amz-SignedHeaders">>,
if Tags == undefined ->
<<"host">>;
Tags =/= undefined ->
<<"host%3Bx-amz-tagging">>
end}
],

URLMap = aws_signature_utils:parse_url(URL),
LongDate = format_datetime_long(DateTime),
Expand All @@ -276,9 +292,15 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me

FinalQueryParams = add_date_header(FinalQueryParams2, LongDate),
HostHeader = host_header_from_url(URLMap),
Headers =
if Tags == undefined ->
[HostHeader];
Tags =/= undefined ->
[HostHeader, {<<"X-Amz-Tagging">>, Tags}]
end,

CanonicalRequest =
canonical_request(Method, URLMap, [HostHeader], BodyDigest, URIEncodePath, FinalQueryParams),
canonical_request(Method, URLMap, Headers, BodyDigest, URIEncodePath, FinalQueryParams),

HashedCanonicalRequest = aws_signature_utils:sha256_hexdigest(CanonicalRequest),
SigningKey = signing_key(SecretAccessKey, ShortDate, Region, Service),
Expand Down Expand Up @@ -1055,6 +1077,36 @@ sign_v4_query_params_with_authority_well_known_port_test() ->

?assertEqual(Expected, Actual).

sign_v4_query_params_with_tagging_test() ->
AccessKeyID = <<"AKIAIOSFODNN7EXAMPLE">>,
SecretAccessKey = <<"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">>,
Region = <<"us-east-1">>,
Service = <<"s3">>,
DateTime = {{2013, 5, 24}, {0, 0, 0}},
Method = <<"GET">>,
URL = <<"https://examplebucket.s3.amazonaws.com/test.txt">>,

Expected =
<<"https://examplebucket.s3.amazonaws.com/test.txt?",
"X-Amz-Algorithm=AWS4-HMAC-SHA256&",
"X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&",
"X-Amz-Date=20130524T000000Z&",
"X-Amz-Expires=86400&",
"X-Amz-Signature=5c14ef7998d657c3b8293b37abefaef5fa98cc775bcbfffdb2027f4ce05772ef&",
"X-Amz-SignedHeaders=host%3Bx-amz-tagging">>,

Actual =
sign_v4_query_params(AccessKeyID,
SecretAccessKey,
Region,
Service,
DateTime,
Method,
URL,
[{tags, <<"key1=value1&key2=value2">>}]),

?assertEqual(Expected, Actual).

format_date_long_test() ->
Expected = <<"20210126T200815Z">>,
Actual = format_datetime_long({{2021,1,26}, {20,8,15}}),
Expand Down

0 comments on commit a4ec790

Please sign in to comment.