文件
mynode/packages/lib/services/e2ee/ppk/ppk.test.ts
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

116 行
4.9 KiB
TypeScript

import { afterAllCleanUp, encryptionService, expectNotThrow, expectThrow, setupDatabaseAndSynchronizer, switchClient } from '../../../testing/test-utils';
import { PublicKeyAlgorithm } from '../types';
import { decryptPrivateKey, ppkDecryptMasterKeyContent, ppkGenerateMasterKey, ppkPasswordIsValid, mkReencryptFromPasswordToPublicKey, mkReencryptFromPublicKeyToPassword, generateKeyPairWithAlgorithm, supportsPpkAlgorithm } from './ppk';
import { runIntegrationTests } from './ppkTestUtils';
describe('ppk', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
});
afterAll(async () => {
await afterAllCleanUp();
});
describe.each([
PublicKeyAlgorithm.RsaV1,
PublicKeyAlgorithm.RsaV2,
PublicKeyAlgorithm.RsaV3,
])('(algorithm %j)', (algorithm) => {
it('should create a public private key pair', async () => {
const ppk = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), '111111');
const privateKey = await decryptPrivateKey(encryptionService(), ppk.privateKey, '111111');
const publicKey = ppk.publicKey;
expect(privateKey.length).toBeGreaterThan(350);
expect(publicKey.length).toBeGreaterThan(350);
if (algorithm === PublicKeyAlgorithm.RsaV1) {
expect(privateKey).toContain('BEGIN RSA PRIVATE KEY');
expect(privateKey).toContain('END RSA PRIVATE KEY');
expect(publicKey).toContain('BEGIN RSA PUBLIC KEY');
expect(publicKey).toContain('END RSA PUBLIC KEY');
} else {
expect(JSON.parse(privateKey)).toMatchObject({
alg: 'RSA-OAEP-256',
key_ops: ['decrypt'],
// ...other properties...
});
expect(JSON.parse(publicKey.replace(/^[^;]+;/, ''))).toMatchObject({
alg: 'RSA-OAEP-256',
key_ops: ['encrypt'],
// ...other properties...
});
expect(publicKey).toMatch(/^rsa-v\d+;/);
expect(publicKey.startsWith(`${algorithm};`)).toBe(true);
}
// Should support the just-created key
expect(supportsPpkAlgorithm(ppk)).toBe(true);
});
it('should create different key pairs every time', async () => {
const ppk1 = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), '111111');
const ppk2 = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), '111111');
const privateKey1 = await decryptPrivateKey(encryptionService(), ppk1.privateKey, '111111');
const privateKey2 = await decryptPrivateKey(encryptionService(), ppk2.privateKey, '111111');
const publicKey1 = ppk1.publicKey;
const publicKey2 = ppk2.publicKey;
expect(privateKey1).not.toBe(privateKey2);
expect(publicKey1).not.toBe(publicKey2);
});
it('should encrypt a master key using PPK', (async () => {
const ppk = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), '111111');
const masterKey = await ppkGenerateMasterKey(encryptionService(), ppk, '111111');
const plainText = await ppkDecryptMasterKeyContent(encryptionService(), masterKey, ppk, '111111');
expect(plainText.length).toBeGreaterThan(50); // Just checking it's not empty
expect(plainText).not.toBe(masterKey.content);
}));
it('should check if a PPK password is valid', (async () => {
const ppk = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), '111111');
expect(await ppkPasswordIsValid(encryptionService(), ppk, '222')).toBe(false);
expect(await ppkPasswordIsValid(encryptionService(), ppk, '111111')).toBe(true);
await expectThrow(async () => ppkPasswordIsValid(encryptionService(), null, '111111'));
}));
it('should transmit key using a public-private key', (async () => {
// This simulate sending a key from one user to another using
// public-private key encryption. For example used when sharing a
// notebook while E2EE is enabled.
// User 1 generates a master key
const key1 = await encryptionService().generateMasterKey('mk_1111');
// Using user 2 private key, he reencrypts the master key
const ppk2 = await generateKeyPairWithAlgorithm(algorithm, encryptionService(), 'ppk_1111');
const ppkEncrypted = await mkReencryptFromPasswordToPublicKey(encryptionService(), key1, 'mk_1111', ppk2);
// Once user 2 gets the master key, he can decrypt it using his private key
const key2 = await mkReencryptFromPublicKeyToPassword(encryptionService(), ppkEncrypted, ppk2, 'ppk_1111', 'mk_2222');
// Once it's done, both users should have the same master key
const plaintext1 = await encryptionService().decryptMasterKeyContent(key1, 'mk_1111');
const plaintext2 = await encryptionService().decryptMasterKeyContent(key2, 'mk_2222');
expect(plaintext1).toBe(plaintext2);
// We should make sure that the keys are also different when encrypted
// since they should be using different passwords.
expect(key1.content).not.toBe(key2.content);
}));
it('should decrypt and encrypt data from different devices', (async () => {
await expectNotThrow(async () => runIntegrationTests(true));
}));
});
});