diff --git a/SETUP.md b/SETUP.md index 8bb83c2..5740b95 100644 --- a/SETUP.md +++ b/SETUP.md @@ -75,6 +75,7 @@ Configurations are loaded through environment variables. `.env` files are suppor | `PN_ACT_CONFIG_CDN_BASE_URL` | URL for serving CDN contents (usually the same as s3 endpoint) | No | | `PN_ACT_CONFIG_WEBSITE_BASE` | Website URL | Yes | | `PN_ACT_CONFIG_AES_KEY` | AES-256 key used for encrypting tokens | No | +| `PN_ACT_CONFIG_DATASTORE_SIGNATURE_SECRET` | HMAC secret key (16 bytes in hex format) used to sign uploaded DataStore files | No | | `PN_ACT_CONFIG_GRPC_MASTER_API_KEY_ACCOUNT` | Master API key to interact with the account gRPC service | No | | `PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API` | Master API key to interact with the API gRPC service | No | | `PN_ACT_CONFIG_GRPC_PORT` | gRPC server port | No | diff --git a/src/config-manager.ts b/src/config-manager.ts index 28a081c..2d8f0e0 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -13,6 +13,8 @@ export const disabledFeatures = { s3: false }; +const hexadecimalStringRegex = /^[0-9a-f]+$/i; + LOG_INFO('Loading config'); let mongooseConnectOptions: mongoose.ConnectOptions = {}; @@ -71,7 +73,10 @@ export const config: Config = { }, port: Number(process.env.PN_ACT_CONFIG_GRPC_PORT || ''), }, - server_environment: process.env.PN_ACT_CONFIG_SERVER_ENVIRONMENT || '' + server_environment: process.env.PN_ACT_CONFIG_SERVER_ENVIRONMENT || '', + datastore: { + signature_secret: process.env.PN_ACT_CONFIG_DATASTORE_SIGNATURE_SECRET || '' + } }; if (process.env.PN_ACT_CONFIG_STRIPE_SECRET_KEY) { @@ -194,4 +199,13 @@ if (!config.grpc.port) { if (!config.stripe?.secret_key) { LOG_WARN('Failed to find Stripe api key! If a PNID is deleted with an active subscription, the subscription will *NOT* be canceled! Set the PN_ACT_CONFIG_STRIPE_SECRET_KEY environment variable to enable'); -} \ No newline at end of file +} + +if (!config.datastore.signature_secret) { + LOG_ERROR('Datastore signature secret key is not set. Set the PN_ACT_CONFIG_DATASTORE_SIGNATURE_SECRET environment variable'); + process.exit(0); +} +if (config.datastore.signature_secret.length !== 32 || !hexadecimalStringRegex.test(config.datastore.signature_secret)) { + LOG_ERROR('Datastore signature secret key must be a 32-character hexadecimal string.'); + process.exit(0); +} diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index 6e3585e..b5f35bc 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -3,11 +3,10 @@ import crypto from 'node:crypto'; import express from 'express'; import Dicer from 'dicer'; import { uploadCDNAsset } from '@/util'; +import { config } from '@/config-manager'; const router = express.Router(); -const signatureSecret = fs.readFileSync(`${__dirname}/../../../../certs/nex/datastore/secret.key`); - function multipartParser(request: express.Request, response: express.Response, next: express.NextFunction): void { const RE_BOUNDARY = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i; const RE_FILE_NAME = /name="(.*)"/; @@ -86,7 +85,7 @@ router.post('/upload', multipartParser, async (request: express.Request, respons const data = `${pid}${bucket}${key}${date}`; - const hmac = crypto.createHmac('sha256', signatureSecret).update(data).digest('hex'); + const hmac = crypto.createHmac('sha256', config.datastore.signature_secret).update(data).digest('hex'); console.log(hmac, signature); diff --git a/src/types/common/config.ts b/src/types/common/config.ts index 0b27a16..0ae43fb 100644 --- a/src/types/common/config.ts +++ b/src/types/common/config.ts @@ -47,4 +47,7 @@ export interface Config { secret_key: string; }; server_environment: string; + datastore: { + signature_secret: string; + }; }