Skip to content

Commit

Permalink
fix(@whook/aws-lambda): fix lambdas build for multiple headers
Browse files Browse the repository at this point in the history
  • Loading branch information
nfroidure committed Oct 5, 2020
1 parent b97b774 commit ed5537a
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 19 deletions.
30 changes: 27 additions & 3 deletions packages/whook-aws-lambda/src/wrappers/awsHTTPLambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ async function awsRequestEventToRequest(event: any): Promise<WhookRequest> {
type AWSResponseEvent = {
statusCode: number;
headers: { [name: string]: string };
multiValueHeaders: { [name: string]: string[] };
body?: string;
isBase64Encoded?: boolean;
};
Expand All @@ -493,7 +494,28 @@ async function responseToAWSResponseEvent(
): Promise<AWSResponseEvent> {
const amazonResponse: AWSResponseEvent = {
statusCode: response.status,
headers: response.headers,
headers: Object.keys(response.headers || {}).reduce(
(stringHeaders, name) => ({
...stringHeaders,
...(typeof response.headers[name] === 'string'
? {
[name]: response.headers[name],
}
: {}),
}),
{},
),
multiValueHeaders: Object.keys(response.headers || {}).reduce(
(stringHeaders, name) => ({
...stringHeaders,
...((response.headers[name] as any) instanceof Array
? {
[name]: response.headers[name],
}
: {}),
}),
{},
),
};

if (response.body) {
Expand All @@ -511,8 +533,10 @@ async function responseToAWSResponseEvent(
});
});
if (
response.headers['content-type'].startsWith('image/') ||
response.headers['content-type'].startsWith('application/pdf')
(response.headers['content-type'] as 'string').startsWith('image/') ||
(response.headers['content-type'] as 'string').startsWith(
'application/pdf',
)
) {
amazonResponse.body = buf.toString('base64');
amazonResponse.isBase64Encoded = true;
Expand Down
20 changes: 15 additions & 5 deletions packages/whook-cors/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,21 @@ export async function augmentAPIWithCORS(

export { initOptionsWithCORS };

function mergeVaryHeaders(baseHeader: string, addedValue: string): string {
const baseHeaderValues = baseHeader
.split(',')
.filter(identity)
.map((v) => v.trim().toLowerCase());
function mergeVaryHeaders(
baseHeader: string | string[],
addedValue: string,
): string {
const baseHeaderValues = (baseHeader instanceof Array
? baseHeader
: [baseHeader]
)
.map((value) =>
value
.split(',')
.filter(identity)
.map((v) => v.trim().toLowerCase()),
)
.reduce((allValues, values) => [...allValues, ...values], []);

if (baseHeaderValues.includes('*')) {
return '*';
Expand Down
10 changes: 5 additions & 5 deletions packages/whook-http-router/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,21 +408,21 @@ async function initHTTPRouter({
operation.responses[response.status] &&
operation.responses[response.status].content &&
operation.responses[response.status].content[
response.headers['content-type']
response.headers['content-type'] as string
] &&
operation.responses[response.status].content[
response.headers['content-type']
response.headers['content-type'] as string
].schema &&
(operation.responses[response.status].content[
response.headers['content-type']
response.headers['content-type'] as string
].schema.type !== 'string' ||
operation.responses[response.status].content[
response.headers['content-type']
response.headers['content-type'] as string
].schema.format !== 'binary');

if (
responseHasSchema &&
!STRINGIFYERS[response.headers['content-type']]
!STRINGIFYERS[response.headers['content-type'] as string]
) {
throw new HTTPError(
500,
Expand Down
2 changes: 1 addition & 1 deletion packages/whook-http-transaction/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export type WhookRequest = {
export type WhookResponse<
S = number,
H = {
[name: string]: string;
[name: string]: string | string[];
},
B = any
> = {
Expand Down
13 changes: 13 additions & 0 deletions packages/whook-http-transaction/src/services/obfuscator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ describe('Obfuscator Service', () => {
}
`);
});

it('should work with set-cookie sensible headers', () => {
expect(
obfuscator.obfuscateSensibleHeaders({
'Set-Cookie':
'refresh_token=XdJ2%2BXmU0GLqB9bOfFOKWzg4ixn%2BfmJlWEHb%2FPXFrN4MHmteVfAC1WNMVCbSwT9M%2FbkJmIgdFXvDvEMDvZw0elIRvClwjaLVXgQqGSbtbkMTSv%2BtvvdnqIrfYRSuwhX2v5YqvUJsKk1RmxRekOyq5gthUutdT8iHc0PMdKiojm0UTdEq3Jzefc70BhdXnjDH9uQJMb5JfuzZKbx994yk9NdQMnjYUC4Fo6i0SFqPtLGi4mxnOp8Rug5Zm11tdej9sA4UXPsITx%2BhKkdVEm0J%2BqXVeCD7kD7Ybuw%2Bno%2FcxNwSCYy7WFPG6VNTAWPP9jctqWYCICiDjYNgFM0IoikCNQ%3D%3D; Domain=app.diagrams-technologies.com; Path=/v0/auth; HttpOnly; Secure; SameSite=Strict',
}),
).toMatchInlineSnapshot(`
Object {
"Set-Cookie": "refresh_token=XdJ...%3D; Domain=app.diagrams-technologies.com; Path=/v0/auth; HttpOnly; Secure; SameSite=Strict",
}
`);
});
});

describe('obfuscateSensibleProps()', () => {
Expand Down
33 changes: 28 additions & 5 deletions packages/whook-http-transaction/src/services/obfuscator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ const DEFAULT_SENSIBLE_HEADERS: SensibleValueDescriptor[] = [
clearIndices: [0],
},
{ name: 'cookie', pattern: /^(.*)$/i, clearIndices: [] },
{
name: 'set-cookie',
pattern: /^([^=]+=)([^;]*)(.*)$/i,
clearIndices: [0, 2],
},
];
const DEFAULT_SENSIBLE_PROPS: SensibleValueDescriptor[] = [
{
Expand Down Expand Up @@ -121,7 +126,23 @@ async function initObfuscator({
);
}

function selectivelyObfuscate(pattern, clearIndices, value) {
function selectivelyObfuscateAll(
pattern: RegExp,
clearIndices: number[],
values: string | string[],
) {
return values instanceof Array
? values.map((value) =>
selectivelyObfuscate(pattern, clearIndices, value),
)
: selectivelyObfuscate(pattern, clearIndices, values);
}

function selectivelyObfuscate(
pattern: RegExp,
clearIndices: number[],
value: string,
) {
// SECURITY: Here, we first test the pattern to ensure
// the selective obfuscation will work, if not, we obfuscate
// the whole value to default to security
Expand All @@ -139,7 +160,9 @@ async function initObfuscator({
: obfuscate(value);
}

function obfuscateSensibleHeaders(headers: { [name: string]: string }) {
function obfuscateSensibleHeaders(headers: {
[name: string]: string | string[];
}) {
return Object.keys(headers).reduce((finalHeaders, headerName) => {
const sensibleHeader = SENSIBLE_HEADERS.find(
(sensibleHeader) =>
Expand All @@ -148,7 +171,7 @@ async function initObfuscator({
return {
...finalHeaders,
[headerName]: sensibleHeader
? selectivelyObfuscate(
? selectivelyObfuscateAll(
sensibleHeader.pattern,
sensibleHeader.clearIndices,
headers[headerName],
Expand All @@ -158,7 +181,7 @@ async function initObfuscator({
}, {});
}

function obfuscateSensibleProps(propValue, propName = '_') {
function obfuscateSensibleProps(propValue: any, propName = '_') {
if (propValue instanceof Array) {
return propValue.map((value) => obfuscateSensibleProps(value, propName));
} else if (typeof propValue === 'object' && propValue !== null) {
Expand All @@ -183,7 +206,7 @@ async function initObfuscator({
? selectivelyObfuscate(
sensibleProp.pattern,
sensibleProp.clearIndices,
propValue,
propValue.toString(),
)
: propValue;
} else if (null === propValue) {
Expand Down

0 comments on commit ed5537a

Please sign in to comment.