refactor: root key manager (#2344)

This commit is contained in:
Mo
2023-07-04 07:31:50 -05:00
committed by GitHub
parent b4a90025c4
commit b06999d25b
56 changed files with 1400 additions and 1231 deletions

View File

@@ -17,9 +17,9 @@ import { GetRevision } from './GetRevision'
describe('GetRevision', () => {
let revisionManager: RevisionClientInterface
let protocolService: EncryptionProviderInterface
let encryptionService: EncryptionProviderInterface
const createUseCase = () => new GetRevision(revisionManager, protocolService)
const createUseCase = () => new GetRevision(revisionManager, encryptionService)
beforeEach(() => {
revisionManager = {} as jest.Mocked<RevisionClientInterface>
@@ -35,13 +35,13 @@ describe('GetRevision', () => {
updated_at: '2021-01-01T00:00:00.000Z'
} as jest.Mocked<Revision>)
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
protocolService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
encryptionService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
const encryptedPayload = {
content: 'foobar',
} as jest.Mocked<EncryptedPayloadInterface>
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
protocolService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
encryptionService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
isRemotePayloadAllowed.mockImplementation(() => true)
})
@@ -59,7 +59,7 @@ describe('GetRevision', () => {
})
it('it should get a revision without uuid from embedded params', async () => {
protocolService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: undefined })
encryptionService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: undefined })
const useCase = createUseCase()
@@ -73,7 +73,7 @@ describe('GetRevision', () => {
})
it('it should get a revision without embedded params', async () => {
protocolService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue(undefined)
encryptionService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue(undefined)
const useCase = createUseCase()
@@ -130,7 +130,7 @@ describe('GetRevision', () => {
errorDecrypting: true,
} as jest.Mocked<EncryptedPayloadInterface>
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
protocolService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
encryptionService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
const useCase = createUseCase()

View File

@@ -15,7 +15,10 @@ import { EncryptionProviderInterface } from '@standardnotes/encryption'
import { GetRevisionDTO } from './GetRevisionDTO'
export class GetRevision implements UseCaseInterface<HistoryEntry> {
constructor(private revisionManager: RevisionClientInterface, private protocolService: EncryptionProviderInterface) {}
constructor(
private revisionManager: RevisionClientInterface,
private encryptionService: EncryptionProviderInterface,
) {}
async execute(dto: GetRevisionDTO): Promise<Result<HistoryEntry>> {
const itemUuidOrError = Uuid.create(dto.itemUuid)
@@ -63,7 +66,7 @@ export class GetRevision implements UseCaseInterface<HistoryEntry> {
* these olders revisions (which have not been mutated after copy) with the source item's
* uuid.
*/
const embeddedParams = this.protocolService.getEmbeddedPayloadAuthenticatedData(serverPayload)
const embeddedParams = this.encryptionService.getEmbeddedPayloadAuthenticatedData(serverPayload)
const sourceItemUuid = embeddedParams?.u as string | undefined
const payload = serverPayload.copy({
@@ -76,7 +79,7 @@ export class GetRevision implements UseCaseInterface<HistoryEntry> {
const encryptedPayload = new EncryptedPayload(payload)
const decryptedPayload = await this.protocolService.decryptSplitSingle<NoteContent>({
const decryptedPayload = await this.encryptionService.decryptSplitSingle<NoteContent>({
usesItemsKeyWithKeyLookup: { items: [encryptedPayload] },
})

View File

@@ -14,7 +14,7 @@ import { SignInWithRecoveryCodes } from './SignInWithRecoveryCodes'
describe('SignInWithRecoveryCodes', () => {
let authManager: AuthClientInterface
let protocolService: EncryptionProviderInterface
let encryptionService: EncryptionProviderInterface
let inMemoryStore: KeyValueStoreInterface<string>
let crypto: PureCryptoInterface
let sessionManager: SessionsClientInterface
@@ -22,7 +22,7 @@ describe('SignInWithRecoveryCodes', () => {
const createUseCase = () => new SignInWithRecoveryCodes(
authManager,
protocolService,
encryptionService,
inMemoryStore,
crypto,
sessionManager,
@@ -50,17 +50,17 @@ describe('SignInWithRecoveryCodes', () => {
})
rootKey.payload = payload
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
protocolService.hasAccount = jest.fn()
protocolService.computeRootKey = jest.fn().mockReturnValue(rootKey)
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(true)
protocolService.supportedVersions = jest.fn().mockReturnValue([
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
encryptionService.hasAccount = jest.fn()
encryptionService.computeRootKey = jest.fn().mockReturnValue(rootKey)
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(true)
encryptionService.supportedVersions = jest.fn().mockReturnValue([
'001',
'002',
'003',
'004',
])
protocolService.isVersionNewerThanLibraryVersion = jest.fn()
encryptionService.isVersionNewerThanLibraryVersion = jest.fn()
inMemoryStore = {} as jest.Mocked<KeyValueStoreInterface<string>>
inMemoryStore.setValue = jest.fn()
@@ -79,7 +79,7 @@ describe('SignInWithRecoveryCodes', () => {
})
it('should fail if an account already exists', async () => {
protocolService.hasAccount = jest.fn().mockReturnValue(true)
encryptionService.hasAccount = jest.fn().mockReturnValue(true)
const useCase = createUseCase()
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
@@ -99,7 +99,7 @@ describe('SignInWithRecoveryCodes', () => {
})
it('should fail if key params has unsupported deriviation', async () => {
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
const useCase = createUseCase()
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
@@ -109,7 +109,7 @@ describe('SignInWithRecoveryCodes', () => {
})
it('should fail if key params has unsupported version', async () => {
protocolService.isVersionNewerThanLibraryVersion = jest.fn().mockReturnValue(true)
encryptionService.isVersionNewerThanLibraryVersion = jest.fn().mockReturnValue(true)
authManager.recoveryKeyParams = jest.fn().mockReturnValue({
identifier: 'test@test.te',
@@ -120,7 +120,7 @@ describe('SignInWithRecoveryCodes', () => {
version: '006',
})
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
const useCase = createUseCase()
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
@@ -130,7 +130,7 @@ describe('SignInWithRecoveryCodes', () => {
})
it('should fail if key params has expired version', async () => {
protocolService.isVersionNewerThanLibraryVersion = jest.fn().mockReturnValue(false)
encryptionService.isVersionNewerThanLibraryVersion = jest.fn().mockReturnValue(false)
authManager.recoveryKeyParams = jest.fn().mockReturnValue({
identifier: 'test@test.te',
@@ -141,7 +141,7 @@ describe('SignInWithRecoveryCodes', () => {
version: '006',
})
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
const useCase = createUseCase()
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })

View File

@@ -20,7 +20,7 @@ import { SignInWithRecoveryCodesDTO } from './SignInWithRecoveryCodesDTO'
export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
constructor(
private authManager: AuthClientInterface,
private protocolService: EncryptionProviderInterface,
private encryptionService: EncryptionProviderInterface,
private inMemoryStore: KeyValueStoreInterface<string>,
private crypto: PureCryptoInterface,
private sessionManager: SessionsClientInterface,
@@ -28,7 +28,7 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
) {}
async execute(dto: SignInWithRecoveryCodesDTO): Promise<Result<void>> {
if (this.protocolService.hasAccount()) {
if (this.encryptionService.hasAccount()) {
return Result.fail('Tried to sign in when an account already exists.')
}
@@ -48,19 +48,19 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
const rootKeyParams = CreateAnyKeyParams(recoveryKeyParams)
if (!this.protocolService.supportedVersions().includes(rootKeyParams.version)) {
if (this.protocolService.isVersionNewerThanLibraryVersion(rootKeyParams.version)) {
if (!this.encryptionService.supportedVersions().includes(rootKeyParams.version)) {
if (this.encryptionService.isVersionNewerThanLibraryVersion(rootKeyParams.version)) {
return Result.fail(UNSUPPORTED_PROTOCOL_VERSION)
}
return Result.fail(EXPIRED_PROTOCOL_VERSION)
}
if (!this.protocolService.platformSupportsKeyDerivation(rootKeyParams)) {
if (!this.encryptionService.platformSupportsKeyDerivation(rootKeyParams)) {
return Result.fail(UNSUPPORTED_KEY_DERIVATION)
}
const rootKey = await this.protocolService.computeRootKey(dto.password, rootKeyParams)
const rootKey = await this.encryptionService.computeRootKey(dto.password, rootKeyParams)
const signInResult = await this.authManager.signInWithRecoveryCodes({
codeVerifier,