mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
EIMS_PRIVATE_KEY_BASE64 / EIMS_CERTIFICATE_BASE64, alternative to the existing _PATH vars. Wins over the path when set; falls back to the file otherwise. Neither var required at boot on its own — the either/or check moved out of the flat REQUIRED_VARS list. Lets a dockerized deployment receive the key/cert the same way it already receives every other EIMS_* secret (plain env var into the container) instead of needing a host bind mount into the container filesystem.
93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { KeyObject, createPrivateKey } from "node:crypto";
|
|
import { Injectable, Logger } from "@nestjs/common";
|
|
import { ConfigService } from "@nestjs/config";
|
|
import { EimsConfig } from "../../config/eims.config";
|
|
import { EimsConfigException } from "./eims.errors";
|
|
|
|
/**
|
|
* Loads the INSA-issued EIMS credentials from disk, once, and keeps them in memory.
|
|
*
|
|
* The certificate is sent as base64 of the **exact bytes of the issued file** — it is deliberately
|
|
* never parsed, re-encoded or re-exported, because that is what produced a working live login.
|
|
* The private key never leaves this process: it is only ever used to produce a signature.
|
|
*/
|
|
@Injectable()
|
|
export class EimsCredentialsProvider {
|
|
private readonly logger = new Logger(EimsCredentialsProvider.name);
|
|
private privateKey: KeyObject | null = null;
|
|
private certificateBase64: string | null = null;
|
|
|
|
constructor(private readonly config: ConfigService) {}
|
|
|
|
private get cfg(): EimsConfig {
|
|
return this.config.get<EimsConfig>("eims")!;
|
|
}
|
|
|
|
/**
|
|
* RSA private key, parsed once. `privateKeyBase64` wins when set (no file I/O at all — for a
|
|
* container that can't be given a host bind mount); otherwise falls back to `privateKeyPath`.
|
|
* Throws a config error if neither is usable.
|
|
*/
|
|
getPrivateKey(): KeyObject {
|
|
if (this.privateKey) return this.privateKey;
|
|
|
|
const { privateKeyBase64, privateKeyPath: path } = this.cfg;
|
|
const source = privateKeyBase64 ? "EIMS_PRIVATE_KEY_BASE64" : `EIMS_PRIVATE_KEY_PATH (${path})`;
|
|
if (!privateKeyBase64 && !path) throw new EimsConfigException("EIMS_PRIVATE_KEY_PATH is not set");
|
|
|
|
let key: KeyObject;
|
|
try {
|
|
const bytes = privateKeyBase64 ? Buffer.from(privateKeyBase64, "base64") : readFileSync(path);
|
|
key = createPrivateKey(bytes);
|
|
} catch (err) {
|
|
// The source is operational information, not a secret; the key material never appears.
|
|
throw new EimsConfigException(
|
|
`EIMS private key from ${source} could not be read or parsed: ${(err as Error).message}`,
|
|
);
|
|
}
|
|
if (key.asymmetricKeyType !== "rsa") {
|
|
throw new EimsConfigException(
|
|
`EIMS private key from ${source} is ${key.asymmetricKeyType ?? "of unknown type"}; EIMS requires RSA`,
|
|
);
|
|
}
|
|
|
|
this.privateKey = key;
|
|
this.logger.log(`EIMS private key loaded (RSA-${key.asymmetricKeyDetails?.modulusLength ?? "?"})`);
|
|
return key;
|
|
}
|
|
|
|
/**
|
|
* Base64 of the certificate file's exact bytes. No parsing, no re-encoding. `certificateBase64`
|
|
* config wins when set (already base64, used as-is); otherwise read from `certificatePath`.
|
|
*/
|
|
getCertificateBase64(): string {
|
|
if (this.certificateBase64) return this.certificateBase64;
|
|
|
|
const { certificateBase64: inline, certificatePath: path } = this.cfg;
|
|
if (inline) {
|
|
this.certificateBase64 = inline;
|
|
this.logger.log(`EIMS certificate bundle loaded from EIMS_CERTIFICATE_BASE64`);
|
|
return this.certificateBase64;
|
|
}
|
|
|
|
if (!path) throw new EimsConfigException("EIMS_CERTIFICATE_PATH is not set");
|
|
|
|
let bytes: Buffer;
|
|
try {
|
|
bytes = readFileSync(path);
|
|
} catch (err) {
|
|
throw new EimsConfigException(
|
|
`EIMS certificate at ${path} could not be read: ${(err as Error).message}`,
|
|
);
|
|
}
|
|
if (bytes.length === 0) {
|
|
throw new EimsConfigException(`EIMS certificate at ${path} is empty`);
|
|
}
|
|
|
|
this.certificateBase64 = bytes.toString("base64");
|
|
this.logger.log(`EIMS certificate bundle loaded (${bytes.length} bytes)`);
|
|
return this.certificateBase64;
|
|
}
|
|
}
|