Skip to content

Commit 97a8446

Browse files
authored
Merge branch 'main' into siglead-management
2 parents c9e5a37 + 898dc96 commit 97a8446

File tree

8 files changed

+102
-33
lines changed

8 files changed

+102
-33
lines changed

src/api/index.ts

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,76 @@
1-
/* eslint import/no-nodejs-modules: ["error", {"allow": ["crypto"]}] */
1+
/* eslint import/no-nodejs-modules: ["error", {"allow": ["crypto", "path", "url"]}] */
22

33
import { randomUUID } from "crypto";
4+
import { fileURLToPath } from "url";
5+
import path from "path";
46
import fastify, { FastifyInstance } from "fastify";
5-
import FastifyAuthProvider from "@fastify/auth";
6-
import fastifyStatic from "@fastify/static";
7-
import fastifyAuthPlugin, { getSecretValue } from "./plugins/auth.js";
8-
import protectedRoute from "./routes/protected.js";
9-
import errorHandlerPlugin from "./plugins/errorHandler.js";
107
import { RunEnvironment, runEnvironments } from "../common/roles.js";
118
import { InternalServerError } from "../common/errors/index.js";
12-
import eventsPlugin from "./routes/events.js";
13-
import cors from "@fastify/cors";
149
import {
1510
environmentConfig,
1611
genericConfig,
1712
SecretConfig,
1813
} from "../common/config.js";
19-
import organizationsPlugin from "./routes/organizations.js";
20-
import authorizeFromSchemaPlugin from "./plugins/authorizeFromSchema.js";
21-
import evaluatePoliciesPlugin from "./plugins/evaluatePolicies.js";
22-
import icalPlugin from "./routes/ics.js";
23-
import vendingPlugin from "./routes/vending.js";
2414
import * as dotenv from "dotenv";
25-
import iamRoutes from "./routes/iam.js";
26-
import ticketsPlugin from "./routes/tickets.js";
27-
import linkryRoutes from "./routes/linkry.js";
28-
import sigleadRoutes from "./routes/siglead.js";
2915
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
3016
import NodeCache from "node-cache";
3117
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
3218
import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
33-
import mobileWalletRoute from "./routes/mobileWallet.js";
34-
import stripeRoutes from "./routes/stripe.js";
35-
import membershipPlugin from "./routes/membership.js";
36-
import path from "path"; // eslint-disable-line import/no-nodejs-modules
37-
import roomRequestRoutes from "./routes/roomRequests.js";
38-
import logsPlugin from "./routes/logs.js";
39-
4019
import {
4120
fastifyZodOpenApiPlugin,
4221
fastifyZodOpenApiTransform,
4322
fastifyZodOpenApiTransformObject,
4423
serializerCompiler,
4524
validatorCompiler,
4625
} from "fastify-zod-openapi";
47-
import { ZodOpenApiVersion } from "zod-openapi";
26+
import { type ZodOpenApiVersion } from "zod-openapi";
4827
import { withTags } from "./components/index.js";
28+
import RedisModule from "ioredis";
29+
30+
/** BEGIN EXTERNAL PLUGINS */
31+
import fastifyIp from "fastify-ip";
32+
import cors from "@fastify/cors";
33+
import FastifyAuthProvider from "@fastify/auth";
34+
import fastifyStatic from "@fastify/static";
35+
/** END EXTERNAL PLUGINS */
36+
37+
/** BEGIN INTERNAL PLUGINS */
38+
import locationPlugin from "./plugins/location.js";
39+
import fastifyAuthPlugin, { getSecretValue } from "./plugins/auth.js";
40+
import errorHandlerPlugin from "./plugins/errorHandler.js";
41+
import authorizeFromSchemaPlugin from "./plugins/authorizeFromSchema.js";
42+
import evaluatePoliciesPlugin from "./plugins/evaluatePolicies.js";
43+
/** END INTERNAL PLUGINS */
44+
45+
/** BEGIN ROUTES */
46+
import organizationsPlugin from "./routes/organizations.js";
47+
import icalPlugin from "./routes/ics.js";
48+
import vendingPlugin from "./routes/vending.js";
49+
import iamRoutes from "./routes/iam.js";
50+
import ticketsPlugin from "./routes/tickets.js";
51+
import linkryRoutes from "./routes/linkry.js";
52+
import mobileWalletRoute from "./routes/mobileWallet.js";
53+
import stripeRoutes from "./routes/stripe.js";
54+
import membershipPlugin from "./routes/membership.js";
55+
import roomRequestRoutes from "./routes/roomRequests.js";
56+
import logsPlugin from "./routes/logs.js";
4957
import apiKeyRoute from "./routes/apiKey.js";
5058
import clearSessionRoute from "./routes/clearSession.js";
51-
import RedisModule from "ioredis";
52-
import { fileURLToPath } from "url"; // eslint-disable-line import/no-nodejs-modules
59+
import protectedRoute from "./routes/protected.js";
60+
import eventsPlugin from "./routes/events.js";
61+
import sigleadRoutes from "./routes/siglead.js";
62+
/** END ROUTES */
63+
5364
const __filename = fileURLToPath(import.meta.url);
5465
const __dirname = path.dirname(__filename);
5566

5667
dotenv.config();
5768

5869
const now = () => Date.now();
70+
const isRunningInLambda =
71+
process.env.LAMBDA_TASK_ROOT || process.env.AWS_LAMBDA_FUNCTION_NAME;
5972

6073
async function init(prettyPrint: boolean = false, initClients: boolean = true) {
61-
const isRunningInLambda =
62-
process.env.LAMBDA_TASK_ROOT || process.env.AWS_LAMBDA_FUNCTION_NAME;
6374
let isSwaggerServer = false;
6475
const transport = prettyPrint
6576
? {
@@ -96,6 +107,7 @@ async function init(prettyPrint: boolean = false, initClients: boolean = true) {
96107
await app.register(evaluatePoliciesPlugin);
97108
await app.register(errorHandlerPlugin);
98109
await app.register(fastifyZodOpenApiPlugin);
110+
await app.register(locationPlugin);
99111
if (!isRunningInLambda) {
100112
try {
101113
const fastifySwagger = import("@fastify/swagger");
@@ -279,6 +291,14 @@ async function init(prettyPrint: boolean = false, initClients: boolean = true) {
279291
await app.refreshSecretConfig();
280292
app.redisClient = new RedisModule.default(app.secretConfig.redis_url);
281293
}
294+
if (isRunningInLambda) {
295+
await app.register(fastifyIp.default, {
296+
order: ["x-forwarded-for"],
297+
strict: true,
298+
isAWS: false,
299+
});
300+
}
301+
282302
app.addHook("onRequest", (req, _, done) => {
283303
req.startTime = now();
284304
const hostname = req.hostname;
@@ -339,6 +359,7 @@ async function init(prettyPrint: boolean = false, initClients: boolean = true) {
339359
origin: app.environmentConfig.ValidCorsOrigins,
340360
methods: ["GET", "HEAD", "POST", "PATCH", "DELETE"],
341361
});
362+
342363
app.addHook("onSend", async (request, reply) => {
343364
reply.header("X-Request-Id", request.id);
344365
});

src/api/lambda.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const handler = async (event: APIGatewayEvent, context: Context) => {
2929
isBase64Encoded: false,
3030
};
3131
}
32+
delete event.headers["x-origin-verify"];
3233
}
3334
// else proceed with handler logic
3435
return await realHandler(event, context).catch((e) => {

src/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"dotenv": "^16.5.0",
4141
"esbuild": "^0.25.3",
4242
"fastify": "^5.3.2",
43+
"fastify-ip": "^1.2.0",
4344
"fastify-plugin": "^5.0.1",
4445
"fastify-raw-body": "^5.0.0",
4546
"fastify-zod-openapi": "^5.0.1",

src/api/plugins/errorHandler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ const errorHandlerPlugin = fp(async (fastify) => {
4747
},
4848
);
4949
fastify.setNotFoundHandler((request: FastifyRequest) => {
50-
throw new NotFoundError({ endpointName: request.url });
50+
throw new NotFoundError({
51+
endpointName: `${request.method} ${request.url}`,
52+
});
5153
});
5254
});
5355

src/api/plugins/location.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import fp from "fastify-plugin";
2+
3+
const locationPlugin = fp(async (fastify, opts) => {
4+
const processHeader = (headerValue: string | string[] | undefined) => {
5+
if (Array.isArray(headerValue)) {
6+
return headerValue.join(",");
7+
}
8+
return headerValue;
9+
};
10+
11+
fastify.decorateRequest("location", {
12+
getter() {
13+
return {
14+
country: processHeader(this.headers["cloudfront-viewer-country"]),
15+
city: processHeader(this.headers["cloudfront-viewer-city"]),
16+
region: processHeader(this.headers["cloudfront-viewer-country-region"]),
17+
latitude: processHeader(this.headers["cloudfront-viewer-latitude"]),
18+
longitude: processHeader(this.headers["cloudfront-viewer-longitude"]),
19+
postalCode: processHeader(
20+
this.headers["cloudfront-viewer-postal-code"],
21+
),
22+
};
23+
},
24+
});
25+
});
26+
27+
export default locationPlugin;

src/api/routes/apiKey.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ Key ID: acmuiuc_${keyId}
105105
106106
Key Description: ${description}
107107
108-
IP address: ${request.ip}.
109-
108+
IP address: ${request.ip}
109+
${request.location.city && request.location.region && request.location.country ? `\nLocation: ${request.location.city}, ${request.location.region}, ${request.location.country}\n` : ""}
110110
Roles: ${roles.join(", ")}.
111111
112112
If you did not create this API key, please secure your account and notify the ACM Infrastructure team.
@@ -210,7 +210,7 @@ This email confirms that an API key for the Core API has been deleted from your
210210
Key ID: acmuiuc_${keyId}
211211
212212
IP address: ${request.ip}.
213-
213+
${request.location.city && request.location.region && request.location.country ? `\nLocation: ${request.location.city}, ${request.location.region}, ${request.location.country}\n` : ""}
214214
If you did not delete this API key, please secure your account and notify the ACM Infrastructure team.
215215
`,
216216
callToActionButton: {

src/api/types.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ import { AvailableAuthorizationPolicy } from "common/policies/definition.js";
1212
import type RedisModule from "ioredis";
1313
type Redis = RedisModule.default;
1414

15+
interface CloudfrontLocation {
16+
country: string | undefined;
17+
city: string | undefined;
18+
region: string | undefined;
19+
latitude: string | undefined;
20+
longitude: string | undefined;
21+
postalCode: string | undefined;
22+
}
23+
1524
declare module "fastify" {
1625
interface FastifyInstance {
1726
authenticate: (
@@ -45,6 +54,7 @@ declare module "fastify" {
4554
userRoles?: Set<AppRoles>;
4655
tokenPayload?: AadToken;
4756
policyRestrictions?: AvailableAuthorizationPolicy[];
57+
location: CloudfrontLocation;
4858
}
4959
}
5060

yarn.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5633,6 +5633,13 @@ fastest-levenshtein@^1.0.16:
56335633
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
56345634
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
56355635

5636+
fastify-ip@^1.2.0:
5637+
version "1.2.0"
5638+
resolved "https://registry.yarnpkg.com/fastify-ip/-/fastify-ip-1.2.0.tgz#bd65121e843f407870da11f1a721afe5083f44a1"
5639+
integrity sha512-n7BqGlEMZmaG/zEdrp7/fShBUNWfgT6EKXfC3FERTzuSPZSo8gxfq0kjD8PhAjD1I1o7oqo5Wc/m7jr+Fn+HRg==
5640+
dependencies:
5641+
fastify-plugin "^5.0.1"
5642+
56365643
fastify-plugin@^5.0.0, fastify-plugin@^5.0.1:
56375644
version "5.0.1"
56385645
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-5.0.1.tgz#82d44e6fe34d1420bb5a4f7bee434d501e41939f"

0 commit comments

Comments
 (0)