feat(eims): allow private key/cert as inline base64 env vars

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.
This commit is contained in:
Hagernesh
2026-08-17 09:14:38 +00:00
parent 28c9dd93e0
commit 4a4b1981cb
4 changed files with 72 additions and 20 deletions

View File

@@ -30,6 +30,14 @@ export interface EimsConfig {
privateKeyPath: string;
/** Filesystem path to the INSA-issued certificate bundle; sent as base64 of its exact bytes. */
certificatePath: string;
/**
* Inline alternative to `privateKeyPath` — the key file's own bytes, base64-encoded, so a
* container that can't be given a host bind mount can still receive it as a plain env var.
* Takes precedence over the path when set. Either one must be present when EIMS is enabled.
*/
privateKeyBase64: string;
/** Inline alternative to `certificatePath`, same precedence rule. */
certificateBase64: string;
httpTimeoutMs: number;
/** Re-authenticate this many ms before the access token actually expires. */
tokenSkewMs: number;
@@ -135,14 +143,14 @@ export interface EimsInvoiceConfig {
buyerIdNumber: string | null;
}
const REQUIRED_VARS = [
"EIMS_CLIENT_ID",
"EIMS_CLIENT_SECRET",
"EIMS_API_KEY",
"EIMS_TIN",
"EIMS_PRIVATE_KEY_PATH",
"EIMS_CERTIFICATE_PATH",
] as const;
const REQUIRED_VARS = ["EIMS_CLIENT_ID", "EIMS_CLIENT_SECRET", "EIMS_API_KEY", "EIMS_TIN"] as const;
// Key/cert each have two ways in (file path or inline base64) — checked separately from
// REQUIRED_VARS since it's "at least one of", not "this exact var".
const REQUIRED_EITHER_OR: Array<[string, string]> = [
["EIMS_PRIVATE_KEY_PATH", "EIMS_PRIVATE_KEY_BASE64"],
["EIMS_CERTIFICATE_PATH", "EIMS_CERTIFICATE_BASE64"],
];
const positiveInt = (raw: string | undefined, fallback: number, name: string): number => {
if (raw === undefined || raw === "") return fallback;
@@ -189,6 +197,8 @@ export default registerAs("eims", (): EimsConfig => {
systemType: process.env.EIMS_SYSTEM_TYPE ?? "",
privateKeyPath: process.env.EIMS_PRIVATE_KEY_PATH ?? "",
certificatePath: process.env.EIMS_CERTIFICATE_PATH ?? "",
privateKeyBase64: process.env.EIMS_PRIVATE_KEY_BASE64 ?? "",
certificateBase64: process.env.EIMS_CERTIFICATE_BASE64 ?? "",
httpTimeoutMs,
tokenSkewMs,
autoSubmit: (process.env.EIMS_AUTO_SUBMIT ?? "false").toLowerCase() === "true",
@@ -245,7 +255,10 @@ export default registerAs("eims", (): EimsConfig => {
if (!enabled) return base;
const missing = REQUIRED_VARS.filter((name) => !process.env[name]);
const missing: string[] = REQUIRED_VARS.filter((name) => !process.env[name]);
for (const [pathVar, base64Var] of REQUIRED_EITHER_OR) {
if (!process.env[pathVar] && !process.env[base64Var]) missing.push(`${pathVar} or ${base64Var}`);
}
if (missing.length > 0) {
throw new Error(
`EIMS integration is enabled (EIMS_ENABLED=true) but the following env vars are missing: ${missing.join(", ")}`,