From 329a9dfee54245cb3b7fd42d013c645564706759 Mon Sep 17 00:00:00 2001 From: Awosdot Date: Tue, 25 Aug 2026 06:48:38 +0100 Subject: [PATCH 1/6] feat(backend): add request-id-scoped child logging (#368) --- backend/package-lock.json | 159 ++++++++++++-------------------------- backend/package.json | 4 +- package-lock.json | 6 ++ 3 files changed, 57 insertions(+), 112 deletions(-) create mode 100644 package-lock.json diff --git a/backend/package-lock.json b/backend/package-lock.json index 2a41a465..74938ed0 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,7 +12,7 @@ "@stellar/stellar-sdk": "^12.0.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", - "csurf": "^1.11.0", + "csurf": "^1.2.2", "date-fns": "^3.6.0", "date-fns-tz": "^3.2.0", "dotenv": "^16.4.5", @@ -30,7 +30,7 @@ "socket.io": "^4.8.3", "swagger-jsdoc": "6.2.8", "swagger-ui-express": "5.0.1", - "uuid": "^10.0.0", + "uuid": "^14.0.2", "zod": "^3.25.76" }, "devDependencies": { @@ -2549,6 +2549,12 @@ ], "license": "MIT" }, + "node_modules/base64-url": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz", + "integrity": "sha512-UiVPRwO/m133KIQrOEIqO07D8jaYjFIx7/lYRWTRVR23tDSn00Ves6A+Bk0eLmhyz6IJGSFlNCKUuUBO2ssytA==", + "license": "ISC" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -3169,100 +3175,31 @@ "node": ">= 8" } }, - "node_modules/csrf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", - "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "node_modules/csrf-tokens": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/csrf-tokens/-/csrf-tokens-2.0.0.tgz", + "integrity": "sha512-IzcrVVxQJvHoeNSSA9zc9LqIBUPM3OdRUzJ/4ooSbROhvJOSAi6qve2J6XEhmltcECmf/UiR/pgzkHXY5x1mGA==", "license": "MIT", "dependencies": { - "rndm": "1.2.0", - "tsscmp": "1.0.6", - "uid-safe": "2.1.5" - }, - "engines": { - "node": ">= 0.8" + "base64-url": "1", + "rndm": "1", + "scmp": "~0.0.3", + "uid-safe": "1" } }, "node_modules/csurf": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", - "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.2.2.tgz", + "integrity": "sha512-wCwNMBSAzrj4918iemazALbLZBYQRVN4BpnSpVBcE5Cx5cx/5HPkkpidpL0k+Tbk3Dlg0pDSY3mUvh7Gqc5H7w==", "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", "license": "MIT", "dependencies": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "csrf": "3.1.0", - "http-errors": "~1.7.3" + "csrf-tokens": "~2.0.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/csurf/node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/csurf/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "license": "ISC" - }, - "node_modules/csurf/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/date-fns": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", @@ -6279,6 +6216,13 @@ "url": "https://opencollective.com/napi-postinstall" } }, + "node_modules/native-or-bluebird": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.1.2.tgz", + "integrity": "sha512-Bgn5FHNkd+lPTjIzq1NVU/VZTvPKFvhdIDEyYjxrKNrScSXbVvNVzOKwoleysun0/HoN7R+TXmK9mCtEs84osA==", + "deprecated": "'native-or-bluebird' is deprecated. Please use 'any-promise' instead.", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7110,15 +7054,6 @@ ], "license": "MIT" }, - "node_modules/random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7395,6 +7330,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scmp": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-0.0.3.tgz", + "integrity": "sha512-ya4sPuUOfcrJnfC+OUqTFgFVBEMOXMS1Xopn0wwIhxKwD4eveTwJoIUN9u1QHJ47nL29/m545dV8KqI92MlHPw==", + "deprecated": "scmp v2 uses improved core crypto comparison since Node v6.6.0", + "license": "BSD" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8177,15 +8119,6 @@ "license": "0BSD", "optional": true }, - "node_modules/tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "license": "MIT", - "engines": { - "node": ">=0.6.x" - } - }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -8340,17 +8273,24 @@ "license": "MIT" }, "node_modules/uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-1.1.0.tgz", + "integrity": "sha512-7+QtWs9zioL/iQX61G+4h3EPyr3H+tINIp0IAV4EL32vdf7qmFyuW0BgRqWl7p5oZOsEQrlL0bY7m5D8tp7b1w==", "license": "MIT", "dependencies": { - "random-bytes": "~1.0.0" + "base64-url": "1.2.1", + "native-or-bluebird": "~1.1.2" }, "engines": { "node": ">= 0.8" } }, + "node_modules/uid-safe/node_modules/base64-url": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", + "integrity": "sha512-V8E0l1jyyeSSS9R+J9oljx5eq2rqzClInuwaPcyuv0Mm3ViI/3/rcc4rCEO8i4eQ4I0O0FAGYDA2i5xWHHPhzg==", + "license": "ISC" + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -8468,17 +8408,16 @@ } }, "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", + "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/v8-to-istanbul": { diff --git a/backend/package.json b/backend/package.json index bf1cb985..53f54972 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,7 +16,7 @@ "@stellar/stellar-sdk": "^12.0.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", - "csurf": "^1.11.0", + "csurf": "^1.2.2", "date-fns": "^3.6.0", "date-fns-tz": "^3.2.0", "dotenv": "^16.4.5", @@ -34,7 +34,7 @@ "socket.io": "^4.8.3", "swagger-jsdoc": "6.2.8", "swagger-ui-express": "5.0.1", - "uuid": "^10.0.0", + "uuid": "^14.0.2", "zod": "^3.25.76" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..771c9315 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "GreenPay", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From a76aba819c6d1051dca399994e3c1e52fdcadbaa Mon Sep 17 00:00:00 2001 From: Awosdot Date: Tue, 25 Aug 2026 07:12:34 +0100 Subject: [PATCH 2/6] fix(backend): replace remaining uuid requires and update csrf test assertion --- backend/src/routes/csrf.test.js | 6 +++--- backend/src/services/notificationFailures.js | 2 +- backend/src/services/summaryQueue.js | 2 +- backend/src/services/turrets.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/routes/csrf.test.js b/backend/src/routes/csrf.test.js index a4e1f6ae..790c6786 100644 --- a/backend/src/routes/csrf.test.js +++ b/backend/src/routes/csrf.test.js @@ -20,9 +20,9 @@ describe("CSRF protection", () => { .expect(403); expect(res.body.error).toMatchObject({ - code: "EBADCSRFTOKEN", - message: expect.stringMatching(/csrf/i), - }); + code: "FORBIDDEN", + message: expect.stringMatching(/csrf/i), +}); }); it("allows mutating requests when a valid X-CSRF-Token header is provided", async () => { diff --git a/backend/src/services/notificationFailures.js b/backend/src/services/notificationFailures.js index 14fcfb3b..724d8131 100644 --- a/backend/src/services/notificationFailures.js +++ b/backend/src/services/notificationFailures.js @@ -8,7 +8,7 @@ */ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { logger: rootLogger } = require("../utils/logger"); diff --git a/backend/src/services/summaryQueue.js b/backend/src/services/summaryQueue.js index 609086af..c6ccb104 100644 --- a/backend/src/services/summaryQueue.js +++ b/backend/src/services/summaryQueue.js @@ -7,7 +7,7 @@ "use strict"; const crypto = require("crypto"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const PgBoss = require("pg-boss"); const pool = require("../db/pool"); const { env } = require("../config/env"); diff --git a/backend/src/services/turrets.js b/backend/src/services/turrets.js index 072b78a7..97dea74f 100644 --- a/backend/src/services/turrets.js +++ b/backend/src/services/turrets.js @@ -29,7 +29,7 @@ */ const { Server, TransactionBuilder, Networks, Memo, Operation, Asset } = require("@stellar/stellar-sdk"); -const { v4: uuidv4 } = require("uuid"); +const { randomUUID: uuidv4 } = require("crypto"); const pool = require("../db/pool"); const { env } = require("../config/env"); From 6d7624c860e253769f5e7fda05884f5def88d648 Mon Sep 17 00:00:00 2001 From: Awosdot Date: Tue, 25 Aug 2026 07:15:48 +0100 Subject: [PATCH 3/6] fix(backend): replace uuid requires and fix csrf test assertion --- backend/src/eventSourcing/commandBus.js | 2 +- backend/src/eventSourcing/commands.js | 2 +- backend/src/eventSourcing/events.js | 2 +- backend/src/eventSourcing/migrate.js | 2 +- backend/src/middleware/correlationId.js | 2 +- backend/src/middleware/correlationId.test.js | 2 +- backend/src/routes/donations.js | 2 +- backend/src/routes/leaderboard.integration.test.js | 2 +- backend/src/routes/notifications.js | 2 +- backend/src/routes/projects.js | 2 +- backend/src/routes/ratings.js | 2 +- backend/src/routes/subscriptions.js | 2 +- backend/src/routes/updates.js | 4 ++-- backend/src/services/audit.js | 2 +- backend/src/services/indexerService.integration.test.js | 2 +- backend/src/services/indexerService.js | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/backend/src/eventSourcing/commandBus.js b/backend/src/eventSourcing/commandBus.js index 6c13aaa0..2e23413b 100644 --- a/backend/src/eventSourcing/commandBus.js +++ b/backend/src/eventSourcing/commandBus.js @@ -1,6 +1,6 @@ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { ProjectAggregate, DonorAggregate, MatchAggregate, JobAggregate, round7 } = require("./aggregates"); const { eventStore } = require("./eventStore"); diff --git a/backend/src/eventSourcing/commands.js b/backend/src/eventSourcing/commands.js index a43c10b2..b4cb5c70 100644 --- a/backend/src/eventSourcing/commands.js +++ b/backend/src/eventSourcing/commands.js @@ -1,6 +1,6 @@ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { xlmToStroops, stroopsToXlm } = require("../utils/xlm"); class Command { diff --git a/backend/src/eventSourcing/events.js b/backend/src/eventSourcing/events.js index 4fd13afb..17708d4c 100644 --- a/backend/src/eventSourcing/events.js +++ b/backend/src/eventSourcing/events.js @@ -1,6 +1,6 @@ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { getCorrelationId } = require("../utils/logger"); const { xlmToStroops, stroopsToXlm } = require("../utils/xlm"); diff --git a/backend/src/eventSourcing/migrate.js b/backend/src/eventSourcing/migrate.js index 8a545db7..65800dee 100644 --- a/backend/src/eventSourcing/migrate.js +++ b/backend/src/eventSourcing/migrate.js @@ -1,7 +1,7 @@ "use strict"; const pool = require("../db/pool"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { MigratedDonationEvent, MilestoneReachedEvent, diff --git a/backend/src/middleware/correlationId.js b/backend/src/middleware/correlationId.js index 17ec5696..0f25b47d 100644 --- a/backend/src/middleware/correlationId.js +++ b/backend/src/middleware/correlationId.js @@ -35,7 +35,7 @@ */ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { runWithCorrelationId } = require("../utils/logger"); /** Maximum character length accepted from the X-Correlation-ID header. */ diff --git a/backend/src/middleware/correlationId.test.js b/backend/src/middleware/correlationId.test.js index 7435401c..db60f917 100644 --- a/backend/src/middleware/correlationId.test.js +++ b/backend/src/middleware/correlationId.test.js @@ -3,7 +3,7 @@ */ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { correlationIdMiddleware, sanitiseCorrelationId, diff --git a/backend/src/routes/donations.js b/backend/src/routes/donations.js index 9fe3bf09..7463beb9 100644 --- a/backend/src/routes/donations.js +++ b/backend/src/routes/donations.js @@ -4,7 +4,7 @@ "use strict"; const express = require("express"); const router = express.Router(); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { createLayeredRateLimiter } = require("../middleware/rateLimiter"); const { createApiError } = require("../middleware/apiEnvelope"); diff --git a/backend/src/routes/leaderboard.integration.test.js b/backend/src/routes/leaderboard.integration.test.js index 471777c4..40c1e403 100644 --- a/backend/src/routes/leaderboard.integration.test.js +++ b/backend/src/routes/leaderboard.integration.test.js @@ -18,7 +18,7 @@ const path = require("path"); const express = require("express"); const request = require("supertest"); const { execFileSync } = require("child_process"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { createHash } = require("crypto"); const pool = require("../db/pool"); diff --git a/backend/src/routes/notifications.js b/backend/src/routes/notifications.js index 3f679dcf..c4dc8dc5 100644 --- a/backend/src/routes/notifications.js +++ b/backend/src/routes/notifications.js @@ -10,7 +10,7 @@ "use strict"; const express = require("express"); const router = express.Router(); -const { v4: uuidv4 } = require("uuid"); +const { randomUUID: uuidv4 } = require("crypto"); const pool = require("../db/pool"); const { createLayeredRateLimiter } = require("../middleware/rateLimiter"); const { createApiError } = require("../middleware/apiEnvelope"); diff --git a/backend/src/routes/projects.js b/backend/src/routes/projects.js index e1cc6827..07525bee 100644 --- a/backend/src/routes/projects.js +++ b/backend/src/routes/projects.js @@ -5,7 +5,7 @@ const crypto = require("crypto"); const express = require("express"); const router = express.Router(); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { adminRequired } = require("../middleware/auth"); const { createLayeredRateLimiter } = require("../middleware/rateLimiter"); diff --git a/backend/src/routes/ratings.js b/backend/src/routes/ratings.js index 1599a728..06f4b71b 100644 --- a/backend/src/routes/ratings.js +++ b/backend/src/routes/ratings.js @@ -4,7 +4,7 @@ "use strict"; const express = require("express"); const router = express.Router(); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { mapProjectRatingRow } = require("../services/store"); const { createApiError } = require("../middleware/apiEnvelope"); diff --git a/backend/src/routes/subscriptions.js b/backend/src/routes/subscriptions.js index bf30b76c..3e38af6c 100644 --- a/backend/src/routes/subscriptions.js +++ b/backend/src/routes/subscriptions.js @@ -18,7 +18,7 @@ "use strict"; const express = require("express"); const router = express.Router(); -const { v4: uuidv4 } = require("uuid"); +const { randomUUID: uuidv4 } = require("crypto"); const pool = require("../db/pool"); const { createRateLimiter } = require("../middleware/rateLimiter"); diff --git a/backend/src/routes/updates.js b/backend/src/routes/updates.js index de4785bd..a7ee2403 100644 --- a/backend/src/routes/updates.js +++ b/backend/src/routes/updates.js @@ -10,7 +10,7 @@ "use strict"; const express = require("express"); const router = express.Router(); -const { v4: uuidv4 } = require("uuid"); +const { randomUUID: uuidv4 } = require("crypto"); const pool = require("../db/pool"); const { createLayeredRateLimiter } = require("../middleware/rateLimiter"); const { mapProjectUpdateRow, mapProjectRow } = require("../services/store"); @@ -152,7 +152,7 @@ router.post("/:updateId/like", likeLimiter, async (req, res, next) => { // Like await pool.query( "INSERT INTO update_likes (id, update_id, donor_address, created_at) VALUES ($1, $2, $3, NOW())", - [require("uuid").v4(), req.params.updateId, donorAddress], + [require("crypto").randomUUID(), req.params.updateId, donorAddress], ); } diff --git a/backend/src/services/audit.js b/backend/src/services/audit.js index aa8a5a9b..e572e600 100644 --- a/backend/src/services/audit.js +++ b/backend/src/services/audit.js @@ -1,6 +1,6 @@ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); async function logAdminAction({ actor, action, targetType, targetId, metadata, ipAddress }) { diff --git a/backend/src/services/indexerService.integration.test.js b/backend/src/services/indexerService.integration.test.js index 19a4e760..a04b0412 100644 --- a/backend/src/services/indexerService.integration.test.js +++ b/backend/src/services/indexerService.integration.test.js @@ -16,7 +16,7 @@ const fs = require("fs"); const path = require("path"); const { createHash } = require("crypto"); const { execFileSync } = require("child_process"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const indexerService = require("./indexerService"); diff --git a/backend/src/services/indexerService.js b/backend/src/services/indexerService.js index 1ecb2db4..f95f298e 100644 --- a/backend/src/services/indexerService.js +++ b/backend/src/services/indexerService.js @@ -5,7 +5,7 @@ const { server: stellarServer, rpcServer, CONTRACT_ID } = require("./stellar"); const pool = require("../db/pool"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const { execute } = require("../eventSourcing/commandBus"); const { DonationRecordedEvent, MatchAppliedEvent } = require("../eventSourcing/events"); const { stroopsToXlm, xlmToStroops } = require("../utils/xlm"); From c722ad8fca6333b2715f36599e21cc4137c84941 Mon Sep 17 00:00:00 2001 From: Awosdot Date: Tue, 25 Aug 2026 06:28:39 +0000 Subject: [PATCH 4/6] fix(backend): revert accidental csurf downgrade to 1.2.2 csurf ^1.2.2 pulls in the old csrf-tokens/uid-safe/base64-url chain, which has 4 high-severity advisories and fails the npm audit CI gate. Restore ^1.11.0 and the EBADCSRFTOKEN assertion it produces. --- backend/package-lock.json | 148 ++++++++++++++++++++++---------- backend/package.json | 2 +- backend/src/routes/csrf.test.js | 6 +- 3 files changed, 108 insertions(+), 48 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 74938ed0..03549044 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,7 +12,7 @@ "@stellar/stellar-sdk": "^12.0.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", - "csurf": "^1.2.2", + "csurf": "^1.11.0", "date-fns": "^3.6.0", "date-fns-tz": "^3.2.0", "dotenv": "^16.4.5", @@ -2549,12 +2549,6 @@ ], "license": "MIT" }, - "node_modules/base64-url": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz", - "integrity": "sha512-UiVPRwO/m133KIQrOEIqO07D8jaYjFIx7/lYRWTRVR23tDSn00Ves6A+Bk0eLmhyz6IJGSFlNCKUuUBO2ssytA==", - "license": "ISC" - }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -3175,31 +3169,100 @@ "node": ">= 8" } }, - "node_modules/csrf-tokens": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/csrf-tokens/-/csrf-tokens-2.0.0.tgz", - "integrity": "sha512-IzcrVVxQJvHoeNSSA9zc9LqIBUPM3OdRUzJ/4ooSbROhvJOSAi6qve2J6XEhmltcECmf/UiR/pgzkHXY5x1mGA==", + "node_modules/csrf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", "license": "MIT", "dependencies": { - "base64-url": "1", - "rndm": "1", - "scmp": "~0.0.3", - "uid-safe": "1" + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/csurf": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.2.2.tgz", - "integrity": "sha512-wCwNMBSAzrj4918iemazALbLZBYQRVN4BpnSpVBcE5Cx5cx/5HPkkpidpL0k+Tbk3Dlg0pDSY3mUvh7Gqc5H7w==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", + "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", "license": "MIT", "dependencies": { - "csrf-tokens": "~2.0.0" + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "csrf": "3.1.0", + "http-errors": "~1.7.3" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/csurf/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/csurf/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "license": "ISC" + }, + "node_modules/csurf/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/date-fns": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", @@ -6216,13 +6279,6 @@ "url": "https://opencollective.com/napi-postinstall" } }, - "node_modules/native-or-bluebird": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.1.2.tgz", - "integrity": "sha512-Bgn5FHNkd+lPTjIzq1NVU/VZTvPKFvhdIDEyYjxrKNrScSXbVvNVzOKwoleysun0/HoN7R+TXmK9mCtEs84osA==", - "deprecated": "'native-or-bluebird' is deprecated. Please use 'any-promise' instead.", - "license": "MIT" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7054,6 +7110,15 @@ ], "license": "MIT" }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7330,13 +7395,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/scmp": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/scmp/-/scmp-0.0.3.tgz", - "integrity": "sha512-ya4sPuUOfcrJnfC+OUqTFgFVBEMOXMS1Xopn0wwIhxKwD4eveTwJoIUN9u1QHJ47nL29/m545dV8KqI92MlHPw==", - "deprecated": "scmp v2 uses improved core crypto comparison since Node v6.6.0", - "license": "BSD" - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8119,6 +8177,15 @@ "license": "0BSD", "optional": true }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -8273,24 +8340,17 @@ "license": "MIT" }, "node_modules/uid-safe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-1.1.0.tgz", - "integrity": "sha512-7+QtWs9zioL/iQX61G+4h3EPyr3H+tINIp0IAV4EL32vdf7qmFyuW0BgRqWl7p5oZOsEQrlL0bY7m5D8tp7b1w==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", "license": "MIT", "dependencies": { - "base64-url": "1.2.1", - "native-or-bluebird": "~1.1.2" + "random-bytes": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/uid-safe/node_modules/base64-url": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", - "integrity": "sha512-V8E0l1jyyeSSS9R+J9oljx5eq2rqzClInuwaPcyuv0Mm3ViI/3/rcc4rCEO8i4eQ4I0O0FAGYDA2i5xWHHPhzg==", - "license": "ISC" - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/backend/package.json b/backend/package.json index 53f54972..66a729b0 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,7 +16,7 @@ "@stellar/stellar-sdk": "^12.0.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", - "csurf": "^1.2.2", + "csurf": "^1.11.0", "date-fns": "^3.6.0", "date-fns-tz": "^3.2.0", "dotenv": "^16.4.5", diff --git a/backend/src/routes/csrf.test.js b/backend/src/routes/csrf.test.js index 790c6786..a4e1f6ae 100644 --- a/backend/src/routes/csrf.test.js +++ b/backend/src/routes/csrf.test.js @@ -20,9 +20,9 @@ describe("CSRF protection", () => { .expect(403); expect(res.body.error).toMatchObject({ - code: "FORBIDDEN", - message: expect.stringMatching(/csrf/i), -}); + code: "EBADCSRFTOKEN", + message: expect.stringMatching(/csrf/i), + }); }); it("allows mutating requests when a valid X-CSRF-Token header is provided", async () => { From 0efd43f4e7c0f672fd43307085f852834507dcc7 Mon Sep 17 00:00:00 2001 From: Awosdot Date: Mon, 31 Aug 2026 12:28:50 +0100 Subject: [PATCH 5/6] fix(backend): remove duplicate router declaration and restore validated updateId in like route --- backend/src/routes/updates.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/routes/updates.js b/backend/src/routes/updates.js index b0ddf501..ceca9d08 100644 --- a/backend/src/routes/updates.js +++ b/backend/src/routes/updates.js @@ -8,7 +8,6 @@ "use strict"; const express = require("express"); -const router = express.Router(); const { randomUUID: uuidv4 } = require("crypto"); const pool = require("../db/pool"); const { adminRequired } = require("../middleware/auth"); @@ -659,7 +658,7 @@ router.post("/:updateId/like", likeLimiter, async (req, res, next) => { } else { await pool.query( "INSERT INTO update_likes (id, update_id, donor_address, created_at) VALUES ($1, $2, $3, NOW())", - [require("crypto").randomUUID(), req.params.updateId, donorAddress], + [uuidv4(), updateId, donorAddress], ); } const countResult = await pool.query("SELECT COUNT(*) as count FROM update_likes WHERE update_id = $1", [updateId]); From f61f199b041eb06238684a031be6f43b58b55777 Mon Sep 17 00:00:00 2001 From: Awosdot Date: Mon, 31 Aug 2026 12:35:54 +0100 Subject: [PATCH 6/6] fix(backend): finish uuid-to-crypto migration to unbreak Jest on ESM-only uuid@14 --- backend/src/routes/impact.js | 2 +- backend/src/routes/integrity.js | 2 +- backend/src/routes/pagination.integration.test.js | 2 +- .../donationIntegrity.integration.test.js | 2 +- backend/src/services/donationIntegrity.js | 2 +- backend/src/services/onboarding/accountUpgrade.js | 2 +- backend/src/services/onboarding/funnel.js | 2 +- .../src/services/onboarding/sponsoredAccounts.js | 2 +- .../services/projectSearch.integration.test.js | 15 +++++++++++++-- 9 files changed, 21 insertions(+), 10 deletions(-) diff --git a/backend/src/routes/impact.js b/backend/src/routes/impact.js index 55511aec..95abb375 100644 --- a/backend/src/routes/impact.js +++ b/backend/src/routes/impact.js @@ -8,7 +8,7 @@ "use strict"; const express = require("express"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const router = express.Router(); const pool = require("../db/pool"); const cache = require("../services/cache"); diff --git a/backend/src/routes/integrity.js b/backend/src/routes/integrity.js index b1e59268..d69e44a2 100644 --- a/backend/src/routes/integrity.js +++ b/backend/src/routes/integrity.js @@ -2,7 +2,7 @@ const crypto = require("crypto"); const express = require("express"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const cache = require("../services/cache"); const { adminRequired } = require("../middleware/auth"); diff --git a/backend/src/routes/pagination.integration.test.js b/backend/src/routes/pagination.integration.test.js index 6999453b..cd788fac 100644 --- a/backend/src/routes/pagination.integration.test.js +++ b/backend/src/routes/pagination.integration.test.js @@ -15,7 +15,7 @@ const path = require("path"); const express = require("express"); const request = require("supertest"); const { execFileSync } = require("child_process"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { apiEnvelope, errorHandler } = require("../middleware/apiEnvelope"); diff --git a/backend/src/services/donationIntegrity.integration.test.js b/backend/src/services/donationIntegrity.integration.test.js index 8320cfd7..4b862776 100644 --- a/backend/src/services/donationIntegrity.integration.test.js +++ b/backend/src/services/donationIntegrity.integration.test.js @@ -5,7 +5,7 @@ const path = require("path"); const { createHash } = require("crypto"); const { execFileSync } = require("child_process"); const { Keypair } = require("@stellar/stellar-sdk"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const express = require("express"); const request = require("supertest"); const pool = require("../db/pool"); diff --git a/backend/src/services/donationIntegrity.js b/backend/src/services/donationIntegrity.js index a36b0ae8..7b3cb096 100644 --- a/backend/src/services/donationIntegrity.js +++ b/backend/src/services/donationIntegrity.js @@ -1,6 +1,6 @@ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../db/pool"); const { Keypair } = require("@stellar/stellar-sdk"); const { stroopsToXlm } = require("../utils/xlm"); diff --git a/backend/src/services/onboarding/accountUpgrade.js b/backend/src/services/onboarding/accountUpgrade.js index f30cb4fb..bf477d91 100644 --- a/backend/src/services/onboarding/accountUpgrade.js +++ b/backend/src/services/onboarding/accountUpgrade.js @@ -31,7 +31,7 @@ const crypto = require("crypto"); const { Keypair, Networks, StrKey, Transaction } = require("@stellar/stellar-sdk"); const { env } = require("../../config/env"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../../db/pool"); const { logger: rootLogger } = require("../../utils/logger"); diff --git a/backend/src/services/onboarding/funnel.js b/backend/src/services/onboarding/funnel.js index 7796c686..5af9f69c 100644 --- a/backend/src/services/onboarding/funnel.js +++ b/backend/src/services/onboarding/funnel.js @@ -21,7 +21,7 @@ */ "use strict"; -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../../db/pool"); const { logger: rootLogger } = require("../../utils/logger"); diff --git a/backend/src/services/onboarding/sponsoredAccounts.js b/backend/src/services/onboarding/sponsoredAccounts.js index 54bcd5f8..03256d96 100644 --- a/backend/src/services/onboarding/sponsoredAccounts.js +++ b/backend/src/services/onboarding/sponsoredAccounts.js @@ -45,7 +45,7 @@ const { BASE_FEE, } = require("@stellar/stellar-sdk"); -const { v4: uuid } = require("uuid"); +const { randomUUID: uuid } = require("crypto"); const pool = require("../../db/pool"); const { env } = require("../../config/env"); const { logger: rootLogger } = require("../../utils/logger"); diff --git a/backend/src/services/projectSearch.integration.test.js b/backend/src/services/projectSearch.integration.test.js index 8ee88a6b..45845d88 100644 --- a/backend/src/services/projectSearch.integration.test.js +++ b/backend/src/services/projectSearch.integration.test.js @@ -12,12 +12,23 @@ const path = require("path"); const express = require("express"); const request = require("supertest"); const { execFileSync } = require("child_process"); -const { v4: uuid, v5: uuidv5 } = require("uuid"); +const crypto = require("crypto"); +const { randomUUID: uuid } = crypto; const FIXTURE_NAMESPACE = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; +// RFC 4122 UUID v5 (namespace + name, SHA-1 based) — deterministic fixture ids. +// Reimplemented here because the removal of the `uuid` package dependency +// left no CommonJS-compatible v5 generator; crypto.randomUUID() only covers v4. function fixtureId(key) { - return uuidv5(key, FIXTURE_NAMESPACE); + const namespaceBytes = Buffer.from(FIXTURE_NAMESPACE.replace(/-/g, ""), "hex"); + const nameBytes = Buffer.from(key, "utf8"); + const hash = crypto.createHash("sha1").update(Buffer.concat([namespaceBytes, nameBytes])).digest(); + const bytes = Buffer.from(hash.subarray(0, 16)); + bytes[6] = (bytes[6] & 0x0f) | 0x50; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + const hex = bytes.toString("hex"); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; } const pool = require("../db/pool");