Skip to content

Commit

Permalink
forward apig api-key to proxy server
Browse files Browse the repository at this point in the history
  • Loading branch information
Inqnuam committed Jul 9, 2024
1 parent f9a8d91 commit 69d0278
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"archiver": "^5.3.1",
"esbuild": "0.21.5",
"fast-xml-parser": "^4.4.0",
"local-aws-sqs": "^1.0.1",
"local-aws-sqs": "^1.0.2",
"serve-static": "^1.15.0"
},
"devDependencies": {
Expand Down
28 changes: 8 additions & 20 deletions src/plugins/lambda/events/apg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { LambdaEndpoint } from "../../../lib/parseEvents/endpoints";
import { CommonEventGenerator } from "./common";
import { log } from "../../../lib/utils/colorize";
import { randomUUID } from "crypto";
import { capitalize } from "../utils";

interface CommonApgEvent {
body?: string;
Expand Down Expand Up @@ -97,7 +96,6 @@ export class ApgRequestHandler extends CommonEventGenerator {
: ApgRequestHandler.createApgV2Event({ req, mockEvent, parsedURL, requestId, isBase64Encoded, body });
}

static knownHeaders: string[] = ["content-length", "host", "user-agent"];
static skipHeaders: string[] = ["connection", "content"];
static createApgV2Event = ({
req,
Expand Down Expand Up @@ -193,7 +191,6 @@ export class ApgRequestHandler extends CommonEventGenerator {
mockEvent,
parsedURL,
lambdaName,
multiValueHeaders,
isBase64Encoded,
requestId,
body,
Expand All @@ -218,21 +215,11 @@ export class ApgRequestHandler extends CommonEventGenerator {
event.path = parsedURL.pathname;
event.httpMethod = method!;

const headers = ApgRequestHandler.getCustomHeaders(req, mockEvent);
const { headers, multiValueHeaders, apiKey } = ApgRequestHandler.getApiGV1Headers(req, mockEvent);

event.headers = headers;

event.multiValueHeaders = multiValueHeaders;
const sourceIp = String(req.socket.remoteAddress);
const mergedMultiValueHeaders: any = {
"X-Forwarded-For": [sourceIp],
"X-Forwarded-Proto": ["http"],
"X-Forwarded-Port": [String(ApgRequestHandler.port)],
};
Object.entries(multiValueHeaders).forEach(([key, value]) => {
mergedMultiValueHeaders[this.#normalizeHeaderKey(key)] = value;
});

event.multiValueHeaders = mergedMultiValueHeaders;

const queryStringParameters: any = Object.fromEntries(parsedURL.searchParams);
event.queryStringParameters = Object.keys(queryStringParameters).length ? queryStringParameters : null;
Expand Down Expand Up @@ -274,6 +261,10 @@ export class ApgRequestHandler extends CommonEventGenerator {
requestContext.stage = "$default";
} else {
requestContext.stage = "dev";
if (mockEvent.private) {
requestContext.identity.apiKey = apiKey;
requestContext.identity.apiKeyId = "abcdefghjk";
}
}
event.requestContext = requestContext;

Expand Down Expand Up @@ -316,9 +307,6 @@ export class ApgRequestHandler extends CommonEventGenerator {
return this.res.end(body);
};

static #normalizeHeaderKey = (key: string) => {
return key.toLowerCase().split("-").map(capitalize).join("-");
};
#normalizeV1Value = (v: any) => {
let value: string | null = "";
const vType = typeof v;
Expand Down Expand Up @@ -347,7 +335,7 @@ export class ApgRequestHandler extends CommonEventGenerator {

if (output.headers && typeof output.headers == "object" && !Array.isArray(output.headers)) {
Object.entries(output.headers).forEach(([k, v]) => {
const key = ApgRequestHandler.#normalizeHeaderKey(k);
const key = ApgRequestHandler.normalizeHeaderKey(k);
const value = this.#normalizeV1Value(v);

headers.push([key, value]);
Expand All @@ -356,7 +344,7 @@ export class ApgRequestHandler extends CommonEventGenerator {

if (output.multiValueHeaders && typeof output.multiValueHeaders == "object" && !Array.isArray(output.multiValueHeaders)) {
Object.entries(output.multiValueHeaders).forEach(([k, v]) => {
const key = ApgRequestHandler.#normalizeHeaderKey(k);
const key = ApgRequestHandler.normalizeHeaderKey(k);

if (!Array.isArray(v)) {
throw new Error();
Expand Down
79 changes: 79 additions & 0 deletions src/plugins/lambda/events/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { IncomingMessage, IncomingHttpHeaders } from "http";
import type { LambdaEndpoint } from "../../../lib/parseEvents/endpoints";
import { capitalize } from "../utils";

export type normalizedSearchParams = { toString: () => string } & { [key: string]: string[] | undefined };

Expand All @@ -23,6 +24,10 @@ export class CommonEventGenerator {
static unavailable = '{"message":"Service Unavailable"}';
static timeoutRegex = /after.\d+.*seconds/;
static apgRequestTimeout = 30;

static normalizeHeaderKey = (key: string) => {
return key.toLowerCase().split("-").map(capitalize).join("-");
};
static getMultiValueHeaders = (rawHeaders: string[]) => {
let multiValueHeaders: any = {};
const multiKeys = rawHeaders.filter((x, i) => i % 2 == 0).map((x) => x.toLowerCase());
Expand Down Expand Up @@ -60,6 +65,80 @@ export class CommonEventGenerator {
return true;
};

static knownHeaders: string[] = ["accept", "accept-encoding", "user-agent", "host", "via", "content-length"];
static getApiGV1Headers(req: IncomingMessage, mockEvent: LambdaEndpoint) {
const { rawHeaders } = req;

let apiKey: string | undefined = undefined;

const reqHeaders: any = { "X-Forwarded-For": req.socket.remoteAddress, "X-Forwarded-Proto": "http", "X-Forwarded-Port": String(CommonEventGenerator.port) };

for (let i = 0; i < rawHeaders.length; ) {
let key = rawHeaders[i];
const loweredKey = key.toLowerCase();

if (["connection", "x-mock-type"].includes(loweredKey)) {
i = i + 2;
continue;
}

if (this.knownHeaders.includes(loweredKey)) {
key = this.normalizeHeaderKey(loweredKey);
}

const value = rawHeaders[i + 1];
reqHeaders[key] = value;

if (loweredKey == "x-api-key") {
apiKey = value;
}

i = i + 2;
}

const headers: any = {};

for (const key of Object.keys(reqHeaders).sort((a, b) => a.localeCompare(b))) {
headers[key] = reqHeaders[key];
}

const reqMultiValueHeaders: Record<string, any[]> = {
"X-Forwarded-For": [req.socket.remoteAddress],
"X-Forwarded-Proto": ["http"],
"X-Forwarded-Port": [String(CommonEventGenerator.port)],
};

for (let i = 0; i < rawHeaders.length; ) {
let key = rawHeaders[i];
const loweredKey = key.toLowerCase();

if (["connection", "x-mock-type"].includes(loweredKey)) {
i = i + 2;
continue;
}

if (this.knownHeaders.includes(loweredKey)) {
key = this.normalizeHeaderKey(loweredKey);
}

const value = rawHeaders[i + 1];

if (reqMultiValueHeaders[key]) {
reqMultiValueHeaders[key].push(value);
} else {
reqMultiValueHeaders[key] = [value];
}

i = i + 2;
}

const multiValueHeaders: Record<string, any[]> = {};
for (const key of Object.keys(reqMultiValueHeaders).sort((a, b) => a.localeCompare(b))) {
multiValueHeaders[key] = reqMultiValueHeaders[key];
}

return { headers, multiValueHeaders, apiKey };
}
static getCustomHeaders(req: IncomingMessage, mockEvent: LambdaEndpoint) {
const { headers } = req;
delete headers["x-mock-type"];
Expand Down
2 changes: 1 addition & 1 deletion templates/simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"devDependencies": {
"prettier": "3.2.5",
"serverless": "^3.38.0",
"serverless-aws-lambda": "^4.8.1",
"serverless-aws-lambda": "^4.8.2",
"serverless-aws-lambda-vitest": "^2.0.0",
"typescript": "^5.5.3"
},
Expand Down

0 comments on commit 69d0278

Please sign in to comment.