Electron impl wraps safeStorage (Win Credential Manager). MemoryImpl uses base64 (no real crypto) — clearly marks isEncryptionAvailable()=false for test/headless envs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
// Verschluesselt String-Payloads im OS-Keystore (Win Credential Manager via
|
|
// Electron safeStorage). MemorySecureStorage ist fuer Tests/Headless-Envs —
|
|
// gibt plaintext zurueck und meldet isEncryptionAvailable() === false, damit
|
|
// Caller das in den Log schreiben oder verweigern koennen.
|
|
|
|
export interface SecureStorage {
|
|
isEncryptionAvailable(): boolean;
|
|
encrypt(plaintext: string): string;
|
|
decrypt(ciphertext: string): string;
|
|
}
|
|
|
|
export class MemorySecureStorage implements SecureStorage {
|
|
isEncryptionAvailable(): boolean {
|
|
return false;
|
|
}
|
|
encrypt(plaintext: string): string {
|
|
// Base64 als Kennzeichnung — kein Schutz, nur damit `decrypt(encrypt(x)) === x`
|
|
// semantisch konsistent ist (kein literal plaintext zwischen den Methoden).
|
|
return Buffer.from(plaintext, 'utf-8').toString('base64');
|
|
}
|
|
decrypt(ciphertext: string): string {
|
|
return Buffer.from(ciphertext, 'base64').toString('utf-8');
|
|
}
|
|
}
|
|
|
|
interface SafeStorageLike {
|
|
isEncryptionAvailable(): boolean;
|
|
encryptString(plain: string): Buffer;
|
|
decryptString(buf: Buffer): string;
|
|
}
|
|
|
|
/**
|
|
* Wrappt electron.safeStorage. Setzt voraus, dass `app.whenReady()` gefired ist.
|
|
* Wird per Lazy-Require konstruiert, sodass Module ausserhalb von Electron
|
|
* (zB Tests) das Modul importieren koennen ohne Crash.
|
|
*/
|
|
export function createElectronSecureStorage(): SecureStorage {
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
const electron = require('electron');
|
|
const safeStorage = electron?.safeStorage as SafeStorageLike | undefined;
|
|
if (!safeStorage) {
|
|
throw new Error('Electron safeStorage not available (called before app.whenReady?)');
|
|
}
|
|
|
|
return {
|
|
isEncryptionAvailable(): boolean {
|
|
return safeStorage.isEncryptionAvailable();
|
|
},
|
|
encrypt(plaintext: string): string {
|
|
const buf = safeStorage.encryptString(plaintext);
|
|
return buf.toString('base64');
|
|
},
|
|
decrypt(ciphertext: string): string {
|
|
const buf = Buffer.from(ciphertext, 'base64');
|
|
return safeStorage.decryptString(buf);
|
|
},
|
|
};
|
|
}
|