Skip to content

Commit

Permalink
Merge pull request #2484 from NDLANO/express5
Browse files Browse the repository at this point in the history
Express 5
  • Loading branch information
jnatten authored Oct 10, 2024
2 parents 9d50f97 + a7a9be9 commit 508b598
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 197 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"start": "cross-env NODE_ENV=development NODE_OPTIONS='--max-old-space-size=3072 --preserve-symlinks' concurrently \"yarn start:tsc\" \"tsx src/index.ts\"",
"start-with-local-converter": "LOCAL_CONVERTER=true NODE_OPTIONS='--preserve-symlinks' yarn start",
"start-prod": "cross-env NODE_ENV=production node build/server.mjs",
"start-minimal": "NODE_ENV=development NODE_OPTIONS='--max-old-space-size=3072 --preserve-symlinks' tsx src/index.ts",
"now-start": "cross-env NODE_ENV=production NOW=true node build/server.mjs",
"test": "vitest --run",
"tdd": "vitest",
Expand Down Expand Up @@ -46,7 +47,7 @@
"@testing-library/react": "^15.0.2",
"@types/auth0-js": "^9.13.2",
"@types/diff-match-patch": "^1.0.32",
"@types/express": "^4.17.21",
"@types/express": "^5.0.0",
"@types/node": "^20.12.12",
"@types/node-fetch": "^2.6.2",
"@types/prismjs": "^1.26.0",
Expand Down Expand Up @@ -114,7 +115,7 @@
"diff-match-patch": "^1.0.5",
"downshift": "^3.2.12",
"escape-html": "^1.0.3",
"express": "^4.19.2",
"express": "^5.0.0",
"express-jwt": "^8.4.1",
"form-data": "^4.0.0",
"formik": "^2.4.5",
Expand Down
118 changes: 47 additions & 71 deletions src/server/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type NdlaUser = {
};

// Temporal hack to send users to prod
router.get("*", (req, res, next) => {
router.get("*splat", (req, res, next) => {
if (!req.hostname.includes("ed.ff")) {
next();
} else {
Expand Down Expand Up @@ -60,91 +60,67 @@ router.get("/get_brightcove_token", (_, res) => {
.catch((err) => res.status(INTERNAL_SERVER_ERROR).send(err.message));
});

router.get(
"/get_note_users",
jwt({
const jwtMiddleware = async (req: express.Request, res: express.Response, next: express.NextFunction) => {
await jwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
jwksUri: `https://${config.auth0Domain}/.well-known/jwks.json`,
}) as GetVerificationKey,
audience: "ndla_system",
issuer: `https://${config.auth0Domain}/`,
algorithms: ["RS256"],
}),
async (req: Request, res) => {
const {
auth: untypedUser,
query: { userIds },
} = req;

const user = untypedUser as NdlaUser;

const hasWriteAccess =
user &&
user.permissions &&
(user.permissions.includes(DRAFT_WRITE_SCOPE) || user.permissions.includes(DRAFT_PUBLISH_SCOPE));

if (!hasWriteAccess) {
res.status(FORBIDDEN).json({ status: FORBIDDEN, text: "No access allowed" });
} else {
try {
const managementToken = await getToken(`https://${config.auth0Domain}/api/v2/`);
const users = await fetchAuth0UsersById(managementToken, userIds as string);
res.status(OK).json(users);
} catch (err) {
res.status(INTERNAL_SERVER_ERROR).send((err as NdlaError).message);
}
}
},
);
})(req, res, next);
};

router.get(
"/get_editors",
jwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
jwksUri: `https://${config.auth0Domain}/.well-known/jwks.json`,
}) as GetVerificationKey,
audience: "ndla_system",
issuer: `https://${config.auth0Domain}/`,
algorithms: ["RS256"],
}),
async (_, res) => {
try {
const managementToken = await getToken(`https://${config.auth0Domain}/api/v2/`);
const editors = await getEditors(managementToken);
res.status(OK).json(editors);
} catch (err) {
res.status(INTERNAL_SERVER_ERROR).send((err as NdlaError).message);
}
},
);
router.get("/get_note_users", jwtMiddleware, async (req: Request, res) => {
const {
auth: untypedUser,
query: { userIds },
} = req;

router.get(
"/get_responsibles",
jwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
jwksUri: `https://${config.auth0Domain}/.well-known/jwks.json`,
}) as GetVerificationKey,
audience: "ndla_system",
issuer: `https://${config.auth0Domain}/`,
algorithms: ["RS256"],
}),
async (req, res) => {
const {
query: { permission },
} = req;
const user = untypedUser as NdlaUser;

const hasWriteAccess =
user &&
user.permissions &&
(user.permissions.includes(DRAFT_WRITE_SCOPE) || user.permissions.includes(DRAFT_PUBLISH_SCOPE));

if (!hasWriteAccess) {
res.status(FORBIDDEN).json({ status: FORBIDDEN, text: "No access allowed" });
} else {
try {
const managementToken = await getToken(`https://${config.auth0Domain}/api/v2/`);
const editors = await getResponsibles(managementToken, permission as string);
res.status(OK).json(editors);
const users = await fetchAuth0UsersById(managementToken, userIds as string);
res.status(OK).json(users);
} catch (err) {
res.status(INTERNAL_SERVER_ERROR).send((err as NdlaError).message);
}
},
);
}
});

router.get("/get_editors", jwtMiddleware, async (_, res) => {
try {
const managementToken = await getToken(`https://${config.auth0Domain}/api/v2/`);
const editors = await getEditors(managementToken);
res.status(OK).json(editors);
} catch (err) {
res.status(INTERNAL_SERVER_ERROR).send((err as NdlaError).message);
}
});

router.get("/get_responsibles", jwtMiddleware, async (req, res) => {
const {
query: { permission },
} = req;

try {
const managementToken = await getToken(`https://${config.auth0Domain}/api/v2/`);
const editors = await getResponsibles(managementToken, permission as string);
res.status(OK).json(editors);
} catch (err) {
res.status(INTERNAL_SERVER_ERROR).send((err as NdlaError).message);
}
});

router.post("/csp-report", (req, res) => {
const { body } = req;
Expand Down
11 changes: 4 additions & 7 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import fs from "fs/promises";
import { join } from "path";
import bodyParser from "body-parser";
import compression from "compression";
import express from "express";
import helmet from "helmet";
Expand Down Expand Up @@ -45,7 +44,7 @@ if (!isProduction) {
const allowedBodyContentTypes = ["application/csp-report", "application/json"];

// Temporal hack to send users to prod
app.get("*", (req, res, next) => {
app.get("*splat", (req, res, next) => {
if (!req.hostname.includes("ed.ff")) {
next();
} else {
Expand All @@ -57,11 +56,9 @@ app.get("*", (req, res, next) => {
if (!config.isVercel) {
app.use(compression());
}
app.use(express.json({ limit: "1mb" }));
app.use(express.json());

app.use(
bodyParser.json({
express.json({
limit: "1mb",
type: (req) => {
const contentType = req.headers["content-type"];
if (typeof contentType === "string") return allowedBodyContentTypes.includes(contentType);
Expand Down Expand Up @@ -91,7 +88,7 @@ const serializedConfig = serialize(config);

app.use(api);

app.get("*", async (req, res) => {
app.get("*splat", async (req, res) => {
try {
const url = req.originalUrl.replace(base, "");

Expand Down
Loading

0 comments on commit 508b598

Please sign in to comment.