summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-05-31 20:29:26 +0200
committerRory& <root@rory.gay>2025-05-31 20:29:26 +0200
commit41ca4013e394d454f1d9b97b873b908a002d36b4 (patch)
tree8c7b2ae96d5c2ccea1bc8e47132e569e1f5fc5e4
parentAdd plan and readme (diff)
downloadnodejs-final-assignment-41ca4013e394d454f1d9b97b873b908a002d36b4.tar.xz
Generate jwt secrets
-rw-r--r--.env2
-rw-r--r--.idea/vcs.xml1
-rw-r--r--README.md1
-rw-r--r--src/api/routes/auth/registerRoute.js2
-rw-r--r--src/api/routes/statusRoute.js2
-rw-r--r--src/api/start.js2
-rw-r--r--src/db/db.js1
-rw-r--r--src/db/schemas/user.js2
-rw-r--r--src/util/index.js1
-rw-r--r--src/util/jwtUtils.js63
-rw-r--r--src/util/secretUtils.js3
11 files changed, 76 insertions, 4 deletions
diff --git a/.env b/.env
new file mode 100644

index 0000000..1effdc1 --- /dev/null +++ b/.env
@@ -0,0 +1,2 @@ +export DATABASE_SECRET_PATH=/home/Rory/.config/SafeNSound/mongodb +export JWT_SECRET_PATH=/home/Rory/.config/SafeNSound diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1dd..f9c95a4 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml
@@ -2,5 +2,6 @@ <project version="4"> <component name="VcsDirectoryMappings"> <mapping directory="" vcs="Git" /> + <mapping directory="$PROJECT_DIR$/testFrontend/SafeNSound" vcs="Git" /> </component> </project> \ No newline at end of file diff --git a/README.md b/README.md
index 6386c3a..a3069c3 100644 --- a/README.md +++ b/README.md
@@ -13,3 +13,4 @@ Environment variables: | `PORT` | `3000` | The port the server will run on. | | `LOG_REQUESTS` | `-` | Requests to log to the console by status, `-` to invert. | | `DATABASE_SECRET_PATH` | `` | The path to the mongodb connection string. | +| `JWT_SECRET_PATH` | `` | The path to the JWT secret certificate. | \ No newline at end of file diff --git a/src/api/routes/auth/registerRoute.js b/src/api/routes/auth/registerRoute.js
index 8ad4f07..f2befd8 100644 --- a/src/api/routes/auth/registerRoute.js +++ b/src/api/routes/auth/registerRoute.js
@@ -1,4 +1,4 @@ -import { User } from '#db/index.js'; +import { DbUser } from '#db/index.js'; export const registerRoute = { route: '/auth/register', diff --git a/src/api/routes/statusRoute.js b/src/api/routes/statusRoute.js
index 41208a4..5c3231b 100644 --- a/src/api/routes/statusRoute.js +++ b/src/api/routes/statusRoute.js
@@ -1,4 +1,4 @@ -import { User } from '#db/schemas/user.js'; +import { DbUser } from '#db/index.js'; export const statusRoute = { route: '/status', diff --git a/src/api/start.js b/src/api/start.js
index 6aa4567..6f57afd 100644 --- a/src/api/start.js +++ b/src/api/start.js
@@ -2,12 +2,14 @@ import express from 'express'; import { registerRoutes } from './routes.js'; import { useCors, useLogging } from './middlewares/index.js'; import { initDb } from '#db/index.js'; +import {initJwt} from "#util/index.js"; const app = express(); const PORT = process.env.PORT ?? 3000; const logRequests = process.env['LOG_REQUESTS'] ?? '-'; await initDb(); +await initJwt(); // Configure Express app.use(express.json()); diff --git a/src/db/db.js b/src/db/db.js
index 9a7b50e..b9a425c 100644 --- a/src/db/db.js +++ b/src/db/db.js
@@ -3,6 +3,7 @@ import { readSecret } from '#util/secretUtils.js'; export async function initDb() { const connectionString = await readSecret( + "MongoDB connection string", process.env['DATABASE_SECRET_PATH'] ); try { diff --git a/src/db/schemas/user.js b/src/db/schemas/user.js
index 22856b2..1a7e048 100644 --- a/src/db/schemas/user.js +++ b/src/db/schemas/user.js
@@ -23,7 +23,7 @@ export const userSchema = new Schema({ }, type: { type: String, - enum: ['user', 'admin'], + enum: ['user', 'monitor', 'admin'], default: 'user' }, createdAt: { diff --git a/src/util/index.js b/src/util/index.js
index 6b51d7b..e5f345c 100644 --- a/src/util/index.js +++ b/src/util/index.js
@@ -1 +1,2 @@ export * from './secretUtils.js'; +export * from './jwtUtils.js'; \ No newline at end of file diff --git a/src/util/jwtUtils.js b/src/util/jwtUtils.js new file mode 100644
index 0000000..115c9c5 --- /dev/null +++ b/src/util/jwtUtils.js
@@ -0,0 +1,63 @@ +import {existsSync} from 'fs'; +import {readFile, writeFile} from "node:fs/promises"; +import {generateKeyPairSync, createHash, createPublicKey, createPrivateKey} from 'node:crypto'; + +let privateKey, publicKey, fingerprint; + +export async function initJwt() { + const secretPath = process.env.JWT_SECRET_PATH; + if (!secretPath || !existsSync(secretPath)) { + throw new Error('JWT secret path is not defined in environment variables, or the directory does not exist.'); + } + + const privateKeyPath = `${secretPath}/jwt.key`; + const publicKeyPath = `${secretPath}/jwt.key.pub`; + + if (!existsSync(privateKeyPath)) { + console.log("[JWT] Generating new keypair"); + const keyPair = generateKeyPairSync("ec", { + namedCurve: "secp521r1", + }); + + privateKey = keyPair.privateKey; + publicKey = keyPair.publicKey; + + await Promise.all([ + writeFile( + privateKeyPath, + privateKey.export({format: "pem", type: "sec1"}), + ), + writeFile( + publicKeyPath, + publicKey.export({format: "pem", type: "spki"}), + ), + ]); + console.log("[JWT] Keypair generated successfully."); + } else { + console.log("[JWT] Using existing keypair"); + const loadedPrivateKey = await readFile(privateKeyPath, 'utf8'); + const loadedPublicKey = await readFile(publicKeyPath, 'utf8'); + + privateKey = createPrivateKey(loadedPrivateKey); + publicKey = createPublicKey(loadedPublicKey); + } + + fingerprint = createHash("sha256") + .update(publicKey.export({format: "pem", type: "spki"})) + .digest("hex"); +} + +/** + * @type {import('jsonwebtoken').JwtOptions} + */ +const jwtOptions = { + algorithm: 'ES512', +} + +export async function generateJwtToken(user) { + +} + +export async function validateJwtToken(token) { + +} \ No newline at end of file diff --git a/src/util/secretUtils.js b/src/util/secretUtils.js
index bbad8ca..92e1b1c 100644 --- a/src/util/secretUtils.js +++ b/src/util/secretUtils.js
@@ -1,6 +1,7 @@ import fs from 'node:fs/promises'; -export async function readSecret(path) { +export async function readSecret(name, path) { + console.log(`[SECRET] Reading secret "${name}" from path: ${path}`); if (!path) { throw new Error('Path to secret file is required'); }