diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cow_base64url.erl | 81 | ||||
-rw-r--r-- | src/cow_multipart.erl | 2 |
2 files changed, 82 insertions, 1 deletions
diff --git a/src/cow_base64url.erl b/src/cow_base64url.erl new file mode 100644 index 0000000..ff375f7 --- /dev/null +++ b/src/cow_base64url.erl @@ -0,0 +1,81 @@ +%% Copyright (c) 2017, Loïc Hoguin <[email protected]> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +%% This module implements "base64url" following the algorithm +%% found in Appendix C of RFC7515. The option #{padding => false} +%% must be given to reproduce this variant exactly. The default +%% will leave the padding characters. +-module(cow_base64url). + +-export([decode/1]). +-export([decode/2]). +-export([encode/1]). +-export([encode/2]). + +-ifdef(TEST). +-include_lib("proper/include/proper.hrl"). +-endif. + +decode(Enc) -> + decode(Enc, #{}). + +decode(Enc0, Opts) -> + Enc1 = << << case C of + $- -> $+; + $_ -> $/; + _ -> C + end >> || << C >> <= Enc0 >>, + Enc = case Opts of + #{padding := false} -> + case byte_size(Enc1) rem 4 of + 0 -> Enc1; + 2 -> << Enc1/binary, "==" >>; + 3 -> << Enc1/binary, "=" >> + end; + _ -> + Enc1 + end, + base64:decode(Enc). + +encode(Dec) -> + encode(Dec, #{}). + +encode(Dec, Opts) -> + encode(base64:encode(Dec), Opts, <<>>). + +encode(<<$+, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, $->>); +encode(<<$/, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, $_>>); +encode(<<$=, _/bits>>, #{padding := false}, Acc) -> Acc; +encode(<<C, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, C>>); +encode(<<>>, _, Acc) -> Acc. + +-ifdef(TEST). + +rfc7515_test() -> + Dec = <<3,236,255,224,193>>, + Enc = <<"A-z_4ME">>, + Pad = <<"A-z_4ME=">>, + Dec = decode(<<Enc/binary,$=>>), + Dec = decode(Enc, #{padding => false}), + Pad = encode(Dec), + Enc = encode(Dec, #{padding => false}), + ok. + +prop_identity() -> + ?FORALL(B, binary(), B =:= decode(encode(B))). + +prop_identity_no_padding() -> + ?FORALL(B, binary(), B =:= decode(encode(B, #{padding => false}), #{padding => false})). + +-endif. diff --git a/src/cow_multipart.erl b/src/cow_multipart.erl index f573be5..7ccda0d 100644 --- a/src/cow_multipart.erl +++ b/src/cow_multipart.erl @@ -424,7 +424,7 @@ horse_parse() -> -spec boundary() -> binary(). boundary() -> - base64:encode(crypto:strong_rand_bytes(48)). + cow_base64url:encode(crypto:strong_rand_bytes(48), #{padding => false}). %% @doc Return the first part's head. %% |