diff --git a/lib/util/util.js b/lib/util/util.js index f42ce48b3..b4c86d6b7 100644 --- a/lib/util/util.js +++ b/lib/util/util.js @@ -60,7 +60,9 @@ const pickAll = (keys, obj) => { return result; }; +const validBase64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/][AQgw]={0,2}|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=?)?$/; function base64ToUtf8(base64) { + if (!validBase64.test(base64?.trim())) throw new Error('Invalid base64 string.'); return Buffer.from(base64, 'base64').toString('utf8'); } diff --git a/test/unit/util/util.js b/test/unit/util/util.js index bd7e44749..cfa7837e0 100644 --- a/test/unit/util/util.js +++ b/test/unit/util/util.js @@ -70,6 +70,39 @@ describe('util/util', () => { const base64 = utf8ToBase64(input); base64ToUtf8(base64).should.be.eql(input); }); + + describe('base64ToUtf8()', () => { + it(`should throw if no arg supplied`, () => { + (() => base64ToUtf8()).should.throw('Invalid base64 string.'); + }); + + [ + undefined, + null, + '!', + ].forEach(malformed64 => { + it(`should reject malformed input '${malformed64}'`, () => { + (() => base64ToUtf8(malformed64)).should.throw('Invalid base64 string.'); + }); + }); + + [ + [ '', '' ], + [ ' ', '' ], + [ 'c29tZSB0ZXh0', 'some text' ], // eslint-disable-line no-multi-spaces + [ 'c29tZSB0ZXh0 ', 'some text' ], // eslint-disable-line no-multi-spaces + [ ' c29tZSB0ZXh0 ', 'some text' ], + [ 'c29tZSB0ZXh0IA', 'some text ' ], // eslint-disable-line no-multi-spaces + [ 'c29tZSB0ZXh0IA=', 'some text ' ], // eslint-disable-line no-multi-spaces + [ 'c29tZSB0ZXh0IA==', 'some text ' ], + [ 'c29tZSB0ZXh0IDE=', 'some text 1' ], + [ 'c29tZSB0ZXh0IDEx', 'some text 11' ], + ].forEach(([ good64, expected ]) => { + it(`should decode '${good64}' to '${expected}'`, () => { + base64ToUtf8(good64).should.equal(expected); + }); + }); + }); }); });