@scaffoldly/serverless-util
Version:
Scaffoldly Serverless Helper Functionality
191 lines • 7.25 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.snsEventResponseMapper = exports.dynamoDBStreamEventResponseMapper = exports.snsEventRequestMapper = exports.snsExtractTopicName = exports.dynamoDBStreamEventRequestMapper = exports.extractRequestToken = exports.extractToken = exports.extractAuthorization = exports.constructServiceUrl = exports.assertProcessUuid = void 0;
const auth_1 = require("./auth");
const constants_1 = require("./constants");
const db_1 = require("./db");
const errors_1 = require("./errors");
const assertProcessUuid = (actual, expected = constants_1.PROCESS_UUID) => {
if (!actual) {
throw new Error('Missing Process UUID: actual is undefined');
}
if (!expected) {
throw new Error('Missing Process UUID: expected is undefined');
}
if (!actual.toLowerCase) {
throw new Error('Missing Process UUID: actual.toLowerCase is undefined');
}
if (!expected.toLowerCase) {
throw new Error('Missing Process UUID: expected.toLowerCase is undefined');
}
if (actual.toLowerCase() === expected.toLowerCase()) {
return true;
}
throw new Error(`Provided process UUID (${actual}) does not match expected process UUID`);
};
exports.assertProcessUuid = assertProcessUuid;
const constructServiceUrl = (request, serviceSlug, path) => {
const { headers } = request;
const { host } = headers;
const ssl = headers['x-forwarded-proto'] === 'https';
let slug = serviceSlug ? `/${serviceSlug}` : '';
let actualPath = path || '';
if (!actualPath.startsWith('/') && actualPath.length !== 0) {
actualPath = `/${actualPath}`;
}
return `${ssl ? 'https' : 'http'}://${host}${slug}${actualPath}`;
};
exports.constructServiceUrl = constructServiceUrl;
const extractAuthorization = (request) => {
if (!request) {
console.warn('Unable to extract authorization header: Request is null');
return null;
}
const { headers } = request;
if (!headers) {
console.warn('Unable to extract authorization header: No headers');
return null;
}
const { authorization } = headers;
if (authorization) {
return authorization;
}
const { Authorization } = headers;
if (Authorization) {
return Authorization;
}
console.warn("Missing header named 'Authorization' or 'authorization'");
return null;
};
exports.extractAuthorization = extractAuthorization;
const extractToken = (authorization, authTypes = auth_1.AUTH_PREFIXES) => {
if (!authorization) {
console.warn('Missing authorization header');
return null;
}
let token = authorization;
const parts = token.split(' ');
if (parts.length > 2) {
console.warn('Malformed authorization header: Extra spaces');
return null;
}
if (parts.length === 2) {
const prefix = parts[0];
authTypes = authTypes.map((t) => t.toLowerCase());
if (authTypes.indexOf(prefix.toLowerCase()) === -1) {
console.warn(`Invalid token type: ${prefix}`);
return null;
}
[, token] = parts;
}
return token;
};
exports.extractToken = extractToken;
const extractRequestToken = (request) => {
const authorization = exports.extractAuthorization(request);
if (!authorization) {
throw new errors_1.HttpError(401, 'Unauthorized');
}
const token = exports.extractToken(authorization);
if (!token) {
throw new errors_1.HttpError(401, 'Unauthorized');
}
return token;
};
exports.extractRequestToken = extractRequestToken;
const dynamoDBStreamEventRequestMapper = (path, id = constants_1.PROCESS_UUID) => {
return (container) => {
const body = {
Records: container.event.Records.reduce((acc, record) => {
if (!record.dynamodb || !record.eventID || !record.eventName || !record.eventSourceARN || !record.awsRegion) {
return acc;
}
const tableName = db_1.dynamoDBStreamEventExtractTableName(record.eventSourceARN);
if (!tableName) {
return acc;
}
acc.push({
dynamodb: {
Keys: record.dynamodb.Keys ? db_1.unmarshallDynamoDBImage(record.dynamodb.Keys) : undefined,
New: record.dynamodb.NewImage ? db_1.unmarshallDynamoDBImage(record.dynamodb.NewImage) : undefined,
Old: record.dynamodb.OldImage ? db_1.unmarshallDynamoDBImage(record.dynamodb.OldImage) : undefined,
},
eventID: record.eventID,
eventName: record.eventName,
eventSourceARN: record.eventSourceARN,
awsRegion: record.awsRegion,
tableName,
});
return acc;
}, []),
};
return {
hostname: 'dynamodb.amazonaws.com',
method: 'POST',
path,
headers: {
[constants_1.PROCESS_UUID_HEADER]: id,
[constants_1.MAPPED_EVENT_HEADER]: constants_1.MAPPED_EVENT_DYNAMODB_STREAM,
},
body,
};
};
};
exports.dynamoDBStreamEventRequestMapper = dynamoDBStreamEventRequestMapper;
const snsExtractTopicName = (topicArn) => {
// TODO Proper ARN Parser
if (!topicArn) {
return;
}
const parts = topicArn.split(':');
if (parts.length !== 6) {
return;
}
return parts[5];
};
exports.snsExtractTopicName = snsExtractTopicName;
const snsEventRequestMapper = (path, id = constants_1.PROCESS_UUID) => {
return (container) => {
const body = {
Records: container.event.Records.reduce((acc, record) => {
const topicName = exports.snsExtractTopicName(record.Sns.TopicArn);
if (!topicName) {
return acc;
}
// TODO Verify Signature
let obj = undefined;
try {
obj = JSON.parse(record.Sns.Message);
}
catch (e) {
console.warn('Unable to parse message into JSON');
}
acc.push({
...record,
Sns: {
...record.Sns,
Subject: record.Sns.Subject || '',
Object: obj,
TopicName: topicName,
},
});
return acc;
}, []),
};
return {
hostname: 'sns.amazonaws.com',
method: 'POST',
path,
headers: {
[constants_1.PROCESS_UUID_HEADER]: id,
[constants_1.MAPPED_EVENT_HEADER]: constants_1.MAPPED_EVENT_SNS,
},
body,
};
};
};
exports.snsEventRequestMapper = snsEventRequestMapper;
const emptyResponseMapper = () => () => { };
exports.dynamoDBStreamEventResponseMapper = emptyResponseMapper;
exports.snsEventResponseMapper = emptyResponseMapper;
//# sourceMappingURL=http.js.map
;