@tshifhiwa/ohrm-ui-automation-framework
Version:
Playwright and TypeScript–based test automation framework for validating core UI features and workflows of the OrangeHRM demo application.
125 lines (109 loc) • 5.64 kB
text/typescript
import EnvironmentDetector from "../../environment/detector/environmentDetector.js";
import SecureKeyGenerator from "../key/secureKeyGenerator.js";
import { EnvironmentFileEncryptor } from "../manager/environmentFileEncryptor.js";
import EnvironmentConfigManager from "../../environment/manager/handlers/environmentConfigManager.js";
import SecretFileManager from "../../environment/manager/handlers/secretFileManager.js";
import SecretMetadataManager from "../../cryptography/rotation/manager/secretMetadataManager.js";
import type { SecretKeyResult } from "../rotation/types/secretKeyResult.type.js"
import ErrorHandler from "../../errorHandling/errorHandler.js";
import logger from "../../logger/loggerManager.js";
export class CryptoCoordinator {
private environmentFileEncryptor: EnvironmentFileEncryptor;
private readonly currentEnvironmentStage = EnvironmentDetector.getCurrentEnvironmentStage();
constructor(environmentFileEncryptor: EnvironmentFileEncryptor) {
this.environmentFileEncryptor = environmentFileEncryptor;
}
/**
* Generates a new secret key based on the current environment stage.
* If the secret key already exists, it will be skipped and the existing key will be returned.
* The rotation days can be specified as an option, otherwise, the default of 90 days will be used.
* The performedBy option can be used to specify who performed the key generation.
* @param {rotationDays?: number, performedBy?: string} options - Optional parameters to control behavior
* @returns {Promise<SecretKeyResult>} - Promise resolving to the generated or existing secret key
*/
public async generateAndStoreSecretKey(
options: {
rotationDays?: number;
performedBy?: string;
} = {},
): Promise<SecretKeyResult> {
try {
const { rotationDays = 90, performedBy = "system" } = options;
const currentEnvKey = EnvironmentConfigManager.getCurrentEnvSecretKey();
const currentEnv = this.currentEnvironmentStage;
// Check if key already exists and if rotation is needed
const existingMetadata = await SecretMetadataManager.getKeyMetadata(currentEnvKey);
if (existingMetadata) {
const rotationStatus = await SecretMetadataManager.checkKeyRotationStatus(currentEnvKey);
if (rotationStatus.needsRotation) {
logger.warn(
`Existing key "${currentEnvKey}" has expired ${Math.abs(rotationStatus.daysUntilExpiration)} days ago. ` +
`Consider using SecretKeyRotationManager.rotateKeyWithReEncryption() instead.`,
);
} else {
logger.info(
`Key "${currentEnvKey}" already exists and is valid for ${rotationStatus.daysUntilExpiration} more days. ` +
`Skipping generation due to skipIfExists option.`,
);
}
}
const generatedSecretKey = SecureKeyGenerator.generateBase64SecretKey();
await SecretFileManager.storeEnvironmentKey(currentEnvKey, generatedSecretKey, {
skipIfExists: true,
});
await SecretFileManager.ensureSecretKeyExists(currentEnvKey);
// Track the secret key creation (only if it was actually created)
if (!existingMetadata) {
await SecretMetadataManager.trackSecretKey(currentEnvKey, currentEnv, {
rotationDays,
isRotation: false,
algorithm: "base64",
keyLength: 256,
performedBy,
});
logger.info(`Secret key "${currentEnvKey}" generated and tracked successfully`);
}
return { envKey: currentEnvKey, secretKey: generatedSecretKey };
} catch (error) {
ErrorHandler.captureError(
error,
"generateSecretKey",
`Failed to generate secret key "${EnvironmentConfigManager.getCurrentEnvSecretKey()}"`,
);
throw error;
}
}
/**
* Encrypts environment variables specified by `envVariables` using the current secret key.
* Before encrypting, checks if the secret key is valid and not expired.
* If the key has expired, logs a warning and suggests rotating the key using SecretKeyRotationManager.rotateKeyWithReEncryption().
* If the key is expiring soon, logs a notice with the number of days until expiration.
* @param {string[]} envVariables - Optional list of environment variables to encrypt.
* @returns {Promise<void>} - Promise resolved when encryption is complete.
*/
public async encryptEnvironmentVariables(envVariables?: string[]): Promise<void> {
try {
const currentEnvKey = EnvironmentConfigManager.getCurrentEnvSecretKey();
// Verify key exists and is valid before encrypting
const rotationStatus = await SecretMetadataManager.checkKeyRotationStatus(currentEnvKey);
if (rotationStatus.status === "expired") {
logger.warn(
`Warning: Secret key "${currentEnvKey}" has expired. ` +
`Consider rotating the key using SecretKeyRotationManager.rotateKeyWithReEncryption() before encrypting sensitive data.`,
);
} else if (rotationStatus.status === "expiring_soon") {
logger.info(
`Notice: Secret key "${currentEnvKey}" expires in ${rotationStatus.daysUntilExpiration} days.`,
);
}
await this.environmentFileEncryptor.encryptEnvironmentVariables(envVariables);
} catch (error) {
ErrorHandler.captureError(
error,
"encryptEnvironmentVariables",
"Failed to encrypt environment variables",
);
throw error;
}
}
}