Cleanup files and improve file manager.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { FieldEncryption } from './encryption.js';
|
||||
import { EncryptionKeyManager } from './encryption-key-manager.js';
|
||||
import { databaseLogger } from './logger.js';
|
||||
import { FieldEncryption } from "./encryption.js";
|
||||
import { EncryptionKeyManager } from "./encryption-key-manager.js";
|
||||
import { databaseLogger } from "./logger.js";
|
||||
|
||||
interface EncryptionContext {
|
||||
masterPassword: string;
|
||||
@@ -14,26 +14,29 @@ class DatabaseEncryption {
|
||||
|
||||
static async initialize(config: Partial<EncryptionContext> = {}) {
|
||||
const keyManager = EncryptionKeyManager.getInstance();
|
||||
const masterPassword = config.masterPassword || await keyManager.initializeKey();
|
||||
const masterPassword =
|
||||
config.masterPassword || (await keyManager.initializeKey());
|
||||
|
||||
this.context = {
|
||||
masterPassword,
|
||||
encryptionEnabled: config.encryptionEnabled ?? true,
|
||||
forceEncryption: config.forceEncryption ?? false,
|
||||
migrateOnAccess: config.migrateOnAccess ?? true
|
||||
migrateOnAccess: config.migrateOnAccess ?? true,
|
||||
};
|
||||
|
||||
databaseLogger.info('Database encryption initialized', {
|
||||
operation: 'encryption_init',
|
||||
databaseLogger.info("Database encryption initialized", {
|
||||
operation: "encryption_init",
|
||||
enabled: this.context.encryptionEnabled,
|
||||
forceEncryption: this.context.forceEncryption,
|
||||
dynamicKey: !config.masterPassword
|
||||
dynamicKey: !config.masterPassword,
|
||||
});
|
||||
}
|
||||
|
||||
static getContext(): EncryptionContext {
|
||||
if (!this.context) {
|
||||
throw new Error('DatabaseEncryption not initialized. Call initialize() first.');
|
||||
throw new Error(
|
||||
"DatabaseEncryption not initialized. Call initialize() first.",
|
||||
);
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
@@ -48,15 +51,25 @@ class DatabaseEncryption {
|
||||
for (const [fieldName, value] of Object.entries(record)) {
|
||||
if (FieldEncryption.shouldEncryptField(tableName, fieldName) && value) {
|
||||
try {
|
||||
const fieldKey = FieldEncryption.getFieldKey(context.masterPassword, `${tableName}.${fieldName}`);
|
||||
encryptedRecord[fieldName] = FieldEncryption.encryptField(value as string, fieldKey);
|
||||
const fieldKey = FieldEncryption.getFieldKey(
|
||||
context.masterPassword,
|
||||
`${tableName}.${fieldName}`,
|
||||
);
|
||||
encryptedRecord[fieldName] = FieldEncryption.encryptField(
|
||||
value as string,
|
||||
fieldKey,
|
||||
);
|
||||
hasEncryption = true;
|
||||
} catch (error) {
|
||||
databaseLogger.error(`Failed to encrypt field ${tableName}.${fieldName}`, error, {
|
||||
operation: 'field_encryption',
|
||||
table: tableName,
|
||||
field: fieldName
|
||||
});
|
||||
databaseLogger.error(
|
||||
`Failed to encrypt field ${tableName}.${fieldName}`,
|
||||
error,
|
||||
{
|
||||
operation: "field_encryption",
|
||||
table: tableName,
|
||||
field: fieldName,
|
||||
},
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -64,8 +77,8 @@ class DatabaseEncryption {
|
||||
|
||||
if (hasEncryption) {
|
||||
databaseLogger.debug(`Encrypted sensitive fields for ${tableName}`, {
|
||||
operation: 'record_encryption',
|
||||
table: tableName
|
||||
operation: "record_encryption",
|
||||
table: tableName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,28 +96,41 @@ class DatabaseEncryption {
|
||||
for (const [fieldName, value] of Object.entries(record)) {
|
||||
if (FieldEncryption.shouldEncryptField(tableName, fieldName) && value) {
|
||||
try {
|
||||
const fieldKey = FieldEncryption.getFieldKey(context.masterPassword, `${tableName}.${fieldName}`);
|
||||
const fieldKey = FieldEncryption.getFieldKey(
|
||||
context.masterPassword,
|
||||
`${tableName}.${fieldName}`,
|
||||
);
|
||||
|
||||
if (FieldEncryption.isEncrypted(value as string)) {
|
||||
decryptedRecord[fieldName] = FieldEncryption.decryptField(value as string, fieldKey);
|
||||
decryptedRecord[fieldName] = FieldEncryption.decryptField(
|
||||
value as string,
|
||||
fieldKey,
|
||||
);
|
||||
hasDecryption = true;
|
||||
} else if (context.encryptionEnabled && !context.forceEncryption) {
|
||||
decryptedRecord[fieldName] = value;
|
||||
needsMigration = context.migrateOnAccess;
|
||||
} else if (context.forceEncryption) {
|
||||
databaseLogger.warn(`Unencrypted field detected in force encryption mode`, {
|
||||
operation: 'decryption_warning',
|
||||
table: tableName,
|
||||
field: fieldName
|
||||
});
|
||||
databaseLogger.warn(
|
||||
`Unencrypted field detected in force encryption mode`,
|
||||
{
|
||||
operation: "decryption_warning",
|
||||
table: tableName,
|
||||
field: fieldName,
|
||||
},
|
||||
);
|
||||
decryptedRecord[fieldName] = value;
|
||||
}
|
||||
} catch (error) {
|
||||
databaseLogger.error(`Failed to decrypt field ${tableName}.${fieldName}`, error, {
|
||||
operation: 'field_decryption',
|
||||
table: tableName,
|
||||
field: fieldName
|
||||
});
|
||||
databaseLogger.error(
|
||||
`Failed to decrypt field ${tableName}.${fieldName}`,
|
||||
error,
|
||||
{
|
||||
operation: "field_decryption",
|
||||
table: tableName,
|
||||
field: fieldName,
|
||||
},
|
||||
);
|
||||
|
||||
if (context.forceEncryption) {
|
||||
throw error;
|
||||
@@ -115,13 +141,6 @@ class DatabaseEncryption {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDecryption) {
|
||||
databaseLogger.debug(`Decrypted sensitive fields for ${tableName}`, {
|
||||
operation: 'record_decryption',
|
||||
table: tableName
|
||||
});
|
||||
}
|
||||
|
||||
if (needsMigration) {
|
||||
this.scheduleFieldMigration(tableName, record);
|
||||
}
|
||||
@@ -131,7 +150,7 @@ class DatabaseEncryption {
|
||||
|
||||
static decryptRecords(tableName: string, records: any[]): any[] {
|
||||
if (!Array.isArray(records)) return records;
|
||||
return records.map(record => this.decryptRecord(tableName, record));
|
||||
return records.map((record) => this.decryptRecord(tableName, record));
|
||||
}
|
||||
|
||||
private static scheduleFieldMigration(tableName: string, record: any) {
|
||||
@@ -139,11 +158,15 @@ class DatabaseEncryption {
|
||||
try {
|
||||
await this.migrateRecord(tableName, record);
|
||||
} catch (error) {
|
||||
databaseLogger.error(`Failed to migrate record ${tableName}:${record.id}`, error, {
|
||||
operation: 'migration_failed',
|
||||
table: tableName,
|
||||
recordId: record.id
|
||||
});
|
||||
databaseLogger.error(
|
||||
`Failed to migrate record ${tableName}:${record.id}`,
|
||||
error,
|
||||
{
|
||||
operation: "migration_failed",
|
||||
table: tableName,
|
||||
recordId: record.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
@@ -156,49 +179,61 @@ class DatabaseEncryption {
|
||||
const updatedRecord = { ...record };
|
||||
|
||||
for (const [fieldName, value] of Object.entries(record)) {
|
||||
if (FieldEncryption.shouldEncryptField(tableName, fieldName) &&
|
||||
value && !FieldEncryption.isEncrypted(value as string)) {
|
||||
if (
|
||||
FieldEncryption.shouldEncryptField(tableName, fieldName) &&
|
||||
value &&
|
||||
!FieldEncryption.isEncrypted(value as string)
|
||||
) {
|
||||
try {
|
||||
const fieldKey = FieldEncryption.getFieldKey(context.masterPassword, `${tableName}.${fieldName}`);
|
||||
updatedRecord[fieldName] = FieldEncryption.encryptField(value as string, fieldKey);
|
||||
const fieldKey = FieldEncryption.getFieldKey(
|
||||
context.masterPassword,
|
||||
`${tableName}.${fieldName}`,
|
||||
);
|
||||
updatedRecord[fieldName] = FieldEncryption.encryptField(
|
||||
value as string,
|
||||
fieldKey,
|
||||
);
|
||||
needsUpdate = true;
|
||||
} catch (error) {
|
||||
databaseLogger.error(`Failed to migrate field ${tableName}.${fieldName}`, error, {
|
||||
operation: 'field_migration',
|
||||
table: tableName,
|
||||
field: fieldName,
|
||||
recordId: record.id
|
||||
});
|
||||
databaseLogger.error(
|
||||
`Failed to migrate field ${tableName}.${fieldName}`,
|
||||
error,
|
||||
{
|
||||
operation: "field_migration",
|
||||
table: tableName,
|
||||
field: fieldName,
|
||||
recordId: record.id,
|
||||
},
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsUpdate) {
|
||||
databaseLogger.info(`Migrated record to encrypted format`, {
|
||||
operation: 'record_migration',
|
||||
table: tableName,
|
||||
recordId: record.id
|
||||
});
|
||||
}
|
||||
|
||||
return updatedRecord;
|
||||
}
|
||||
|
||||
static validateConfiguration(): boolean {
|
||||
try {
|
||||
const context = this.getContext();
|
||||
const testData = 'test-encryption-data';
|
||||
const testKey = FieldEncryption.getFieldKey(context.masterPassword, 'test');
|
||||
const testData = "test-encryption-data";
|
||||
const testKey = FieldEncryption.getFieldKey(
|
||||
context.masterPassword,
|
||||
"test",
|
||||
);
|
||||
|
||||
const encrypted = FieldEncryption.encryptField(testData, testKey);
|
||||
const decrypted = FieldEncryption.decryptField(encrypted, testKey);
|
||||
|
||||
return decrypted === testData;
|
||||
} catch (error) {
|
||||
databaseLogger.error('Encryption configuration validation failed', error, {
|
||||
operation: 'config_validation'
|
||||
});
|
||||
databaseLogger.error(
|
||||
"Encryption configuration validation failed",
|
||||
error,
|
||||
{
|
||||
operation: "config_validation",
|
||||
},
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -210,14 +245,14 @@ class DatabaseEncryption {
|
||||
enabled: context.encryptionEnabled,
|
||||
forceEncryption: context.forceEncryption,
|
||||
migrateOnAccess: context.migrateOnAccess,
|
||||
configValid: this.validateConfiguration()
|
||||
configValid: this.validateConfiguration(),
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
enabled: false,
|
||||
forceEncryption: false,
|
||||
migrateOnAccess: false,
|
||||
configValid: false
|
||||
configValid: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -230,7 +265,7 @@ class DatabaseEncryption {
|
||||
return {
|
||||
...encryptionStatus,
|
||||
key: keyStatus,
|
||||
initialized: this.context !== null
|
||||
initialized: this.context !== null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -241,12 +276,12 @@ class DatabaseEncryption {
|
||||
this.context = null;
|
||||
await this.initialize({ masterPassword: newKey });
|
||||
|
||||
databaseLogger.warn('Database encryption reinitialized with new key', {
|
||||
operation: 'encryption_reinit',
|
||||
requiresMigration: true
|
||||
databaseLogger.warn("Database encryption reinitialized with new key", {
|
||||
operation: "encryption_reinit",
|
||||
requiresMigration: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { DatabaseEncryption };
|
||||
export type { EncryptionContext };
|
||||
export type { EncryptionContext };
|
||||
|
||||
Reference in New Issue
Block a user