Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/lib/isBase32.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
import assertString from './util/assertString';
import includes from './util/includesArray';
import merge from './util/merge';

const base32 = /^[A-Z2-7]+=*$/;
const crockfordBase32 = /^[A-HJKMNP-TV-Z0-9]+$/;

/**
* RFC 4648 (section 6) encodes each 40-bit group as 8 characters. A final
* group of 1, 2, 3 or 4 octets encodes to 2, 4, 5 or 7 characters and is then
* padded to 8, so an encoder only ever emits 0, 1, 3, 4 or 6 padding
* characters - never 2, 5 or 7.
*/
const validPaddingLengths = [0, 1, 3, 4, 6];

const defaultBase32Options = {
crockford: false,
};

/* `str` has already been matched against `base32`, so any '=' is part of the
single trailing padding run. */
function hasValidPadding(str) {
const paddingStart = str.indexOf('=');

return includes(validPaddingLengths, paddingStart === -1 ? 0 : str.length - paddingStart);
}

export default function isBase32(str, options) {
assertString(str);
options = merge(options, defaultBase32Options);
Expand All @@ -16,5 +33,5 @@ export default function isBase32(str, options) {
return crockfordBase32.test(str);
}

return str.length % 8 === 0 && base32.test(str);
return str.length % 8 === 0 && base32.test(str) && hasValidPadding(str);
}
25 changes: 25 additions & 0 deletions test/validators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7503,6 +7503,31 @@ describe('Validators', () => {
});
});

it('should reject base32 strings with an impossible number of padding characters', () => {
// RFC 4648 (section 6) pads the final group to 8 characters, so an encoder
// emits 0, 1, 3, 4 or 6 padding characters - never 2, 5 or 7.
test({
validator: 'isBase32',
valid: [
'ZG======',
'JBSQ====',
'JBSWY===',
'JBSWY3A=',
'JBSWY3DP',
'JBSWY3DPEA======',
],
invalid: [
'JBSWY3==',
'JBS=====',
'J=======',
'JBSWY3DPJBSWY3==',
'JBSWY3DPJBS=====',
'JBSWY3DPJ=======',
'JBSWY3==========',
],
});
});

it('should validate base32 strings with crockford alternative', () => {
test({
validator: 'isBase32',
Expand Down
Loading