fix: harden managed online backup key handling
Require canonical encrypted envelopes and surface typed sanitized keyring corruption states. Persist crash-durable primary and recovery files, prevalidate removal plans, isolate renderer refresh authority, and cover the real hidden Windows DPAPI and IPC composition.
This commit is contained in:
@@ -36,6 +36,17 @@ test('encrypts and decrypts fields when secure storage is available', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('recognizes only canonical enc:v1 envelopes as encrypted', () => {
|
||||
withSecretStore(availableSafeStorage(), secretStore => {
|
||||
const canonical = `enc:v1:${Buffer.from('protected:secret').toString('base64')}`;
|
||||
assert.equal(secretStore.isEncrypted(canonical), true);
|
||||
assert.equal(secretStore.isEncrypted('secret'), false);
|
||||
assert.equal(secretStore.isEncrypted(canonical.replace('enc:v1:', 'enc:v2:')), false);
|
||||
assert.equal(secretStore.isEncrypted(canonical.replace(/=+$/u, '')), false);
|
||||
assert.equal(secretStore.isEncrypted(`${canonical}\n`), false);
|
||||
});
|
||||
});
|
||||
|
||||
test('refuses plaintext storage by default when secure storage is unavailable', () => {
|
||||
withSecretStore(null, secretStore => {
|
||||
assert.throws(
|
||||
@@ -94,7 +105,7 @@ test('throws an identifiable error when decryption fails', () => {
|
||||
const failure = new Error('decryption failed');
|
||||
withSecretStore(availableSafeStorage({ decryptString: () => { throw failure; } }), secretStore => {
|
||||
assert.throws(
|
||||
() => secretStore.decryptField('enc:v1:invalid'),
|
||||
() => secretStore.decryptField('enc:v1:aW52YWxpZA=='),
|
||||
error => error instanceof secretStore.SecretStoreError
|
||||
&& error.code === 'SECRET_STORE_DECRYPT_FAILED'
|
||||
&& error.cause === failure
|
||||
@@ -102,6 +113,23 @@ test('throws an identifiable error when decryption fails', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('rejects malformed enc:v1 values instead of treating them as legacy plaintext', () => {
|
||||
let decryptCalls = 0;
|
||||
withSecretStore(availableSafeStorage({
|
||||
decryptString: () => {
|
||||
decryptCalls++;
|
||||
return 'unexpected';
|
||||
}
|
||||
}), secretStore => {
|
||||
assert.throws(
|
||||
() => secretStore.decryptField('enc:v1:YWJjZA'),
|
||||
error => error instanceof secretStore.SecretStoreError
|
||||
&& error.code === 'SECRET_STORE_DECRYPT_FAILED'
|
||||
);
|
||||
assert.equal(decryptCalls, 0);
|
||||
});
|
||||
});
|
||||
|
||||
test('keeps legacy plaintext values readable without secure storage', () => {
|
||||
withSecretStore(null, secretStore => {
|
||||
assert.equal(secretStore.decryptField('legacy-secret'), 'legacy-secret');
|
||||
|
||||
Reference in New Issue
Block a user