serverless-offline-local-auth-plugin
Version:
Forked from: [serverless-offline-auth-plugin](https://github.com/nlang/serverless-offline-local-authorizers-plugin).
218 lines (217 loc) • 10.7 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsLocalAuthorizerPlugin = void 0;
const fs_1 = require("fs");
const GENERATE_JS_FILE_V3 = (lambdaEndpoint, lambdaFnName) => {
const clauses = [
'// AUTO GENERATED FILE PLEASE DO NOT MODIFY //',
`const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');`,
`const autoLocalAuthProxy = async (event, _context) => {
const client = new LambdaClient({ endpoint: '${lambdaEndpoint}', credentials: { accessKeyId: '', secretAccessKey: '' }});
const cmd = new InvokeCommand({
FunctionName: '${lambdaFnName}',
InvocationType: 'RequestResponse',
Payload: JSON.stringify(event),
});
const res = await client.send(cmd)
if (res.StatusCode === 200) {
const buffer = Buffer.from(res.Payload, 'binary').toString('utf-8')
return JSON.parse(buffer)
}
throw Error('Authorizer failed to validate request')
};`,
`module.exports = { autoLocalAuthProxy };`,
'// AUTO GENERATED FILE PLEASE DO NOT MODIFY //',
];
return clauses.join('\n');
};
const GENERATE_JS_FILE_V2 = (lambdaEndpoint, lambdaFnName) => {
const clauses = [
'// AUTO GENERATED FILE PLEASE DO NOT MODIFY //',
`const AWS = require('aws-sdk');`,
`const autoLocalAuthProxy = async (event, _context) => {
const lambda = new AWS.Lambda({ endpoint: '${lambdaEndpoint}' });
const res = await lambda.invoke({
FunctionName: '${lambdaFnName}',
InvocationType: 'RequestResponse',
Payload: JSON.stringify(event),
}).promise();
console.log('RESP', res)
if (res.StatusCode === 200) return JSON.parse(res.Payload)
throw Error('Authorizer failed to validate request')
};`,
`module.exports = { autoLocalAuthProxy };`,
'// AUTO GENERATED FILE PLEASE DO NOT MODIFY //',
];
return clauses.join('\n');
};
class AwsLocalAuthorizerPlugin {
constructor(serverless, options) {
this.serverless = serverless;
this.options = options;
this.config = { mode: 'disabled' };
if (this.serverless.service.provider.name !== "aws") {
throw new this.serverless.classes.Error("aws-local-authorizers plugin only supports AWS as provider.");
}
this.serverless.configSchemaHandler.defineFunctionEventProperties('aws', 'http', {
properties: {
localAuthorizer: {
type: "object",
properties: {
name: { type: "string" },
type: {
anyOf: ['token', 'cognito_user_pools', 'request', 'aws_iam'].map(v => ({ type: 'string', regexp: new RegExp(`^${v}$`, 'i').toString() })),
},
}
},
},
});
this.hooks = {
"initialize": this.onInitialized.bind(this),
"before:offline:start:init": this.onOfflineStartInit.bind(this),
};
}
onInitialized() {
const custom = this.serverless.service.custom;
const mayBeConfig = (custom['serverless-offline'] || {})['serverless-offline-local-auth'] || custom['serverless-offline-local-auth'] || '';
this.serverless.cli.log(`serverless-offline-local-auth [INITIALIZING] ${JSON.stringify(mayBeConfig)}.`, "serverless-offline-local-auth-plugin", { color: 'yellow' });
this.config = this.parseConfiguration(mayBeConfig);
}
// Prepare the configurations
parseConfiguration(mayBeConfig) {
if (!mayBeConfig) {
const authorizersFile = `${this.serverless.config.servicePath}/local-authorizers.js`;
// local-authrizer file detected! enabled it.
if ((0, fs_1.existsSync)(authorizersFile)) {
this.serverless.cli.log('local-authorizer proxy file exists!', "serverless-offline-local-auth-plugin");
return {
mode: 'hardcoded',
lambdaFilePath: authorizersFile,
};
}
return { mode: 'disabled' };
}
else if (typeof mayBeConfig === 'string') {
if (/^disabled$/i.test(mayBeConfig)) {
return { mode: 'disabled' };
}
return {
mode: 'inject',
lambdaAuthFnName: mayBeConfig,
lambdaVersion: 'v3',
};
}
return Object.assign({ mode: 'inject', lambdaVersion: 'v3' }, mayBeConfig);
}
onOfflineStartInit() {
if (this.config.mode === 'disabled') {
this.serverless.cli.log('serverless-offline-local-auth [DISABLED]', "serverless-offline-local-auth-plugin", { color: 'yellow' });
return;
}
this.serverless.cli.log(`serverless-offline-local-auth [ENABLED] >> ${JSON.stringify(this.config)}`, "serverless-offline-local-auth-plugin", { color: 'blue' });
return this.applyLocalAuthorizers();
}
applyLocalAuthorizers() {
return __awaiter(this, void 0, void 0, function* () {
const localAuthorizers = this.appendLocalAuthorizers();
if (!localAuthorizers || !Object.keys(localAuthorizers).length) {
this.serverless.cli.log(`No local authorizers found.`, "serverless-offline-local-auth-plugin", { color: "yellow" });
return;
}
const functions = this.serverless.service.functions;
for (const functionName of Object.keys(functions)) {
const functionDef = functions[functionName];
if (functionDef && Array.isArray(functionDef.events)) {
for (const event of functionDef.events) {
if (!event.http) {
continue;
}
const http = event.http;
let localAuthorizerDef = (http.authorizer && http.authorizer.localAuthorizer) ? http.authorizer.localAuthorizer : http.localAuthorizer;
if (typeof localAuthorizerDef === "string") {
localAuthorizerDef = { name: localAuthorizerDef };
}
if (localAuthorizerDef) {
if (localAuthorizers[localAuthorizerDef.name]) {
const mockFnName = localAuthorizers[localAuthorizerDef.name];
http.authorizer = {
name: mockFnName,
type: localAuthorizerDef.type || "token",
};
}
else {
const keys = Object.keys(localAuthorizers);
this.serverless.cli.log(`Invalid or unknown local authorizer '${JSON.stringify(localAuthorizerDef)}'. it seems there is only ${keys.length} authorizer(s) available ${keys.join(',')}`, "serverless-offline-local-auth-plugin", { color: "yellow" });
}
}
}
}
}
});
}
/**
* @returns list of configured local-authorizers
*/
appendLocalAuthorizers() {
let authorizerSrcFilename = 'local-authorizers.js';
let baseDir = '';
// try to register all configurations
let authorizers = {};
try {
if (this.config.mode === 'disabled') {
throw new Error('WTF error');
}
if (this.config.mode === 'hardcoded') {
authorizerSrcFilename = this.config.lambdaFilePath;
}
else if (this.config.mode === 'inject') {
// Generate the file!
baseDir = '.serverless-offline-local-auth/';
authorizerSrcFilename = `${this.serverless.config.servicePath}/${baseDir}local-authorizers.js`;
// make sure our sub-dir exists.
const basePath = `${this.serverless.config.servicePath}/${baseDir}`;
if (!(0, fs_1.existsSync)(basePath)) {
(0, fs_1.mkdirSync)(basePath, { recursive: true });
}
const content = this.config.lambdaVersion === 'v2'
? GENERATE_JS_FILE_V2(this.config.lambdaEndpoint, this.config.lambdaAuthFnName)
: GENERATE_JS_FILE_V3(this.config.lambdaEndpoint, this.config.lambdaAuthFnName);
(0, fs_1.writeFileSync)(authorizerSrcFilename, content);
}
authorizers = require(authorizerSrcFilename);
}
catch (err) {
console.error(err);
this.serverless.cli.log(`Unable to load local authorizers from ${err && err.message || err}`, "serverless-offline-local-auth-plugin", { color: "red" });
return null;
}
return Object.keys(authorizers).reduce((prev, authorizerName) => {
const functionKey = `$_LOCAL_AUTH_${authorizerName}`;
this.serverless.service.functions[functionKey] = {
memorySize: 256,
timeout: 30,
handler: `${baseDir}local-authorizers.${authorizerName}`,
events: [],
name: `${this.serverless.service.service}-${this.options.stage}-${authorizerName}`,
package: {
include: [[baseDir, authorizerSrcFilename].filter(Boolean).join('/')],
exclude: []
},
runtime: "nodejs14.x"
};
prev[authorizerName] = functionKey;
return prev;
}, {});
}
}
exports.AwsLocalAuthorizerPlugin = AwsLocalAuthorizerPlugin;
//# sourceMappingURL=AwsLocalAuthorizersPlugin.js.map