diff --git a/src/flow.ts b/src/flow.ts index f58a536..b4c1d8b 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -1,4 +1,4 @@ -import { inflateString, base64Decode } from './utility'; +import { inflateString, base64Decode, WrappedError } from './utility'; import { verifyTime } from './validator'; import libsaml from './libsaml'; import { @@ -67,7 +67,13 @@ async function redirectFlow(options): Promise { return Promise.reject('ERR_REDIRECT_FLOW_BAD_ARGS'); } - const xmlString = inflateString(decodeURIComponent(content)); + let xmlString: string + + try { + xmlString = inflateString(decodeURIComponent(content)); + } catch (cause) { + throw new WrappedError('ERR_FAILED_INFLATION', { cause }) + } // validate the xml try { diff --git a/src/utility.ts b/src/utility.ts index 9ea7e16..67aba06 100644 --- a/src/utility.ts +++ b/src/utility.ts @@ -8,6 +8,21 @@ import { inflate, deflate } from 'pako'; const BASE64_STR = 'base64'; +/** + * An Error class with a "cause". + * + * This can be replaced by the native option, once the minimum supported version is >=16.9.0. + * https://nodejs.org/docs/latest-v16.x/api/errors.html#errorcause + */ +export class WrappedError extends Error { + public cause: any; + + constructor(message: string, options: { cause: any }) { + super(message); + this.cause = options.cause; + } +} + /** * @desc Mimic lodash.zipObject * @param arr1 {string[]} diff --git a/test/flow.ts b/test/flow.ts index 19bf553..6d7a972 100644 --- a/test/flow.ts +++ b/test/flow.ts @@ -1382,3 +1382,11 @@ test.serial('should not throw ERR_SUBJECT_UNCONFIRMED for the expired SAML respo } }); + +test('should throw ERR_FAILED_INFLATION when pako is unable to inflate a redirect login request', async t => { + const query = { SAMLRequest: 'foo', Signature: 'bar', SigAlg: 'baz' }; + const error = await t.throwsAsync(idp.parseLoginRequest(sp, 'redirect', { query })); + + t.is(error.message, 'ERR_FAILED_INFLATION'); + t.is(error.cause, 'invalid block type'); // pako throws strings instead of Error instances for bad input +});