Skip to content

Commit

Permalink
buffer: atob throw error when the input string is invalid
Browse files Browse the repository at this point in the history
The specification of `atob` has various different conditions that we need
to abide by. The specific changes that were made:

* `atob` now immediately throws when `undefined`, `false`, or a `number` is
  supplied
* `atob` now strips ASCII whitespace before attempting to decode
* `atob` now validates that the code point's length divided by 4 leaves a
  remainder that is not 1

See: https://infra.spec.whatwg.org/#forgiving-base64-decode

Fixes: nodejs#42646
  • Loading branch information
austinkelleher committed Apr 8, 2022
1 parent dfc2dc8 commit a924347
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
23 changes: 22 additions & 1 deletion lib/buffer.js
Expand Up @@ -1259,7 +1259,28 @@ function atob(input) {
if (arguments.length === 0) {
throw new ERR_MISSING_ARGS('input');
}
input = `${input}`;

if (input === undefined || input === false || typeof input === 'number') {
throw lazyDOMException(
'The string to be decoded is not correctly encoded.',
'ValidationError');
}

// Remove all ASCII whitespace from data.
//
// See #1 - https://infra.spec.whatwg.org/#forgiving-base64
input = `${input}`.replace(/\s/g, '');

// If data's code point length divides by 4 leaving a remainder of 1, then
// return failure.
//
// See #3 - https://infra.spec.whatwg.org/#forgiving-base64
if (input.length % 4 === 1) {
throw lazyDOMException(
'The string to be decoded is not correctly encoded.',
'ValidationError');
}

for (let n = 0; n < input.length; n++) {
if (!ArrayPrototypeIncludes(kForgivingBase64AllowedChars,
StringPrototypeCharCodeAt(input, n)))
Expand Down
9 changes: 9 additions & 0 deletions test/parallel/test-btoa-atob.js
Expand Up @@ -15,3 +15,12 @@ throws(() => buffer.btoa(), /TypeError/);

strictEqual(atob(' '), '');
strictEqual(atob(' YW\tJ\njZA=\r= '), 'abcd');

throws(() => buffer.atob(undefined), /ValidationError/);
throws(() => buffer.atob(false), /ValidationError/);
throws(() => buffer.atob(1), /ValidationError/);
throws(() => buffer.atob(0), /ValidationError/);
throws(() => buffer.atob('a'), /ValidationError/);
throws(() => buffer.atob('a '), /ValidationError/);
throws(() => buffer.atob(' a'), /ValidationError/);
throws(() => buffer.atob('aaaaa'), /ValidationError/);

0 comments on commit a924347

Please sign in to comment.