refactor: root key manager (#2344)
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
export enum RootKeyServiceEvent {
|
|
||||||
RootKeyStatusChanged = 'RootKeyStatusChanged',
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,6 @@ export * from './Service/Encryption/EncryptionProviderInterface'
|
|||||||
export * from './Service/KeySystemKeyManagerInterface'
|
export * from './Service/KeySystemKeyManagerInterface'
|
||||||
export * from './Service/Functions'
|
export * from './Service/Functions'
|
||||||
export * from './Service/RootKey/KeyMode'
|
export * from './Service/RootKey/KeyMode'
|
||||||
export * from './Service/RootKey/RootKeyServiceEvent'
|
|
||||||
|
|
||||||
export * from './Split/AbstractKeySplit'
|
export * from './Split/AbstractKeySplit'
|
||||||
export * from './Split/EncryptionSplit'
|
export * from './Split/EncryptionSplit'
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { InternalEventInterface } from './../Internal/InternalEventInterface'
|
||||||
|
import { InternalEventHandlerInterface } from './../Internal/InternalEventHandlerInterface'
|
||||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
||||||
import {
|
import {
|
||||||
CreateAnyKeyParams,
|
CreateAnyKeyParams,
|
||||||
@@ -16,9 +18,6 @@ import {
|
|||||||
LegacyAttachedData,
|
LegacyAttachedData,
|
||||||
OperatorManager,
|
OperatorManager,
|
||||||
RootKeyEncryptedAuthenticatedData,
|
RootKeyEncryptedAuthenticatedData,
|
||||||
RootKeyServiceEvent,
|
|
||||||
SNRootKey,
|
|
||||||
SNRootKeyParams,
|
|
||||||
SplitPayloadsByEncryptionType,
|
SplitPayloadsByEncryptionType,
|
||||||
V001Algorithm,
|
V001Algorithm,
|
||||||
V002Algorithm,
|
V002Algorithm,
|
||||||
@@ -47,6 +46,7 @@ import {
|
|||||||
KeySystemRootKeyInterface,
|
KeySystemRootKeyInterface,
|
||||||
KeySystemRootKeyParamsInterface,
|
KeySystemRootKeyParamsInterface,
|
||||||
TrustedContactInterface,
|
TrustedContactInterface,
|
||||||
|
RootKeyParamsInterface,
|
||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||||
import { PkcKeyPair, PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
import { PkcKeyPair, PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||||
@@ -78,10 +78,20 @@ import { DeviceInterface } from '../Device/DeviceInterface'
|
|||||||
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
|
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
|
||||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||||
import { SyncEvent } from '../Event/SyncEvent'
|
import { SyncEvent } from '../Event/SyncEvent'
|
||||||
import { RootKeyEncryptionService } from './RootKeyEncryption'
|
|
||||||
import { DecryptBackupFileUseCase } from './DecryptBackupFileUseCase'
|
import { DecryptBackupFileUseCase } from './DecryptBackupFileUseCase'
|
||||||
import { EncryptionServiceEvent } from './EncryptionServiceEvent'
|
import { EncryptionServiceEvent } from './EncryptionServiceEvent'
|
||||||
import { DecryptedParameters } from '@standardnotes/encryption/src/Domain/Types/DecryptedParameters'
|
import { DecryptedParameters } from '@standardnotes/encryption/src/Domain/Types/DecryptedParameters'
|
||||||
|
import { RootKeyManager } from './RootKey/RootKeyManager'
|
||||||
|
import { RootKeyManagerEvent } from './RootKey/RootKeyManagerEvent'
|
||||||
|
import { CreateNewItemsKeyWithRollbackUseCase } from './UseCase/ItemsKey/CreateNewItemsKeyWithRollback'
|
||||||
|
import { DecryptErroredRootPayloadsUseCase } from './UseCase/RootEncryption/DecryptErroredPayloads'
|
||||||
|
import { CreateNewDefaultItemsKeyUseCase } from './UseCase/ItemsKey/CreateNewDefaultItemsKey'
|
||||||
|
import { RootKeyDecryptPayloadUseCase } from './UseCase/RootEncryption/DecryptPayload'
|
||||||
|
import { RootKeyDecryptPayloadWithKeyLookupUseCase } from './UseCase/RootEncryption/DecryptPayloadWithKeyLookup'
|
||||||
|
import { RootKeyEncryptPayloadWithKeyLookupUseCase } from './UseCase/RootEncryption/EncryptPayloadWithKeyLookup'
|
||||||
|
import { RootKeyEncryptPayloadUseCase } from './UseCase/RootEncryption/EncryptPayload'
|
||||||
|
import { ValidateAccountPasswordResult } from './RootKey/ValidateAccountPasswordResult'
|
||||||
|
import { ValidatePasscodeResult } from './RootKey/ValidatePasscodeResult'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The encryption service is responsible for the encryption and decryption of payloads, and
|
* The encryption service is responsible for the encryption and decryption of payloads, and
|
||||||
@@ -110,75 +120,73 @@ import { DecryptedParameters } from '@standardnotes/encryption/src/Domain/Types/
|
|||||||
* It also exposes public methods that allows consumers to retrieve an items key
|
* It also exposes public methods that allows consumers to retrieve an items key
|
||||||
* for a particular payload, and also retrieve all available items keys.
|
* for a particular payload, and also retrieve all available items keys.
|
||||||
*/
|
*/
|
||||||
export class EncryptionService extends AbstractService<EncryptionServiceEvent> implements EncryptionProviderInterface {
|
export class EncryptionService
|
||||||
private operatorManager: OperatorManager
|
extends AbstractService<EncryptionServiceEvent>
|
||||||
|
implements EncryptionProviderInterface, InternalEventHandlerInterface
|
||||||
|
{
|
||||||
|
private operators: OperatorManager
|
||||||
private readonly itemsEncryption: ItemsEncryptionService
|
private readonly itemsEncryption: ItemsEncryptionService
|
||||||
private readonly rootKeyEncryption: RootKeyEncryptionService
|
private readonly rootKeyManager: RootKeyManager
|
||||||
private rootKeyObserverDisposer: () => void
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private itemManager: ItemManagerInterface,
|
private items: ItemManagerInterface,
|
||||||
private mutator: MutatorClientInterface,
|
private mutator: MutatorClientInterface,
|
||||||
private payloadManager: PayloadManagerInterface,
|
private payloads: PayloadManagerInterface,
|
||||||
public deviceInterface: DeviceInterface,
|
public device: DeviceInterface,
|
||||||
private storageService: StorageServiceInterface,
|
private storage: StorageServiceInterface,
|
||||||
public readonly keys: KeySystemKeyManagerInterface,
|
public readonly keys: KeySystemKeyManagerInterface,
|
||||||
private identifier: ApplicationIdentifier,
|
identifier: ApplicationIdentifier,
|
||||||
public crypto: PureCryptoInterface,
|
public crypto: PureCryptoInterface,
|
||||||
protected override internalEventBus: InternalEventBusInterface,
|
protected override internalEventBus: InternalEventBusInterface,
|
||||||
) {
|
) {
|
||||||
super(internalEventBus)
|
super(internalEventBus)
|
||||||
this.crypto = crypto
|
this.crypto = crypto
|
||||||
|
|
||||||
this.operatorManager = new OperatorManager(crypto)
|
this.operators = new OperatorManager(crypto)
|
||||||
|
|
||||||
this.itemsEncryption = new ItemsEncryptionService(
|
this.rootKeyManager = new RootKeyManager(
|
||||||
itemManager,
|
device,
|
||||||
payloadManager,
|
storage,
|
||||||
storageService,
|
items,
|
||||||
this.operatorManager,
|
mutator,
|
||||||
keys,
|
this.operators,
|
||||||
|
identifier,
|
||||||
internalEventBus,
|
internalEventBus,
|
||||||
)
|
)
|
||||||
|
|
||||||
this.rootKeyEncryption = new RootKeyEncryptionService(
|
internalEventBus.addEventHandler(this, RootKeyManagerEvent.RootKeyManagerKeyStatusChanged)
|
||||||
this.itemManager,
|
|
||||||
this.mutator,
|
|
||||||
this.operatorManager,
|
|
||||||
this.deviceInterface,
|
|
||||||
this.storageService,
|
|
||||||
this.payloadManager,
|
|
||||||
keys,
|
|
||||||
this.identifier,
|
|
||||||
this.internalEventBus,
|
|
||||||
)
|
|
||||||
|
|
||||||
this.rootKeyObserverDisposer = this.rootKeyEncryption.addEventObserver((event) => {
|
this.itemsEncryption = new ItemsEncryptionService(items, payloads, storage, this.operators, keys, internalEventBus)
|
||||||
this.itemsEncryption.userVersion = this.getUserVersion()
|
|
||||||
if (event === RootKeyServiceEvent.RootKeyStatusChanged) {
|
|
||||||
void this.notifyEvent(EncryptionServiceEvent.RootKeyStatusChanged)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
UuidGenerator.SetGenerator(this.crypto.generateUUID)
|
UuidGenerator.SetGenerator(this.crypto.generateUUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override deinit(): void {
|
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||||
;(this.itemManager as unknown) = undefined
|
if (event.type === RootKeyManagerEvent.RootKeyManagerKeyStatusChanged) {
|
||||||
;(this.payloadManager as unknown) = undefined
|
this.itemsEncryption.userVersion = this.getUserVersion()
|
||||||
;(this.deviceInterface as unknown) = undefined
|
void this.notifyEvent(EncryptionServiceEvent.RootKeyStatusChanged)
|
||||||
;(this.storageService as unknown) = undefined
|
}
|
||||||
;(this.crypto as unknown) = undefined
|
}
|
||||||
;(this.operatorManager as unknown) = undefined
|
|
||||||
|
|
||||||
this.rootKeyObserverDisposer()
|
public override async blockDeinit(): Promise<void> {
|
||||||
;(this.rootKeyObserverDisposer as unknown) = undefined
|
await Promise.all([this.rootKeyManager.blockDeinit(), this.itemsEncryption.blockDeinit()])
|
||||||
|
|
||||||
|
return super.blockDeinit()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override deinit(): void {
|
||||||
|
;(this.items as unknown) = undefined
|
||||||
|
;(this.payloads as unknown) = undefined
|
||||||
|
;(this.device as unknown) = undefined
|
||||||
|
;(this.storage as unknown) = undefined
|
||||||
|
;(this.crypto as unknown) = undefined
|
||||||
|
;(this.operators as unknown) = undefined
|
||||||
|
|
||||||
this.itemsEncryption.deinit()
|
this.itemsEncryption.deinit()
|
||||||
;(this.itemsEncryption as unknown) = undefined
|
;(this.itemsEncryption as unknown) = undefined
|
||||||
|
|
||||||
this.rootKeyEncryption.deinit()
|
this.rootKeyManager.deinit()
|
||||||
;(this.rootKeyEncryption as unknown) = undefined
|
;(this.rootKeyManager as unknown) = undefined
|
||||||
|
|
||||||
super.deinit()
|
super.deinit()
|
||||||
}
|
}
|
||||||
@@ -210,17 +218,17 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async initialize() {
|
public async initialize() {
|
||||||
await this.rootKeyEncryption.initialize()
|
await this.rootKeyManager.initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns encryption protocol display name for active account/wrapper
|
* Returns encryption protocol display name for active account/wrapper
|
||||||
*/
|
*/
|
||||||
public async getEncryptionDisplayName(): Promise<string> {
|
public async getEncryptionDisplayName(): Promise<string> {
|
||||||
const version = await this.rootKeyEncryption.getEncryptionSourceVersion()
|
const version = await this.rootKeyManager.getEncryptionSourceVersion()
|
||||||
|
|
||||||
if (version) {
|
if (version) {
|
||||||
return this.operatorManager.operatorForVersion(version).getEncryptionDisplayName()
|
return this.operators.operatorForVersion(version).getEncryptionDisplayName()
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error('Attempting to access encryption display name wtihout source')
|
throw Error('Attempting to access encryption display name wtihout source')
|
||||||
@@ -231,15 +239,15 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasAccount() {
|
public hasAccount() {
|
||||||
return this.rootKeyEncryption.hasAccount()
|
return this.rootKeyManager.hasAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasRootKeyEncryptionSource(): boolean {
|
public hasRootKeyEncryptionSource(): boolean {
|
||||||
return this.rootKeyEncryption.hasRootKeyEncryptionSource()
|
return this.rootKeyManager.hasRootKeyEncryptionSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserVersion(): ProtocolVersion | undefined {
|
public getUserVersion(): ProtocolVersion | undefined {
|
||||||
return this.rootKeyEncryption.getUserVersion()
|
return this.rootKeyManager.getUserVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async upgradeAvailable() {
|
public async upgradeAvailable() {
|
||||||
@@ -257,19 +265,34 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void> {
|
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void> {
|
||||||
await this.rootKeyEncryption.reencryptApplicableItemsAfterUserRootKeyChange()
|
await this.rootKeyManager.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
public reencryptKeySystemItemsKeysForVault(keySystemIdentifier: KeySystemIdentifier): Promise<void> {
|
/**
|
||||||
return this.rootKeyEncryption.reencryptKeySystemItemsKeysForVault(keySystemIdentifier)
|
* When the key system root key changes, we must re-encrypt all vault items keys
|
||||||
|
* with this new key system root key (by simply re-syncing).
|
||||||
|
*/
|
||||||
|
public async reencryptKeySystemItemsKeysForVault(keySystemIdentifier: KeySystemIdentifier): Promise<void> {
|
||||||
|
const keySystemItemsKeys = this.keys.getKeySystemItemsKeys(keySystemIdentifier)
|
||||||
|
if (keySystemItemsKeys.length > 0) {
|
||||||
|
await this.mutator.setItemsDirty(keySystemItemsKeys)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createNewItemsKeyWithRollback(): Promise<() => Promise<void>> {
|
public async createNewItemsKeyWithRollback(): Promise<() => Promise<void>> {
|
||||||
return this.rootKeyEncryption.createNewItemsKeyWithRollback()
|
const usecase = new CreateNewItemsKeyWithRollbackUseCase(
|
||||||
|
this.mutator,
|
||||||
|
this.items,
|
||||||
|
this.operators,
|
||||||
|
this.rootKeyManager,
|
||||||
|
)
|
||||||
|
return usecase.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async decryptErroredPayloads(): Promise<void> {
|
public async decryptErroredPayloads(): Promise<void> {
|
||||||
await this.rootKeyEncryption.decryptErroredRootPayloads()
|
const usecase = new DecryptErroredRootPayloadsUseCase(this.payloads, this.operators, this.keys, this.rootKeyManager)
|
||||||
|
await usecase.execute()
|
||||||
|
|
||||||
await this.itemsEncryption.decryptErroredItemPayloads()
|
await this.itemsEncryption.decryptErroredItemPayloads()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,10 +325,18 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
usesKeySystemRootKeyWithKeyLookup,
|
usesKeySystemRootKeyWithKeyLookup,
|
||||||
} = split
|
} = split
|
||||||
|
|
||||||
|
const rootKeyEncryptWithKeyLookupUsecase = new RootKeyEncryptPayloadWithKeyLookupUseCase(
|
||||||
|
this.operators,
|
||||||
|
this.keys,
|
||||||
|
this.rootKeyManager,
|
||||||
|
)
|
||||||
|
|
||||||
|
const rootKeyEncryptUsecase = new RootKeyEncryptPayloadUseCase(this.operators)
|
||||||
|
|
||||||
const signingKeyPair = this.hasSigningKeyPair() ? this.getSigningKeyPair() : undefined
|
const signingKeyPair = this.hasSigningKeyPair() ? this.getSigningKeyPair() : undefined
|
||||||
|
|
||||||
if (usesRootKey) {
|
if (usesRootKey) {
|
||||||
const rootKeyEncrypted = await this.rootKeyEncryption.encryptPayloads(
|
const rootKeyEncrypted = await rootKeyEncryptUsecase.executeMany(
|
||||||
usesRootKey.items,
|
usesRootKey.items,
|
||||||
usesRootKey.key,
|
usesRootKey.key,
|
||||||
signingKeyPair,
|
signingKeyPair,
|
||||||
@@ -314,7 +345,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (usesRootKeyWithKeyLookup) {
|
if (usesRootKeyWithKeyLookup) {
|
||||||
const rootKeyEncrypted = await this.rootKeyEncryption.encryptPayloadsWithKeyLookup(
|
const rootKeyEncrypted = await rootKeyEncryptWithKeyLookupUsecase.executeMany(
|
||||||
usesRootKeyWithKeyLookup.items,
|
usesRootKeyWithKeyLookup.items,
|
||||||
signingKeyPair,
|
signingKeyPair,
|
||||||
)
|
)
|
||||||
@@ -322,7 +353,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (usesKeySystemRootKey) {
|
if (usesKeySystemRootKey) {
|
||||||
const keySystemRootKeyEncrypted = await this.rootKeyEncryption.encryptPayloads(
|
const keySystemRootKeyEncrypted = await rootKeyEncryptUsecase.executeMany(
|
||||||
usesKeySystemRootKey.items,
|
usesKeySystemRootKey.items,
|
||||||
usesKeySystemRootKey.key,
|
usesKeySystemRootKey.key,
|
||||||
signingKeyPair,
|
signingKeyPair,
|
||||||
@@ -331,7 +362,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (usesKeySystemRootKeyWithKeyLookup) {
|
if (usesKeySystemRootKeyWithKeyLookup) {
|
||||||
const keySystemRootKeyEncrypted = await this.rootKeyEncryption.encryptPayloadsWithKeyLookup(
|
const keySystemRootKeyEncrypted = await rootKeyEncryptWithKeyLookupUsecase.executeMany(
|
||||||
usesKeySystemRootKeyWithKeyLookup.items,
|
usesKeySystemRootKeyWithKeyLookup.items,
|
||||||
signingKeyPair,
|
signingKeyPair,
|
||||||
)
|
)
|
||||||
@@ -391,26 +422,32 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
usesKeySystemRootKeyWithKeyLookup,
|
usesKeySystemRootKeyWithKeyLookup,
|
||||||
} = split
|
} = split
|
||||||
|
|
||||||
|
const rootKeyDecryptUseCase = new RootKeyDecryptPayloadUseCase(this.operators)
|
||||||
|
|
||||||
|
const rootKeyDecryptWithKeyLookupUsecase = new RootKeyDecryptPayloadWithKeyLookupUseCase(
|
||||||
|
this.operators,
|
||||||
|
this.keys,
|
||||||
|
this.rootKeyManager,
|
||||||
|
)
|
||||||
|
|
||||||
if (usesRootKey) {
|
if (usesRootKey) {
|
||||||
const rootKeyDecrypted = await this.rootKeyEncryption.decryptPayloads<C>(usesRootKey.items, usesRootKey.key)
|
const rootKeyDecrypted = await rootKeyDecryptUseCase.executeMany<C>(usesRootKey.items, usesRootKey.key)
|
||||||
extendArray(resultParams, rootKeyDecrypted)
|
extendArray(resultParams, rootKeyDecrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usesRootKeyWithKeyLookup) {
|
if (usesRootKeyWithKeyLookup) {
|
||||||
const rootKeyDecrypted = await this.rootKeyEncryption.decryptPayloadsWithKeyLookup<C>(
|
const rootKeyDecrypted = await rootKeyDecryptWithKeyLookupUsecase.executeMany<C>(usesRootKeyWithKeyLookup.items)
|
||||||
usesRootKeyWithKeyLookup.items,
|
|
||||||
)
|
|
||||||
extendArray(resultParams, rootKeyDecrypted)
|
extendArray(resultParams, rootKeyDecrypted)
|
||||||
}
|
}
|
||||||
if (usesKeySystemRootKey) {
|
if (usesKeySystemRootKey) {
|
||||||
const keySystemRootKeyDecrypted = await this.rootKeyEncryption.decryptPayloads<C>(
|
const keySystemRootKeyDecrypted = await rootKeyDecryptUseCase.executeMany<C>(
|
||||||
usesKeySystemRootKey.items,
|
usesKeySystemRootKey.items,
|
||||||
usesKeySystemRootKey.key,
|
usesKeySystemRootKey.key,
|
||||||
)
|
)
|
||||||
extendArray(resultParams, keySystemRootKeyDecrypted)
|
extendArray(resultParams, keySystemRootKeyDecrypted)
|
||||||
}
|
}
|
||||||
if (usesKeySystemRootKeyWithKeyLookup) {
|
if (usesKeySystemRootKeyWithKeyLookup) {
|
||||||
const keySystemRootKeyDecrypted = await this.rootKeyEncryption.decryptPayloadsWithKeyLookup<C>(
|
const keySystemRootKeyDecrypted = await rootKeyDecryptWithKeyLookupUsecase.executeMany<C>(
|
||||||
usesKeySystemRootKeyWithKeyLookup.items,
|
usesKeySystemRootKeyWithKeyLookup.items,
|
||||||
)
|
)
|
||||||
extendArray(resultParams, keySystemRootKeyDecrypted)
|
extendArray(resultParams, keySystemRootKeyDecrypted)
|
||||||
@@ -492,14 +529,14 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
* Returns true if the user's account protocol version is not equal to the latest version.
|
* Returns true if the user's account protocol version is not equal to the latest version.
|
||||||
*/
|
*/
|
||||||
public async passcodeUpgradeAvailable(): Promise<boolean> {
|
public async passcodeUpgradeAvailable(): Promise<boolean> {
|
||||||
return this.rootKeyEncryption.passcodeUpgradeAvailable()
|
return this.rootKeyManager.passcodeUpgradeAvailable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the current environment is capable of supporting
|
* Determines whether the current environment is capable of supporting
|
||||||
* key derivation.
|
* key derivation.
|
||||||
*/
|
*/
|
||||||
public platformSupportsKeyDerivation(keyParams: SNRootKeyParams) {
|
public platformSupportsKeyDerivation(keyParams: RootKeyParamsInterface) {
|
||||||
/**
|
/**
|
||||||
* If the version is 003 or lower, key derivation is supported unless the browser is
|
* If the version is 003 or lower, key derivation is supported unless the browser is
|
||||||
* IE or Edge (or generally, where WebCrypto is not available) or React Native environment is detected.
|
* IE or Edge (or generally, where WebCrypto is not available) or React Native environment is detected.
|
||||||
@@ -548,8 +585,11 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
* Computes a root key given a password and key params.
|
* Computes a root key given a password and key params.
|
||||||
* Delegates computation to respective protocol operator.
|
* Delegates computation to respective protocol operator.
|
||||||
*/
|
*/
|
||||||
public async computeRootKey<K extends RootKeyInterface>(password: string, keyParams: SNRootKeyParams): Promise<K> {
|
public async computeRootKey<K extends RootKeyInterface>(
|
||||||
return this.rootKeyEncryption.computeRootKey(password, keyParams)
|
password: string,
|
||||||
|
keyParams: RootKeyParamsInterface,
|
||||||
|
): Promise<K> {
|
||||||
|
return this.rootKeyManager.computeRootKey(password, keyParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -561,7 +601,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
origination: KeyParamsOrigination,
|
origination: KeyParamsOrigination,
|
||||||
version?: ProtocolVersion,
|
version?: ProtocolVersion,
|
||||||
): Promise<K> {
|
): Promise<K> {
|
||||||
return this.rootKeyEncryption.createRootKey(identifier, password, origination, version)
|
return this.rootKeyManager.createRootKey(identifier, password, origination, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
createRandomizedKeySystemRootKey(dto: {
|
createRandomizedKeySystemRootKey(dto: {
|
||||||
@@ -569,7 +609,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
systemName: string
|
systemName: string
|
||||||
systemDescription?: string
|
systemDescription?: string
|
||||||
}): KeySystemRootKeyInterface {
|
}): KeySystemRootKeyInterface {
|
||||||
return this.operatorManager.defaultOperator().createRandomizedKeySystemRootKey(dto)
|
return this.operators.defaultOperator().createRandomizedKeySystemRootKey(dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
createUserInputtedKeySystemRootKey(dto: {
|
createUserInputtedKeySystemRootKey(dto: {
|
||||||
@@ -578,14 +618,14 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
systemDescription?: string
|
systemDescription?: string
|
||||||
userInputtedPassword: string
|
userInputtedPassword: string
|
||||||
}): KeySystemRootKeyInterface {
|
}): KeySystemRootKeyInterface {
|
||||||
return this.operatorManager.defaultOperator().createUserInputtedKeySystemRootKey(dto)
|
return this.operators.defaultOperator().createUserInputtedKeySystemRootKey(dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
deriveUserInputtedKeySystemRootKey(dto: {
|
deriveUserInputtedKeySystemRootKey(dto: {
|
||||||
keyParams: KeySystemRootKeyParamsInterface
|
keyParams: KeySystemRootKeyParamsInterface
|
||||||
userInputtedPassword: string
|
userInputtedPassword: string
|
||||||
}): KeySystemRootKeyInterface {
|
}): KeySystemRootKeyInterface {
|
||||||
return this.operatorManager.defaultOperator().deriveUserInputtedKeySystemRootKey(dto)
|
return this.operators.defaultOperator().deriveUserInputtedKeySystemRootKey(dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
createKeySystemItemsKey(
|
createKeySystemItemsKey(
|
||||||
@@ -594,7 +634,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
sharedVaultUuid: string | undefined,
|
sharedVaultUuid: string | undefined,
|
||||||
rootKeyToken: string,
|
rootKeyToken: string,
|
||||||
): KeySystemItemsKeyInterface {
|
): KeySystemItemsKeyInterface {
|
||||||
return this.operatorManager
|
return this.operators
|
||||||
.defaultOperator()
|
.defaultOperator()
|
||||||
.createKeySystemItemsKey(uuid, keySystemIdentifier, sharedVaultUuid, rootKeyToken)
|
.createKeySystemItemsKey(uuid, keySystemIdentifier, sharedVaultUuid, rootKeyToken)
|
||||||
}
|
}
|
||||||
@@ -605,7 +645,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
senderSigningKeyPair: PkcKeyPair
|
senderSigningKeyPair: PkcKeyPair
|
||||||
recipientPublicKey: string
|
recipientPublicKey: string
|
||||||
}): AsymmetricallyEncryptedString {
|
}): AsymmetricallyEncryptedString {
|
||||||
const operator = this.operatorManager.defaultOperator()
|
const operator = this.operators.defaultOperator()
|
||||||
const encrypted = operator.asymmetricEncrypt({
|
const encrypted = operator.asymmetricEncrypt({
|
||||||
stringToEncrypt: JSON.stringify(dto.message),
|
stringToEncrypt: JSON.stringify(dto.message),
|
||||||
senderKeyPair: dto.senderKeyPair,
|
senderKeyPair: dto.senderKeyPair,
|
||||||
@@ -620,9 +660,9 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
trustedSender: TrustedContactInterface | undefined
|
trustedSender: TrustedContactInterface | undefined
|
||||||
privateKey: string
|
privateKey: string
|
||||||
}): M | undefined {
|
}): M | undefined {
|
||||||
const defaultOperator = this.operatorManager.defaultOperator()
|
const defaultOperator = this.operators.defaultOperator()
|
||||||
const version = defaultOperator.versionForAsymmetricallyEncryptedString(dto.encryptedString)
|
const version = defaultOperator.versionForAsymmetricallyEncryptedString(dto.encryptedString)
|
||||||
const keyOperator = this.operatorManager.operatorForVersion(version)
|
const keyOperator = this.operators.operatorForVersion(version)
|
||||||
const decryptedResult = keyOperator.asymmetricDecrypt({
|
const decryptedResult = keyOperator.asymmetricDecrypt({
|
||||||
stringToDecrypt: dto.encryptedString,
|
stringToDecrypt: dto.encryptedString,
|
||||||
recipientSecretKey: dto.privateKey,
|
recipientSecretKey: dto.privateKey,
|
||||||
@@ -652,17 +692,17 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
asymmetricSignatureVerifyDetached(
|
asymmetricSignatureVerifyDetached(
|
||||||
encryptedString: AsymmetricallyEncryptedString,
|
encryptedString: AsymmetricallyEncryptedString,
|
||||||
): AsymmetricSignatureVerificationDetachedResult {
|
): AsymmetricSignatureVerificationDetachedResult {
|
||||||
const defaultOperator = this.operatorManager.defaultOperator()
|
const defaultOperator = this.operators.defaultOperator()
|
||||||
const version = defaultOperator.versionForAsymmetricallyEncryptedString(encryptedString)
|
const version = defaultOperator.versionForAsymmetricallyEncryptedString(encryptedString)
|
||||||
const keyOperator = this.operatorManager.operatorForVersion(version)
|
const keyOperator = this.operators.operatorForVersion(version)
|
||||||
return keyOperator.asymmetricSignatureVerifyDetached(encryptedString)
|
return keyOperator.asymmetricSignatureVerifyDetached(encryptedString)
|
||||||
}
|
}
|
||||||
|
|
||||||
getSenderPublicKeySetFromAsymmetricallyEncryptedString(string: AsymmetricallyEncryptedString): PublicKeySet {
|
getSenderPublicKeySetFromAsymmetricallyEncryptedString(string: AsymmetricallyEncryptedString): PublicKeySet {
|
||||||
const defaultOperator = this.operatorManager.defaultOperator()
|
const defaultOperator = this.operators.defaultOperator()
|
||||||
const version = defaultOperator.versionForAsymmetricallyEncryptedString(string)
|
const version = defaultOperator.versionForAsymmetricallyEncryptedString(string)
|
||||||
|
|
||||||
const keyOperator = this.operatorManager.operatorForVersion(version)
|
const keyOperator = this.operators.operatorForVersion(version)
|
||||||
return keyOperator.getSenderPublicKeySetFromAsymmetricallyEncryptedString(string)
|
return keyOperator.getSenderPublicKeySetFromAsymmetricallyEncryptedString(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +724,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createEncryptedBackupFile(): Promise<BackupFile> {
|
public async createEncryptedBackupFile(): Promise<BackupFile> {
|
||||||
const payloads = this.itemManager.items.map((item) => item.payload)
|
const payloads = this.items.items.map((item) => item.payload)
|
||||||
|
|
||||||
const split = SplitPayloadsByEncryptionType(payloads)
|
const split = SplitPayloadsByEncryptionType(payloads)
|
||||||
|
|
||||||
@@ -705,7 +745,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public createDecryptedBackupFile(): BackupFile {
|
public createDecryptedBackupFile(): BackupFile {
|
||||||
const payloads = this.payloadManager.nonDeletedItems.filter((item) => item.content_type !== ContentType.ItemsKey)
|
const payloads = this.payloads.nonDeletedItems.filter((item) => item.content_type !== ContentType.ItemsKey)
|
||||||
|
|
||||||
const data: BackupFile = {
|
const data: BackupFile = {
|
||||||
version: ProtocolVersionLatest,
|
version: ProtocolVersionLatest,
|
||||||
@@ -725,22 +765,22 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasPasscode(): boolean {
|
public hasPasscode(): boolean {
|
||||||
return this.rootKeyEncryption.hasPasscode()
|
return this.rootKeyManager.hasPasscode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns True if the root key has not yet been unwrapped (passcode locked).
|
* @returns True if the root key has not yet been unwrapped (passcode locked).
|
||||||
*/
|
*/
|
||||||
public async isPasscodeLocked() {
|
public async isPasscodeLocked() {
|
||||||
return (await this.rootKeyEncryption.hasRootKeyWrapper()) && this.rootKeyEncryption.getRootKey() == undefined
|
return (await this.rootKeyManager.hasRootKeyWrapper()) && this.rootKeyManager.getRootKey() == undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRootKeyParams() {
|
public getRootKeyParams() {
|
||||||
return this.rootKeyEncryption.getRootKeyParams()
|
return this.rootKeyManager.getRootKeyParams()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAccountKeyParams() {
|
public getAccountKeyParams() {
|
||||||
return this.rootKeyEncryption.memoizedRootKeyParams
|
return this.rootKeyManager.getMemoizedRootKeyParams()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -748,7 +788,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
* Wrapping key params are read from disk.
|
* Wrapping key params are read from disk.
|
||||||
*/
|
*/
|
||||||
public async computeWrappingKey(passcode: string) {
|
public async computeWrappingKey(passcode: string) {
|
||||||
const keyParams = this.rootKeyEncryption.getSureRootKeyWrapperKeyParams()
|
const keyParams = this.rootKeyManager.getSureRootKeyWrapperKeyParams()
|
||||||
const key = await this.computeRootKey(passcode, keyParams)
|
const key = await this.computeRootKey(passcode, keyParams)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
@@ -760,7 +800,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
* After unwrapping, the root key is automatically loaded.
|
* After unwrapping, the root key is automatically loaded.
|
||||||
*/
|
*/
|
||||||
public async unwrapRootKey(wrappingKey: RootKeyInterface) {
|
public async unwrapRootKey(wrappingKey: RootKeyInterface) {
|
||||||
return this.rootKeyEncryption.unwrapRootKey(wrappingKey)
|
return this.rootKeyManager.unwrapRootKey(wrappingKey)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Encrypts rootKey and saves it in storage instead of keychain, and then
|
* Encrypts rootKey and saves it in storage instead of keychain, and then
|
||||||
@@ -768,42 +808,42 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
* payloads in the keychain. If the root key is not wrapped, it is stored
|
* payloads in the keychain. If the root key is not wrapped, it is stored
|
||||||
* in plain form in the user's secure keychain.
|
* in plain form in the user's secure keychain.
|
||||||
*/
|
*/
|
||||||
public async setNewRootKeyWrapper(wrappingKey: SNRootKey) {
|
public async setNewRootKeyWrapper(wrappingKey: RootKeyInterface) {
|
||||||
return this.rootKeyEncryption.setNewRootKeyWrapper(wrappingKey)
|
return this.rootKeyManager.setNewRootKeyWrapper(wrappingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async removePasscode(): Promise<void> {
|
public async removePasscode(): Promise<void> {
|
||||||
await this.rootKeyEncryption.removeRootKeyWrapper()
|
await this.rootKeyManager.removeRootKeyWrapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setRootKey(key: RootKeyInterface, wrappingKey?: SNRootKey) {
|
public async setRootKey(key: RootKeyInterface, wrappingKey?: RootKeyInterface) {
|
||||||
await this.rootKeyEncryption.setRootKey(key, wrappingKey)
|
await this.rootKeyManager.setRootKey(key, wrappingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the in-memory root key value.
|
* Returns the in-memory root key value.
|
||||||
*/
|
*/
|
||||||
public getRootKey(): RootKeyInterface | undefined {
|
public getRootKey(): RootKeyInterface | undefined {
|
||||||
return this.rootKeyEncryption.getRootKey()
|
return this.rootKeyManager.getRootKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSureRootKey(): RootKeyInterface {
|
public getSureRootKey(): RootKeyInterface {
|
||||||
return this.rootKeyEncryption.getRootKey() as RootKeyInterface
|
return this.rootKeyManager.getRootKey() as RootKeyInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes root key and wrapper from keychain. Used when signing out of application.
|
* Deletes root key and wrapper from keychain. Used when signing out of application.
|
||||||
*/
|
*/
|
||||||
public async deleteWorkspaceSpecificKeyStateFromDevice() {
|
public async deleteWorkspaceSpecificKeyStateFromDevice() {
|
||||||
await this.rootKeyEncryption.deleteWorkspaceSpecificKeyStateFromDevice()
|
await this.rootKeyManager.deleteWorkspaceSpecificKeyStateFromDevice()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async validateAccountPassword(password: string) {
|
public async validateAccountPassword(password: string): Promise<ValidateAccountPasswordResult> {
|
||||||
return this.rootKeyEncryption.validateAccountPassword(password)
|
return this.rootKeyManager.validateAccountPassword(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async validatePasscode(passcode: string) {
|
public async validatePasscode(passcode: string): Promise<ValidatePasscodeResult> {
|
||||||
return this.rootKeyEncryption.validatePasscode(passcode)
|
return this.rootKeyManager.validatePasscode(passcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEmbeddedPayloadAuthenticatedData<D extends ItemAuthenticatedData>(
|
public getEmbeddedPayloadAuthenticatedData<D extends ItemAuthenticatedData>(
|
||||||
@@ -814,7 +854,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const operator = this.operatorManager.operatorForVersion(version)
|
const operator = this.operators.operatorForVersion(version)
|
||||||
|
|
||||||
const authenticatedData = operator.getPayloadAuthenticatedDataForExternalUse(
|
const authenticatedData = operator.getPayloadAuthenticatedDataForExternalUse(
|
||||||
encryptedInputParametersFromPayload(payload),
|
encryptedInputParametersFromPayload(payload),
|
||||||
@@ -824,7 +864,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the key params attached to this key's encrypted payload */
|
/** Returns the key params attached to this key's encrypted payload */
|
||||||
public getKeyEmbeddedKeyParamsFromItemsKey(key: EncryptedPayloadInterface): SNRootKeyParams | undefined {
|
public getKeyEmbeddedKeyParamsFromItemsKey(key: EncryptedPayloadInterface): RootKeyParamsInterface | undefined {
|
||||||
const authenticatedData = this.getEmbeddedPayloadAuthenticatedData(key)
|
const authenticatedData = this.getEmbeddedPayloadAuthenticatedData(key)
|
||||||
if (!authenticatedData) {
|
if (!authenticatedData) {
|
||||||
return undefined
|
return undefined
|
||||||
@@ -847,7 +887,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootKey = this.rootKeyEncryption.getRootKey()
|
const rootKey = this.rootKeyManager.getRootKey()
|
||||||
if (!rootKey) {
|
if (!rootKey) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -872,7 +912,8 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createNewDefaultItemsKey(): Promise<ItemsKeyInterface> {
|
public async createNewDefaultItemsKey(): Promise<ItemsKeyInterface> {
|
||||||
return this.rootKeyEncryption.createNewDefaultItemsKey()
|
const usecase = new CreateNewDefaultItemsKeyUseCase(this.mutator, this.items, this.operators, this.rootKeyManager)
|
||||||
|
return usecase.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPasswordCreatedDate(): Date | undefined {
|
public getPasswordCreatedDate(): Date | undefined {
|
||||||
@@ -943,7 +984,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.itemsEncryption.getItemsKeys().length === 0) {
|
if (this.itemsEncryption.getItemsKeys().length === 0) {
|
||||||
await this.rootKeyEncryption.createNewDefaultItemsKey()
|
await this.createNewDefaultItemsKey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -951,7 +992,7 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
const userVersion = this.getUserVersion()
|
const userVersion = this.getUserVersion()
|
||||||
const accountVersionedKey = this.itemsEncryption.getItemsKeys().find((key) => key.keyVersion === userVersion)
|
const accountVersionedKey = this.itemsEncryption.getItemsKeys().find((key) => key.keyVersion === userVersion)
|
||||||
if (isNullOrUndefined(accountVersionedKey)) {
|
if (isNullOrUndefined(accountVersionedKey)) {
|
||||||
await this.rootKeyEncryption.createNewDefaultItemsKey()
|
await this.createNewDefaultItemsKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.syncUnsyncedItemsKeys()
|
this.syncUnsyncedItemsKeys()
|
||||||
@@ -961,8 +1002,8 @@ export class EncryptionService extends AbstractService<EncryptionServiceEvent> i
|
|||||||
/** Always create a new items key after full sync, if no items key is found */
|
/** Always create a new items key after full sync, if no items key is found */
|
||||||
const currentItemsKey = findDefaultItemsKey(this.itemsEncryption.getItemsKeys())
|
const currentItemsKey = findDefaultItemsKey(this.itemsEncryption.getItemsKeys())
|
||||||
if (!currentItemsKey) {
|
if (!currentItemsKey) {
|
||||||
await this.rootKeyEncryption.createNewDefaultItemsKey()
|
await this.createNewDefaultItemsKey()
|
||||||
if (this.rootKeyEncryption.keyMode === KeyMode.WrapperOnly) {
|
if (this.rootKeyManager.getKeyMode() === KeyMode.WrapperOnly) {
|
||||||
return this.itemsEncryption.repersistAllItems()
|
return this.itemsEncryption.repersistAllItems()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,491 @@
|
|||||||
|
import {
|
||||||
|
AnyKeyParamsContent,
|
||||||
|
ApplicationIdentifier,
|
||||||
|
KeyParamsOrigination,
|
||||||
|
ProtocolVersion,
|
||||||
|
ProtocolVersionLatest,
|
||||||
|
} from '@standardnotes/common'
|
||||||
|
import {
|
||||||
|
KeyMode,
|
||||||
|
CreateNewRootKey,
|
||||||
|
CreateAnyKeyParams,
|
||||||
|
SNRootKey,
|
||||||
|
isErrorDecryptingParameters,
|
||||||
|
OperatorManager,
|
||||||
|
} from '@standardnotes/encryption'
|
||||||
|
import {
|
||||||
|
ContentTypesUsingRootKeyEncryption,
|
||||||
|
DecryptedPayload,
|
||||||
|
DecryptedTransferPayload,
|
||||||
|
EncryptedPayload,
|
||||||
|
EncryptedTransferPayload,
|
||||||
|
FillItemContentSpecialized,
|
||||||
|
NamespacedRootKeyInKeychain,
|
||||||
|
RootKeyContent,
|
||||||
|
RootKeyInterface,
|
||||||
|
RootKeyParamsInterface,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
import { DeviceInterface } from '../../Device/DeviceInterface'
|
||||||
|
import { InternalEventBusInterface } from '../../Internal/InternalEventBusInterface'
|
||||||
|
import { StorageKey } from '../../Storage/StorageKeys'
|
||||||
|
import { StorageServiceInterface } from '../../Storage/StorageServiceInterface'
|
||||||
|
import { StorageValueModes } from '../../Storage/StorageTypes'
|
||||||
|
import { RootKeyEncryptPayloadUseCase } from '../UseCase/RootEncryption/EncryptPayload'
|
||||||
|
import { RootKeyDecryptPayloadUseCase } from '../UseCase/RootEncryption/DecryptPayload'
|
||||||
|
import { AbstractService } from '../../Service/AbstractService'
|
||||||
|
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||||
|
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||||
|
import { RootKeyManagerEvent } from './RootKeyManagerEvent'
|
||||||
|
import { ValidatePasscodeResult } from './ValidatePasscodeResult'
|
||||||
|
import { ValidateAccountPasswordResult } from './ValidateAccountPasswordResult'
|
||||||
|
|
||||||
|
export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
|
||||||
|
private rootKey?: RootKeyInterface
|
||||||
|
private keyMode = KeyMode.RootKeyNone
|
||||||
|
private memoizedRootKeyParams?: RootKeyParamsInterface
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private device: DeviceInterface,
|
||||||
|
private storage: StorageServiceInterface,
|
||||||
|
private items: ItemManagerInterface,
|
||||||
|
private mutator: MutatorClientInterface,
|
||||||
|
private operators: OperatorManager,
|
||||||
|
private identifier: ApplicationIdentifier,
|
||||||
|
eventBus: InternalEventBusInterface,
|
||||||
|
) {
|
||||||
|
super(eventBus)
|
||||||
|
}
|
||||||
|
|
||||||
|
override deinit() {
|
||||||
|
super.deinit()
|
||||||
|
this.rootKey = undefined
|
||||||
|
this.memoizedRootKeyParams = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
public async initialize(): Promise<void> {
|
||||||
|
const wrappedRootKey = this.getWrappedRootKey()
|
||||||
|
const accountKeyParams = this.recomputeAccountKeyParams()
|
||||||
|
const hasWrapper = await this.hasRootKeyWrapper()
|
||||||
|
const hasRootKey = wrappedRootKey != undefined || accountKeyParams != undefined
|
||||||
|
|
||||||
|
if (hasWrapper && hasRootKey) {
|
||||||
|
this.keyMode = KeyMode.RootKeyPlusWrapper
|
||||||
|
} else if (hasWrapper && !hasRootKey) {
|
||||||
|
this.keyMode = KeyMode.WrapperOnly
|
||||||
|
} else if (!hasWrapper && hasRootKey) {
|
||||||
|
this.keyMode = KeyMode.RootKeyOnly
|
||||||
|
} else if (!hasWrapper && !hasRootKey) {
|
||||||
|
this.keyMode = KeyMode.RootKeyNone
|
||||||
|
} else {
|
||||||
|
throw 'Invalid key mode condition'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.RootKeyOnly) {
|
||||||
|
this.setRootKeyInstance(await this.getRootKeyFromKeychain())
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMemoizedRootKeyParams(): RootKeyParamsInterface | undefined {
|
||||||
|
return this.memoizedRootKeyParams
|
||||||
|
}
|
||||||
|
|
||||||
|
public getKeyMode(): KeyMode {
|
||||||
|
return this.keyMode
|
||||||
|
}
|
||||||
|
|
||||||
|
public async hasRootKeyWrapper(): Promise<boolean> {
|
||||||
|
const wrapper = this.getRootKeyWrapperKeyParams()
|
||||||
|
return wrapper != undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRootKeyWrapperKeyParams(): RootKeyParamsInterface | undefined {
|
||||||
|
const rawKeyParams = this.storage.getValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
||||||
|
|
||||||
|
if (!rawKeyParams) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async passcodeUpgradeAvailable(): Promise<boolean> {
|
||||||
|
const passcodeParams = this.getRootKeyWrapperKeyParams()
|
||||||
|
if (!passcodeParams) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return passcodeParams.version !== ProtocolVersionLatest
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasAccount(): boolean {
|
||||||
|
switch (this.keyMode) {
|
||||||
|
case KeyMode.RootKeyNone:
|
||||||
|
case KeyMode.WrapperOnly:
|
||||||
|
return false
|
||||||
|
case KeyMode.RootKeyOnly:
|
||||||
|
case KeyMode.RootKeyPlusWrapper:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
throw Error(`Unhandled keyMode value '${this.keyMode}'.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getUserVersion(): ProtocolVersion | undefined {
|
||||||
|
const keyParams = this.memoizedRootKeyParams
|
||||||
|
return keyParams?.version
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasRootKeyEncryptionSource(): boolean {
|
||||||
|
return this.hasAccount() || this.hasPasscode()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async computeRootKey<K extends RootKeyInterface>(
|
||||||
|
password: string,
|
||||||
|
keyParams: RootKeyParamsInterface,
|
||||||
|
): Promise<K> {
|
||||||
|
const version = keyParams.version
|
||||||
|
const operator = this.operators.operatorForVersion(version)
|
||||||
|
return operator.computeRootKey(password, keyParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes root key and wrapper from keychain. Used when signing out of application.
|
||||||
|
*/
|
||||||
|
public async deleteWorkspaceSpecificKeyStateFromDevice(): Promise<void> {
|
||||||
|
await this.device.clearNamespacedKeychainValue(this.identifier)
|
||||||
|
|
||||||
|
await this.storage.removeValue(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
|
||||||
|
await this.storage.removeValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
||||||
|
await this.storage.removeValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
||||||
|
|
||||||
|
this.keyMode = KeyMode.RootKeyNone
|
||||||
|
this.setRootKeyInstance(undefined)
|
||||||
|
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createRootKey<K extends RootKeyInterface>(
|
||||||
|
identifier: string,
|
||||||
|
password: string,
|
||||||
|
origination: KeyParamsOrigination,
|
||||||
|
version?: ProtocolVersion,
|
||||||
|
): Promise<K> {
|
||||||
|
const operator = version ? this.operators.operatorForVersion(version) : this.operators.defaultOperator()
|
||||||
|
return operator.createRootKey(identifier, password, origination)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async validateAccountPassword(password: string): Promise<ValidateAccountPasswordResult> {
|
||||||
|
const key = await this.computeRootKey(password, this.memoizedRootKeyParams as RootKeyParamsInterface)
|
||||||
|
const valid = this.getSureRootKey().compare(key)
|
||||||
|
if (valid) {
|
||||||
|
return { valid, artifacts: { rootKey: key } }
|
||||||
|
} else {
|
||||||
|
return { valid: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async validatePasscode(passcode: string): Promise<ValidatePasscodeResult> {
|
||||||
|
const keyParams = this.getSureRootKeyWrapperKeyParams()
|
||||||
|
const key = await this.computeRootKey(passcode, keyParams)
|
||||||
|
const valid = await this.validateWrappingKey(key)
|
||||||
|
if (valid) {
|
||||||
|
return { valid, artifacts: { wrappingKey: key } }
|
||||||
|
} else {
|
||||||
|
return { valid: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getEncryptionSourceVersion(): Promise<ProtocolVersion> {
|
||||||
|
if (this.hasAccount()) {
|
||||||
|
return this.getSureUserVersion()
|
||||||
|
} else if (this.hasPasscode()) {
|
||||||
|
const passcodeParams = this.getSureRootKeyWrapperKeyParams()
|
||||||
|
return passcodeParams.version
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error('Attempting to access encryption source version without source')
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSureUserVersion(): ProtocolVersion {
|
||||||
|
const keyParams = this.memoizedRootKeyParams as RootKeyParamsInterface
|
||||||
|
return keyParams.version
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleKeyStatusChange(): Promise<void> {
|
||||||
|
this.recomputeAccountKeyParams()
|
||||||
|
void this.notifyEvent(RootKeyManagerEvent.RootKeyManagerKeyStatusChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasPasscode(): boolean {
|
||||||
|
return this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
public recomputeAccountKeyParams(): RootKeyParamsInterface | undefined {
|
||||||
|
const rawKeyParams = this.storage.getValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
||||||
|
|
||||||
|
if (!rawKeyParams) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.memoizedRootKeyParams = CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
|
||||||
|
return this.memoizedRootKeyParams
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSureRootKeyWrapperKeyParams() {
|
||||||
|
return this.getRootKeyWrapperKeyParams() as RootKeyParamsInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the current in-memory root key value using the wrappingKey,
|
||||||
|
* then persists the wrapped value to disk.
|
||||||
|
*/
|
||||||
|
public async wrapAndPersistRootKey(wrappingKey: RootKeyInterface): Promise<void> {
|
||||||
|
const rootKey = this.getSureRootKey()
|
||||||
|
|
||||||
|
const value: DecryptedTransferPayload = {
|
||||||
|
...rootKey.payload.ejected(),
|
||||||
|
content: FillItemContentSpecialized(rootKey.persistableValueWhenWrapping()),
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = new DecryptedPayload(value)
|
||||||
|
|
||||||
|
const usecase = new RootKeyEncryptPayloadUseCase(this.operators)
|
||||||
|
const wrappedKey = await usecase.executeOne(payload, wrappingKey)
|
||||||
|
const wrappedKeyPayload = new EncryptedPayload({
|
||||||
|
...payload.ejected(),
|
||||||
|
...wrappedKey,
|
||||||
|
errorDecrypting: false,
|
||||||
|
waitingForKey: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.storage.setValue(StorageKey.WrappedRootKey, wrappedKeyPayload.ejected(), StorageValueModes.Nonwrapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unwrapRootKey(wrappingKey: RootKeyInterface): Promise<void> {
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
this.setRootKeyInstance(wrappingKey)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keyMode !== KeyMode.RootKeyPlusWrapper) {
|
||||||
|
throw 'Invalid key mode condition for unwrapping.'
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrappedKey = this.getWrappedRootKey()
|
||||||
|
const payload = new EncryptedPayload(wrappedKey)
|
||||||
|
const usecase = new RootKeyDecryptPayloadUseCase(this.operators)
|
||||||
|
const decrypted = await usecase.executeOne<RootKeyContent>(payload, wrappingKey)
|
||||||
|
|
||||||
|
if (isErrorDecryptingParameters(decrypted)) {
|
||||||
|
throw Error('Unable to decrypt root key with provided wrapping key.')
|
||||||
|
} else {
|
||||||
|
const decryptedPayload = new DecryptedPayload<RootKeyContent>({
|
||||||
|
...payload.ejected(),
|
||||||
|
...decrypted,
|
||||||
|
})
|
||||||
|
this.setRootKeyInstance(new SNRootKey(decryptedPayload))
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Encrypts rootKey and saves it in storage instead of keychain, and then
|
||||||
|
* clears keychain. This is because we don't want to store large encrypted
|
||||||
|
* payloads in the keychain. If the root key is not wrapped, it is stored
|
||||||
|
* in plain form in the user's secure keychain.
|
||||||
|
*/
|
||||||
|
public async setNewRootKeyWrapper(wrappingKey: RootKeyInterface) {
|
||||||
|
if (this.keyMode === KeyMode.RootKeyNone) {
|
||||||
|
this.keyMode = KeyMode.WrapperOnly
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyOnly) {
|
||||||
|
this.keyMode = KeyMode.RootKeyPlusWrapper
|
||||||
|
} else {
|
||||||
|
throw Error('Attempting to set wrapper on already wrapped key.')
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.device.clearNamespacedKeychainValue(this.identifier)
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
this.setRootKeyInstance(wrappingKey)
|
||||||
|
await this.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||||
|
} else {
|
||||||
|
await this.wrapAndPersistRootKey(wrappingKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.storage.setValue(
|
||||||
|
StorageKey.RootKeyWrapperKeyParams,
|
||||||
|
wrappingKey.keyParams.getPortableValue(),
|
||||||
|
StorageValueModes.Nonwrapped,
|
||||||
|
)
|
||||||
|
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
} else {
|
||||||
|
throw Error('Invalid keyMode on setNewRootKeyWrapper')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes root key wrapper from local storage and stores root key bare in secure keychain.
|
||||||
|
*/
|
||||||
|
public async removeRootKeyWrapper(): Promise<void> {
|
||||||
|
if (this.keyMode !== KeyMode.WrapperOnly && this.keyMode !== KeyMode.RootKeyPlusWrapper) {
|
||||||
|
throw Error('Attempting to remove root key wrapper on unwrapped key.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
this.keyMode = KeyMode.RootKeyNone
|
||||||
|
this.setRootKeyInstance(undefined)
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
this.keyMode = KeyMode.RootKeyOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.storage.removeValue(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
|
||||||
|
await this.storage.removeValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.RootKeyOnly) {
|
||||||
|
await this.saveRootKeyToKeychain()
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setRootKey(key: RootKeyInterface, wrappingKey?: RootKeyInterface) {
|
||||||
|
if (!key.keyParams) {
|
||||||
|
throw Error('keyParams must be supplied if setting root key.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getRootKey() === key) {
|
||||||
|
throw Error('Attempting to set root key as same current value.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
this.keyMode = KeyMode.RootKeyPlusWrapper
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyNone) {
|
||||||
|
this.keyMode = KeyMode.RootKeyOnly
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
/** Root key is simply changing, mode stays the same */
|
||||||
|
/** this.keyMode = this.keyMode; */
|
||||||
|
} else {
|
||||||
|
throw Error(`Unhandled key mode for setNewRootKey ${this.keyMode}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setRootKeyInstance(key)
|
||||||
|
|
||||||
|
this.storage.setValue(StorageKey.RootKeyParams, key.keyParams.getPortableValue(), StorageValueModes.Nonwrapped)
|
||||||
|
|
||||||
|
if (this.keyMode === KeyMode.RootKeyOnly) {
|
||||||
|
await this.saveRootKeyToKeychain()
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
if (!wrappingKey) {
|
||||||
|
throw Error('wrappingKey must be supplied')
|
||||||
|
}
|
||||||
|
await this.wrapAndPersistRootKey(wrappingKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.handleKeyStatusChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRootKeyParams(): RootKeyParamsInterface | undefined {
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
return this.getRootKeyWrapperKeyParams()
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
return this.recomputeAccountKeyParams()
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyNone) {
|
||||||
|
return undefined
|
||||||
|
} else {
|
||||||
|
throw `Unhandled key mode for getRootKeyParams ${this.keyMode}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSureRootKeyParams(): RootKeyParamsInterface {
|
||||||
|
return this.getRootKeyParams() as RootKeyParamsInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
public async saveRootKeyToKeychain() {
|
||||||
|
if (this.getRootKey() == undefined) {
|
||||||
|
throw 'Attempting to non-existent root key to the keychain.'
|
||||||
|
}
|
||||||
|
if (this.keyMode !== KeyMode.RootKeyOnly) {
|
||||||
|
throw 'Should not be persisting wrapped key to keychain.'
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawKey = this.getSureRootKey().getKeychainValue()
|
||||||
|
|
||||||
|
return this.executeCriticalFunction(() => {
|
||||||
|
return this.device.setNamespacedKeychainValue(rawKey, this.identifier)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We know a wrappingKey is correct if it correctly decrypts
|
||||||
|
* wrapped root key.
|
||||||
|
*/
|
||||||
|
public async validateWrappingKey(wrappingKey: RootKeyInterface): Promise<boolean> {
|
||||||
|
const wrappedRootKey = this.getWrappedRootKey()
|
||||||
|
|
||||||
|
/** If wrapper only, storage is encrypted directly with wrappingKey */
|
||||||
|
if (this.keyMode === KeyMode.WrapperOnly) {
|
||||||
|
return this.storage.canDecryptWithKey(wrappingKey)
|
||||||
|
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
||||||
|
/**
|
||||||
|
* In these modes, storage is encrypted with account keys, and
|
||||||
|
* account keys are encrypted with wrappingKey. Here we validate
|
||||||
|
* by attempting to decrypt account keys.
|
||||||
|
*/
|
||||||
|
const wrappedKeyPayload = new EncryptedPayload(wrappedRootKey)
|
||||||
|
const usecase = new RootKeyDecryptPayloadUseCase(this.operators)
|
||||||
|
const decrypted = await usecase.executeOne(wrappedKeyPayload, wrappingKey)
|
||||||
|
return !isErrorDecryptingParameters(decrypted)
|
||||||
|
} else {
|
||||||
|
throw 'Unhandled case in validateWrappingKey'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWrappedRootKey(): EncryptedTransferPayload {
|
||||||
|
return this.storage.getValue<EncryptedTransferPayload>(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRootKeyInstance(rootKey: RootKeyInterface | undefined): void {
|
||||||
|
this.rootKey = rootKey
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRootKey(): RootKeyInterface | undefined {
|
||||||
|
return this.rootKey
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSureRootKey(): RootKeyInterface {
|
||||||
|
return this.rootKey as RootKeyInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRootKeyFromKeychain(): Promise<RootKeyInterface | undefined> {
|
||||||
|
const rawKey = (await this.device.getNamespacedKeychainValue(this.identifier)) as
|
||||||
|
| NamespacedRootKeyInKeychain
|
||||||
|
| undefined
|
||||||
|
|
||||||
|
if (rawKey == undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyParams = this.getSureRootKeyParams()
|
||||||
|
|
||||||
|
return CreateNewRootKey({
|
||||||
|
...rawKey,
|
||||||
|
keyParams: keyParams.getPortableValue(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the root key changes, we must re-encrypt all relevant items with this new root key (by simply re-syncing).
|
||||||
|
*/
|
||||||
|
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void> {
|
||||||
|
const items = this.items.getItems(ContentTypesUsingRootKeyEncryption())
|
||||||
|
if (items.length > 0) {
|
||||||
|
/**
|
||||||
|
* Do not call sync after marking dirty.
|
||||||
|
* Re-encrypting items keys is called by consumers who have specific flows who
|
||||||
|
* will sync on their own timing
|
||||||
|
*/
|
||||||
|
await this.mutator.setItemsDirty(items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum RootKeyManagerEvent {
|
||||||
|
RootKeyManagerKeyStatusChanged = 'RootKeyManagerKeyStatusChanged',
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { RootKeyInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export type ValidateAccountPasswordResult =
|
||||||
|
| {
|
||||||
|
valid: true
|
||||||
|
artifacts: {
|
||||||
|
rootKey: RootKeyInterface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
valid: boolean
|
||||||
|
artifacts?: undefined
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { RootKeyInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export type ValidatePasscodeResult =
|
||||||
|
| {
|
||||||
|
valid: true
|
||||||
|
artifacts: {
|
||||||
|
wrappingKey: RootKeyInterface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
valid: boolean
|
||||||
|
artifacts?: undefined
|
||||||
|
}
|
||||||
@@ -1,716 +0,0 @@
|
|||||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
|
||||||
import {
|
|
||||||
ApplicationIdentifier,
|
|
||||||
ProtocolVersionLatest,
|
|
||||||
ProtocolVersion,
|
|
||||||
AnyKeyParamsContent,
|
|
||||||
KeyParamsOrigination,
|
|
||||||
compareVersions,
|
|
||||||
ProtocolVersionLastNonrootItemsKey,
|
|
||||||
ContentType,
|
|
||||||
} from '@standardnotes/common'
|
|
||||||
import {
|
|
||||||
RootKeyServiceEvent,
|
|
||||||
KeyMode,
|
|
||||||
SNRootKeyParams,
|
|
||||||
OperatorManager,
|
|
||||||
CreateNewRootKey,
|
|
||||||
CreateAnyKeyParams,
|
|
||||||
SNRootKey,
|
|
||||||
isErrorDecryptingParameters,
|
|
||||||
ErrorDecryptingParameters,
|
|
||||||
findDefaultItemsKey,
|
|
||||||
ItemsKeyMutator,
|
|
||||||
encryptPayload,
|
|
||||||
decryptPayload,
|
|
||||||
EncryptedOutputParameters,
|
|
||||||
DecryptedParameters,
|
|
||||||
KeySystemKeyManagerInterface,
|
|
||||||
} from '@standardnotes/encryption'
|
|
||||||
import {
|
|
||||||
ContentTypeUsesKeySystemRootKeyEncryption,
|
|
||||||
ContentTypesUsingRootKeyEncryption,
|
|
||||||
ContentTypeUsesRootKeyEncryption,
|
|
||||||
CreateDecryptedItemFromPayload,
|
|
||||||
DecryptedPayload,
|
|
||||||
DecryptedPayloadInterface,
|
|
||||||
DecryptedTransferPayload,
|
|
||||||
EncryptedPayload,
|
|
||||||
EncryptedPayloadInterface,
|
|
||||||
EncryptedTransferPayload,
|
|
||||||
FillItemContentSpecialized,
|
|
||||||
KeySystemRootKeyInterface,
|
|
||||||
ItemContent,
|
|
||||||
ItemsKeyContent,
|
|
||||||
ItemsKeyContentSpecialized,
|
|
||||||
ItemsKeyInterface,
|
|
||||||
NamespacedRootKeyInKeychain,
|
|
||||||
PayloadEmitSource,
|
|
||||||
PayloadTimestampDefaults,
|
|
||||||
RootKeyContent,
|
|
||||||
RootKeyInterface,
|
|
||||||
SureFindPayload,
|
|
||||||
KeySystemIdentifier,
|
|
||||||
} from '@standardnotes/models'
|
|
||||||
import { UuidGenerator } from '@standardnotes/utils'
|
|
||||||
import { DeviceInterface } from '../Device/DeviceInterface'
|
|
||||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
|
||||||
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
|
||||||
import { StorageKey } from '../Storage/StorageKeys'
|
|
||||||
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
|
|
||||||
import { StorageValueModes } from '../Storage/StorageTypes'
|
|
||||||
import { PayloadManagerInterface } from '../Payloads/PayloadManagerInterface'
|
|
||||||
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
|
||||||
|
|
||||||
export class RootKeyEncryptionService extends AbstractService<RootKeyServiceEvent> {
|
|
||||||
private rootKey?: RootKeyInterface
|
|
||||||
public keyMode = KeyMode.RootKeyNone
|
|
||||||
public memoizedRootKeyParams?: SNRootKeyParams
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private items: ItemManagerInterface,
|
|
||||||
private mutator: MutatorClientInterface,
|
|
||||||
private operatorManager: OperatorManager,
|
|
||||||
public deviceInterface: DeviceInterface,
|
|
||||||
private storageService: StorageServiceInterface,
|
|
||||||
private payloadManager: PayloadManagerInterface,
|
|
||||||
private keys: KeySystemKeyManagerInterface,
|
|
||||||
private identifier: ApplicationIdentifier,
|
|
||||||
protected override internalEventBus: InternalEventBusInterface,
|
|
||||||
) {
|
|
||||||
super(internalEventBus)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override deinit(): void {
|
|
||||||
;(this.items as unknown) = undefined
|
|
||||||
;(this.operatorManager as unknown) = undefined
|
|
||||||
;(this.deviceInterface as unknown) = undefined
|
|
||||||
;(this.storageService as unknown) = undefined
|
|
||||||
;(this.payloadManager as unknown) = undefined
|
|
||||||
;(this.keys as unknown) = undefined
|
|
||||||
|
|
||||||
this.rootKey = undefined
|
|
||||||
this.memoizedRootKeyParams = undefined
|
|
||||||
super.deinit()
|
|
||||||
}
|
|
||||||
|
|
||||||
public async initialize() {
|
|
||||||
const wrappedRootKey = this.getWrappedRootKey()
|
|
||||||
const accountKeyParams = await this.recomputeAccountKeyParams()
|
|
||||||
const hasWrapper = await this.hasRootKeyWrapper()
|
|
||||||
const hasRootKey = wrappedRootKey != undefined || accountKeyParams != undefined
|
|
||||||
|
|
||||||
if (hasWrapper && hasRootKey) {
|
|
||||||
this.keyMode = KeyMode.RootKeyPlusWrapper
|
|
||||||
} else if (hasWrapper && !hasRootKey) {
|
|
||||||
this.keyMode = KeyMode.WrapperOnly
|
|
||||||
} else if (!hasWrapper && hasRootKey) {
|
|
||||||
this.keyMode = KeyMode.RootKeyOnly
|
|
||||||
} else if (!hasWrapper && !hasRootKey) {
|
|
||||||
this.keyMode = KeyMode.RootKeyNone
|
|
||||||
} else {
|
|
||||||
throw 'Invalid key mode condition'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.RootKeyOnly) {
|
|
||||||
this.setRootKeyInstance(await this.getRootKeyFromKeychain())
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async handleKeyStatusChange() {
|
|
||||||
await this.recomputeAccountKeyParams()
|
|
||||||
void this.notifyEvent(RootKeyServiceEvent.RootKeyStatusChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async passcodeUpgradeAvailable() {
|
|
||||||
const passcodeParams = await this.getRootKeyWrapperKeyParams()
|
|
||||||
if (!passcodeParams) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return passcodeParams.version !== ProtocolVersionLatest
|
|
||||||
}
|
|
||||||
|
|
||||||
public async hasRootKeyWrapper() {
|
|
||||||
const wrapper = await this.getRootKeyWrapperKeyParams()
|
|
||||||
return wrapper != undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasAccount() {
|
|
||||||
switch (this.keyMode) {
|
|
||||||
case KeyMode.RootKeyNone:
|
|
||||||
case KeyMode.WrapperOnly:
|
|
||||||
return false
|
|
||||||
case KeyMode.RootKeyOnly:
|
|
||||||
case KeyMode.RootKeyPlusWrapper:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
throw Error(`Unhandled keyMode value '${this.keyMode}'.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasRootKeyEncryptionSource(): boolean {
|
|
||||||
return this.hasAccount() || this.hasPasscode()
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasPasscode() {
|
|
||||||
return this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEncryptionSourceVersion(): Promise<ProtocolVersion> {
|
|
||||||
if (this.hasAccount()) {
|
|
||||||
return this.getSureUserVersion()
|
|
||||||
} else if (this.hasPasscode()) {
|
|
||||||
const passcodeParams = this.getSureRootKeyWrapperKeyParams()
|
|
||||||
return passcodeParams.version
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Error('Attempting to access encryption source version without source')
|
|
||||||
}
|
|
||||||
|
|
||||||
public getUserVersion(): ProtocolVersion | undefined {
|
|
||||||
const keyParams = this.memoizedRootKeyParams
|
|
||||||
return keyParams?.version
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSureUserVersion(): ProtocolVersion {
|
|
||||||
const keyParams = this.memoizedRootKeyParams as SNRootKeyParams
|
|
||||||
return keyParams.version
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getRootKeyFromKeychain() {
|
|
||||||
const rawKey = (await this.deviceInterface.getNamespacedKeychainValue(this.identifier)) as
|
|
||||||
| NamespacedRootKeyInKeychain
|
|
||||||
| undefined
|
|
||||||
|
|
||||||
if (rawKey == undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyParams = this.getSureRootKeyParams()
|
|
||||||
|
|
||||||
return CreateNewRootKey({
|
|
||||||
...rawKey,
|
|
||||||
keyParams: keyParams.getPortableValue(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private async saveRootKeyToKeychain() {
|
|
||||||
if (this.getRootKey() == undefined) {
|
|
||||||
throw 'Attempting to non-existent root key to the keychain.'
|
|
||||||
}
|
|
||||||
if (this.keyMode !== KeyMode.RootKeyOnly) {
|
|
||||||
throw 'Should not be persisting wrapped key to keychain.'
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawKey = this.getSureRootKey().getKeychainValue()
|
|
||||||
|
|
||||||
return this.executeCriticalFunction(() => {
|
|
||||||
return this.deviceInterface.setNamespacedKeychainValue(rawKey, this.identifier)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRootKeyWrapperKeyParams(): SNRootKeyParams | undefined {
|
|
||||||
const rawKeyParams = this.storageService.getValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
|
||||||
|
|
||||||
if (!rawKeyParams) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSureRootKeyWrapperKeyParams() {
|
|
||||||
return this.getRootKeyWrapperKeyParams() as SNRootKeyParams
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRootKeyParams(): SNRootKeyParams | undefined {
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
return this.getRootKeyWrapperKeyParams()
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
return this.recomputeAccountKeyParams()
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyNone) {
|
|
||||||
return undefined
|
|
||||||
} else {
|
|
||||||
throw `Unhandled key mode for getRootKeyParams ${this.keyMode}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSureRootKeyParams(): SNRootKeyParams {
|
|
||||||
return this.getRootKeyParams() as SNRootKeyParams
|
|
||||||
}
|
|
||||||
|
|
||||||
public async computeRootKey<K extends RootKeyInterface>(password: string, keyParams: SNRootKeyParams): Promise<K> {
|
|
||||||
const version = keyParams.version
|
|
||||||
const operator = this.operatorManager.operatorForVersion(version)
|
|
||||||
return operator.computeRootKey(password, keyParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createRootKey<K extends RootKeyInterface>(
|
|
||||||
identifier: string,
|
|
||||||
password: string,
|
|
||||||
origination: KeyParamsOrigination,
|
|
||||||
version?: ProtocolVersion,
|
|
||||||
): Promise<K> {
|
|
||||||
const operator = version ? this.operatorManager.operatorForVersion(version) : this.operatorManager.defaultOperator()
|
|
||||||
return operator.createRootKey(identifier, password, origination)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSureMemoizedRootKeyParams(): SNRootKeyParams {
|
|
||||||
return this.memoizedRootKeyParams as SNRootKeyParams
|
|
||||||
}
|
|
||||||
|
|
||||||
public async validateAccountPassword(password: string) {
|
|
||||||
const key = await this.computeRootKey(password, this.getSureMemoizedRootKeyParams())
|
|
||||||
const valid = this.getSureRootKey().compare(key)
|
|
||||||
if (valid) {
|
|
||||||
return { valid, artifacts: { rootKey: key } }
|
|
||||||
} else {
|
|
||||||
return { valid: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async validatePasscode(passcode: string) {
|
|
||||||
const keyParams = await this.getSureRootKeyWrapperKeyParams()
|
|
||||||
const key = await this.computeRootKey(passcode, keyParams)
|
|
||||||
const valid = await this.validateWrappingKey(key)
|
|
||||||
if (valid) {
|
|
||||||
return { valid, artifacts: { wrappingKey: key } }
|
|
||||||
} else {
|
|
||||||
return { valid: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We know a wrappingKey is correct if it correctly decrypts
|
|
||||||
* wrapped root key.
|
|
||||||
*/
|
|
||||||
public async validateWrappingKey(wrappingKey: SNRootKey) {
|
|
||||||
const wrappedRootKey = this.getWrappedRootKey()
|
|
||||||
|
|
||||||
/** If wrapper only, storage is encrypted directly with wrappingKey */
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
return this.storageService.canDecryptWithKey(wrappingKey)
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
/**
|
|
||||||
* In these modes, storage is encrypted with account keys, and
|
|
||||||
* account keys are encrypted with wrappingKey. Here we validate
|
|
||||||
* by attempting to decrypt account keys.
|
|
||||||
*/
|
|
||||||
const wrappedKeyPayload = new EncryptedPayload(wrappedRootKey)
|
|
||||||
const decrypted = await this.decryptPayload(wrappedKeyPayload, wrappingKey)
|
|
||||||
return !isErrorDecryptingParameters(decrypted)
|
|
||||||
} else {
|
|
||||||
throw 'Unhandled case in validateWrappingKey'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private recomputeAccountKeyParams(): SNRootKeyParams | undefined {
|
|
||||||
const rawKeyParams = this.storageService.getValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
|
||||||
|
|
||||||
if (!rawKeyParams) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.memoizedRootKeyParams = CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
|
|
||||||
return this.memoizedRootKeyParams
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps the current in-memory root key value using the wrappingKey,
|
|
||||||
* then persists the wrapped value to disk.
|
|
||||||
*/
|
|
||||||
private async wrapAndPersistRootKey(wrappingKey: SNRootKey) {
|
|
||||||
const rootKey = this.getSureRootKey()
|
|
||||||
|
|
||||||
const value: DecryptedTransferPayload = {
|
|
||||||
...rootKey.payload.ejected(),
|
|
||||||
content: FillItemContentSpecialized(rootKey.persistableValueWhenWrapping()),
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = new DecryptedPayload(value)
|
|
||||||
|
|
||||||
const wrappedKey = await this.encryptPayload(payload, wrappingKey)
|
|
||||||
const wrappedKeyPayload = new EncryptedPayload({
|
|
||||||
...payload.ejected(),
|
|
||||||
...wrappedKey,
|
|
||||||
errorDecrypting: false,
|
|
||||||
waitingForKey: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
this.storageService.setValue(StorageKey.WrappedRootKey, wrappedKeyPayload.ejected(), StorageValueModes.Nonwrapped)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async unwrapRootKey(wrappingKey: RootKeyInterface) {
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
this.setRootKeyInstance(wrappingKey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.keyMode !== KeyMode.RootKeyPlusWrapper) {
|
|
||||||
throw 'Invalid key mode condition for unwrapping.'
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrappedKey = this.getWrappedRootKey()
|
|
||||||
const payload = new EncryptedPayload(wrappedKey)
|
|
||||||
const decrypted = await this.decryptPayload<RootKeyContent>(payload, wrappingKey)
|
|
||||||
|
|
||||||
if (isErrorDecryptingParameters(decrypted)) {
|
|
||||||
throw Error('Unable to decrypt root key with provided wrapping key.')
|
|
||||||
} else {
|
|
||||||
const decryptedPayload = new DecryptedPayload<RootKeyContent>({
|
|
||||||
...payload.ejected(),
|
|
||||||
...decrypted,
|
|
||||||
})
|
|
||||||
this.setRootKeyInstance(new SNRootKey(decryptedPayload))
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypts rootKey and saves it in storage instead of keychain, and then
|
|
||||||
* clears keychain. This is because we don't want to store large encrypted
|
|
||||||
* payloads in the keychain. If the root key is not wrapped, it is stored
|
|
||||||
* in plain form in the user's secure keychain.
|
|
||||||
*/
|
|
||||||
public async setNewRootKeyWrapper(wrappingKey: SNRootKey) {
|
|
||||||
if (this.keyMode === KeyMode.RootKeyNone) {
|
|
||||||
this.keyMode = KeyMode.WrapperOnly
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyOnly) {
|
|
||||||
this.keyMode = KeyMode.RootKeyPlusWrapper
|
|
||||||
} else {
|
|
||||||
throw Error('Attempting to set wrapper on already wrapped key.')
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.deviceInterface.clearNamespacedKeychainValue(this.identifier)
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
this.setRootKeyInstance(wrappingKey)
|
|
||||||
await this.reencryptApplicableItemsAfterUserRootKeyChange()
|
|
||||||
} else {
|
|
||||||
await this.wrapAndPersistRootKey(wrappingKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.storageService.setValue(
|
|
||||||
StorageKey.RootKeyWrapperKeyParams,
|
|
||||||
wrappingKey.keyParams.getPortableValue(),
|
|
||||||
StorageValueModes.Nonwrapped,
|
|
||||||
)
|
|
||||||
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
} else {
|
|
||||||
throw Error('Invalid keyMode on setNewRootKeyWrapper')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes root key wrapper from local storage and stores root key bare in secure keychain.
|
|
||||||
*/
|
|
||||||
public async removeRootKeyWrapper(): Promise<void> {
|
|
||||||
if (this.keyMode !== KeyMode.WrapperOnly && this.keyMode !== KeyMode.RootKeyPlusWrapper) {
|
|
||||||
throw Error('Attempting to remove root key wrapper on unwrapped key.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
this.keyMode = KeyMode.RootKeyNone
|
|
||||||
this.setRootKeyInstance(undefined)
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
this.keyMode = KeyMode.RootKeyOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.storageService.removeValue(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
|
|
||||||
await this.storageService.removeValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.RootKeyOnly) {
|
|
||||||
await this.saveRootKeyToKeychain()
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
public async setRootKey(key: SNRootKey, wrappingKey?: SNRootKey) {
|
|
||||||
if (!key.keyParams) {
|
|
||||||
throw Error('keyParams must be supplied if setting root key.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getRootKey() === key) {
|
|
||||||
throw Error('Attempting to set root key as same current value.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.WrapperOnly) {
|
|
||||||
this.keyMode = KeyMode.RootKeyPlusWrapper
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyNone) {
|
|
||||||
this.keyMode = KeyMode.RootKeyOnly
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
/** Root key is simply changing, mode stays the same */
|
|
||||||
/** this.keyMode = this.keyMode; */
|
|
||||||
} else {
|
|
||||||
throw Error(`Unhandled key mode for setNewRootKey ${this.keyMode}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setRootKeyInstance(key)
|
|
||||||
|
|
||||||
this.storageService.setValue(
|
|
||||||
StorageKey.RootKeyParams,
|
|
||||||
key.keyParams.getPortableValue(),
|
|
||||||
StorageValueModes.Nonwrapped,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (this.keyMode === KeyMode.RootKeyOnly) {
|
|
||||||
await this.saveRootKeyToKeychain()
|
|
||||||
} else if (this.keyMode === KeyMode.RootKeyPlusWrapper) {
|
|
||||||
if (!wrappingKey) {
|
|
||||||
throw Error('wrappingKey must be supplied')
|
|
||||||
}
|
|
||||||
await this.wrapAndPersistRootKey(wrappingKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes root key and wrapper from keychain. Used when signing out of application.
|
|
||||||
*/
|
|
||||||
public async deleteWorkspaceSpecificKeyStateFromDevice() {
|
|
||||||
await this.deviceInterface.clearNamespacedKeychainValue(this.identifier)
|
|
||||||
await this.storageService.removeValue(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
|
|
||||||
await this.storageService.removeValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
|
|
||||||
await this.storageService.removeValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
|
||||||
this.keyMode = KeyMode.RootKeyNone
|
|
||||||
this.setRootKeyInstance(undefined)
|
|
||||||
|
|
||||||
await this.handleKeyStatusChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
private getWrappedRootKey() {
|
|
||||||
return this.storageService.getValue<EncryptedTransferPayload>(
|
|
||||||
StorageKey.WrappedRootKey,
|
|
||||||
StorageValueModes.Nonwrapped,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public setRootKeyInstance(rootKey: RootKeyInterface | undefined): void {
|
|
||||||
this.rootKey = rootKey
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRootKey(): RootKeyInterface | undefined {
|
|
||||||
return this.rootKey
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSureRootKey(): RootKeyInterface {
|
|
||||||
return this.rootKey as RootKeyInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
private getItemsKeys() {
|
|
||||||
return this.items.getDisplayableItemsKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
private async encryptPayloadWithKeyLookup(
|
|
||||||
payload: DecryptedPayloadInterface,
|
|
||||||
signingKeyPair?: PkcKeyPair,
|
|
||||||
): Promise<EncryptedOutputParameters> {
|
|
||||||
let key: RootKeyInterface | KeySystemRootKeyInterface | undefined
|
|
||||||
if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) {
|
|
||||||
if (!payload.key_system_identifier) {
|
|
||||||
throw Error(`Key system-encrypted payload ${payload.content_type}is missing a key_system_identifier`)
|
|
||||||
}
|
|
||||||
key = this.keys.getPrimaryKeySystemRootKey(payload.key_system_identifier)
|
|
||||||
} else {
|
|
||||||
key = this.getRootKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == undefined) {
|
|
||||||
throw Error('Attempting root key encryption with no root key')
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.encryptPayload(payload, key, signingKeyPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async encryptPayloadsWithKeyLookup(
|
|
||||||
payloads: DecryptedPayloadInterface[],
|
|
||||||
signingKeyPair?: PkcKeyPair,
|
|
||||||
): Promise<EncryptedOutputParameters[]> {
|
|
||||||
return Promise.all(payloads.map((payload) => this.encryptPayloadWithKeyLookup(payload, signingKeyPair)))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async encryptPayload(
|
|
||||||
payload: DecryptedPayloadInterface,
|
|
||||||
key: RootKeyInterface | KeySystemRootKeyInterface,
|
|
||||||
signingKeyPair?: PkcKeyPair,
|
|
||||||
): Promise<EncryptedOutputParameters> {
|
|
||||||
return encryptPayload(payload, key, this.operatorManager, signingKeyPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async encryptPayloads(
|
|
||||||
payloads: DecryptedPayloadInterface[],
|
|
||||||
key: RootKeyInterface | KeySystemRootKeyInterface,
|
|
||||||
signingKeyPair?: PkcKeyPair,
|
|
||||||
) {
|
|
||||||
return Promise.all(payloads.map((payload) => this.encryptPayload(payload, key, signingKeyPair)))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async decryptPayloadWithKeyLookup<C extends ItemContent = ItemContent>(
|
|
||||||
payload: EncryptedPayloadInterface,
|
|
||||||
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
|
|
||||||
let key: RootKeyInterface | KeySystemRootKeyInterface | undefined
|
|
||||||
if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) {
|
|
||||||
if (!payload.key_system_identifier) {
|
|
||||||
throw Error('Key system root key encrypted payload is missing key_system_identifier')
|
|
||||||
}
|
|
||||||
key = this.keys.getPrimaryKeySystemRootKey(payload.key_system_identifier)
|
|
||||||
} else {
|
|
||||||
key = this.getRootKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == undefined) {
|
|
||||||
return {
|
|
||||||
uuid: payload.uuid,
|
|
||||||
errorDecrypting: true,
|
|
||||||
waitingForKey: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.decryptPayload(payload, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async decryptPayload<C extends ItemContent = ItemContent>(
|
|
||||||
payload: EncryptedPayloadInterface,
|
|
||||||
key: RootKeyInterface | KeySystemRootKeyInterface,
|
|
||||||
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
|
|
||||||
return decryptPayload(payload, key, this.operatorManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async decryptPayloadsWithKeyLookup<C extends ItemContent = ItemContent>(
|
|
||||||
payloads: EncryptedPayloadInterface[],
|
|
||||||
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
|
|
||||||
return Promise.all(payloads.map((payload) => this.decryptPayloadWithKeyLookup<C>(payload)))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async decryptPayloads<C extends ItemContent = ItemContent>(
|
|
||||||
payloads: EncryptedPayloadInterface[],
|
|
||||||
key: RootKeyInterface | KeySystemRootKeyInterface,
|
|
||||||
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
|
|
||||||
return Promise.all(payloads.map((payload) => this.decryptPayload<C>(payload, key)))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async decryptErroredRootPayloads(): Promise<void> {
|
|
||||||
const erroredRootPayloads = this.payloadManager.invalidPayloads.filter(
|
|
||||||
(i) =>
|
|
||||||
ContentTypeUsesRootKeyEncryption(i.content_type) || ContentTypeUsesKeySystemRootKeyEncryption(i.content_type),
|
|
||||||
)
|
|
||||||
if (erroredRootPayloads.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultParams = await this.decryptPayloadsWithKeyLookup(erroredRootPayloads)
|
|
||||||
|
|
||||||
const decryptedPayloads = resultParams.map((params) => {
|
|
||||||
const original = SureFindPayload(erroredRootPayloads, params.uuid)
|
|
||||||
if (isErrorDecryptingParameters(params)) {
|
|
||||||
return new EncryptedPayload({
|
|
||||||
...original.ejected(),
|
|
||||||
...params,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return new DecryptedPayload({
|
|
||||||
...original.ejected(),
|
|
||||||
...params,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.payloadManager.emitPayloads(decryptedPayloads, PayloadEmitSource.LocalChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the root key changes, we must re-encrypt all relevant items with this new root key (by simply re-syncing).
|
|
||||||
*/
|
|
||||||
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void> {
|
|
||||||
const items = this.items.getItems(ContentTypesUsingRootKeyEncryption())
|
|
||||||
if (items.length > 0) {
|
|
||||||
/**
|
|
||||||
* Do not call sync after marking dirty.
|
|
||||||
* Re-encrypting items keys is called by consumers who have specific flows who
|
|
||||||
* will sync on their own timing
|
|
||||||
*/
|
|
||||||
await this.mutator.setItemsDirty(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the key system root key changes, we must re-encrypt all vault items keys
|
|
||||||
* with this new key system root key (by simply re-syncing).
|
|
||||||
*/
|
|
||||||
public async reencryptKeySystemItemsKeysForVault(keySystemIdentifier: KeySystemIdentifier): Promise<void> {
|
|
||||||
const keySystemItemsKeys = this.keys.getKeySystemItemsKeys(keySystemIdentifier)
|
|
||||||
if (keySystemItemsKeys.length > 0) {
|
|
||||||
await this.mutator.setItemsDirty(keySystemItemsKeys)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new random items key to use for item encryption, and adds it to model management.
|
|
||||||
* Consumer must call sync. If the protocol version <= 003, only one items key should be created,
|
|
||||||
* and its .itemsKey value should be equal to the root key masterKey value.
|
|
||||||
*/
|
|
||||||
public async createNewDefaultItemsKey(): Promise<ItemsKeyInterface> {
|
|
||||||
const rootKey = this.getSureRootKey()
|
|
||||||
const operatorVersion = rootKey ? rootKey.keyVersion : ProtocolVersionLatest
|
|
||||||
let itemTemplate: ItemsKeyInterface
|
|
||||||
|
|
||||||
if (compareVersions(operatorVersion, ProtocolVersionLastNonrootItemsKey) <= 0) {
|
|
||||||
/** Create root key based items key */
|
|
||||||
const payload = new DecryptedPayload<ItemsKeyContent>({
|
|
||||||
uuid: UuidGenerator.GenerateUuid(),
|
|
||||||
content_type: ContentType.ItemsKey,
|
|
||||||
content: FillItemContentSpecialized<ItemsKeyContentSpecialized, ItemsKeyContent>({
|
|
||||||
itemsKey: rootKey.masterKey,
|
|
||||||
dataAuthenticationKey: rootKey.dataAuthenticationKey,
|
|
||||||
version: operatorVersion,
|
|
||||||
}),
|
|
||||||
...PayloadTimestampDefaults(),
|
|
||||||
})
|
|
||||||
itemTemplate = CreateDecryptedItemFromPayload(payload)
|
|
||||||
} else {
|
|
||||||
/** Create independent items key */
|
|
||||||
itemTemplate = this.operatorManager.operatorForVersion(operatorVersion).createItemsKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemsKeys = this.getItemsKeys()
|
|
||||||
const defaultKeys = itemsKeys.filter((key) => {
|
|
||||||
return key.isDefault
|
|
||||||
})
|
|
||||||
|
|
||||||
for (const key of defaultKeys) {
|
|
||||||
await this.mutator.changeItemsKey(key, (mutator) => {
|
|
||||||
mutator.isDefault = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemsKey = await this.mutator.insertItem<ItemsKeyInterface>(itemTemplate)
|
|
||||||
await this.mutator.changeItemsKey(itemsKey, (mutator) => {
|
|
||||||
mutator.isDefault = true
|
|
||||||
})
|
|
||||||
|
|
||||||
return itemsKey
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createNewItemsKeyWithRollback(): Promise<() => Promise<void>> {
|
|
||||||
const currentDefaultItemsKey = findDefaultItemsKey(this.getItemsKeys())
|
|
||||||
const newDefaultItemsKey = await this.createNewDefaultItemsKey()
|
|
||||||
|
|
||||||
const rollback = async () => {
|
|
||||||
await this.mutator.setItemToBeDeleted(newDefaultItemsKey)
|
|
||||||
|
|
||||||
if (currentDefaultItemsKey) {
|
|
||||||
await this.mutator.changeItem<ItemsKeyMutator>(currentDefaultItemsKey, (mutator) => {
|
|
||||||
mutator.isDefault = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rollback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { OperatorManager } from '@standardnotes/encryption'
|
||||||
|
import {
|
||||||
|
ContentType,
|
||||||
|
ProtocolVersionLastNonrootItemsKey,
|
||||||
|
ProtocolVersionLatest,
|
||||||
|
compareVersions,
|
||||||
|
} from '@standardnotes/common'
|
||||||
|
import {
|
||||||
|
CreateDecryptedItemFromPayload,
|
||||||
|
DecryptedPayload,
|
||||||
|
FillItemContentSpecialized,
|
||||||
|
ItemsKeyContent,
|
||||||
|
ItemsKeyContentSpecialized,
|
||||||
|
ItemsKeyInterface,
|
||||||
|
PayloadTimestampDefaults,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
import { UuidGenerator } from '@standardnotes/utils'
|
||||||
|
import { MutatorClientInterface } from '../../../Mutator/MutatorClientInterface'
|
||||||
|
import { ItemManagerInterface } from '../../../Item/ItemManagerInterface'
|
||||||
|
import { RootKeyManager } from '../../RootKey/RootKeyManager'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new random items key to use for item encryption, and adds it to model management.
|
||||||
|
* Consumer must call sync. If the protocol version <= 003, only one items key should be created,
|
||||||
|
* and its .itemsKey value should be equal to the root key masterKey value.
|
||||||
|
*/
|
||||||
|
export class CreateNewDefaultItemsKeyUseCase {
|
||||||
|
constructor(
|
||||||
|
private mutator: MutatorClientInterface,
|
||||||
|
private items: ItemManagerInterface,
|
||||||
|
private operatorManager: OperatorManager,
|
||||||
|
private rootKeyManager: RootKeyManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(): Promise<ItemsKeyInterface> {
|
||||||
|
const rootKey = this.rootKeyManager.getSureRootKey()
|
||||||
|
const operatorVersion = rootKey ? rootKey.keyVersion : ProtocolVersionLatest
|
||||||
|
let itemTemplate: ItemsKeyInterface
|
||||||
|
|
||||||
|
if (compareVersions(operatorVersion, ProtocolVersionLastNonrootItemsKey) <= 0) {
|
||||||
|
/** Create root key based items key */
|
||||||
|
const payload = new DecryptedPayload<ItemsKeyContent>({
|
||||||
|
uuid: UuidGenerator.GenerateUuid(),
|
||||||
|
content_type: ContentType.ItemsKey,
|
||||||
|
content: FillItemContentSpecialized<ItemsKeyContentSpecialized, ItemsKeyContent>({
|
||||||
|
itemsKey: rootKey.masterKey,
|
||||||
|
dataAuthenticationKey: rootKey.dataAuthenticationKey,
|
||||||
|
version: operatorVersion,
|
||||||
|
}),
|
||||||
|
...PayloadTimestampDefaults(),
|
||||||
|
})
|
||||||
|
itemTemplate = CreateDecryptedItemFromPayload(payload)
|
||||||
|
} else {
|
||||||
|
/** Create independent items key */
|
||||||
|
itemTemplate = this.operatorManager.operatorForVersion(operatorVersion).createItemsKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemsKeys = this.items.getDisplayableItemsKeys()
|
||||||
|
const defaultKeys = itemsKeys.filter((key) => {
|
||||||
|
return key.isDefault
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const key of defaultKeys) {
|
||||||
|
await this.mutator.changeItemsKey(key, (mutator) => {
|
||||||
|
mutator.isDefault = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemsKey = await this.mutator.insertItem<ItemsKeyInterface>(itemTemplate)
|
||||||
|
await this.mutator.changeItemsKey(itemsKey, (mutator) => {
|
||||||
|
mutator.isDefault = true
|
||||||
|
})
|
||||||
|
|
||||||
|
return itemsKey
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ItemsKeyMutator, OperatorManager, findDefaultItemsKey } from '@standardnotes/encryption'
|
||||||
|
import { MutatorClientInterface } from '../../../Mutator/MutatorClientInterface'
|
||||||
|
import { ItemManagerInterface } from '../../../Item/ItemManagerInterface'
|
||||||
|
import { RootKeyManager } from '../../RootKey/RootKeyManager'
|
||||||
|
import { CreateNewDefaultItemsKeyUseCase } from './CreateNewDefaultItemsKey'
|
||||||
|
|
||||||
|
export class CreateNewItemsKeyWithRollbackUseCase {
|
||||||
|
private createDefaultItemsKeyUseCase = new CreateNewDefaultItemsKeyUseCase(
|
||||||
|
this.mutator,
|
||||||
|
this.items,
|
||||||
|
this.operatorManager,
|
||||||
|
this.rootKeyManager,
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private mutator: MutatorClientInterface,
|
||||||
|
private items: ItemManagerInterface,
|
||||||
|
private operatorManager: OperatorManager,
|
||||||
|
private rootKeyManager: RootKeyManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(): Promise<() => Promise<void>> {
|
||||||
|
const currentDefaultItemsKey = findDefaultItemsKey(this.items.getDisplayableItemsKeys())
|
||||||
|
const newDefaultItemsKey = await this.createDefaultItemsKeyUseCase.execute()
|
||||||
|
|
||||||
|
const rollback = async () => {
|
||||||
|
await this.mutator.setItemToBeDeleted(newDefaultItemsKey)
|
||||||
|
|
||||||
|
if (currentDefaultItemsKey) {
|
||||||
|
await this.mutator.changeItem<ItemsKeyMutator>(currentDefaultItemsKey, (mutator) => {
|
||||||
|
mutator.isDefault = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rollback
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
ContentTypeUsesKeySystemRootKeyEncryption,
|
||||||
|
ContentTypeUsesRootKeyEncryption,
|
||||||
|
DecryptedPayload,
|
||||||
|
EncryptedPayload,
|
||||||
|
PayloadEmitSource,
|
||||||
|
SureFindPayload,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
import { PayloadManagerInterface } from './../../../Payloads/PayloadManagerInterface'
|
||||||
|
import { KeySystemKeyManagerInterface, OperatorManager, isErrorDecryptingParameters } from '@standardnotes/encryption'
|
||||||
|
import { RootKeyDecryptPayloadWithKeyLookupUseCase } from './DecryptPayloadWithKeyLookup'
|
||||||
|
import { RootKeyManager } from '../../RootKey/RootKeyManager'
|
||||||
|
|
||||||
|
export class DecryptErroredRootPayloadsUseCase {
|
||||||
|
constructor(
|
||||||
|
private payloads: PayloadManagerInterface,
|
||||||
|
private operatorManager: OperatorManager,
|
||||||
|
private keySystemKeyManager: KeySystemKeyManagerInterface,
|
||||||
|
private rootKeyManager: RootKeyManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(): Promise<void> {
|
||||||
|
const erroredRootPayloads = this.payloads.invalidPayloads.filter(
|
||||||
|
(i) =>
|
||||||
|
ContentTypeUsesRootKeyEncryption(i.content_type) || ContentTypeUsesKeySystemRootKeyEncryption(i.content_type),
|
||||||
|
)
|
||||||
|
if (erroredRootPayloads.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const usecase = new RootKeyDecryptPayloadWithKeyLookupUseCase(
|
||||||
|
this.operatorManager,
|
||||||
|
this.keySystemKeyManager,
|
||||||
|
this.rootKeyManager,
|
||||||
|
)
|
||||||
|
const resultParams = await usecase.executeMany(erroredRootPayloads)
|
||||||
|
|
||||||
|
const decryptedPayloads = resultParams.map((params) => {
|
||||||
|
const original = SureFindPayload(erroredRootPayloads, params.uuid)
|
||||||
|
if (isErrorDecryptingParameters(params)) {
|
||||||
|
return new EncryptedPayload({
|
||||||
|
...original.ejected(),
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return new DecryptedPayload({
|
||||||
|
...original.ejected(),
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.payloads.emitPayloads(decryptedPayloads, PayloadEmitSource.LocalChanged)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {
|
||||||
|
DecryptedParameters,
|
||||||
|
ErrorDecryptingParameters,
|
||||||
|
OperatorManager,
|
||||||
|
decryptPayload,
|
||||||
|
} from '@standardnotes/encryption'
|
||||||
|
import {
|
||||||
|
EncryptedPayloadInterface,
|
||||||
|
ItemContent,
|
||||||
|
KeySystemRootKeyInterface,
|
||||||
|
RootKeyInterface,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
|
||||||
|
export class RootKeyDecryptPayloadUseCase {
|
||||||
|
constructor(private operatorManager: OperatorManager) {}
|
||||||
|
|
||||||
|
async executeOne<C extends ItemContent = ItemContent>(
|
||||||
|
payload: EncryptedPayloadInterface,
|
||||||
|
key: RootKeyInterface | KeySystemRootKeyInterface,
|
||||||
|
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
|
||||||
|
return decryptPayload(payload, key, this.operatorManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeMany<C extends ItemContent = ItemContent>(
|
||||||
|
payloads: EncryptedPayloadInterface[],
|
||||||
|
key: RootKeyInterface | KeySystemRootKeyInterface,
|
||||||
|
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
|
||||||
|
return Promise.all(payloads.map((payload) => this.executeOne<C>(payload, key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import {
|
||||||
|
DecryptedParameters,
|
||||||
|
ErrorDecryptingParameters,
|
||||||
|
KeySystemKeyManagerInterface,
|
||||||
|
OperatorManager,
|
||||||
|
} from '@standardnotes/encryption'
|
||||||
|
import {
|
||||||
|
ContentTypeUsesKeySystemRootKeyEncryption,
|
||||||
|
EncryptedPayloadInterface,
|
||||||
|
ItemContent,
|
||||||
|
KeySystemRootKeyInterface,
|
||||||
|
RootKeyInterface,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
|
||||||
|
import { RootKeyDecryptPayloadUseCase } from './DecryptPayload'
|
||||||
|
import { RootKeyManager } from '../../RootKey/RootKeyManager'
|
||||||
|
|
||||||
|
export class RootKeyDecryptPayloadWithKeyLookupUseCase {
|
||||||
|
constructor(
|
||||||
|
private operatorManager: OperatorManager,
|
||||||
|
private keySystemKeyManager: KeySystemKeyManagerInterface,
|
||||||
|
private rootKeyManager: RootKeyManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async executeOne<C extends ItemContent = ItemContent>(
|
||||||
|
payload: EncryptedPayloadInterface,
|
||||||
|
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
|
||||||
|
let key: RootKeyInterface | KeySystemRootKeyInterface | undefined
|
||||||
|
if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) {
|
||||||
|
if (!payload.key_system_identifier) {
|
||||||
|
throw Error('Key system root key encrypted payload is missing key_system_identifier')
|
||||||
|
}
|
||||||
|
key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(payload.key_system_identifier)
|
||||||
|
} else {
|
||||||
|
key = this.rootKeyManager.getRootKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == undefined) {
|
||||||
|
return {
|
||||||
|
uuid: payload.uuid,
|
||||||
|
errorDecrypting: true,
|
||||||
|
waitingForKey: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const usecase = new RootKeyDecryptPayloadUseCase(this.operatorManager)
|
||||||
|
|
||||||
|
return usecase.executeOne(payload, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeMany<C extends ItemContent = ItemContent>(
|
||||||
|
payloads: EncryptedPayloadInterface[],
|
||||||
|
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
|
||||||
|
return Promise.all(payloads.map((payload) => this.executeOne<C>(payload)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { EncryptedOutputParameters, OperatorManager, encryptPayload } from '@standardnotes/encryption'
|
||||||
|
import { DecryptedPayloadInterface, KeySystemRootKeyInterface, RootKeyInterface } from '@standardnotes/models'
|
||||||
|
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||||
|
|
||||||
|
export class RootKeyEncryptPayloadUseCase {
|
||||||
|
constructor(private operatorManager: OperatorManager) {}
|
||||||
|
|
||||||
|
async executeOne(
|
||||||
|
payload: DecryptedPayloadInterface,
|
||||||
|
key: RootKeyInterface | KeySystemRootKeyInterface,
|
||||||
|
signingKeyPair?: PkcKeyPair,
|
||||||
|
): Promise<EncryptedOutputParameters> {
|
||||||
|
return encryptPayload(payload, key, this.operatorManager, signingKeyPair)
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeMany(
|
||||||
|
payloads: DecryptedPayloadInterface[],
|
||||||
|
key: RootKeyInterface | KeySystemRootKeyInterface,
|
||||||
|
signingKeyPair?: PkcKeyPair,
|
||||||
|
): Promise<EncryptedOutputParameters[]> {
|
||||||
|
return Promise.all(payloads.map((payload) => this.executeOne(payload, key, signingKeyPair)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { EncryptedOutputParameters, KeySystemKeyManagerInterface, OperatorManager } from '@standardnotes/encryption'
|
||||||
|
import {
|
||||||
|
ContentTypeUsesKeySystemRootKeyEncryption,
|
||||||
|
DecryptedPayloadInterface,
|
||||||
|
KeySystemRootKeyInterface,
|
||||||
|
RootKeyInterface,
|
||||||
|
} from '@standardnotes/models'
|
||||||
|
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||||
|
|
||||||
|
import { RootKeyEncryptPayloadUseCase } from './EncryptPayload'
|
||||||
|
import { RootKeyManager } from '../../RootKey/RootKeyManager'
|
||||||
|
|
||||||
|
export class RootKeyEncryptPayloadWithKeyLookupUseCase {
|
||||||
|
constructor(
|
||||||
|
private operatorManager: OperatorManager,
|
||||||
|
private keySystemKeyManager: KeySystemKeyManagerInterface,
|
||||||
|
private rootKeyManager: RootKeyManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async executeOne(
|
||||||
|
payload: DecryptedPayloadInterface,
|
||||||
|
signingKeyPair?: PkcKeyPair,
|
||||||
|
): Promise<EncryptedOutputParameters> {
|
||||||
|
let key: RootKeyInterface | KeySystemRootKeyInterface | undefined
|
||||||
|
if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) {
|
||||||
|
if (!payload.key_system_identifier) {
|
||||||
|
throw Error(`Key system-encrypted payload ${payload.content_type}is missing a key_system_identifier`)
|
||||||
|
}
|
||||||
|
key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(payload.key_system_identifier)
|
||||||
|
} else {
|
||||||
|
key = this.rootKeyManager.getRootKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == undefined) {
|
||||||
|
throw Error('Attempting root key encryption with no root key')
|
||||||
|
}
|
||||||
|
|
||||||
|
const usecase = new RootKeyEncryptPayloadUseCase(this.operatorManager)
|
||||||
|
return usecase.executeOne(payload, key, signingKeyPair)
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeMany(
|
||||||
|
payloads: DecryptedPayloadInterface[],
|
||||||
|
signingKeyPair?: PkcKeyPair,
|
||||||
|
): Promise<EncryptedOutputParameters[]> {
|
||||||
|
return Promise.all(payloads.map((payload) => this.executeOne(payload, signingKeyPair)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ describe('UserService', () => {
|
|||||||
let syncService: SyncServiceInterface
|
let syncService: SyncServiceInterface
|
||||||
let storageService: StorageServiceInterface
|
let storageService: StorageServiceInterface
|
||||||
let itemManager: ItemManagerInterface
|
let itemManager: ItemManagerInterface
|
||||||
let protocolService: EncryptionProviderInterface
|
let encryptionService: EncryptionProviderInterface
|
||||||
let alertService: AlertService
|
let alertService: AlertService
|
||||||
let challengeService: ChallengeServiceInterface
|
let challengeService: ChallengeServiceInterface
|
||||||
let protectionService: ProtectionsClientInterface
|
let protectionService: ProtectionsClientInterface
|
||||||
@@ -33,7 +33,7 @@ describe('UserService', () => {
|
|||||||
syncService,
|
syncService,
|
||||||
storageService,
|
storageService,
|
||||||
itemManager,
|
itemManager,
|
||||||
protocolService,
|
encryptionService,
|
||||||
alertService,
|
alertService,
|
||||||
challengeService,
|
challengeService,
|
||||||
protectionService,
|
protectionService,
|
||||||
@@ -51,7 +51,7 @@ describe('UserService', () => {
|
|||||||
|
|
||||||
itemManager = {} as jest.Mocked<ItemManagerInterface>
|
itemManager = {} as jest.Mocked<ItemManagerInterface>
|
||||||
|
|
||||||
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
|
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
|
||||||
|
|
||||||
alertService = {} as jest.Mocked<AlertService>
|
alertService = {} as jest.Mocked<AlertService>
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class UserService
|
|||||||
private syncService: SyncServiceInterface,
|
private syncService: SyncServiceInterface,
|
||||||
private storageService: StorageServiceInterface,
|
private storageService: StorageServiceInterface,
|
||||||
private itemManager: ItemManagerInterface,
|
private itemManager: ItemManagerInterface,
|
||||||
private protocolService: EncryptionProviderInterface,
|
private encryptionService: EncryptionProviderInterface,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private challengeService: ChallengeServiceInterface,
|
private challengeService: ChallengeServiceInterface,
|
||||||
private protectionService: ProtectionsClientInterface,
|
private protectionService: ProtectionsClientInterface,
|
||||||
@@ -84,14 +84,14 @@ export class UserService
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (!payload.awaitSync) {
|
if (!payload.awaitSync) {
|
||||||
void this.protocolService.decryptErroredPayloads()
|
void this.encryptionService.decryptErroredPayloads()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (payload.awaitSync) {
|
if (payload.awaitSync) {
|
||||||
await syncPromise
|
await syncPromise
|
||||||
|
|
||||||
await this.protocolService.decryptErroredPayloads()
|
await this.encryptionService.decryptErroredPayloads()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ export class UserService
|
|||||||
;(this.syncService as unknown) = undefined
|
;(this.syncService as unknown) = undefined
|
||||||
;(this.storageService as unknown) = undefined
|
;(this.storageService as unknown) = undefined
|
||||||
;(this.itemManager as unknown) = undefined
|
;(this.itemManager as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.alertService as unknown) = undefined
|
;(this.alertService as unknown) = undefined
|
||||||
;(this.challengeService as unknown) = undefined
|
;(this.challengeService as unknown) = undefined
|
||||||
;(this.protectionService as unknown) = undefined
|
;(this.protectionService as unknown) = undefined
|
||||||
@@ -123,7 +123,7 @@ export class UserService
|
|||||||
ephemeral = false,
|
ephemeral = false,
|
||||||
mergeLocal = true,
|
mergeLocal = true,
|
||||||
): Promise<UserRegistrationResponseBody> {
|
): Promise<UserRegistrationResponseBody> {
|
||||||
if (this.protocolService.hasAccount()) {
|
if (this.encryptionService.hasAccount()) {
|
||||||
throw Error('Tried to register when an account already exists.')
|
throw Error('Tried to register when an account already exists.')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ export class UserService
|
|||||||
mergeLocal = true,
|
mergeLocal = true,
|
||||||
awaitSync = false,
|
awaitSync = false,
|
||||||
): Promise<HttpResponse<SignInResponse>> {
|
): Promise<HttpResponse<SignInResponse>> {
|
||||||
if (this.protocolService.hasAccount()) {
|
if (this.encryptionService.hasAccount()) {
|
||||||
throw Error('Tried to sign in when an account already exists.')
|
throw Error('Tried to sign in when an account already exists.')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ export class UserService
|
|||||||
public async signOut(force = false, source = DeinitSource.SignOut): Promise<void> {
|
public async signOut(force = false, source = DeinitSource.SignOut): Promise<void> {
|
||||||
const performSignOut = async () => {
|
const performSignOut = async () => {
|
||||||
await this.sessionManager.signOut()
|
await this.sessionManager.signOut()
|
||||||
await this.protocolService.deleteWorkspaceSpecificKeyStateFromDevice()
|
await this.encryptionService.deleteWorkspaceSpecificKeyStateFromDevice()
|
||||||
await this.storageService.clearAllData()
|
await this.storageService.clearAllData()
|
||||||
await this.notifyEvent(AccountEvent.SignedOut, { payload: { source } })
|
await this.notifyEvent(AccountEvent.SignedOut, { payload: { source } })
|
||||||
}
|
}
|
||||||
@@ -359,8 +359,8 @@ export class UserService
|
|||||||
canceled?: true
|
canceled?: true
|
||||||
error?: { message: string }
|
error?: { message: string }
|
||||||
}> {
|
}> {
|
||||||
const hasPasscode = this.protocolService.hasPasscode()
|
const hasPasscode = this.encryptionService.hasPasscode()
|
||||||
const hasAccount = this.protocolService.hasAccount()
|
const hasAccount = this.encryptionService.hasAccount()
|
||||||
const prompts = []
|
const prompts = []
|
||||||
if (hasPasscode) {
|
if (hasPasscode) {
|
||||||
prompts.push(
|
prompts.push(
|
||||||
@@ -504,14 +504,14 @@ export class UserService
|
|||||||
|
|
||||||
private async setPasscodeWithoutWarning(passcode: string, origination: KeyParamsOrigination) {
|
private async setPasscodeWithoutWarning(passcode: string, origination: KeyParamsOrigination) {
|
||||||
const identifier = UuidGenerator.GenerateUuid()
|
const identifier = UuidGenerator.GenerateUuid()
|
||||||
const key = await this.protocolService.createRootKey(identifier, passcode, origination)
|
const key = await this.encryptionService.createRootKey(identifier, passcode, origination)
|
||||||
await this.protocolService.setNewRootKeyWrapper(key)
|
await this.encryptionService.setNewRootKeyWrapper(key)
|
||||||
await this.rewriteItemsKeys()
|
await this.rewriteItemsKeys()
|
||||||
await this.syncService.sync()
|
await this.syncService.sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async removePasscodeWithoutWarning() {
|
private async removePasscodeWithoutWarning() {
|
||||||
await this.protocolService.removePasscode()
|
await this.encryptionService.removePasscode()
|
||||||
await this.rewriteItemsKeys()
|
await this.rewriteItemsKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +564,7 @@ export class UserService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountPasswordValidation = await this.protocolService.validateAccountPassword(parameters.currentPassword)
|
const accountPasswordValidation = await this.encryptionService.validateAccountPassword(parameters.currentPassword)
|
||||||
if (!accountPasswordValidation.valid) {
|
if (!accountPasswordValidation.valid) {
|
||||||
return {
|
return {
|
||||||
error: Error(Messages.INVALID_PASSWORD),
|
error: Error(Messages.INVALID_PASSWORD),
|
||||||
@@ -597,11 +597,11 @@ export class UserService
|
|||||||
return { error: Error(response.data.error?.message) }
|
return { error: Error(response.data.error?.message) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const rollback = await this.protocolService.createNewItemsKeyWithRollback()
|
const rollback = await this.encryptionService.createNewItemsKeyWithRollback()
|
||||||
await this.protocolService.reencryptApplicableItemsAfterUserRootKeyChange()
|
await this.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||||
await this.syncService.sync({ awaitAll: true })
|
await this.syncService.sync({ awaitAll: true })
|
||||||
|
|
||||||
const defaultItemsKey = this.protocolService.getSureDefaultItemsKey()
|
const defaultItemsKey = this.encryptionService.getSureDefaultItemsKey()
|
||||||
const itemsKeyWasSynced = !defaultItemsKey.neverSynced
|
const itemsKeyWasSynced = !defaultItemsKey.neverSynced
|
||||||
|
|
||||||
if (!itemsKeyWasSynced) {
|
if (!itemsKeyWasSynced) {
|
||||||
@@ -610,7 +610,7 @@ export class UserService
|
|||||||
newRootKey: currentRootKey,
|
newRootKey: currentRootKey,
|
||||||
wrappingKey,
|
wrappingKey,
|
||||||
})
|
})
|
||||||
await this.protocolService.reencryptApplicableItemsAfterUserRootKeyChange()
|
await this.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||||
await rollback()
|
await rollback()
|
||||||
await this.syncService.sync({ awaitAll: true })
|
await this.syncService.sync({ awaitAll: true })
|
||||||
|
|
||||||
@@ -627,11 +627,11 @@ export class UserService
|
|||||||
newEmail?: string
|
newEmail?: string
|
||||||
newPassword?: string
|
newPassword?: string
|
||||||
}): Promise<{ currentRootKey: SNRootKey; newRootKey: SNRootKey }> {
|
}): Promise<{ currentRootKey: SNRootKey; newRootKey: SNRootKey }> {
|
||||||
const currentRootKey = await this.protocolService.computeRootKey(
|
const currentRootKey = await this.encryptionService.computeRootKey(
|
||||||
parameters.currentPassword,
|
parameters.currentPassword,
|
||||||
(await this.protocolService.getRootKeyParams()) as SNRootKeyParams,
|
(await this.encryptionService.getRootKeyParams()) as SNRootKeyParams,
|
||||||
)
|
)
|
||||||
const newRootKey = await this.protocolService.createRootKey(
|
const newRootKey = await this.encryptionService.createRootKey(
|
||||||
parameters.newEmail ?? parameters.currentEmail,
|
parameters.newEmail ?? parameters.currentEmail,
|
||||||
parameters.newPassword ?? parameters.currentPassword,
|
parameters.newPassword ?? parameters.currentPassword,
|
||||||
parameters.origination,
|
parameters.origination,
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ export * from './Encryption/EncryptionService'
|
|||||||
export * from './Encryption/EncryptionServiceEvent'
|
export * from './Encryption/EncryptionServiceEvent'
|
||||||
export * from './Encryption/Functions'
|
export * from './Encryption/Functions'
|
||||||
export * from './Encryption/ItemsEncryption'
|
export * from './Encryption/ItemsEncryption'
|
||||||
export * from './Encryption/RootKeyEncryption'
|
|
||||||
|
|
||||||
export * from './Event/ApplicationEvent'
|
export * from './Event/ApplicationEvent'
|
||||||
export * from './Event/ApplicationEventCallback'
|
export * from './Event/ApplicationEventCallback'
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private deprecatedHttpService!: InternalServices.DeprecatedHttpService
|
private deprecatedHttpService!: InternalServices.DeprecatedHttpService
|
||||||
private declare httpService: HttpServiceInterface
|
private declare httpService: HttpServiceInterface
|
||||||
public payloadManager!: InternalServices.PayloadManager
|
public payloadManager!: InternalServices.PayloadManager
|
||||||
public protocolService!: EncryptionService
|
public encryptionService!: EncryptionService
|
||||||
private diskStorageService!: InternalServices.DiskStorageService
|
private diskStorageService!: InternalServices.DiskStorageService
|
||||||
private inMemoryStore!: ExternalServices.KeyValueStoreInterface<string>
|
private inMemoryStore!: ExternalServices.KeyValueStoreInterface<string>
|
||||||
/**
|
/**
|
||||||
@@ -435,7 +435,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
await this.diskStorageService.initializeFromDisk()
|
await this.diskStorageService.initializeFromDisk()
|
||||||
await this.notifyEvent(ApplicationEvent.StorageReady)
|
await this.notifyEvent(ApplicationEvent.StorageReady)
|
||||||
|
|
||||||
await this.protocolService.initialize()
|
await this.encryptionService.initialize()
|
||||||
|
|
||||||
await this.handleStage(ExternalServices.ApplicationStage.ReadyForLaunch_05)
|
await this.handleStage(ExternalServices.ApplicationStage.ReadyForLaunch_05)
|
||||||
|
|
||||||
@@ -547,9 +547,9 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
let wrappingKey = response.artifacts?.wrappingKey
|
let wrappingKey = response.artifacts?.wrappingKey
|
||||||
if (!wrappingKey) {
|
if (!wrappingKey) {
|
||||||
const value = response.getValueForType(ChallengeValidation.LocalPasscode)
|
const value = response.getValueForType(ChallengeValidation.LocalPasscode)
|
||||||
wrappingKey = await this.protocolService.computeWrappingKey(value.value as string)
|
wrappingKey = await this.encryptionService.computeWrappingKey(value.value as string)
|
||||||
}
|
}
|
||||||
await this.protocolService.unwrapRootKey(wrappingKey)
|
await this.encryptionService.unwrapRootKey(wrappingKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,22 +740,22 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getUserPasswordCreationDate(): Date | undefined {
|
public getUserPasswordCreationDate(): Date | undefined {
|
||||||
return this.protocolService.getPasswordCreatedDate()
|
return this.encryptionService.getPasswordCreatedDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getProtocolEncryptionDisplayName(): Promise<string | undefined> {
|
public getProtocolEncryptionDisplayName(): Promise<string | undefined> {
|
||||||
return this.protocolService.getEncryptionDisplayName()
|
return this.encryptionService.getEncryptionDisplayName()
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserVersion(): Common.ProtocolVersion | undefined {
|
public getUserVersion(): Common.ProtocolVersion | undefined {
|
||||||
return this.protocolService.getUserVersion()
|
return this.encryptionService.getUserVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is an upgrade available for the account or passcode
|
* Returns true if there is an upgrade available for the account or passcode
|
||||||
*/
|
*/
|
||||||
public protocolUpgradeAvailable(): Promise<boolean> {
|
public protocolUpgradeAvailable(): Promise<boolean> {
|
||||||
return this.protocolService.upgradeAvailable()
|
return this.encryptionService.upgradeAvailable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -790,7 +790,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasAccount(): boolean {
|
public hasAccount(): boolean {
|
||||||
return this.protocolService.hasAccount()
|
return this.encryptionService.hasAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -840,7 +840,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createEncryptedBackupFileForAutomatedDesktopBackups(): Promise<BackupFile | undefined> {
|
public async createEncryptedBackupFileForAutomatedDesktopBackups(): Promise<BackupFile | undefined> {
|
||||||
return this.protocolService.createEncryptedBackupFile()
|
return this.encryptionService.createEncryptedBackupFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createEncryptedBackupFile(): Promise<BackupFile | undefined> {
|
public async createEncryptedBackupFile(): Promise<BackupFile | undefined> {
|
||||||
@@ -848,7 +848,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.protocolService.createEncryptedBackupFile()
|
return this.encryptionService.createEncryptedBackupFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createDecryptedBackupFile(): Promise<BackupFile | undefined> {
|
public async createDecryptedBackupFile(): Promise<BackupFile | undefined> {
|
||||||
@@ -856,7 +856,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.protocolService.createDecryptedBackupFile()
|
return this.encryptionService.createDecryptedBackupFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
public isEphemeralSession(): boolean {
|
public isEphemeralSession(): boolean {
|
||||||
@@ -1058,7 +1058,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.syncService,
|
this.syncService,
|
||||||
this.protectionService,
|
this.protectionService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.payloadManager,
|
this.payloadManager,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.historyManager,
|
this.historyManager,
|
||||||
@@ -1083,7 +1083,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async validateAccountPassword(password: string): Promise<boolean> {
|
public async validateAccountPassword(password: string): Promise<boolean> {
|
||||||
const { valid } = await this.protocolService.validateAccountPassword(password)
|
const { valid } = await this.encryptionService.validateAccountPassword(password)
|
||||||
return valid
|
return valid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1096,7 +1096,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasPasscode(): boolean {
|
public hasPasscode(): boolean {
|
||||||
return this.protocolService.hasPasscode()
|
return this.encryptionService.hasPasscode()
|
||||||
}
|
}
|
||||||
|
|
||||||
async isLocked(): Promise<boolean> {
|
async isLocked(): Promise<boolean> {
|
||||||
@@ -1253,7 +1253,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.createKeySystemKeyManager()
|
this.createKeySystemKeyManager()
|
||||||
this.createProtocolService()
|
this.createProtocolService()
|
||||||
|
|
||||||
this.diskStorageService.provideEncryptionProvider(this.protocolService)
|
this.diskStorageService.provideEncryptionProvider(this.encryptionService)
|
||||||
this.createChallengeService()
|
this.createChallengeService()
|
||||||
this.createLegacyHttpManager()
|
this.createLegacyHttpManager()
|
||||||
this.createHttpServiceAndApiService()
|
this.createHttpServiceAndApiService()
|
||||||
@@ -1308,7 +1308,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
;(this.deprecatedHttpService as unknown) = undefined
|
;(this.deprecatedHttpService as unknown) = undefined
|
||||||
;(this.httpService as unknown) = undefined
|
;(this.httpService as unknown) = undefined
|
||||||
;(this.payloadManager as unknown) = undefined
|
;(this.payloadManager as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.diskStorageService as unknown) = undefined
|
;(this.diskStorageService as unknown) = undefined
|
||||||
;(this.inMemoryStore as unknown) = undefined
|
;(this.inMemoryStore as unknown) = undefined
|
||||||
;(this.apiService as unknown) = undefined
|
;(this.apiService as unknown) = undefined
|
||||||
@@ -1392,7 +1392,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private createAsymmetricMessageService() {
|
private createAsymmetricMessageService() {
|
||||||
this.asymmetricMessageService = new ExternalServices.AsymmetricMessageService(
|
this.asymmetricMessageService = new ExternalServices.AsymmetricMessageService(
|
||||||
this.httpService,
|
this.httpService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.contacts,
|
this.contacts,
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
@@ -1410,7 +1410,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.sessionManager,
|
this.sessionManager,
|
||||||
this.options.crypto,
|
this.options.crypto,
|
||||||
this.user,
|
this.user,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.singletonManager,
|
this.singletonManager,
|
||||||
this.internalEventBus,
|
this.internalEventBus,
|
||||||
)
|
)
|
||||||
@@ -1424,7 +1424,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.syncService,
|
this.syncService,
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.sessions,
|
this.sessions,
|
||||||
this.contactService,
|
this.contactService,
|
||||||
this.files,
|
this.files,
|
||||||
@@ -1440,7 +1440,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.syncService,
|
this.syncService,
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.files,
|
this.files,
|
||||||
this.alertService,
|
this.alertService,
|
||||||
this.internalEventBus,
|
this.internalEventBus,
|
||||||
@@ -1468,7 +1468,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.apiService,
|
this.apiService,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
this.syncService,
|
this.syncService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.httpService,
|
this.httpService,
|
||||||
this.alertService,
|
this.alertService,
|
||||||
@@ -1542,7 +1542,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
|
|
||||||
private createMigrationService() {
|
private createMigrationService() {
|
||||||
this.migrationService = new InternalServices.SNMigrationService({
|
this.migrationService = new InternalServices.SNMigrationService({
|
||||||
protocolService: this.protocolService,
|
encryptionService: this.encryptionService,
|
||||||
deviceInterface: this.deviceInterface,
|
deviceInterface: this.deviceInterface,
|
||||||
storageService: this.diskStorageService,
|
storageService: this.diskStorageService,
|
||||||
sessionManager: this.sessionManager,
|
sessionManager: this.sessionManager,
|
||||||
@@ -1567,7 +1567,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.syncService,
|
this.syncService,
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.alertService,
|
this.alertService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.protectionService,
|
this.protectionService,
|
||||||
@@ -1720,7 +1720,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createProtocolService() {
|
private createProtocolService() {
|
||||||
this.protocolService = new EncryptionService(
|
this.encryptionService = new EncryptionService(
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
this.payloadManager,
|
this.payloadManager,
|
||||||
@@ -1732,13 +1732,13 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.internalEventBus,
|
this.internalEventBus,
|
||||||
)
|
)
|
||||||
this.serviceObservers.push(
|
this.serviceObservers.push(
|
||||||
this.protocolService.addEventObserver(async (event) => {
|
this.encryptionService.addEventObserver(async (event) => {
|
||||||
if (event === EncryptionServiceEvent.RootKeyStatusChanged) {
|
if (event === EncryptionServiceEvent.RootKeyStatusChanged) {
|
||||||
await this.notifyEvent(ApplicationEvent.KeyStatusChanged)
|
await this.notifyEvent(ApplicationEvent.KeyStatusChanged)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
this.services.push(this.protocolService)
|
this.services.push(this.encryptionService)
|
||||||
}
|
}
|
||||||
|
|
||||||
private createKeySystemKeyManager() {
|
private createKeySystemKeyManager() {
|
||||||
@@ -1757,7 +1757,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.payloadManager,
|
this.payloadManager,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.alertService,
|
this.alertService,
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
@@ -1774,7 +1774,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.apiService,
|
this.apiService,
|
||||||
this.userApiService,
|
this.userApiService,
|
||||||
this.alertService,
|
this.alertService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.webSocketsService,
|
this.webSocketsService,
|
||||||
this.httpService,
|
this.httpService,
|
||||||
@@ -1789,8 +1789,8 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
case ExternalServices.SessionEvent.Restored: {
|
case ExternalServices.SessionEvent.Restored: {
|
||||||
void (async () => {
|
void (async () => {
|
||||||
await this.sync.sync({ sourceDescription: 'Session restored pre key creation' })
|
await this.sync.sync({ sourceDescription: 'Session restored pre key creation' })
|
||||||
if (this.protocolService.needsNewRootKeyBasedItemsKey()) {
|
if (this.encryptionService.needsNewRootKeyBasedItemsKey()) {
|
||||||
void this.protocolService.createNewDefaultItemsKey().then(() => {
|
void this.encryptionService.createNewDefaultItemsKey().then(() => {
|
||||||
void this.sync.sync({ sourceDescription: 'Session restored post key creation' })
|
void this.sync.sync({ sourceDescription: 'Session restored post key creation' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1816,7 +1816,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.syncService = new InternalServices.SNSyncService(
|
this.syncService = new InternalServices.SNSyncService(
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.sessionManager,
|
this.sessionManager,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
this.payloadManager,
|
this.payloadManager,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
@@ -1832,7 +1832,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
const syncEventCallback = async (eventName: ExternalServices.SyncEvent) => {
|
const syncEventCallback = async (eventName: ExternalServices.SyncEvent) => {
|
||||||
const appEvent = applicationEventForSyncEvent(eventName)
|
const appEvent = applicationEventForSyncEvent(eventName)
|
||||||
if (appEvent) {
|
if (appEvent) {
|
||||||
await this.protocolService.onSyncEvent(eventName)
|
await this.encryptionService.onSyncEvent(eventName)
|
||||||
|
|
||||||
await this.notifyEvent(appEvent)
|
await this.notifyEvent(appEvent)
|
||||||
|
|
||||||
@@ -1852,7 +1852,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private createChallengeService() {
|
private createChallengeService() {
|
||||||
this.challengeService = new InternalServices.ChallengeService(
|
this.challengeService = new InternalServices.ChallengeService(
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.internalEventBus,
|
this.internalEventBus,
|
||||||
)
|
)
|
||||||
this.services.push(this.challengeService)
|
this.services.push(this.challengeService)
|
||||||
@@ -1860,7 +1860,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
|
|
||||||
private createProtectionService() {
|
private createProtectionService() {
|
||||||
this.protectionService = new InternalServices.SNProtectionService(
|
this.protectionService = new InternalServices.SNProtectionService(
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.mutator,
|
this.mutator,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.diskStorageService,
|
this.diskStorageService,
|
||||||
@@ -1895,7 +1895,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.deviceInterface,
|
this.deviceInterface,
|
||||||
this.deprecatedHttpService,
|
this.deprecatedHttpService,
|
||||||
this.payloadManager,
|
this.payloadManager,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.syncService,
|
this.syncService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.listedService,
|
this.listedService,
|
||||||
@@ -1953,7 +1953,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
this.filesBackupService = new FilesBackupService(
|
this.filesBackupService = new FilesBackupService(
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
device as FileBackupsDevice,
|
device as FileBackupsDevice,
|
||||||
this.statusService,
|
this.statusService,
|
||||||
this.options.crypto,
|
this.options.crypto,
|
||||||
@@ -2003,7 +2003,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
private createUseCases() {
|
private createUseCases() {
|
||||||
this._signInWithRecoveryCodes = new SignInWithRecoveryCodes(
|
this._signInWithRecoveryCodes = new SignInWithRecoveryCodes(
|
||||||
this.authManager,
|
this.authManager,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.inMemoryStore,
|
this.inMemoryStore,
|
||||||
this.options.crypto,
|
this.options.crypto,
|
||||||
this.sessionManager,
|
this.sessionManager,
|
||||||
@@ -2030,7 +2030,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
|
|
||||||
this._listRevisions = new ListRevisions(this.revisionManager)
|
this._listRevisions = new ListRevisions(this.revisionManager)
|
||||||
|
|
||||||
this._getRevision = new GetRevision(this.revisionManager, this.protocolService)
|
this._getRevision = new GetRevision(this.revisionManager, this.encryptionService)
|
||||||
|
|
||||||
this._deleteRevision = new DeleteRevision(this.revisionManager)
|
this._deleteRevision = new DeleteRevision(this.revisionManager)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import { GetRevision } from './GetRevision'
|
|||||||
|
|
||||||
describe('GetRevision', () => {
|
describe('GetRevision', () => {
|
||||||
let revisionManager: RevisionClientInterface
|
let revisionManager: RevisionClientInterface
|
||||||
let protocolService: EncryptionProviderInterface
|
let encryptionService: EncryptionProviderInterface
|
||||||
|
|
||||||
const createUseCase = () => new GetRevision(revisionManager, protocolService)
|
const createUseCase = () => new GetRevision(revisionManager, encryptionService)
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
revisionManager = {} as jest.Mocked<RevisionClientInterface>
|
revisionManager = {} as jest.Mocked<RevisionClientInterface>
|
||||||
@@ -35,13 +35,13 @@ describe('GetRevision', () => {
|
|||||||
updated_at: '2021-01-01T00:00:00.000Z'
|
updated_at: '2021-01-01T00:00:00.000Z'
|
||||||
} as jest.Mocked<Revision>)
|
} as jest.Mocked<Revision>)
|
||||||
|
|
||||||
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
|
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
|
||||||
protocolService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
|
encryptionService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
|
||||||
const encryptedPayload = {
|
const encryptedPayload = {
|
||||||
content: 'foobar',
|
content: 'foobar',
|
||||||
} as jest.Mocked<EncryptedPayloadInterface>
|
} as jest.Mocked<EncryptedPayloadInterface>
|
||||||
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
|
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
|
||||||
protocolService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
|
encryptionService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
|
||||||
|
|
||||||
isRemotePayloadAllowed.mockImplementation(() => true)
|
isRemotePayloadAllowed.mockImplementation(() => true)
|
||||||
})
|
})
|
||||||
@@ -59,7 +59,7 @@ describe('GetRevision', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('it should get a revision without uuid from embedded params', async () => {
|
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()
|
const useCase = createUseCase()
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ describe('GetRevision', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('it should get a revision without embedded params', async () => {
|
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()
|
const useCase = createUseCase()
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ describe('GetRevision', () => {
|
|||||||
errorDecrypting: true,
|
errorDecrypting: true,
|
||||||
} as jest.Mocked<EncryptedPayloadInterface>
|
} as jest.Mocked<EncryptedPayloadInterface>
|
||||||
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
|
encryptedPayload.copy = jest.fn().mockReturnValue(encryptedPayload)
|
||||||
protocolService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
|
encryptionService.decryptSplitSingle = jest.fn().mockReturnValue(encryptedPayload)
|
||||||
|
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
|||||||
import { GetRevisionDTO } from './GetRevisionDTO'
|
import { GetRevisionDTO } from './GetRevisionDTO'
|
||||||
|
|
||||||
export class GetRevision implements UseCaseInterface<HistoryEntry> {
|
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>> {
|
async execute(dto: GetRevisionDTO): Promise<Result<HistoryEntry>> {
|
||||||
const itemUuidOrError = Uuid.create(dto.itemUuid)
|
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
|
* these olders revisions (which have not been mutated after copy) with the source item's
|
||||||
* uuid.
|
* uuid.
|
||||||
*/
|
*/
|
||||||
const embeddedParams = this.protocolService.getEmbeddedPayloadAuthenticatedData(serverPayload)
|
const embeddedParams = this.encryptionService.getEmbeddedPayloadAuthenticatedData(serverPayload)
|
||||||
const sourceItemUuid = embeddedParams?.u as string | undefined
|
const sourceItemUuid = embeddedParams?.u as string | undefined
|
||||||
|
|
||||||
const payload = serverPayload.copy({
|
const payload = serverPayload.copy({
|
||||||
@@ -76,7 +79,7 @@ export class GetRevision implements UseCaseInterface<HistoryEntry> {
|
|||||||
|
|
||||||
const encryptedPayload = new EncryptedPayload(payload)
|
const encryptedPayload = new EncryptedPayload(payload)
|
||||||
|
|
||||||
const decryptedPayload = await this.protocolService.decryptSplitSingle<NoteContent>({
|
const decryptedPayload = await this.encryptionService.decryptSplitSingle<NoteContent>({
|
||||||
usesItemsKeyWithKeyLookup: { items: [encryptedPayload] },
|
usesItemsKeyWithKeyLookup: { items: [encryptedPayload] },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { SignInWithRecoveryCodes } from './SignInWithRecoveryCodes'
|
|||||||
|
|
||||||
describe('SignInWithRecoveryCodes', () => {
|
describe('SignInWithRecoveryCodes', () => {
|
||||||
let authManager: AuthClientInterface
|
let authManager: AuthClientInterface
|
||||||
let protocolService: EncryptionProviderInterface
|
let encryptionService: EncryptionProviderInterface
|
||||||
let inMemoryStore: KeyValueStoreInterface<string>
|
let inMemoryStore: KeyValueStoreInterface<string>
|
||||||
let crypto: PureCryptoInterface
|
let crypto: PureCryptoInterface
|
||||||
let sessionManager: SessionsClientInterface
|
let sessionManager: SessionsClientInterface
|
||||||
@@ -22,7 +22,7 @@ describe('SignInWithRecoveryCodes', () => {
|
|||||||
|
|
||||||
const createUseCase = () => new SignInWithRecoveryCodes(
|
const createUseCase = () => new SignInWithRecoveryCodes(
|
||||||
authManager,
|
authManager,
|
||||||
protocolService,
|
encryptionService,
|
||||||
inMemoryStore,
|
inMemoryStore,
|
||||||
crypto,
|
crypto,
|
||||||
sessionManager,
|
sessionManager,
|
||||||
@@ -50,17 +50,17 @@ describe('SignInWithRecoveryCodes', () => {
|
|||||||
})
|
})
|
||||||
rootKey.payload = payload
|
rootKey.payload = payload
|
||||||
|
|
||||||
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
|
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
|
||||||
protocolService.hasAccount = jest.fn()
|
encryptionService.hasAccount = jest.fn()
|
||||||
protocolService.computeRootKey = jest.fn().mockReturnValue(rootKey)
|
encryptionService.computeRootKey = jest.fn().mockReturnValue(rootKey)
|
||||||
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(true)
|
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(true)
|
||||||
protocolService.supportedVersions = jest.fn().mockReturnValue([
|
encryptionService.supportedVersions = jest.fn().mockReturnValue([
|
||||||
'001',
|
'001',
|
||||||
'002',
|
'002',
|
||||||
'003',
|
'003',
|
||||||
'004',
|
'004',
|
||||||
])
|
])
|
||||||
protocolService.isVersionNewerThanLibraryVersion = jest.fn()
|
encryptionService.isVersionNewerThanLibraryVersion = jest.fn()
|
||||||
|
|
||||||
inMemoryStore = {} as jest.Mocked<KeyValueStoreInterface<string>>
|
inMemoryStore = {} as jest.Mocked<KeyValueStoreInterface<string>>
|
||||||
inMemoryStore.setValue = jest.fn()
|
inMemoryStore.setValue = jest.fn()
|
||||||
@@ -79,7 +79,7 @@ describe('SignInWithRecoveryCodes', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should fail if an account already exists', async () => {
|
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 useCase = createUseCase()
|
||||||
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
|
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 () => {
|
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 useCase = createUseCase()
|
||||||
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
|
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 () => {
|
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({
|
authManager.recoveryKeyParams = jest.fn().mockReturnValue({
|
||||||
identifier: 'test@test.te',
|
identifier: 'test@test.te',
|
||||||
@@ -120,7 +120,7 @@ describe('SignInWithRecoveryCodes', () => {
|
|||||||
version: '006',
|
version: '006',
|
||||||
})
|
})
|
||||||
|
|
||||||
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
||||||
|
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
|
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 () => {
|
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({
|
authManager.recoveryKeyParams = jest.fn().mockReturnValue({
|
||||||
identifier: 'test@test.te',
|
identifier: 'test@test.te',
|
||||||
@@ -141,7 +141,7 @@ describe('SignInWithRecoveryCodes', () => {
|
|||||||
version: '006',
|
version: '006',
|
||||||
})
|
})
|
||||||
|
|
||||||
protocolService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
||||||
|
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
|
const result = await useCase.execute({ recoveryCodes: 'recovery-codes', password: 'foobar', username: 'test@test.te' })
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { SignInWithRecoveryCodesDTO } from './SignInWithRecoveryCodesDTO'
|
|||||||
export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
|
export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
|
||||||
constructor(
|
constructor(
|
||||||
private authManager: AuthClientInterface,
|
private authManager: AuthClientInterface,
|
||||||
private protocolService: EncryptionProviderInterface,
|
private encryptionService: EncryptionProviderInterface,
|
||||||
private inMemoryStore: KeyValueStoreInterface<string>,
|
private inMemoryStore: KeyValueStoreInterface<string>,
|
||||||
private crypto: PureCryptoInterface,
|
private crypto: PureCryptoInterface,
|
||||||
private sessionManager: SessionsClientInterface,
|
private sessionManager: SessionsClientInterface,
|
||||||
@@ -28,7 +28,7 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<void> {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(dto: SignInWithRecoveryCodesDTO): Promise<Result<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.')
|
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)
|
const rootKeyParams = CreateAnyKeyParams(recoveryKeyParams)
|
||||||
|
|
||||||
if (!this.protocolService.supportedVersions().includes(rootKeyParams.version)) {
|
if (!this.encryptionService.supportedVersions().includes(rootKeyParams.version)) {
|
||||||
if (this.protocolService.isVersionNewerThanLibraryVersion(rootKeyParams.version)) {
|
if (this.encryptionService.isVersionNewerThanLibraryVersion(rootKeyParams.version)) {
|
||||||
return Result.fail(UNSUPPORTED_PROTOCOL_VERSION)
|
return Result.fail(UNSUPPORTED_PROTOCOL_VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.fail(EXPIRED_PROTOCOL_VERSION)
|
return Result.fail(EXPIRED_PROTOCOL_VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.protocolService.platformSupportsKeyDerivation(rootKeyParams)) {
|
if (!this.encryptionService.platformSupportsKeyDerivation(rootKeyParams)) {
|
||||||
return Result.fail(UNSUPPORTED_KEY_DERIVATION)
|
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({
|
const signInResult = await this.authManager.signInWithRecoveryCodes({
|
||||||
codeVerifier,
|
codeVerifier,
|
||||||
|
|||||||
@@ -207,13 +207,13 @@ export class BaseMigration extends Migration {
|
|||||||
this.services.challengeService.addChallengeObserver(challenge, {
|
this.services.challengeService.addChallengeObserver(challenge, {
|
||||||
onNonvalidatedSubmit: async (challengeResponse) => {
|
onNonvalidatedSubmit: async (challengeResponse) => {
|
||||||
const password = challengeResponse.values[0].value as string
|
const password = challengeResponse.values[0].value as string
|
||||||
const accountParams = this.services.protocolService.createKeyParams(rawAccountParams)
|
const accountParams = this.services.encryptionService.createKeyParams(rawAccountParams)
|
||||||
const rootKey = await this.services.protocolService.computeRootKey(password, accountParams)
|
const rootKey = await this.services.encryptionService.computeRootKey(password, accountParams)
|
||||||
|
|
||||||
/** TS can't detect we returned early above if itemToDecrypt is null */
|
/** TS can't detect we returned early above if itemToDecrypt is null */
|
||||||
assert(itemToDecrypt)
|
assert(itemToDecrypt)
|
||||||
|
|
||||||
const decryptedPayload = await this.services.protocolService.decryptSplitSingle({
|
const decryptedPayload = await this.services.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [itemToDecrypt],
|
items: [itemToDecrypt],
|
||||||
key: rootKey,
|
key: rootKey,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { ChallengeService, SNSingletonManager, SNFeaturesService, DiskStorageSer
|
|||||||
import { LegacySession, MapperInterface } from '@standardnotes/domain-core'
|
import { LegacySession, MapperInterface } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
export type MigrationServices = {
|
export type MigrationServices = {
|
||||||
protocolService: EncryptionService
|
encryptionService: EncryptionService
|
||||||
deviceInterface: DeviceInterface
|
deviceInterface: DeviceInterface
|
||||||
storageService: DiskStorageService
|
storageService: DiskStorageService
|
||||||
challengeService: ChallengeService
|
challengeService: ChallengeService
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export class Migration2_0_15 extends Migration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async createNewDefaultItemsKeyIfNecessary() {
|
private async createNewDefaultItemsKeyIfNecessary() {
|
||||||
if (this.services.protocolService.needsNewRootKeyBasedItemsKey()) {
|
if (this.services.encryptionService.needsNewRootKeyBasedItemsKey()) {
|
||||||
await this.services.protocolService.createNewDefaultItemsKey()
|
await this.services.encryptionService.createNewDefaultItemsKey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
public deviceInterface: DeviceInterface,
|
public deviceInterface: DeviceInterface,
|
||||||
private httpService: DeprecatedHttpService,
|
private httpService: DeprecatedHttpService,
|
||||||
private payloadManager: PayloadManager,
|
private payloadManager: PayloadManager,
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
private syncService: SNSyncService,
|
private syncService: SNSyncService,
|
||||||
private challengeService: ChallengeService,
|
private challengeService: ChallengeService,
|
||||||
private listedService: ListedService,
|
private listedService: ListedService,
|
||||||
@@ -81,7 +81,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
;(this.payloadManager as unknown) = undefined
|
;(this.payloadManager as unknown) = undefined
|
||||||
;(this.listedService as unknown) = undefined
|
;(this.listedService as unknown) = undefined
|
||||||
;(this.challengeService as unknown) = undefined
|
;(this.challengeService as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.syncService as unknown) = undefined
|
;(this.syncService as unknown) = undefined
|
||||||
this.payloadRequestHandlers.length = 0
|
this.payloadRequestHandlers.length = 0
|
||||||
this.previousPasswords.length = 0
|
this.previousPasswords.length = 0
|
||||||
@@ -207,7 +207,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let decryptedPayload = await this.protocolService.decryptSplitSingle<ActionExtensionContent>({
|
let decryptedPayload = await this.encryptionService.decryptSplitSingle<ActionExtensionContent>({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -218,7 +218,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rootKey) {
|
if (rootKey) {
|
||||||
decryptedPayload = await this.protocolService.decryptSplitSingle({
|
decryptedPayload = await this.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
key: rootKey,
|
key: rootKey,
|
||||||
@@ -230,7 +230,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const itemsKey of this.itemManager.getDisplayableItemsKeys()) {
|
for (const itemsKey of this.itemManager.getDisplayableItemsKeys()) {
|
||||||
const decryptedPayload = await this.protocolService.decryptSplitSingle<ActionExtensionContent>({
|
const decryptedPayload = await this.encryptionService.decryptSplitSingle<ActionExtensionContent>({
|
||||||
usesItemsKey: {
|
usesItemsKey: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
key: itemsKey,
|
key: itemsKey,
|
||||||
@@ -256,7 +256,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
)
|
)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const keyParams = this.protocolService.createKeyParams(keyParamsData)
|
const keyParams = this.encryptionService.createKeyParams(keyParamsData)
|
||||||
|
|
||||||
/* Try previous passwords */
|
/* Try previous passwords */
|
||||||
for (const passwordCandidate of this.previousPasswords) {
|
for (const passwordCandidate of this.previousPasswords) {
|
||||||
@@ -266,7 +266,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
|
|
||||||
triedPasswords.push(passwordCandidate)
|
triedPasswords.push(passwordCandidate)
|
||||||
|
|
||||||
const key = await this.protocolService.computeRootKey(passwordCandidate, keyParams)
|
const key = await this.encryptionService.computeRootKey(passwordCandidate, keyParams)
|
||||||
if (!key) {
|
if (!key) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -341,7 +341,7 @@ export class SNActionsService extends AbstractService {
|
|||||||
return item.payload.ejected()
|
return item.payload.ejected()
|
||||||
}
|
}
|
||||||
|
|
||||||
const encrypted = await this.protocolService.encryptSplitSingle({
|
const encrypted = await this.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: { items: [item.payload] },
|
usesItemsKeyWithKeyLookup: { items: [item.payload] },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private storageService: DiskStorageService,
|
private storageService: DiskStorageService,
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
protected override internalEventBus: InternalEventBusInterface,
|
protected override internalEventBus: InternalEventBusInterface,
|
||||||
) {
|
) {
|
||||||
super(internalEventBus)
|
super(internalEventBus)
|
||||||
@@ -52,7 +52,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
|
|
||||||
public override deinit() {
|
public override deinit() {
|
||||||
;(this.storageService as unknown) = undefined
|
;(this.storageService as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.sendChallenge as unknown) = undefined
|
;(this.sendChallenge as unknown) = undefined
|
||||||
;(this.challengeOperations as unknown) = undefined
|
;(this.challengeOperations as unknown) = undefined
|
||||||
;(this.challengeObservers as unknown) = undefined
|
;(this.challengeObservers as unknown) = undefined
|
||||||
@@ -79,9 +79,9 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
public async validateChallengeValue(value: ChallengeValue): Promise<ChallengeValidationResponse> {
|
public async validateChallengeValue(value: ChallengeValue): Promise<ChallengeValidationResponse> {
|
||||||
switch (value.prompt.validation) {
|
switch (value.prompt.validation) {
|
||||||
case ChallengeValidation.LocalPasscode:
|
case ChallengeValidation.LocalPasscode:
|
||||||
return this.protocolService.validatePasscode(value.value as string)
|
return this.encryptionService.validatePasscode(value.value as string)
|
||||||
case ChallengeValidation.AccountPassword:
|
case ChallengeValidation.AccountPassword:
|
||||||
return this.protocolService.validateAccountPassword(value.value as string)
|
return this.encryptionService.validateAccountPassword(value.value as string)
|
||||||
case ChallengeValidation.Biometric:
|
case ChallengeValidation.Biometric:
|
||||||
return { valid: value.value === true }
|
return { valid: value.value === true }
|
||||||
case ChallengeValidation.Authenticator:
|
case ChallengeValidation.Authenticator:
|
||||||
@@ -104,7 +104,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
async promptForAccountPassword(): Promise<string | null> {
|
async promptForAccountPassword(): Promise<string | null> {
|
||||||
if (!this.protocolService.hasAccount()) {
|
if (!this.encryptionService.hasAccount()) {
|
||||||
throw Error('Requiring account password for challenge with no account')
|
throw Error('Requiring account password for challenge with no account')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
canceled?: undefined
|
canceled?: undefined
|
||||||
}
|
}
|
||||||
> {
|
> {
|
||||||
if (!this.protocolService.hasPasscode()) {
|
if (!this.encryptionService.hasPasscode()) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,12 +154,12 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrappingKey = await this.protocolService.computeWrappingKey(passcode)
|
const wrappingKey = await this.encryptionService.computeWrappingKey(passcode)
|
||||||
return { wrappingKey }
|
return { wrappingKey }
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPasscodeLocked() {
|
public isPasscodeLocked() {
|
||||||
return this.protocolService.isPasscodeLocked()
|
return this.encryptionService.isPasscodeLocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
public addChallengeObserver(challenge: Challenge, observer: ChallengeObserver): () => void {
|
public addChallengeObserver(challenge: Challenge, observer: ChallengeObserver): () => void {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class KeyRecoveryOperation {
|
|||||||
constructor(
|
constructor(
|
||||||
private queueItem: DecryptionQueueItem,
|
private queueItem: DecryptionQueueItem,
|
||||||
private itemManager: ItemManager,
|
private itemManager: ItemManager,
|
||||||
private protocolService: EncryptionProviderInterface,
|
private encryptionService: EncryptionProviderInterface,
|
||||||
private challengeService: ChallengeServiceInterface,
|
private challengeService: ChallengeServiceInterface,
|
||||||
private clientParams: SNRootKeyParams | undefined,
|
private clientParams: SNRootKeyParams | undefined,
|
||||||
private serverParams: SNRootKeyParams | undefined,
|
private serverParams: SNRootKeyParams | undefined,
|
||||||
@@ -43,7 +43,7 @@ export class KeyRecoveryOperation {
|
|||||||
|
|
||||||
const decryptionResult = await DecryptItemsKeyByPromptingUser(
|
const decryptionResult = await DecryptItemsKeyByPromptingUser(
|
||||||
this.queueItem.encryptedKey,
|
this.queueItem.encryptedKey,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
this.queueItem.keyParams,
|
this.queueItem.keyParams,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
private itemManager: ItemManager,
|
private itemManager: ItemManager,
|
||||||
private payloadManager: PayloadManager,
|
private payloadManager: PayloadManager,
|
||||||
private apiService: SNApiService,
|
private apiService: SNApiService,
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
private challengeService: ChallengeService,
|
private challengeService: ChallengeService,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private storageService: DiskStorageService,
|
private storageService: DiskStorageService,
|
||||||
@@ -121,7 +121,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
;(this.itemManager as unknown) = undefined
|
;(this.itemManager as unknown) = undefined
|
||||||
;(this.payloadManager as unknown) = undefined
|
;(this.payloadManager as unknown) = undefined
|
||||||
;(this.apiService as unknown) = undefined
|
;(this.apiService as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.challengeService as unknown) = undefined
|
;(this.challengeService as unknown) = undefined
|
||||||
;(this.alertService as unknown) = undefined
|
;(this.alertService as unknown) = undefined
|
||||||
;(this.storageService as unknown) = undefined
|
;(this.storageService as unknown) = undefined
|
||||||
@@ -251,7 +251,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getClientKeyParams() {
|
private getClientKeyParams() {
|
||||||
return this.protocolService.getAccountKeyParams()
|
return this.encryptionService.getAccountKeyParams()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async performServerSignIn(): Promise<SNRootKey | undefined> {
|
private async performServerSignIn(): Promise<SNRootKey | undefined> {
|
||||||
@@ -279,7 +279,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootKey = await this.protocolService.computeRootKey(password, serverParams)
|
const rootKey = await this.encryptionService.computeRootKey(password, serverParams)
|
||||||
|
|
||||||
const signInResponse = await this.userService.correctiveSignIn(rootKey)
|
const signInResponse = await this.userService.correctiveSignIn(rootKey)
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getWrappingKeyIfApplicable(): Promise<SNRootKey | undefined> {
|
private async getWrappingKeyIfApplicable(): Promise<SNRootKey | undefined> {
|
||||||
if (!this.protocolService.hasPasscode()) {
|
if (!this.encryptionService.hasPasscode()) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const { wrappingKey, canceled } = await this.challengeService.getWrappingKeyIfApplicable()
|
const { wrappingKey, canceled } = await this.challengeService.getWrappingKeyIfApplicable()
|
||||||
@@ -312,7 +312,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
|
|
||||||
private addKeysToQueue(keys: EncryptedPayloadInterface[]) {
|
private addKeysToQueue(keys: EncryptedPayloadInterface[]) {
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const keyParams = this.protocolService.getKeyEmbeddedKeyParamsFromItemsKey(key)
|
const keyParams = this.encryptionService.getKeyEmbeddedKeyParamsFromItemsKey(key)
|
||||||
if (!keyParams) {
|
if (!keyParams) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -356,12 +356,12 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
serverParams = await this.getLatestKeyParamsFromServer(clientParams.identifier)
|
serverParams = await this.getLatestKeyParamsFromServer(clientParams.identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deallocedAfterNetworkRequest = this.protocolService == undefined
|
const deallocedAfterNetworkRequest = this.encryptionService == undefined
|
||||||
if (deallocedAfterNetworkRequest) {
|
if (deallocedAfterNetworkRequest) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentialsMissing = !this.protocolService.hasAccount() && !this.protocolService.hasPasscode()
|
const credentialsMissing = !this.encryptionService.hasAccount() && !this.encryptionService.hasPasscode()
|
||||||
|
|
||||||
if (credentialsMissing) {
|
if (credentialsMissing) {
|
||||||
const rootKey = await this.performServerSignIn()
|
const rootKey = await this.performServerSignIn()
|
||||||
@@ -426,7 +426,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
const operation = new KeyRecoveryOperation(
|
const operation = new KeyRecoveryOperation(
|
||||||
queueItem,
|
queueItem,
|
||||||
this.itemManager,
|
this.itemManager,
|
||||||
this.protocolService,
|
this.encryptionService,
|
||||||
this.challengeService,
|
this.challengeService,
|
||||||
clientParams,
|
clientParams,
|
||||||
serverParams,
|
serverParams,
|
||||||
@@ -460,7 +460,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
if (replacesRootKey) {
|
if (replacesRootKey) {
|
||||||
const wrappingKey = await this.getWrappingKeyIfApplicable()
|
const wrappingKey = await this.getWrappingKeyIfApplicable()
|
||||||
|
|
||||||
await this.protocolService.setRootKey(rootKey, wrappingKey)
|
await this.encryptionService.setRootKey(rootKey, wrappingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientKeyParams = this.getClientKeyParams()
|
const clientKeyParams = this.getClientKeyParams()
|
||||||
@@ -475,7 +475,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
|||||||
: qItem.encryptedKey
|
: qItem.encryptedKey
|
||||||
})
|
})
|
||||||
|
|
||||||
const matchingResults = await this.protocolService.decryptSplit({
|
const matchingResults = await this.encryptionService.decryptSplit({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: matchingKeys,
|
items: matchingKeys,
|
||||||
key: rootKey,
|
key: rootKey,
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ const setupRandomUuid = () => {
|
|||||||
|
|
||||||
describe('protectionService', () => {
|
describe('protectionService', () => {
|
||||||
let mutator: MutatorClientInterface
|
let mutator: MutatorClientInterface
|
||||||
let protocolService: EncryptionService
|
let encryptionService: EncryptionService
|
||||||
let challengeService: ChallengeService
|
let challengeService: ChallengeService
|
||||||
let storageService: DiskStorageService
|
let storageService: DiskStorageService
|
||||||
let internalEventBus: InternalEventBusInterface
|
let internalEventBus: InternalEventBusInterface
|
||||||
let protectionService: SNProtectionService
|
let protectionService: SNProtectionService
|
||||||
|
|
||||||
const createService = () => {
|
const createService = () => {
|
||||||
return new SNProtectionService(protocolService, mutator, challengeService, storageService, internalEventBus)
|
return new SNProtectionService(encryptionService, mutator, challengeService, storageService, internalEventBus)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createFile = (name: string, isProtected?: boolean) => {
|
const createFile = (name: string, isProtected?: boolean) => {
|
||||||
@@ -59,9 +59,9 @@ describe('protectionService', () => {
|
|||||||
storageService = {} as jest.Mocked<DiskStorageService>
|
storageService = {} as jest.Mocked<DiskStorageService>
|
||||||
storageService.getValue = jest.fn()
|
storageService.getValue = jest.fn()
|
||||||
|
|
||||||
protocolService = {} as jest.Mocked<EncryptionService>
|
encryptionService = {} as jest.Mocked<EncryptionService>
|
||||||
protocolService.hasAccount = jest.fn().mockReturnValue(true)
|
encryptionService.hasAccount = jest.fn().mockReturnValue(true)
|
||||||
protocolService.hasPasscode = jest.fn().mockReturnValue(false)
|
encryptionService.hasPasscode = jest.fn().mockReturnValue(false)
|
||||||
|
|
||||||
mutator = {} as jest.Mocked<MutatorClientInterface>
|
mutator = {} as jest.Mocked<MutatorClientInterface>
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
private mobileBiometricsTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
|
private mobileBiometricsTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
private mutator: MutatorClientInterface,
|
private mutator: MutatorClientInterface,
|
||||||
private challengeService: ChallengeService,
|
private challengeService: ChallengeService,
|
||||||
private storageService: DiskStorageService,
|
private storageService: DiskStorageService,
|
||||||
@@ -87,7 +87,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
|
|
||||||
public override deinit(): void {
|
public override deinit(): void {
|
||||||
clearTimeout(this.sessionExpiryTimeout)
|
clearTimeout(this.sessionExpiryTimeout)
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.challengeService as unknown) = undefined
|
;(this.challengeService as unknown) = undefined
|
||||||
;(this.storageService as unknown) = undefined
|
;(this.storageService as unknown) = undefined
|
||||||
super.deinit()
|
super.deinit()
|
||||||
@@ -103,7 +103,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasProtectionSources(): boolean {
|
public hasProtectionSources(): boolean {
|
||||||
return this.protocolService.hasAccount() || this.protocolService.hasPasscode() || this.hasBiometricsEnabled()
|
return this.encryptionService.hasAccount() || this.encryptionService.hasPasscode() || this.hasBiometricsEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasUnprotectedAccessSession(): boolean {
|
public hasUnprotectedAccessSession(): boolean {
|
||||||
@@ -148,7 +148,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
if (this.hasBiometricsEnabled()) {
|
if (this.hasBiometricsEnabled()) {
|
||||||
prompts.push(new ChallengePrompt(ChallengeValidation.Biometric))
|
prompts.push(new ChallengePrompt(ChallengeValidation.Biometric))
|
||||||
}
|
}
|
||||||
if (this.protocolService.hasPasscode()) {
|
if (this.encryptionService.hasPasscode()) {
|
||||||
prompts.push(new ChallengePrompt(ChallengeValidation.LocalPasscode))
|
prompts.push(new ChallengePrompt(ChallengeValidation.LocalPasscode))
|
||||||
}
|
}
|
||||||
if (prompts.length > 0) {
|
if (prompts.length > 0) {
|
||||||
@@ -354,19 +354,19 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
|||||||
prompts.push(new ChallengePrompt(ChallengeValidation.Biometric))
|
prompts.push(new ChallengePrompt(ChallengeValidation.Biometric))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.protocolService.hasPasscode()) {
|
if (this.encryptionService.hasPasscode()) {
|
||||||
prompts.push(new ChallengePrompt(ChallengeValidation.LocalPasscode))
|
prompts.push(new ChallengePrompt(ChallengeValidation.LocalPasscode))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requireAccountPassword) {
|
if (requireAccountPassword) {
|
||||||
if (!this.protocolService.hasAccount()) {
|
if (!this.encryptionService.hasAccount()) {
|
||||||
throw Error('Requiring account password for challenge with no account')
|
throw Error('Requiring account password for challenge with no account')
|
||||||
}
|
}
|
||||||
prompts.push(new ChallengePrompt(ChallengeValidation.AccountPassword))
|
prompts.push(new ChallengePrompt(ChallengeValidation.AccountPassword))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prompts.length === 0) {
|
if (prompts.length === 0) {
|
||||||
if (fallBackToAccountPassword && this.protocolService.hasAccount()) {
|
if (fallBackToAccountPassword && this.encryptionService.hasAccount()) {
|
||||||
prompts.push(new ChallengePrompt(ChallengeValidation.AccountPassword))
|
prompts.push(new ChallengePrompt(ChallengeValidation.AccountPassword))
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export class SNSessionManager
|
|||||||
private apiService: SNApiService,
|
private apiService: SNApiService,
|
||||||
private userApiService: UserApiServiceInterface,
|
private userApiService: UserApiServiceInterface,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
private challengeService: ChallengeService,
|
private challengeService: ChallengeService,
|
||||||
private webSocketsService: SNWebSocketsService,
|
private webSocketsService: SNWebSocketsService,
|
||||||
private httpService: HttpServiceInterface,
|
private httpService: HttpServiceInterface,
|
||||||
@@ -119,7 +119,7 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
override deinit(): void {
|
override deinit(): void {
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.diskStorageService as unknown) = undefined
|
;(this.diskStorageService as unknown) = undefined
|
||||||
;(this.apiService as unknown) = undefined
|
;(this.apiService as unknown) = undefined
|
||||||
;(this.alertService as unknown) = undefined
|
;(this.alertService as unknown) = undefined
|
||||||
@@ -205,11 +205,11 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getPublicKey(): string {
|
public getPublicKey(): string {
|
||||||
return this.protocolService.getKeyPair().publicKey
|
return this.encryptionService.getKeyPair().publicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSigningPublicKey(): string {
|
public getSigningPublicKey(): string {
|
||||||
return this.protocolService.getSigningKeyPair().publicKey
|
return this.encryptionService.getSigningKeyPair().publicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
public get userUuid(): string {
|
public get userUuid(): string {
|
||||||
@@ -285,7 +285,7 @@ export class SNSessionManager
|
|||||||
onNonvalidatedSubmit: async (challengeResponse) => {
|
onNonvalidatedSubmit: async (challengeResponse) => {
|
||||||
const email = challengeResponse.values[0].value as string
|
const email = challengeResponse.values[0].value as string
|
||||||
const password = challengeResponse.values[1].value as string
|
const password = challengeResponse.values[1].value as string
|
||||||
const currentKeyParams = this.protocolService.getAccountKeyParams()
|
const currentKeyParams = this.encryptionService.getAccountKeyParams()
|
||||||
const { response } = await this.signIn(
|
const { response } = await this.signIn(
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
@@ -403,7 +403,7 @@ export class SNSessionManager
|
|||||||
|
|
||||||
email = cleanedEmailString(email)
|
email = cleanedEmailString(email)
|
||||||
|
|
||||||
const rootKey = await this.protocolService.createRootKey<RootKeyWithKeyPairsInterface>(
|
const rootKey = await this.encryptionService.createRootKey<RootKeyWithKeyPairsInterface>(
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
Common.KeyParamsOrigination.Registration,
|
Common.KeyParamsOrigination.Registration,
|
||||||
@@ -525,8 +525,8 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const keyParams = paramsResult.keyParams as SNRootKeyParams
|
const keyParams = paramsResult.keyParams as SNRootKeyParams
|
||||||
if (!this.protocolService.supportedVersions().includes(keyParams.version)) {
|
if (!this.encryptionService.supportedVersions().includes(keyParams.version)) {
|
||||||
if (this.protocolService.isVersionNewerThanLibraryVersion(keyParams.version)) {
|
if (this.encryptionService.isVersionNewerThanLibraryVersion(keyParams.version)) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(UNSUPPORTED_PROTOCOL_VERSION),
|
response: this.apiService.createErrorResponse(UNSUPPORTED_PROTOCOL_VERSION),
|
||||||
}
|
}
|
||||||
@@ -539,7 +539,7 @@ export class SNSessionManager
|
|||||||
|
|
||||||
if (Common.isProtocolVersionExpired(keyParams.version)) {
|
if (Common.isProtocolVersionExpired(keyParams.version)) {
|
||||||
/* Cost minimums only apply to now outdated versions (001 and 002) */
|
/* Cost minimums only apply to now outdated versions (001 and 002) */
|
||||||
const minimum = this.protocolService.costMinimumForVersion(keyParams.version)
|
const minimum = this.encryptionService.costMinimumForVersion(keyParams.version)
|
||||||
if (keyParams.content002.pw_cost < minimum) {
|
if (keyParams.content002.pw_cost < minimum) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(INVALID_PASSWORD_COST),
|
response: this.apiService.createErrorResponse(INVALID_PASSWORD_COST),
|
||||||
@@ -560,14 +560,14 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.protocolService.platformSupportsKeyDerivation(keyParams)) {
|
if (!this.encryptionService.platformSupportsKeyDerivation(keyParams)) {
|
||||||
return {
|
return {
|
||||||
response: this.apiService.createErrorResponse(UNSUPPORTED_KEY_DERIVATION),
|
response: this.apiService.createErrorResponse(UNSUPPORTED_KEY_DERIVATION),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strict) {
|
if (strict) {
|
||||||
minAllowedVersion = this.protocolService.getLatestVersion()
|
minAllowedVersion = this.encryptionService.getLatestVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minAllowedVersion != undefined) {
|
if (minAllowedVersion != undefined) {
|
||||||
@@ -577,7 +577,7 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const rootKey = await this.protocolService.computeRootKey(password, keyParams)
|
const rootKey = await this.encryptionService.computeRootKey(password, keyParams)
|
||||||
const signInResponse = await this.bypassChecksAndSignInWithRootKey(email, rootKey, ephemeral)
|
const signInResponse = await this.bypassChecksAndSignInWithRootKey(email, rootKey, ephemeral)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -641,8 +641,8 @@ export class SNSessionManager
|
|||||||
let oldSigningKeyPair: PkcKeyPair | undefined
|
let oldSigningKeyPair: PkcKeyPair | undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
oldKeyPair = this.protocolService.getKeyPair()
|
oldKeyPair = this.encryptionService.getKeyPair()
|
||||||
oldSigningKeyPair = this.protocolService.getSigningKeyPair()
|
oldSigningKeyPair = this.encryptionService.getSigningKeyPair()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
void error
|
void error
|
||||||
}
|
}
|
||||||
@@ -718,7 +718,7 @@ export class SNSessionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
private decodeDemoShareToken(token: Base64String): ShareToken {
|
private decodeDemoShareToken(token: Base64String): ShareToken {
|
||||||
const jsonString = this.protocolService.crypto.base64Decode(token)
|
const jsonString = this.encryptionService.crypto.base64Decode(token)
|
||||||
return JSON.parse(jsonString)
|
return JSON.parse(jsonString)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,7 +735,7 @@ export class SNSessionManager
|
|||||||
host: string,
|
host: string,
|
||||||
wrappingKey?: SNRootKey,
|
wrappingKey?: SNRootKey,
|
||||||
) {
|
) {
|
||||||
await this.protocolService.setRootKey(rootKey, wrappingKey)
|
await this.encryptionService.setRootKey(rootKey, wrappingKey)
|
||||||
|
|
||||||
this.memoizeUser(user)
|
this.memoizeUser(user)
|
||||||
this.diskStorageService.setValue(StorageKey.User, user)
|
this.diskStorageService.setValue(StorageKey.User, user)
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class SNSyncService
|
|||||||
constructor(
|
constructor(
|
||||||
private itemManager: ItemManager,
|
private itemManager: ItemManager,
|
||||||
private sessionManager: SNSessionManager,
|
private sessionManager: SNSessionManager,
|
||||||
private protocolService: EncryptionService,
|
private encryptionService: EncryptionService,
|
||||||
private storageService: DiskStorageService,
|
private storageService: DiskStorageService,
|
||||||
private payloadManager: PayloadManager,
|
private payloadManager: PayloadManager,
|
||||||
private apiService: SNApiService,
|
private apiService: SNApiService,
|
||||||
@@ -189,7 +189,7 @@ export class SNSyncService
|
|||||||
this.dealloced = true
|
this.dealloced = true
|
||||||
;(this.sessionManager as unknown) = undefined
|
;(this.sessionManager as unknown) = undefined
|
||||||
;(this.itemManager as unknown) = undefined
|
;(this.itemManager as unknown) = undefined
|
||||||
;(this.protocolService as unknown) = undefined
|
;(this.encryptionService as unknown) = undefined
|
||||||
;(this.payloadManager as unknown) = undefined
|
;(this.payloadManager as unknown) = undefined
|
||||||
;(this.storageService as unknown) = undefined
|
;(this.storageService as unknown) = undefined
|
||||||
;(this.apiService as unknown) = undefined
|
;(this.apiService as unknown) = undefined
|
||||||
@@ -250,7 +250,7 @@ export class SNSyncService
|
|||||||
const encryptionSplit = SplitPayloadsByEncryptionType(encryptedPayloads)
|
const encryptionSplit = SplitPayloadsByEncryptionType(encryptedPayloads)
|
||||||
const decryptionSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
const decryptionSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
||||||
|
|
||||||
const newlyDecryptedPayloads = await this.protocolService.decryptSplit(decryptionSplit)
|
const newlyDecryptedPayloads = await this.encryptionService.decryptSplit(decryptionSplit)
|
||||||
|
|
||||||
await this.payloadManager.emitPayloads(
|
await this.payloadManager.emitPayloads(
|
||||||
[...alreadyDecryptedPayloads, ...newlyDecryptedPayloads],
|
[...alreadyDecryptedPayloads, ...newlyDecryptedPayloads],
|
||||||
@@ -369,7 +369,7 @@ export class SNSyncService
|
|||||||
const encryptionSplit = SplitPayloadsByEncryptionType(encrypted)
|
const encryptionSplit = SplitPayloadsByEncryptionType(encrypted)
|
||||||
const decryptionSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
const decryptionSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
||||||
|
|
||||||
const results = await this.protocolService.decryptSplit(decryptionSplit)
|
const results = await this.encryptionService.decryptSplit(decryptionSplit)
|
||||||
|
|
||||||
await this.payloadManager.emitPayloads([...nonencrypted, ...results], PayloadEmitSource.LocalDatabaseLoaded)
|
await this.payloadManager.emitPayloads([...nonencrypted, ...results], PayloadEmitSource.LocalDatabaseLoaded)
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ export class SNSyncService
|
|||||||
|
|
||||||
const keyLookupSplit = CreateEncryptionSplitWithKeyLookup(encryptionSplit)
|
const keyLookupSplit = CreateEncryptionSplitWithKeyLookup(encryptionSplit)
|
||||||
|
|
||||||
const encryptedResults = await this.protocolService.encryptSplit(keyLookupSplit)
|
const encryptedResults = await this.encryptionService.encryptSplit(keyLookupSplit)
|
||||||
|
|
||||||
const contextPayloads = [
|
const contextPayloads = [
|
||||||
...encryptedResults.map(CreateEncryptedServerSyncPushPayload),
|
...encryptedResults.map(CreateEncryptedServerSyncPushPayload),
|
||||||
@@ -1138,7 +1138,7 @@ export class SNSyncService
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await this.protocolService.decryptSplit<ItemsKeyContent>(rootKeySplit)
|
const results = await this.encryptionService.decryptSplit<ItemsKeyContent>(rootKeySplit)
|
||||||
|
|
||||||
results.forEach((result) => {
|
results.forEach((result) => {
|
||||||
if (isDecryptedPayload<ItemsKeyContent>(result) && result.content_type === ContentType.ItemsKey) {
|
if (isDecryptedPayload<ItemsKeyContent>(result) && result.content_type === ContentType.ItemsKey) {
|
||||||
@@ -1168,7 +1168,7 @@ export class SNSyncService
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await this.protocolService.decryptSplit<KeySystemItemsKeyContent>(keySystemRootKeySplit)
|
const results = await this.encryptionService.decryptSplit<KeySystemItemsKeyContent>(keySystemRootKeySplit)
|
||||||
|
|
||||||
results.forEach((result) => {
|
results.forEach((result) => {
|
||||||
if (
|
if (
|
||||||
@@ -1213,7 +1213,7 @@ export class SNSyncService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.protocolService.decryptSplitSingle(keyedSplit)
|
return this.encryptionService.decryptSplitSingle(keyedSplit)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1399,7 +1399,7 @@ export class SNSyncService
|
|||||||
|
|
||||||
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
||||||
|
|
||||||
const decryptionResults = await this.protocolService.decryptSplit(keyedSplit)
|
const decryptionResults = await this.encryptionService.decryptSplit(keyedSplit)
|
||||||
|
|
||||||
this.setInSync(false)
|
this.setInSync(false)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ describe('001 protocol operations', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('cost minimum', () => {
|
it('cost minimum', () => {
|
||||||
expect(application.protocolService.costMinimumForVersion('001')).to.equal(3000)
|
expect(application.encryptionService.costMinimumForVersion('001')).to.equal(3000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('generates valid keys for registration', async () => {
|
it('generates valid keys for registration', async () => {
|
||||||
@@ -46,7 +46,7 @@ describe('001 protocol operations', () => {
|
|||||||
|
|
||||||
it('generates valid keys from existing params and decrypts', async () => {
|
it('generates valid keys from existing params and decrypts', async () => {
|
||||||
const password = 'password'
|
const password = 'password'
|
||||||
const keyParams = await application.protocolService.createKeyParams({
|
const keyParams = await application.encryptionService.createKeyParams({
|
||||||
pw_func: 'pbkdf2',
|
pw_func: 'pbkdf2',
|
||||||
pw_alg: 'sha512',
|
pw_alg: 'sha512',
|
||||||
pw_key_size: 512,
|
pw_key_size: 512,
|
||||||
@@ -67,7 +67,7 @@ describe('001 protocol operations', () => {
|
|||||||
'sVuHmG0XAp1PRDE8r8XqFXijjP8Pqdwal9YFRrXK4hKLt1yyq8MwQU+1Z95Tz/b7ajYdidwFE0iDwd8Iu8281VtJsQ4yhh2tJiAzBy6newyHfhA5nH93yZ3iXRJaG87bgNQE9lsXzTV/OHAvqMuQtw/QVSWI3Qy1Pyu1Tn72q7FPKKhRRkzEEZ+Ax0BA1fHg',
|
'sVuHmG0XAp1PRDE8r8XqFXijjP8Pqdwal9YFRrXK4hKLt1yyq8MwQU+1Z95Tz/b7ajYdidwFE0iDwd8Iu8281VtJsQ4yhh2tJiAzBy6newyHfhA5nH93yZ3iXRJaG87bgNQE9lsXzTV/OHAvqMuQtw/QVSWI3Qy1Pyu1Tn72q7FPKKhRRkzEEZ+Ax0BA1fHg',
|
||||||
uuid: '54001a6f-7c22-4b34-8316-fadf9b1fc255',
|
uuid: '54001a6f-7c22-4b34-8316-fadf9b1fc255',
|
||||||
})
|
})
|
||||||
const decrypted = await application.protocolService.decryptSplitSingle({
|
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
key: key,
|
key: key,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe('002 protocol operations', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('cost minimum', () => {
|
it('cost minimum', () => {
|
||||||
expect(application.protocolService.costMinimumForVersion('002')).to.equal(3000)
|
expect(application.encryptionService.costMinimumForVersion('002')).to.equal(3000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('generates valid keys for registration', async () => {
|
it('generates valid keys for registration', async () => {
|
||||||
@@ -46,7 +46,7 @@ describe('002 protocol operations', () => {
|
|||||||
|
|
||||||
it('generates valid keys from existing params and decrypts', async () => {
|
it('generates valid keys from existing params and decrypts', async () => {
|
||||||
const password = 'password'
|
const password = 'password'
|
||||||
const keyParams = await application.protocolService.createKeyParams({
|
const keyParams = await application.encryptionService.createKeyParams({
|
||||||
pw_salt: '8d381ef44cdeab1489194f87066b747b46053a833ee24956e846e7b40440f5f4',
|
pw_salt: '8d381ef44cdeab1489194f87066b747b46053a833ee24956e846e7b40440f5f4',
|
||||||
pw_cost: 101000,
|
pw_cost: 101000,
|
||||||
version: '002',
|
version: '002',
|
||||||
@@ -64,7 +64,7 @@ describe('002 protocol operations', () => {
|
|||||||
'002:24a8e8f7728bbe06605d8209d87ad338d3d15ef81154bb64d3967c77daa01333:959b042a-3892-461e-8c50-477c10c7c40a:f1d294388742dca34f6f266a01483a4e:VdlEDyjhZ35GbJDg8ruSZv3Tp6WtMME3T5LLvcBYLHIMhrMi0RlPK83lK6F0aEaZvY82pZ0ntU+XpAX7JMSEdKdPXsACML7WeFrqKb3z2qHnA7NxgnIC0yVT/Z2mRrvlY3NNrUPGwJbfRcvfS7FVyw87MemT9CSubMZRviXvXETx82t7rsgjV/AIwOOeWhFi',
|
'002:24a8e8f7728bbe06605d8209d87ad338d3d15ef81154bb64d3967c77daa01333:959b042a-3892-461e-8c50-477c10c7c40a:f1d294388742dca34f6f266a01483a4e:VdlEDyjhZ35GbJDg8ruSZv3Tp6WtMME3T5LLvcBYLHIMhrMi0RlPK83lK6F0aEaZvY82pZ0ntU+XpAX7JMSEdKdPXsACML7WeFrqKb3z2qHnA7NxgnIC0yVT/Z2mRrvlY3NNrUPGwJbfRcvfS7FVyw87MemT9CSubMZRviXvXETx82t7rsgjV/AIwOOeWhFi',
|
||||||
uuid: '959b042a-3892-461e-8c50-477c10c7c40a',
|
uuid: '959b042a-3892-461e-8c50-477c10c7c40a',
|
||||||
})
|
})
|
||||||
const decrypted = await application.protocolService.decryptSplitSingle({
|
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
key: key,
|
key: key,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ describe('003 protocol operations', () => {
|
|||||||
|
|
||||||
it('cost minimum should throw', () => {
|
it('cost minimum should throw', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
sharedApplication.protocolService.costMinimumForVersion('003')
|
sharedApplication.encryptionService.costMinimumForVersion('003')
|
||||||
}).to.throw('Cost minimums only apply to versions <= 002')
|
}).to.throw('Cost minimums only apply to versions <= 002')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ describe('003 protocol operations', () => {
|
|||||||
it('computes proper keys for sign in', async () => {
|
it('computes proper keys for sign in', async () => {
|
||||||
const identifier = 'foo@bar.com'
|
const identifier = 'foo@bar.com'
|
||||||
const password = 'very_secure'
|
const password = 'very_secure'
|
||||||
const keyParams = sharedApplication.protocolService.createKeyParams({
|
const keyParams = sharedApplication.encryptionService.createKeyParams({
|
||||||
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
version: '003',
|
version: '003',
|
||||||
@@ -73,7 +73,7 @@ describe('003 protocol operations', () => {
|
|||||||
it('can decrypt item generated with web version 3.3.6', async () => {
|
it('can decrypt item generated with web version 3.3.6', async () => {
|
||||||
const identifier = 'demo@standardnotes.org'
|
const identifier = 'demo@standardnotes.org'
|
||||||
const password = 'password'
|
const password = 'password'
|
||||||
const keyParams = sharedApplication.protocolService.createKeyParams({
|
const keyParams = sharedApplication.encryptionService.createKeyParams({
|
||||||
pw_nonce: '31107837b44d86179140b7c602a55d694243e2e9ced0c4c914ac21ad90215055',
|
pw_nonce: '31107837b44d86179140b7c602a55d694243e2e9ced0c4c914ac21ad90215055',
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
version: '003',
|
version: '003',
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ describe('004 protocol operations', function () {
|
|||||||
|
|
||||||
it('cost minimum should throw', function () {
|
it('cost minimum should throw', function () {
|
||||||
expect(function () {
|
expect(function () {
|
||||||
application.protocolService.costMinimumForVersion('004')
|
application.encryptionService.costMinimumForVersion('004')
|
||||||
}).to.throw('Cost minimums only apply to versions <= 002')
|
}).to.throw('Cost minimums only apply to versions <= 002')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('generates valid keys for registration', async function () {
|
it('generates valid keys for registration', async function () {
|
||||||
const key = await application.protocolService.createRootKey(
|
const key = await application.encryptionService.createRootKey(
|
||||||
_identifier,
|
_identifier,
|
||||||
_password,
|
_password,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
@@ -51,7 +51,7 @@ describe('004 protocol operations', function () {
|
|||||||
it('computes proper keys for sign in', async function () {
|
it('computes proper keys for sign in', async function () {
|
||||||
const identifier = 'foo@bar.com'
|
const identifier = 'foo@bar.com'
|
||||||
const password = 'very_secure'
|
const password = 'very_secure'
|
||||||
const keyParams = application.protocolService.createKeyParams({
|
const keyParams = application.encryptionService.createKeyParams({
|
||||||
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
version: '004',
|
version: '004',
|
||||||
@@ -64,7 +64,7 @@ describe('004 protocol operations', function () {
|
|||||||
|
|
||||||
it('generates random key', async function () {
|
it('generates random key', async function () {
|
||||||
const length = 96
|
const length = 96
|
||||||
const key = await application.protocolService.crypto.generateRandomKey(length)
|
const key = await application.encryptionService.crypto.generateRandomKey(length)
|
||||||
expect(key.length).to.equal(length / 4)
|
expect(key.length).to.equal(length / 4)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ describe('004 protocol operations', function () {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const operator = application.protocolService.operatorManager.operatorForVersion(ProtocolVersion.V004)
|
const operator = application.encryptionService.operators.operatorForVersion(ProtocolVersion.V004)
|
||||||
|
|
||||||
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
||||||
const decrypted = await operator.generateDecryptedParameters(encrypted, rootKey)
|
const decrypted = await operator.generateDecryptedParameters(encrypted, rootKey)
|
||||||
@@ -97,7 +97,7 @@ describe('004 protocol operations', function () {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const operator = application.protocolService.operatorManager.operatorForVersion(ProtocolVersion.V004)
|
const operator = application.encryptionService.operators.operatorForVersion(ProtocolVersion.V004)
|
||||||
|
|
||||||
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
||||||
const decrypted = await operator.generateDecryptedParameters(
|
const decrypted = await operator.generateDecryptedParameters(
|
||||||
@@ -112,7 +112,7 @@ describe('004 protocol operations', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('generates existing keys for key params', async function () {
|
it('generates existing keys for key params', async function () {
|
||||||
const key = await application.protocolService.computeRootKey(_password, rootKeyParams)
|
const key = await application.encryptionService.computeRootKey(_password, rootKeyParams)
|
||||||
expect(key.compare(rootKey)).to.be.true
|
expect(key.compare(rootKey)).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ describe('actions service', () => {
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
})
|
})
|
||||||
|
|
||||||
const rootKey = await this.application.protocolService.createRootKey(
|
const rootKey = await this.application.encryptionService.createRootKey(
|
||||||
this.email,
|
this.email,
|
||||||
this.password,
|
this.password,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
@@ -117,7 +117,7 @@ describe('actions service', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -359,14 +359,14 @@ describe('actions service', () => {
|
|||||||
const response = await this.actionsManager.runAction(this.encryptedPostAction, this.noteItem)
|
const response = await this.actionsManager.runAction(this.encryptedPostAction, this.noteItem)
|
||||||
|
|
||||||
expect(response.items[0].enc_item_key).to.satisfy((string) => {
|
expect(response.items[0].enc_item_key).to.satisfy((string) => {
|
||||||
return string.startsWith(this.application.protocolService.getLatestVersion())
|
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
expect(response.items[0].uuid).to.eq(this.noteItem.uuid)
|
expect(response.items[0].uuid).to.eq(this.noteItem.uuid)
|
||||||
expect(response.items[0].auth_hash).to.not.be.ok
|
expect(response.items[0].auth_hash).to.not.be.ok
|
||||||
expect(response.items[0].content_type).to.be.ok
|
expect(response.items[0].content_type).to.be.ok
|
||||||
expect(response.items[0].created_at).to.be.ok
|
expect(response.items[0].created_at).to.be.ok
|
||||||
expect(response.items[0].content).to.satisfy((string) => {
|
expect(response.items[0].content).to.satisfy((string) => {
|
||||||
return string.startsWith(this.application.protocolService.getLatestVersion())
|
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ describe('basic auth', function () {
|
|||||||
it('successfully register new account', async function () {
|
it('successfully register new account', async function () {
|
||||||
const response = await this.application.register(this.email, this.password)
|
const response = await this.application.register(this.email, this.password)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails register new account with short password', async function () {
|
it('fails register new account with short password', async function () {
|
||||||
@@ -49,18 +49,18 @@ describe('basic auth', function () {
|
|||||||
'For your security, please choose a longer password or, ideally, a passphrase, and try again.',
|
'For your security, please choose a longer password or, ideally, a passphrase, and try again.',
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(await this.application.protocolService.getRootKey()).to.not.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('successfully signs out of account', async function () {
|
it('successfully signs out of account', async function () {
|
||||||
await this.application.register(this.email, this.password)
|
await this.application.register(this.email, this.password)
|
||||||
|
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
|
|
||||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||||
|
|
||||||
expect(await this.application.protocolService.getRootKey()).to.not.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
expect(this.application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyNone)
|
expect(this.application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyNone)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('successfully signs in to registered account', async function () {
|
it('successfully signs in to registered account', async function () {
|
||||||
@@ -69,7 +69,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.not.be.ok
|
expect(response.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
}).timeout(20000)
|
}).timeout(20000)
|
||||||
|
|
||||||
it('cannot sign while already signed in', async function () {
|
it('cannot sign while already signed in', async function () {
|
||||||
@@ -79,7 +79,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.not.be.ok
|
expect(response.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
|
|
||||||
let error
|
let error
|
||||||
try {
|
try {
|
||||||
@@ -99,7 +99,7 @@ describe('basic auth', function () {
|
|||||||
error = e
|
error = e
|
||||||
}
|
}
|
||||||
expect(error).to.be.ok
|
expect(error).to.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
}).timeout(20000)
|
}).timeout(20000)
|
||||||
|
|
||||||
it('cannot perform two sign-ins at the same time', async function () {
|
it('cannot perform two sign-ins at the same time', async function () {
|
||||||
@@ -111,7 +111,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.not.be.ok
|
expect(response.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
})(),
|
})(),
|
||||||
(async () => {
|
(async () => {
|
||||||
/** Make sure the first function runs first */
|
/** Make sure the first function runs first */
|
||||||
@@ -134,7 +134,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.register(this.email, this.password)
|
const response = await this.application.register(this.email, this.password)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.error).to.not.be.ok
|
expect(response.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
})(),
|
})(),
|
||||||
(async () => {
|
(async () => {
|
||||||
/** Make sure the first function runs first */
|
/** Make sure the first function runs first */
|
||||||
@@ -204,7 +204,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(uppercase, this.password, undefined, undefined, undefined, true)
|
const response = await this.application.signIn(uppercase, this.password, undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.not.be.ok
|
expect(response.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
}).timeout(20000)
|
}).timeout(20000)
|
||||||
|
|
||||||
it('can sign into account regardless of whitespace', async function () {
|
it('can sign into account regardless of whitespace', async function () {
|
||||||
@@ -220,7 +220,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(withspace, this.password, undefined, undefined, undefined, true)
|
const response = await this.application.signIn(withspace, this.password, undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.not.be.ok
|
expect(response.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
}).timeout(20000)
|
}).timeout(20000)
|
||||||
|
|
||||||
it('fails login with wrong password', async function () {
|
it('fails login with wrong password', async function () {
|
||||||
@@ -229,7 +229,7 @@ describe('basic auth', function () {
|
|||||||
const response = await this.application.signIn(this.email, 'wrongpassword', undefined, undefined, undefined, true)
|
const response = await this.application.signIn(this.email, 'wrongpassword', undefined, undefined, undefined, true)
|
||||||
expect(response).to.be.ok
|
expect(response).to.be.ok
|
||||||
expect(response.data.error).to.be.ok
|
expect(response.data.error).to.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.not.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
}).timeout(20000)
|
}).timeout(20000)
|
||||||
|
|
||||||
it('fails to change to short password', async function () {
|
it('fails to change to short password', async function () {
|
||||||
@@ -339,7 +339,7 @@ describe('basic auth', function () {
|
|||||||
expect(signinResponse).to.be.ok
|
expect(signinResponse).to.be.ok
|
||||||
expect(signinResponse.data.error).to.not.be.ok
|
expect(signinResponse.data.error).to.not.be.ok
|
||||||
|
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
|
|
||||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||||
@@ -421,7 +421,7 @@ describe('basic auth', function () {
|
|||||||
|
|
||||||
expect(signinResponse).to.be.ok
|
expect(signinResponse).to.be.ok
|
||||||
expect(signinResponse.data.error).to.not.be.ok
|
expect(signinResponse.data.error).to.not.be.ok
|
||||||
expect(await this.application.protocolService.getRootKey()).to.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
}
|
}
|
||||||
}).timeout(80000)
|
}).timeout(80000)
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ describe('backups', function () {
|
|||||||
|
|
||||||
it('backup file should have a version number', async function () {
|
it('backup file should have a version number', async function () {
|
||||||
let data = await this.application.createDecryptedBackupFile()
|
let data = await this.application.createDecryptedBackupFile()
|
||||||
expect(data.version).to.equal(this.application.protocolService.getLatestVersion())
|
expect(data.version).to.equal(this.application.encryptionService.getLatestVersion())
|
||||||
await this.application.addPasscode('passcode')
|
await this.application.addPasscode('passcode')
|
||||||
data = await this.application.createEncryptedBackupFileForAutomatedDesktopBackups()
|
data = await this.application.createEncryptedBackupFileForAutomatedDesktopBackups()
|
||||||
expect(data.version).to.equal(this.application.protocolService.getLatestVersion())
|
expect(data.version).to.equal(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('no passcode + no account backup file should have correct number of items', async function () {
|
it('no passcode + no account backup file should have correct number of items', async function () {
|
||||||
@@ -143,7 +143,7 @@ describe('backups', function () {
|
|||||||
|
|
||||||
const note = await Factory.createSyncedNote(this.application)
|
const note = await Factory.createSyncedNote(this.application)
|
||||||
|
|
||||||
const encrypted = await this.application.protocolService.encryptSplitSingle({
|
const encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note.payload],
|
items: [note.payload],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe('device authentication', function () {
|
|||||||
await application.addPasscode(passcode)
|
await application.addPasscode(passcode)
|
||||||
expect(await application.hasPasscode()).to.equal(true)
|
expect(await application.hasPasscode()).to.equal(true)
|
||||||
expect(await application.protectionService.createLaunchChallenge()).to.be.ok
|
expect(await application.protectionService.createLaunchChallenge()).to.be.ok
|
||||||
expect(application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.WrapperOnly)
|
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||||
await Factory.safeDeinit(application)
|
await Factory.safeDeinit(application)
|
||||||
|
|
||||||
/** Recreate application and initialize */
|
/** Recreate application and initialize */
|
||||||
@@ -49,10 +49,10 @@ describe('device authentication', function () {
|
|||||||
tmpApplication.submitValuesForChallenge(challenge, initialValues)
|
tmpApplication.submitValuesForChallenge(challenge, initialValues)
|
||||||
}
|
}
|
||||||
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.not.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||||
await tmpApplication.launch(true)
|
await tmpApplication.launch(true)
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||||
expect(tmpApplication.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.WrapperOnly)
|
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||||
await Factory.safeDeinit(tmpApplication)
|
await Factory.safeDeinit(tmpApplication)
|
||||||
}).timeout(10000)
|
}).timeout(10000)
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ describe('device authentication', function () {
|
|||||||
await application.protections.enableBiometrics()
|
await application.protections.enableBiometrics()
|
||||||
expect(await application.hasPasscode()).to.equal(true)
|
expect(await application.hasPasscode()).to.equal(true)
|
||||||
expect((await application.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
expect((await application.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||||
expect(application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.WrapperOnly)
|
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||||
await Factory.safeDeinit(application)
|
await Factory.safeDeinit(application)
|
||||||
|
|
||||||
/** Recreate application and initialize */
|
/** Recreate application and initialize */
|
||||||
@@ -98,11 +98,11 @@ describe('device authentication', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.not.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||||
expect((await tmpApplication.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
expect((await tmpApplication.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||||
await tmpApplication.launch(true)
|
await tmpApplication.launch(true)
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||||
expect(tmpApplication.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.WrapperOnly)
|
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||||
await Factory.safeDeinit(tmpApplication)
|
await Factory.safeDeinit(tmpApplication)
|
||||||
}).timeout(Factory.TwentySecondTimeout)
|
}).timeout(Factory.TwentySecondTimeout)
|
||||||
|
|
||||||
@@ -119,11 +119,11 @@ describe('device authentication', function () {
|
|||||||
const sampleStorageKey = 'foo'
|
const sampleStorageKey = 'foo'
|
||||||
const sampleStorageValue = 'bar'
|
const sampleStorageValue = 'bar'
|
||||||
await application.diskStorageService.setValue(sampleStorageKey, sampleStorageValue)
|
await application.diskStorageService.setValue(sampleStorageKey, sampleStorageValue)
|
||||||
expect(application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyOnly)
|
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyOnly)
|
||||||
const passcode = 'foobar'
|
const passcode = 'foobar'
|
||||||
Factory.handlePasswordChallenges(application, password)
|
Factory.handlePasswordChallenges(application, password)
|
||||||
await application.addPasscode(passcode)
|
await application.addPasscode(passcode)
|
||||||
expect(application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyPlusWrapper)
|
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||||
expect(await application.hasPasscode()).to.equal(true)
|
expect(await application.hasPasscode()).to.equal(true)
|
||||||
await Factory.safeDeinit(application)
|
await Factory.safeDeinit(application)
|
||||||
|
|
||||||
@@ -154,11 +154,11 @@ describe('device authentication', function () {
|
|||||||
await tmpApplication.prepareForLaunch({
|
await tmpApplication.prepareForLaunch({
|
||||||
receiveChallenge: receiveChallenge,
|
receiveChallenge: receiveChallenge,
|
||||||
})
|
})
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.not.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||||
await tmpApplication.launch(true)
|
await tmpApplication.launch(true)
|
||||||
expect(await tmpApplication.diskStorageService.getValue(sampleStorageKey)).to.equal(sampleStorageValue)
|
expect(await tmpApplication.diskStorageService.getValue(sampleStorageKey)).to.equal(sampleStorageValue)
|
||||||
expect(await tmpApplication.protocolService.getRootKey()).to.be.ok
|
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||||
expect(tmpApplication.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyPlusWrapper)
|
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||||
await Factory.safeDeinit(tmpApplication)
|
await Factory.safeDeinit(tmpApplication)
|
||||||
}).timeout(Factory.TwentySecondTimeout)
|
}).timeout(Factory.TwentySecondTimeout)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,21 +37,21 @@ describe('key recovery service', function () {
|
|||||||
|
|
||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
const randomRootKey = await application.protocolService.createRootKey(
|
const randomRootKey = await application.encryptionService.createRootKey(
|
||||||
unassociatedIdentifier,
|
unassociatedIdentifier,
|
||||||
unassociatedPassword,
|
unassociatedPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
)
|
)
|
||||||
const randomItemsKey = await application.protocolService.operatorManager.defaultOperator().createItemsKey()
|
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||||
|
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [randomItemsKey.payload],
|
items: [randomItemsKey.payload],
|
||||||
key: randomRootKey,
|
key: randomRootKey,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const errored = await application.protocolService.decryptSplitSingle({
|
const errored = await application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [encrypted],
|
items: [encrypted],
|
||||||
},
|
},
|
||||||
@@ -89,13 +89,13 @@ describe('key recovery service', function () {
|
|||||||
})
|
})
|
||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
const randomRootKey = await application.protocolService.createRootKey(
|
const randomRootKey = await application.encryptionService.createRootKey(
|
||||||
unassociatedIdentifier,
|
unassociatedIdentifier,
|
||||||
unassociatedPassword,
|
unassociatedPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
)
|
)
|
||||||
|
|
||||||
const randomItemsKey = await application.protocolService.operatorManager.defaultOperator().createItemsKey()
|
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||||
|
|
||||||
await application.payloadManager.emitPayload(
|
await application.payloadManager.emitPayload(
|
||||||
randomItemsKey.payload.copy({ dirty: true, dirtyIndex: getIncrementedDirtyIndex() }),
|
randomItemsKey.payload.copy({ dirty: true, dirtyIndex: getIncrementedDirtyIndex() }),
|
||||||
@@ -106,14 +106,14 @@ describe('key recovery service', function () {
|
|||||||
|
|
||||||
const originalSyncTime = application.payloadManager.findOne(randomItemsKey.uuid).lastSyncEnd.getTime()
|
const originalSyncTime = application.payloadManager.findOne(randomItemsKey.uuid).lastSyncEnd.getTime()
|
||||||
|
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [randomItemsKey.payload],
|
items: [randomItemsKey.payload],
|
||||||
key: randomRootKey,
|
key: randomRootKey,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const errored = await application.protocolService.decryptSplitSingle({
|
const errored = await application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [encrypted],
|
items: [encrypted],
|
||||||
},
|
},
|
||||||
@@ -214,15 +214,15 @@ describe('key recovery service', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** Create items key associated with a random root key */
|
/** Create items key associated with a random root key */
|
||||||
const randomRootKey = await application.protocolService.createRootKey(
|
const randomRootKey = await application.encryptionService.createRootKey(
|
||||||
unassociatedIdentifier,
|
unassociatedIdentifier,
|
||||||
unassociatedPassword,
|
unassociatedPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
)
|
)
|
||||||
const randomItemsKey = await application.protocolService.operatorManager.defaultOperator().createItemsKey()
|
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||||
const randomItemsKey2 = await application.protocolService.operatorManager.defaultOperator().createItemsKey()
|
const randomItemsKey2 = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||||
|
|
||||||
const encrypted = await application.protocolService.encryptSplit({
|
const encrypted = await application.encryptionService.encryptSplit({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [randomItemsKey.payload, randomItemsKey2.payload],
|
items: [randomItemsKey.payload, randomItemsKey2.payload],
|
||||||
key: randomRootKey,
|
key: randomRootKey,
|
||||||
@@ -230,7 +230,7 @@ describe('key recovery service', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** Attempt decryption and insert into rotation in errored state */
|
/** Attempt decryption and insert into rotation in errored state */
|
||||||
const decrypted = await application.protocolService.decryptSplit({
|
const decrypted = await application.encryptionService.decryptSplit({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: encrypted,
|
items: encrypted,
|
||||||
},
|
},
|
||||||
@@ -293,8 +293,8 @@ describe('key recovery service', function () {
|
|||||||
expect(key.errorDecrypting).to.not.be.ok
|
expect(key.errorDecrypting).to.not.be.ok
|
||||||
}
|
}
|
||||||
|
|
||||||
const aKey = await contextA.application.protocolService.getRootKey()
|
const aKey = await contextA.application.encryptionService.getRootKey()
|
||||||
const bKey = await contextB.application.protocolService.getRootKey()
|
const bKey = await contextB.application.encryptionService.getRootKey()
|
||||||
expect(aKey.compare(bKey)).to.equal(true)
|
expect(aKey.compare(bKey)).to.equal(true)
|
||||||
|
|
||||||
expect(contextA.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
|
expect(contextA.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
|
||||||
@@ -379,7 +379,7 @@ describe('key recovery service', function () {
|
|||||||
await application.launch(true)
|
await application.launch(true)
|
||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
const correctRootKey = await application.protocolService.getRootKey()
|
const correctRootKey = await application.encryptionService.getRootKey()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Change our root key locally so that its keys params doesn't match the server's
|
* 1. Change our root key locally so that its keys params doesn't match the server's
|
||||||
@@ -390,7 +390,7 @@ describe('key recovery service', function () {
|
|||||||
const unassociatedIdentifier = 'foorand'
|
const unassociatedIdentifier = 'foorand'
|
||||||
|
|
||||||
/** Create items key associated with a random root key */
|
/** Create items key associated with a random root key */
|
||||||
const randomRootKey = await application.protocolService.createRootKey(
|
const randomRootKey = await application.encryptionService.createRootKey(
|
||||||
unassociatedIdentifier,
|
unassociatedIdentifier,
|
||||||
unassociatedPassword,
|
unassociatedPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
@@ -398,11 +398,11 @@ describe('key recovery service', function () {
|
|||||||
|
|
||||||
const signInFunction = sinon.spy(application.keyRecoveryService, 'performServerSignIn')
|
const signInFunction = sinon.spy(application.keyRecoveryService, 'performServerSignIn')
|
||||||
|
|
||||||
await application.protocolService.setRootKey(randomRootKey)
|
await application.encryptionService.setRootKey(randomRootKey)
|
||||||
|
|
||||||
const correctItemsKey = await application.protocolService.operatorManager.defaultOperator().createItemsKey()
|
const correctItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||||
|
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [correctItemsKey.payload],
|
items: [correctItemsKey.payload],
|
||||||
key: randomRootKey,
|
key: randomRootKey,
|
||||||
@@ -428,7 +428,7 @@ describe('key recovery service', function () {
|
|||||||
|
|
||||||
expect(signInFunction.callCount).to.equal(1)
|
expect(signInFunction.callCount).to.equal(1)
|
||||||
|
|
||||||
const clientRootKey = await application.protocolService.getRootKey()
|
const clientRootKey = await application.encryptionService.getRootKey()
|
||||||
expect(clientRootKey.compare(correctRootKey)).to.equal(true)
|
expect(clientRootKey.compare(correctRootKey)).to.equal(true)
|
||||||
|
|
||||||
const decryptedKey = application.items.findItem(correctItemsKey.uuid)
|
const decryptedKey = application.items.findItem(correctItemsKey.uuid)
|
||||||
@@ -448,8 +448,8 @@ describe('key recovery service', function () {
|
|||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
/** Create and emit errored encrypted items key payload */
|
/** Create and emit errored encrypted items key payload */
|
||||||
const itemsKey = await application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [itemsKey.payload],
|
items: [itemsKey.payload],
|
||||||
},
|
},
|
||||||
@@ -485,8 +485,8 @@ describe('key recovery service', function () {
|
|||||||
await context.launch()
|
await context.launch()
|
||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
const itemsKey = await application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [itemsKey.payload],
|
items: [itemsKey.payload],
|
||||||
},
|
},
|
||||||
@@ -524,8 +524,8 @@ describe('key recovery service', function () {
|
|||||||
await context.register()
|
await context.register()
|
||||||
|
|
||||||
/** Create and emit errored encrypted items key payload */
|
/** Create and emit errored encrypted items key payload */
|
||||||
const itemsKey = await application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [itemsKey.payload],
|
items: [itemsKey.payload],
|
||||||
},
|
},
|
||||||
@@ -589,17 +589,17 @@ describe('key recovery service', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** Create items key associated with a random root key */
|
/** Create items key associated with a random root key */
|
||||||
const randomRootKey = await application.protocolService.createRootKey(
|
const randomRootKey = await application.encryptionService.createRootKey(
|
||||||
unassociatedIdentifier,
|
unassociatedIdentifier,
|
||||||
unassociatedPassword,
|
unassociatedPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
ProtocolVersion.V003,
|
ProtocolVersion.V003,
|
||||||
)
|
)
|
||||||
const randomItemsKey = await application.protocolService.operatorManager
|
const randomItemsKey = await application.encryptionService.operators
|
||||||
.operatorForVersion(ProtocolVersion.V003)
|
.operatorForVersion(ProtocolVersion.V003)
|
||||||
.createItemsKey()
|
.createItemsKey()
|
||||||
|
|
||||||
const encrypted = await application.protocolService.encryptSplitSingle({
|
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [randomItemsKey.payload],
|
items: [randomItemsKey.payload],
|
||||||
key: randomRootKey,
|
key: randomRootKey,
|
||||||
@@ -607,7 +607,7 @@ describe('key recovery service', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** Attempt decryption and insert into rotation in errored state */
|
/** Attempt decryption and insert into rotation in errored state */
|
||||||
const decrypted = await application.protocolService.decryptSplitSingle({
|
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [encrypted],
|
items: [encrypted],
|
||||||
},
|
},
|
||||||
@@ -653,9 +653,9 @@ describe('key recovery service', function () {
|
|||||||
contextA.password = newPassword
|
contextA.password = newPassword
|
||||||
await appB.sync.sync()
|
await appB.sync.sync()
|
||||||
|
|
||||||
const newDefaultKey = appB.protocolService.getSureDefaultItemsKey()
|
const newDefaultKey = appB.encryptionService.getSureDefaultItemsKey()
|
||||||
|
|
||||||
const encrypted = await appB.protocolService.encryptSplitSingle({
|
const encrypted = await appB.encryptionService.encryptSplitSingle({
|
||||||
usesRootKeyWithKeyLookup: {
|
usesRootKeyWithKeyLookup: {
|
||||||
items: [newDefaultKey.payload],
|
items: [newDefaultKey.payload],
|
||||||
},
|
},
|
||||||
@@ -676,13 +676,13 @@ describe('key recovery service', function () {
|
|||||||
const stored = (await appA.deviceInterface.getAllDatabaseEntries(appA.identifier)).find(
|
const stored = (await appA.deviceInterface.getAllDatabaseEntries(appA.identifier)).find(
|
||||||
(payload) => payload.uuid === newDefaultKey.uuid,
|
(payload) => payload.uuid === newDefaultKey.uuid,
|
||||||
)
|
)
|
||||||
const storedParams = await appA.protocolService.getKeyEmbeddedKeyParamsFromItemsKey(new EncryptedPayload(stored))
|
const storedParams = await appA.encryptionService.getKeyEmbeddedKeyParamsFromItemsKey(new EncryptedPayload(stored))
|
||||||
|
|
||||||
const correctStored = (await appB.deviceInterface.getAllDatabaseEntries(appB.identifier)).find(
|
const correctStored = (await appB.deviceInterface.getAllDatabaseEntries(appB.identifier)).find(
|
||||||
(payload) => payload.uuid === newDefaultKey.uuid,
|
(payload) => payload.uuid === newDefaultKey.uuid,
|
||||||
)
|
)
|
||||||
|
|
||||||
const correctParams = await appB.protocolService.getKeyEmbeddedKeyParamsFromItemsKey(
|
const correctParams = await appB.encryptionService.getKeyEmbeddedKeyParamsFromItemsKey(
|
||||||
new EncryptedPayload(correctStored),
|
new EncryptedPayload(correctStored),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ describe('keys', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should not have root key by default', async function () {
|
it('should not have root key by default', async function () {
|
||||||
expect(await this.application.protocolService.getRootKey()).to.not.be.ok
|
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('validates content types requiring root encryption', function () {
|
it('validates content types requiring root encryption', function () {
|
||||||
@@ -43,7 +43,7 @@ describe('keys', function () {
|
|||||||
/** Items key available by default */
|
/** Items key available by default */
|
||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
const processedPayload = CreateEncryptedLocalStorageContextPayload(
|
const processedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -54,44 +54,44 @@ describe('keys', function () {
|
|||||||
|
|
||||||
it('has root key and one items key after registering user', async function () {
|
it('has root key and one items key after registering user', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
expect(this.application.protocolService.getRootKey()).to.be.ok
|
expect(this.application.encryptionService.getRootKey()).to.be.ok
|
||||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('changing root key with passcode should re-wrap root key', async function () {
|
it('changing root key with passcode should re-wrap root key', async function () {
|
||||||
const email = 'foo'
|
const email = 'foo'
|
||||||
const password = 'bar'
|
const password = 'bar'
|
||||||
const key = await this.application.protocolService.createRootKey(email, password, KeyParamsOrigination.Registration)
|
const key = await this.application.encryptionService.createRootKey(email, password, KeyParamsOrigination.Registration)
|
||||||
await this.application.protocolService.setRootKey(key)
|
await this.application.encryptionService.setRootKey(key)
|
||||||
Factory.handlePasswordChallenges(this.application, password)
|
Factory.handlePasswordChallenges(this.application, password)
|
||||||
await this.application.addPasscode(password)
|
await this.application.addPasscode(password)
|
||||||
|
|
||||||
/** We should be able to decrypt wrapped root key with passcode */
|
/** We should be able to decrypt wrapped root key with passcode */
|
||||||
const wrappingKeyParams = await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()
|
const wrappingKeyParams = await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()
|
||||||
const wrappingKey = await this.application.protocolService.computeRootKey(password, wrappingKeyParams)
|
const wrappingKey = await this.application.encryptionService.computeRootKey(password, wrappingKeyParams)
|
||||||
await this.application.protocolService.unwrapRootKey(wrappingKey).catch((error) => {
|
await this.application.encryptionService.unwrapRootKey(wrappingKey).catch((error) => {
|
||||||
expect(error).to.not.be.ok
|
expect(error).to.not.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
const newPassword = 'bar'
|
const newPassword = 'bar'
|
||||||
const newKey = await this.application.protocolService.createRootKey(
|
const newKey = await this.application.encryptionService.createRootKey(
|
||||||
email,
|
email,
|
||||||
newPassword,
|
newPassword,
|
||||||
KeyParamsOrigination.Registration,
|
KeyParamsOrigination.Registration,
|
||||||
)
|
)
|
||||||
await this.application.protocolService.setRootKey(newKey, wrappingKey)
|
await this.application.encryptionService.setRootKey(newKey, wrappingKey)
|
||||||
await this.application.protocolService.unwrapRootKey(wrappingKey).catch((error) => {
|
await this.application.encryptionService.unwrapRootKey(wrappingKey).catch((error) => {
|
||||||
expect(error).to.not.be.ok
|
expect(error).to.not.be.ok
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('items key should be encrypted with root key', async function () {
|
it('items key should be encrypted with root key', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
const itemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
const rootKey = await this.application.protocolService.getRootKey()
|
const rootKey = await this.application.encryptionService.getRootKey()
|
||||||
|
|
||||||
/** Encrypt items key */
|
/** Encrypt items key */
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [itemsKey.payloadRepresentation()],
|
items: [itemsKey.payloadRepresentation()],
|
||||||
key: rootKey,
|
key: rootKey,
|
||||||
@@ -102,7 +102,7 @@ describe('keys', function () {
|
|||||||
expect(encryptedPayload.items_key_id).to.not.be.ok
|
expect(encryptedPayload.items_key_id).to.not.be.ok
|
||||||
|
|
||||||
/** Attempt to decrypt with root key. Should succeed. */
|
/** Attempt to decrypt with root key. Should succeed. */
|
||||||
const decryptedPayload = await this.application.protocolService.decryptSplitSingle({
|
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [encryptedPayload],
|
items: [encryptedPayload],
|
||||||
key: rootKey,
|
key: rootKey,
|
||||||
@@ -142,35 +142,35 @@ describe('keys', function () {
|
|||||||
|
|
||||||
it('should use items key for encryption of note', async function () {
|
it('should use items key for encryption of note', async function () {
|
||||||
const notePayload = Factory.createNotePayload()
|
const notePayload = Factory.createNotePayload()
|
||||||
const keyToUse = await this.application.protocolService.itemsEncryption.keyToUseForItemEncryption(notePayload)
|
const keyToUse = await this.application.encryptionService.itemsEncryption.keyToUseForItemEncryption(notePayload)
|
||||||
expect(keyToUse.content_type).to.equal(ContentType.ItemsKey)
|
expect(keyToUse.content_type).to.equal(ContentType.ItemsKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('encrypting an item should associate an items key to it', async function () {
|
it('encrypting an item should associate an items key to it', async function () {
|
||||||
const note = Factory.createNotePayload()
|
const note = Factory.createNotePayload()
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note],
|
items: [note],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemsKey = this.application.protocolService.itemsKeyForEncryptedPayload(encryptedPayload)
|
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||||
expect(itemsKey).to.be.ok
|
expect(itemsKey).to.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('decrypt encrypted item with associated key', async function () {
|
it('decrypt encrypted item with associated key', async function () {
|
||||||
const note = Factory.createNotePayload()
|
const note = Factory.createNotePayload()
|
||||||
const title = note.content.title
|
const title = note.content.title
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note],
|
items: [note],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemsKey = this.application.protocolService.itemsKeyForEncryptedPayload(encryptedPayload)
|
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||||
expect(itemsKey).to.be.ok
|
expect(itemsKey).to.be.ok
|
||||||
|
|
||||||
const decryptedPayload = await this.application.protocolService.decryptSplitSingle({
|
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [encryptedPayload],
|
items: [encryptedPayload],
|
||||||
},
|
},
|
||||||
@@ -182,17 +182,17 @@ describe('keys', function () {
|
|||||||
it('decrypts items waiting for keys', async function () {
|
it('decrypts items waiting for keys', async function () {
|
||||||
const notePayload = Factory.createNotePayload()
|
const notePayload = Factory.createNotePayload()
|
||||||
const title = notePayload.content.title
|
const title = notePayload.content.title
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [notePayload],
|
items: [notePayload],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemsKey = this.application.protocolService.itemsKeyForEncryptedPayload(encryptedPayload)
|
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||||
|
|
||||||
await this.application.itemManager.removeItemLocally(itemsKey)
|
await this.application.itemManager.removeItemLocally(itemsKey)
|
||||||
|
|
||||||
const erroredPayload = await this.application.protocolService.decryptSplitSingle({
|
const erroredPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [encryptedPayload],
|
items: [encryptedPayload],
|
||||||
},
|
},
|
||||||
@@ -208,7 +208,7 @@ describe('keys', function () {
|
|||||||
await this.application.mutator.emitItemsFromPayloads([keyPayload], PayloadEmitSource.LocalChanged)
|
await this.application.mutator.emitItemsFromPayloads([keyPayload], PayloadEmitSource.LocalChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeping is required to trigger asyncronous protocolService.decryptItemsWaitingForKeys,
|
* Sleeping is required to trigger asyncronous encryptionService.decryptItemsWaitingForKeys,
|
||||||
* which occurs after keys are mapped above.
|
* which occurs after keys are mapped above.
|
||||||
*/
|
*/
|
||||||
await Factory.sleep(0.2)
|
await Factory.sleep(0.2)
|
||||||
@@ -223,7 +223,7 @@ describe('keys', function () {
|
|||||||
it('attempting to emit errored items key for which there exists a non errored master copy should ignore it', async function () {
|
it('attempting to emit errored items key for which there exists a non errored master copy should ignore it', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
|
|
||||||
const itemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
|
|
||||||
expect(itemsKey.errorDecrypting).to.not.be.ok
|
expect(itemsKey.errorDecrypting).to.not.be.ok
|
||||||
|
|
||||||
@@ -250,13 +250,13 @@ describe('keys', function () {
|
|||||||
it('generating export params with logged in account should produce encrypted payload', async function () {
|
it('generating export params with logged in account should produce encrypted payload', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
expect(typeof encryptedPayload.content).to.equal('string')
|
expect(typeof encryptedPayload.content).to.equal('string')
|
||||||
expect(encryptedPayload.content.substring(0, 3)).to.equal(this.application.protocolService.getLatestVersion())
|
expect(encryptedPayload.content.substring(0, 3)).to.equal(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('When setting passcode, should encrypt items keys', async function () {
|
it('When setting passcode, should encrypt items keys', async function () {
|
||||||
@@ -276,7 +276,7 @@ describe('keys', function () {
|
|||||||
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
||||||
|
|
||||||
const authenticatedData = this.context.encryption.getEmbeddedPayloadAuthenticatedData(itemsKeyPayload)
|
const authenticatedData = this.context.encryption.getEmbeddedPayloadAuthenticatedData(itemsKeyPayload)
|
||||||
const rootKeyParams = await this.application.protocolService.getRootKeyParams()
|
const rootKeyParams = await this.application.encryptionService.getRootKeyParams()
|
||||||
|
|
||||||
expect(authenticatedData.kp).to.be.ok
|
expect(authenticatedData.kp).to.be.ok
|
||||||
expect(authenticatedData.kp).to.eql(rootKeyParams.getPortableValue())
|
expect(authenticatedData.kp).to.eql(rootKeyParams.getPortableValue())
|
||||||
@@ -286,8 +286,8 @@ describe('keys', function () {
|
|||||||
it('correctly validates local passcode', async function () {
|
it('correctly validates local passcode', async function () {
|
||||||
const passcode = 'foo'
|
const passcode = 'foo'
|
||||||
await this.application.addPasscode('foo')
|
await this.application.addPasscode('foo')
|
||||||
expect((await this.application.protocolService.validatePasscode('wrong')).valid).to.equal(false)
|
expect((await this.application.encryptionService.validatePasscode('wrong')).valid).to.equal(false)
|
||||||
expect((await this.application.protocolService.validatePasscode(passcode)).valid).to.equal(true)
|
expect((await this.application.encryptionService.validatePasscode(passcode)).valid).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('signing into 003 account should delete latest offline items key and create 003 items key', async function () {
|
it('signing into 003 account should delete latest offline items key and create 003 items key', async function () {
|
||||||
@@ -296,8 +296,8 @@ describe('keys', function () {
|
|||||||
* Upon signing into an 003 account, the application should delete any neverSynced items keys,
|
* Upon signing into an 003 account, the application should delete any neverSynced items keys,
|
||||||
* and create a new default items key that is the default for a given protocol version.
|
* and create a new default items key that is the default for a given protocol version.
|
||||||
*/
|
*/
|
||||||
const defaultItemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
const latestVersion = this.application.protocolService.getLatestVersion()
|
const latestVersion = this.application.encryptionService.getLatestVersion()
|
||||||
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
||||||
|
|
||||||
/** Register with 003 version */
|
/** Register with 003 version */
|
||||||
@@ -312,7 +312,7 @@ describe('keys', function () {
|
|||||||
expect(itemsKeys.length).to.equal(1)
|
expect(itemsKeys.length).to.equal(1)
|
||||||
const newestItemsKey = itemsKeys[0]
|
const newestItemsKey = itemsKeys[0]
|
||||||
expect(newestItemsKey.keyVersion).to.equal(ProtocolVersion.V003)
|
expect(newestItemsKey.keyVersion).to.equal(ProtocolVersion.V003)
|
||||||
const rootKey = await this.application.protocolService.getRootKey()
|
const rootKey = await this.application.encryptionService.getRootKey()
|
||||||
expect(newestItemsKey.itemsKey).to.equal(rootKey.masterKey)
|
expect(newestItemsKey.itemsKey).to.equal(rootKey.masterKey)
|
||||||
expect(newestItemsKey.dataAuthenticationKey).to.equal(rootKey.dataAuthenticationKey)
|
expect(newestItemsKey.dataAuthenticationKey).to.equal(rootKey.dataAuthenticationKey)
|
||||||
})
|
})
|
||||||
@@ -347,12 +347,12 @@ describe('keys', function () {
|
|||||||
expect(itemsKeys.length).to.equal(1)
|
expect(itemsKeys.length).to.equal(1)
|
||||||
const originalItemsKey = itemsKeys[0]
|
const originalItemsKey = itemsKeys[0]
|
||||||
|
|
||||||
const originalRootKey = await this.application.protocolService.getRootKey()
|
const originalRootKey = await this.application.encryptionService.getRootKey()
|
||||||
/** Expect that we can decrypt raw payload with current root key */
|
/** Expect that we can decrypt raw payload with current root key */
|
||||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||||
const itemsKeyRawPayload = rawPayloads.find((p) => p.uuid === originalItemsKey.uuid)
|
const itemsKeyRawPayload = rawPayloads.find((p) => p.uuid === originalItemsKey.uuid)
|
||||||
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
||||||
const decrypted = await this.application.protocolService.decryptSplitSingle({
|
const decrypted = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [itemsKeyPayload],
|
items: [itemsKeyPayload],
|
||||||
key: originalRootKey,
|
key: originalRootKey,
|
||||||
@@ -366,7 +366,7 @@ describe('keys', function () {
|
|||||||
Factory.handlePasswordChallenges(this.application, passcode)
|
Factory.handlePasswordChallenges(this.application, passcode)
|
||||||
await this.application.changePasscode('bar')
|
await this.application.changePasscode('bar')
|
||||||
|
|
||||||
const newRootKey = await this.application.protocolService.getRootKey()
|
const newRootKey = await this.application.encryptionService.getRootKey()
|
||||||
expect(newRootKey).to.not.equal(originalRootKey)
|
expect(newRootKey).to.not.equal(originalRootKey)
|
||||||
expect(newRootKey.masterKey).to.not.equal(originalRootKey.masterKey)
|
expect(newRootKey.masterKey).to.not.equal(originalRootKey.masterKey)
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ describe('keys', function () {
|
|||||||
expect(itemsKeyRawPayload2.content).to.not.equal(itemsKeyRawPayload.content)
|
expect(itemsKeyRawPayload2.content).to.not.equal(itemsKeyRawPayload.content)
|
||||||
|
|
||||||
const itemsKeyPayload2 = new EncryptedPayload(itemsKeyRawPayload2)
|
const itemsKeyPayload2 = new EncryptedPayload(itemsKeyRawPayload2)
|
||||||
const decrypted2 = await this.application.protocolService.decryptSplitSingle({
|
const decrypted2 = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [itemsKeyPayload2],
|
items: [itemsKeyPayload2],
|
||||||
key: originalRootKey,
|
key: originalRootKey,
|
||||||
@@ -388,7 +388,7 @@ describe('keys', function () {
|
|||||||
expect(decrypted2.errorDecrypting).to.equal(true)
|
expect(decrypted2.errorDecrypting).to.equal(true)
|
||||||
|
|
||||||
/** Should be able to decrypt with new root key */
|
/** Should be able to decrypt with new root key */
|
||||||
const decrypted3 = await this.application.protocolService.decryptSplitSingle({
|
const decrypted3 = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [itemsKeyPayload2],
|
items: [itemsKeyPayload2],
|
||||||
key: newRootKey,
|
key: newRootKey,
|
||||||
@@ -405,17 +405,17 @@ describe('keys', function () {
|
|||||||
})
|
})
|
||||||
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
||||||
expect(itemsKeys.length).to.equal(1)
|
expect(itemsKeys.length).to.equal(1)
|
||||||
const defaultItemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
|
|
||||||
const result = await this.application.changePassword(this.password, 'foobarfoo')
|
const result = await this.application.changePassword(this.password, 'foobarfoo')
|
||||||
expect(result.error).to.not.be.ok
|
expect(result.error).to.not.be.ok
|
||||||
|
|
||||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||||
const newDefaultItemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const newDefaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
||||||
|
|
||||||
const note = await Factory.createSyncedNote(this.application)
|
const note = await Factory.createSyncedNote(this.application)
|
||||||
const payload = await this.application.protocolService.encryptSplitSingle({
|
const payload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note.payload],
|
items: [note.payload],
|
||||||
},
|
},
|
||||||
@@ -432,18 +432,18 @@ describe('keys', function () {
|
|||||||
})
|
})
|
||||||
const itemsKeys = application.itemManager.getDisplayableItemsKeys()
|
const itemsKeys = application.itemManager.getDisplayableItemsKeys()
|
||||||
expect(itemsKeys.length).to.equal(1)
|
expect(itemsKeys.length).to.equal(1)
|
||||||
const defaultItemsKey = application.protocolService.getSureDefaultItemsKey()
|
const defaultItemsKey = application.encryptionService.getSureDefaultItemsKey()
|
||||||
|
|
||||||
const newEmail = UuidGenerator.GenerateUuid()
|
const newEmail = UuidGenerator.GenerateUuid()
|
||||||
const result = await application.changeEmail(newEmail, password)
|
const result = await application.changeEmail(newEmail, password)
|
||||||
expect(result.error).to.not.be.ok
|
expect(result.error).to.not.be.ok
|
||||||
|
|
||||||
expect(application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
expect(application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||||
const newDefaultItemsKey = application.protocolService.getSureDefaultItemsKey()
|
const newDefaultItemsKey = application.encryptionService.getSureDefaultItemsKey()
|
||||||
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
||||||
|
|
||||||
const note = await Factory.createSyncedNote(application)
|
const note = await Factory.createSyncedNote(application)
|
||||||
const payload = await application.protocolService.encryptSplitSingle({
|
const payload = await application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note.payload],
|
items: [note.payload],
|
||||||
},
|
},
|
||||||
@@ -480,7 +480,7 @@ describe('keys', function () {
|
|||||||
|
|
||||||
it('loading the keychain root key should also load its key params', async function () {
|
it('loading the keychain root key should also load its key params', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
const rootKey = await this.application.protocolService.rootKeyEncryption.getRootKeyFromKeychain()
|
const rootKey = await this.application.encryptionService.rootKeyManager.getRootKeyFromKeychain()
|
||||||
expect(rootKey.keyParams).to.be.ok
|
expect(rootKey.keyParams).to.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -497,7 +497,7 @@ describe('keys', function () {
|
|||||||
|
|
||||||
it('persisted key params should exactly equal in memory rootKey.keyParams', async function () {
|
it('persisted key params should exactly equal in memory rootKey.keyParams', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
const rootKey = await this.application.protocolService.getRootKey()
|
const rootKey = await this.application.encryptionService.getRootKey()
|
||||||
const rawKeyParams = await this.application.diskStorageService.getValue(
|
const rawKeyParams = await this.application.diskStorageService.getValue(
|
||||||
StorageKey.RootKeyParams,
|
StorageKey.RootKeyParams,
|
||||||
StorageValueModes.Nonwrapped,
|
StorageValueModes.Nonwrapped,
|
||||||
@@ -507,7 +507,7 @@ describe('keys', function () {
|
|||||||
|
|
||||||
it('key params should have expected values', async function () {
|
it('key params should have expected values', async function () {
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
const keyParamsObject = await this.application.protocolService.getRootKeyParams()
|
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||||
const keyParams = keyParamsObject.content
|
const keyParams = keyParamsObject.content
|
||||||
expect(keyParams.identifier).to.be.ok
|
expect(keyParams.identifier).to.be.ok
|
||||||
expect(keyParams.pw_nonce).to.be.ok
|
expect(keyParams.pw_nonce).to.be.ok
|
||||||
@@ -533,7 +533,7 @@ describe('keys', function () {
|
|||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
})
|
})
|
||||||
const keyParamsObject = await this.application.protocolService.getRootKeyParams()
|
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||||
const keyParams = keyParamsObject.content
|
const keyParams = keyParamsObject.content
|
||||||
|
|
||||||
expect(keyParams.created).to.be.ok
|
expect(keyParams.created).to.be.ok
|
||||||
@@ -551,7 +551,7 @@ describe('keys', function () {
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
version: ProtocolVersion.V003,
|
version: ProtocolVersion.V003,
|
||||||
})
|
})
|
||||||
const keyParamsObject = await this.application.protocolService.getRootKeyParams()
|
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||||
const keyParams = keyParamsObject.content
|
const keyParams = keyParamsObject.content
|
||||||
|
|
||||||
expect(keyParams.created).to.be.ok
|
expect(keyParams.created).to.be.ok
|
||||||
@@ -566,12 +566,12 @@ describe('keys', function () {
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
version: ProtocolVersion.V003,
|
version: ProtocolVersion.V003,
|
||||||
})
|
})
|
||||||
expect(await this.application.protocolService.getEncryptionDisplayName()).to.equal('AES-256')
|
expect(await this.application.encryptionService.getEncryptionDisplayName()).to.equal('AES-256')
|
||||||
|
|
||||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||||
/** Register with 004 account */
|
/** Register with 004 account */
|
||||||
await this.application.register(this.email + 'new', this.password)
|
await this.application.register(this.email + 'new', this.password)
|
||||||
expect(await this.application.protocolService.getEncryptionDisplayName()).to.equal('XChaCha20-Poly1305')
|
expect(await this.application.encryptionService.getEncryptionDisplayName()).to.equal('XChaCha20-Poly1305')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('when launching app with no keychain but data, should present account recovery challenge', async function () {
|
it('when launching app with no keychain but data, should present account recovery challenge', async function () {
|
||||||
@@ -599,7 +599,7 @@ describe('keys', function () {
|
|||||||
await recreatedApp.prepareForLaunch({ receiveChallenge })
|
await recreatedApp.prepareForLaunch({ receiveChallenge })
|
||||||
await recreatedApp.launch(true)
|
await recreatedApp.launch(true)
|
||||||
|
|
||||||
expect(recreatedApp.protocolService.getRootKey()).to.be.ok
|
expect(recreatedApp.encryptionService.getRootKey()).to.be.ok
|
||||||
expect(totalChallenges).to.equal(expectedChallenges)
|
expect(totalChallenges).to.equal(expectedChallenges)
|
||||||
await Factory.safeDeinit(recreatedApp)
|
await Factory.safeDeinit(recreatedApp)
|
||||||
})
|
})
|
||||||
@@ -684,11 +684,11 @@ describe('keys', function () {
|
|||||||
|
|
||||||
/** Change password through session manager directly instead of application,
|
/** Change password through session manager directly instead of application,
|
||||||
* as not to create any items key (to simulate 003 client behavior) */
|
* as not to create any items key (to simulate 003 client behavior) */
|
||||||
const currentRootKey = await oldClient.protocolService.computeRootKey(
|
const currentRootKey = await oldClient.encryptionService.computeRootKey(
|
||||||
this.password,
|
this.password,
|
||||||
await oldClient.protocolService.getRootKeyParams(),
|
await oldClient.encryptionService.getRootKeyParams(),
|
||||||
)
|
)
|
||||||
const operator = oldClient.protocolService.operatorManager.operatorForVersion(ProtocolVersion.V003)
|
const operator = oldClient.encryptionService.operators.operatorForVersion(ProtocolVersion.V003)
|
||||||
const newRootKey = await operator.createRootKey(this.email, this.password)
|
const newRootKey = await operator.createRootKey(this.email, this.password)
|
||||||
Object.defineProperty(oldClient.apiService, 'apiVersion', {
|
Object.defineProperty(oldClient.apiService, 'apiVersion', {
|
||||||
get: function () {
|
get: function () {
|
||||||
@@ -734,11 +734,11 @@ describe('keys', function () {
|
|||||||
|
|
||||||
/** Change password through session manager directly instead of application,
|
/** Change password through session manager directly instead of application,
|
||||||
* as not to create any items key (to simulate 003 client behavior) */
|
* as not to create any items key (to simulate 003 client behavior) */
|
||||||
const currentRootKey = await this.application.protocolService.computeRootKey(
|
const currentRootKey = await this.application.encryptionService.computeRootKey(
|
||||||
this.password,
|
this.password,
|
||||||
await this.application.protocolService.getRootKeyParams(),
|
await this.application.encryptionService.getRootKeyParams(),
|
||||||
)
|
)
|
||||||
const operator = this.application.protocolService.operatorManager.operatorForVersion(ProtocolVersion.V003)
|
const operator = this.application.encryptionService.operators.operatorForVersion(ProtocolVersion.V003)
|
||||||
const newRootKeyTemplate = await operator.createRootKey(this.email, this.password)
|
const newRootKeyTemplate = await operator.createRootKey(this.email, this.password)
|
||||||
const newRootKey = CreateNewRootKey({
|
const newRootKey = CreateNewRootKey({
|
||||||
...newRootKeyTemplate.content,
|
...newRootKeyTemplate.content,
|
||||||
@@ -761,7 +761,7 @@ describe('keys', function () {
|
|||||||
currentServerPassword: currentRootKey.serverPassword,
|
currentServerPassword: currentRootKey.serverPassword,
|
||||||
newRootKey,
|
newRootKey,
|
||||||
})
|
})
|
||||||
await this.application.protocolService.reencryptApplicableItemsAfterUserRootKeyChange()
|
await this.application.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||||
/** Note: this may result in a deadlock if features_service syncs and results in an error */
|
/** Note: this may result in a deadlock if features_service syncs and results in an error */
|
||||||
await this.application.sync.sync({ awaitAll: true })
|
await this.application.sync.sync({ awaitAll: true })
|
||||||
|
|
||||||
@@ -786,7 +786,7 @@ describe('keys', function () {
|
|||||||
* will have an updated_at value, which tell our protocol service that this key has been
|
* will have an updated_at value, which tell our protocol service that this key has been
|
||||||
* synced before, which sort of "lies" to the protocol service because now it thinks it doesnt
|
* synced before, which sort of "lies" to the protocol service because now it thinks it doesnt
|
||||||
* need to create a new items key because one has already been synced with the account.
|
* need to create a new items key because one has already been synced with the account.
|
||||||
* The corrective action was to do a final check in protocolService.handleDownloadFirstSyncCompletion
|
* The corrective action was to do a final check in encryptionService.handleDownloadFirstSyncCompletion
|
||||||
* to ensure there exists an items key corresponding to the user's account version.
|
* to ensure there exists an items key corresponding to the user's account version.
|
||||||
*/
|
*/
|
||||||
const promise = this.context.awaitNextSucessfulSync()
|
const promise = this.context.awaitNextSucessfulSync()
|
||||||
@@ -794,7 +794,7 @@ describe('keys', function () {
|
|||||||
await promise
|
await promise
|
||||||
|
|
||||||
await this.application.itemManager.removeAllItemsFromMemory()
|
await this.application.itemManager.removeAllItemsFromMemory()
|
||||||
expect(this.application.protocolService.getSureDefaultItemsKey()).to.not.be.ok
|
expect(this.application.encryptionService.getSureDefaultItemsKey()).to.not.be.ok
|
||||||
|
|
||||||
const protocol003 = new SNProtocolOperator003(new SNWebCrypto())
|
const protocol003 = new SNProtocolOperator003(new SNWebCrypto())
|
||||||
const key = await protocol003.createItemsKey()
|
const key = await protocol003.createItemsKey()
|
||||||
@@ -810,14 +810,14 @@ describe('keys', function () {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultKey = this.application.protocolService.getSureDefaultItemsKey()
|
const defaultKey = this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
expect(defaultKey.keyVersion).to.equal(ProtocolVersion.V003)
|
expect(defaultKey.keyVersion).to.equal(ProtocolVersion.V003)
|
||||||
expect(defaultKey.uuid).to.equal(key.uuid)
|
expect(defaultKey.uuid).to.equal(key.uuid)
|
||||||
|
|
||||||
await Factory.registerUserToApplication({ application: this.application })
|
await Factory.registerUserToApplication({ application: this.application })
|
||||||
|
|
||||||
const notePayload = Factory.createNotePayload()
|
const notePayload = Factory.createNotePayload()
|
||||||
expect(await this.application.protocolService.itemsEncryption.keyToUseForItemEncryption(notePayload)).to.be.ok
|
expect(await this.application.encryptionService.itemsEncryption.keyToUseForItemEncryption(notePayload)).to.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('having unsynced items keys should resync them upon download first sync completion', async function () {
|
it('having unsynced items keys should resync them upon download first sync completion', async function () {
|
||||||
@@ -856,7 +856,7 @@ describe('keys', function () {
|
|||||||
email: this.email,
|
email: this.email,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
})
|
})
|
||||||
const defaultKeys = otherClient.protocolService.itemsEncryption.getItemsKeys().filter((key) => {
|
const defaultKeys = otherClient.encryptionService.itemsEncryption.getItemsKeys().filter((key) => {
|
||||||
return key.isDefault
|
return key.isDefault
|
||||||
})
|
})
|
||||||
expect(defaultKeys.length).to.equal(1)
|
expect(defaultKeys.length).to.equal(1)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export class AppContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get encryption() {
|
get encryption() {
|
||||||
return this.application.protocolService
|
return this.application.encryptionService
|
||||||
}
|
}
|
||||||
|
|
||||||
get contacts() {
|
get contacts() {
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ export function registerUserToApplication({ application, email, password, epheme
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function setOldVersionPasscode({ application, passcode, version }) {
|
export async function setOldVersionPasscode({ application, passcode, version }) {
|
||||||
const identifier = await application.protocolService.crypto.generateUUID()
|
const identifier = await application.encryptionService.crypto.generateUUID()
|
||||||
const operator = application.protocolService.operatorManager.operatorForVersion(version)
|
const operator = application.encryptionService.operators.operatorForVersion(version)
|
||||||
const key = await operator.createRootKey(identifier, passcode, KeyParamsOrigination.PasscodeCreate)
|
const key = await operator.createRootKey(identifier, passcode, KeyParamsOrigination.PasscodeCreate)
|
||||||
await application.protocolService.setNewRootKeyWrapper(key)
|
await application.encryptionService.setNewRootKeyWrapper(key)
|
||||||
await application.userService.rewriteItemsKeys()
|
await application.userService.rewriteItemsKeys()
|
||||||
await application.syncService.sync(syncOptions)
|
await application.syncService.sync(syncOptions)
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ export async function setOldVersionPasscode({ application, passcode, version })
|
|||||||
export async function registerOldUser({ application, email, password, version }) {
|
export async function registerOldUser({ application, email, password, version }) {
|
||||||
if (!email) email = Utils.generateUuid()
|
if (!email) email = Utils.generateUuid()
|
||||||
if (!password) password = Utils.generateUuid()
|
if (!password) password = Utils.generateUuid()
|
||||||
const operator = application.protocolService.operatorManager.operatorForVersion(version)
|
const operator = application.encryptionService.operators.operatorForVersion(version)
|
||||||
const accountKey = await operator.createRootKey(email, password, KeyParamsOrigination.Registration)
|
const accountKey = await operator.createRootKey(email, password, KeyParamsOrigination.Registration)
|
||||||
|
|
||||||
const response = await application.userApiService.register({
|
const response = await application.userApiService.register({
|
||||||
@@ -145,7 +145,7 @@ export async function registerOldUser({ application, email, password, version })
|
|||||||
mode: SyncMode.DownloadFirst,
|
mode: SyncMode.DownloadFirst,
|
||||||
...syncOptions,
|
...syncOptions,
|
||||||
})
|
})
|
||||||
await application.protocolService.decryptErroredPayloads()
|
await application.encryptionService.decryptErroredPayloads()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createStorageItemPayload(contentType) {
|
export function createStorageItemPayload(contentType) {
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ describe('app models', () => {
|
|||||||
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||||
|
|
||||||
/** Encrypt item1 and emit as errored so it persists with items_key_id */
|
/** Encrypt item1 and emit as errored so it persists with items_key_id */
|
||||||
const encrypted = await this.application.protocolService.encryptSplitSingle({
|
const encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [item1.payload],
|
items: [item1.payload],
|
||||||
},
|
},
|
||||||
@@ -297,7 +297,7 @@ describe('app models', () => {
|
|||||||
expect(this.application.payloadManager.findOne(item1.uuid).errorDecrypting).to.equal(true)
|
expect(this.application.payloadManager.findOne(item1.uuid).errorDecrypting).to.equal(true)
|
||||||
expect(this.application.payloadManager.findOne(item1.uuid).items_key_id).to.equal(itemsKey.uuid)
|
expect(this.application.payloadManager.findOne(item1.uuid).items_key_id).to.equal(itemsKey.uuid)
|
||||||
|
|
||||||
sinon.stub(this.application.protocolService.itemsEncryption, 'decryptErroredItemPayloads').callsFake(() => {
|
sinon.stub(this.application.encryptionService.itemsEncryption, 'decryptErroredItemPayloads').callsFake(() => {
|
||||||
// prevent auto decryption
|
// prevent auto decryption
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ describe('payload encryption', function () {
|
|||||||
lastSyncBegan: new Date(),
|
lastSyncBegan: new Date(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const encryptedPayload = await this.application.protocolService.encryptSplitSingle({
|
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [notePayload],
|
items: [notePayload],
|
||||||
},
|
},
|
||||||
@@ -114,7 +114,7 @@ describe('payload encryption', function () {
|
|||||||
it('returns valid encrypted params for syncing', async function () {
|
it('returns valid encrypted params for syncing', async function () {
|
||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -126,7 +126,7 @@ describe('payload encryption', function () {
|
|||||||
expect(encryptedPayload.content_type).to.be.ok
|
expect(encryptedPayload.content_type).to.be.ok
|
||||||
expect(encryptedPayload.created_at).to.be.ok
|
expect(encryptedPayload.created_at).to.be.ok
|
||||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||||
return string.startsWith(this.application.protocolService.getLatestVersion())
|
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
}).timeout(5000)
|
}).timeout(5000)
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ describe('payload encryption', function () {
|
|||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
|
|
||||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -150,14 +150,14 @@ describe('payload encryption', function () {
|
|||||||
expect(encryptedPayload.deleted).to.not.be.ok
|
expect(encryptedPayload.deleted).to.not.be.ok
|
||||||
expect(encryptedPayload.errorDecrypting).to.not.be.ok
|
expect(encryptedPayload.errorDecrypting).to.not.be.ok
|
||||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||||
return string.startsWith(this.application.protocolService.getLatestVersion())
|
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('omits deleted for export file', async function () {
|
it('omits deleted for export file', async function () {
|
||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -170,7 +170,7 @@ describe('payload encryption', function () {
|
|||||||
expect(encryptedPayload.created_at).to.be.ok
|
expect(encryptedPayload.created_at).to.be.ok
|
||||||
expect(encryptedPayload.deleted).to.not.be.ok
|
expect(encryptedPayload.deleted).to.not.be.ok
|
||||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||||
return string.startsWith(this.application.protocolService.getLatestVersion())
|
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -19,43 +19,43 @@ describe('protocol', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('checks version to make sure its 004', function () {
|
it('checks version to make sure its 004', function () {
|
||||||
expect(this.application.protocolService.getLatestVersion()).to.equal('004')
|
expect(this.application.encryptionService.getLatestVersion()).to.equal('004')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('checks supported versions to make sure it includes 001, 002, 003, 004', function () {
|
it('checks supported versions to make sure it includes 001, 002, 003, 004', function () {
|
||||||
expect(this.application.protocolService.supportedVersions()).to.eql(['001', '002', '003', '004'])
|
expect(this.application.encryptionService.supportedVersions()).to.eql(['001', '002', '003', '004'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('platform derivation support', function () {
|
it('platform derivation support', function () {
|
||||||
expect(
|
expect(
|
||||||
this.application.protocolService.platformSupportsKeyDerivation({
|
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||||
version: '001',
|
version: '001',
|
||||||
}),
|
}),
|
||||||
).to.equal(true)
|
).to.equal(true)
|
||||||
expect(
|
expect(
|
||||||
this.application.protocolService.platformSupportsKeyDerivation({
|
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||||
version: '002',
|
version: '002',
|
||||||
}),
|
}),
|
||||||
).to.equal(true)
|
).to.equal(true)
|
||||||
expect(
|
expect(
|
||||||
this.application.protocolService.platformSupportsKeyDerivation({
|
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||||
version: '003',
|
version: '003',
|
||||||
}),
|
}),
|
||||||
).to.equal(true)
|
).to.equal(true)
|
||||||
expect(
|
expect(
|
||||||
this.application.protocolService.platformSupportsKeyDerivation({
|
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||||
version: '004',
|
version: '004',
|
||||||
}),
|
}),
|
||||||
).to.equal(true)
|
).to.equal(true)
|
||||||
expect(
|
expect(
|
||||||
this.application.protocolService.platformSupportsKeyDerivation({
|
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||||
version: '005',
|
version: '005',
|
||||||
}),
|
}),
|
||||||
).to.equal(true)
|
).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('key params versions <= 002 should include pw_cost in portable value', function () {
|
it('key params versions <= 002 should include pw_cost in portable value', function () {
|
||||||
const keyParams002 = this.application.protocolService.createKeyParams({
|
const keyParams002 = this.application.encryptionService.createKeyParams({
|
||||||
version: '002',
|
version: '002',
|
||||||
pw_cost: 5000,
|
pw_cost: 5000,
|
||||||
})
|
})
|
||||||
@@ -63,15 +63,15 @@ describe('protocol', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('version comparison of 002 should be older than library version', function () {
|
it('version comparison of 002 should be older than library version', function () {
|
||||||
expect(this.application.protocolService.isVersionNewerThanLibraryVersion('002')).to.equal(false)
|
expect(this.application.encryptionService.isVersionNewerThanLibraryVersion('002')).to.equal(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('version comparison of 005 should be newer than library version', function () {
|
it('version comparison of 005 should be newer than library version', function () {
|
||||||
expect(this.application.protocolService.isVersionNewerThanLibraryVersion('005')).to.equal(true)
|
expect(this.application.encryptionService.isVersionNewerThanLibraryVersion('005')).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('library version should not be outdated', function () {
|
it('library version should not be outdated', function () {
|
||||||
var currentVersion = this.application.protocolService.getLatestVersion()
|
var currentVersion = this.application.encryptionService.getLatestVersion()
|
||||||
expect(isProtocolVersionExpired(currentVersion)).to.equal(false)
|
expect(isProtocolVersionExpired(currentVersion)).to.equal(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ describe('protocol', function () {
|
|||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
let error
|
let error
|
||||||
try {
|
try {
|
||||||
await this.application.protocolService.decryptSplitSingle({
|
await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -106,7 +106,7 @@ describe('protocol', function () {
|
|||||||
await this.application.addPasscode('123')
|
await this.application.addPasscode('123')
|
||||||
const payload = Factory.createNotePayload()
|
const payload = Factory.createNotePayload()
|
||||||
const result = CreateEncryptedServerSyncPushPayload(
|
const result = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -121,7 +121,7 @@ describe('protocol', function () {
|
|||||||
it('encrypted payload for server should include duplicate_of field', async function () {
|
it('encrypted payload for server should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -134,7 +134,7 @@ describe('protocol', function () {
|
|||||||
it('ejected payload for server should include duplicate_of field', async function () {
|
it('ejected payload for server should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -147,7 +147,7 @@ describe('protocol', function () {
|
|||||||
it('encrypted payload for storage should include duplicate_of field', async function () {
|
it('encrypted payload for storage should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -160,7 +160,7 @@ describe('protocol', function () {
|
|||||||
it('ejected payload for storage should include duplicate_of field', async function () {
|
it('ejected payload for storage should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -173,7 +173,7 @@ describe('protocol', function () {
|
|||||||
it('encrypted payload for file should include duplicate_of field', async function () {
|
it('encrypted payload for file should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
@@ -186,7 +186,7 @@ describe('protocol', function () {
|
|||||||
it('ejected payload for file should include duplicate_of field', async function () {
|
it('ejected payload for file should include duplicate_of field', async function () {
|
||||||
const payload = Factory.createNotePayload('Test')
|
const payload = Factory.createNotePayload('Test')
|
||||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ describe('account recovery', function () {
|
|||||||
|
|
||||||
application = await context.signout()
|
application = await context.signout()
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
|
|
||||||
await application.signInWithRecoveryCodes.execute({
|
await application.signInWithRecoveryCodes.execute({
|
||||||
recoveryCodes: generatedRecoveryCodes.getValue(),
|
recoveryCodes: generatedRecoveryCodes.getValue(),
|
||||||
@@ -52,7 +52,7 @@ describe('account recovery', function () {
|
|||||||
password: context.password,
|
password: context.password,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.be.ok
|
expect(await application.encryptionService.getRootKey()).to.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should automatically generate new recovery code after recovery sign in', async () => {
|
it('should automatically generate new recovery code after recovery sign in', async () => {
|
||||||
@@ -96,7 +96,7 @@ describe('account recovery', function () {
|
|||||||
|
|
||||||
application = await context.signout()
|
application = await context.signout()
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
|
|
||||||
await application.signInWithRecoveryCodes.execute({
|
await application.signInWithRecoveryCodes.execute({
|
||||||
recoveryCodes: generatedRecoveryCodes.getValue(),
|
recoveryCodes: generatedRecoveryCodes.getValue(),
|
||||||
@@ -104,7 +104,7 @@ describe('account recovery', function () {
|
|||||||
password: 'foobar',
|
password: 'foobar',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not allow to sign in with invalid recovery code', async () => {
|
it('should not allow to sign in with invalid recovery code', async () => {
|
||||||
@@ -112,7 +112,7 @@ describe('account recovery', function () {
|
|||||||
|
|
||||||
application = await context.signout()
|
application = await context.signout()
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
|
|
||||||
await application.signInWithRecoveryCodes.execute({
|
await application.signInWithRecoveryCodes.execute({
|
||||||
recoveryCodes: 'invalid recovery code',
|
recoveryCodes: 'invalid recovery code',
|
||||||
@@ -120,13 +120,13 @@ describe('account recovery', function () {
|
|||||||
password: context.paswword,
|
password: context.paswword,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not allow to sign in with recovery code if user has none', async () => {
|
it('should not allow to sign in with recovery code if user has none', async () => {
|
||||||
application = await context.signout()
|
application = await context.signout()
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
|
|
||||||
await application.signInWithRecoveryCodes.execute({
|
await application.signInWithRecoveryCodes.execute({
|
||||||
recoveryCodes: 'foo bar',
|
recoveryCodes: 'foo bar',
|
||||||
@@ -134,6 +134,6 @@ describe('account recovery', function () {
|
|||||||
password: context.paswword,
|
password: context.paswword,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(await application.protocolService.getRootKey()).to.not.be.ok
|
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -574,7 +574,7 @@ describe('server session', function () {
|
|||||||
password: password,
|
password: password,
|
||||||
})
|
})
|
||||||
|
|
||||||
const oldRootKey = await appA.protocolService.getRootKey()
|
const oldRootKey = await appA.encryptionService.getRootKey()
|
||||||
|
|
||||||
/** Set the session as nonsense */
|
/** Set the session as nonsense */
|
||||||
appA.diskStorageService.setValue(StorageKey.Session, {
|
appA.diskStorageService.setValue(StorageKey.Session, {
|
||||||
@@ -597,7 +597,7 @@ describe('server session', function () {
|
|||||||
expect(appA.apiService.session.refreshToken.value).to.not.equal('bar')
|
expect(appA.apiService.session.refreshToken.value).to.not.equal('bar')
|
||||||
|
|
||||||
/** Expect that the session recovery replaces the global root key */
|
/** Expect that the session recovery replaces the global root key */
|
||||||
const newRootKey = await appA.protocolService.getRootKey()
|
const newRootKey = await appA.encryptionService.getRootKey()
|
||||||
expect(oldRootKey).to.not.equal(newRootKey)
|
expect(oldRootKey).to.not.equal(newRootKey)
|
||||||
|
|
||||||
await Factory.safeDeinit(appA)
|
await Factory.safeDeinit(appA)
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ describe('storage manager', function () {
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
})
|
})
|
||||||
const accountKey = await this.application.protocolService.getRootKey()
|
const accountKey = await this.application.encryptionService.getRootKey()
|
||||||
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ describe('storage manager', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** Should not be wrapped root key yet */
|
/** Should not be wrapped root key yet */
|
||||||
expect(await this.application.protocolService.rootKeyEncryption.getWrappedRootKey()).to.not.be.ok
|
expect(await this.application.encryptionService.rootKeyManager.getWrappedRootKey()).to.not.be.ok
|
||||||
|
|
||||||
const passcode = '123'
|
const passcode = '123'
|
||||||
Factory.handlePasswordChallenges(this.application, this.password)
|
Factory.handlePasswordChallenges(this.application, this.password)
|
||||||
@@ -209,15 +209,15 @@ describe('storage manager', function () {
|
|||||||
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
||||||
|
|
||||||
/** Root key should now be wrapped */
|
/** Root key should now be wrapped */
|
||||||
expect(await this.application.protocolService.rootKeyEncryption.getWrappedRootKey()).to.be.ok
|
expect(await this.application.encryptionService.rootKeyManager.getWrappedRootKey()).to.be.ok
|
||||||
|
|
||||||
const accountKey = await this.application.protocolService.getRootKey()
|
const accountKey = await this.application.encryptionService.getRootKey()
|
||||||
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
||||||
const passcodeKey = await this.application.protocolService.computeWrappingKey(passcode)
|
const passcodeKey = await this.application.encryptionService.computeWrappingKey(passcode)
|
||||||
const wrappedRootKey = await this.application.protocolService.rootKeyEncryption.getWrappedRootKey()
|
const wrappedRootKey = await this.application.encryptionService.rootKeyManager.getWrappedRootKey()
|
||||||
/** Expect that we can decrypt wrapped root key with passcode key */
|
/** Expect that we can decrypt wrapped root key with passcode key */
|
||||||
const payload = new EncryptedPayload(wrappedRootKey)
|
const payload = new EncryptedPayload(wrappedRootKey)
|
||||||
const decrypted = await this.application.protocolService.decryptSplitSingle({
|
const decrypted = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesRootKey: {
|
usesRootKey: {
|
||||||
items: [payload],
|
items: [payload],
|
||||||
key: passcodeKey,
|
key: passcodeKey,
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ describe('offline syncing', () => {
|
|||||||
|
|
||||||
const payload = rawPayloads2[0]
|
const payload = rawPayloads2[0]
|
||||||
expect(typeof payload.content).to.equal('string')
|
expect(typeof payload.content).to.equal('string')
|
||||||
expect(payload.content.startsWith(this.application.protocolService.getLatestVersion())).to.equal(true)
|
expect(payload.content.startsWith(this.application.encryptionService.getLatestVersion())).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('signing out while offline should succeed', async function () {
|
it('signing out while offline should succeed', async function () {
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ describe('online syncing', function () {
|
|||||||
await this.application.syncService.sync(syncOptions)
|
await this.application.syncService.sync(syncOptions)
|
||||||
|
|
||||||
const encrypted = CreateEncryptedServerSyncPushPayload(
|
const encrypted = CreateEncryptedServerSyncPushPayload(
|
||||||
await this.application.protocolService.encryptSplitSingle({
|
await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note.payloadRepresentation()],
|
items: [note.payloadRepresentation()],
|
||||||
},
|
},
|
||||||
@@ -295,7 +295,7 @@ describe('online syncing', function () {
|
|||||||
|
|
||||||
expect(typeof mappedItem.content).to.equal('string')
|
expect(typeof mappedItem.content).to.equal('string')
|
||||||
|
|
||||||
const decryptedPayload = await this.application.protocolService.decryptSplitSingle({
|
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [errorred],
|
items: [errorred],
|
||||||
},
|
},
|
||||||
@@ -515,7 +515,7 @@ describe('online syncing', function () {
|
|||||||
|
|
||||||
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
||||||
|
|
||||||
const decryptionResults = await this.application.protocolService.decryptSplit(keyedSplit)
|
const decryptionResults = await this.application.encryptionService.decryptSplit(keyedSplit)
|
||||||
|
|
||||||
await this.application.mutator.emitItemsFromPayloads(decryptionResults, PayloadEmitSource.LocalChanged)
|
await this.application.mutator.emitItemsFromPayloads(decryptionResults, PayloadEmitSource.LocalChanged)
|
||||||
|
|
||||||
@@ -918,7 +918,7 @@ describe('online syncing', function () {
|
|||||||
const lastSyncBegan = note.lastSyncBegan
|
const lastSyncBegan = note.lastSyncBegan
|
||||||
const lastSyncEnd = note.lastSyncEnd
|
const lastSyncEnd = note.lastSyncEnd
|
||||||
|
|
||||||
const encrypted = await this.application.protocolService.encryptSplitSingle({
|
const encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||||
usesItemsKeyWithKeyLookup: {
|
usesItemsKeyWithKeyLookup: {
|
||||||
items: [note.payload],
|
items: [note.payload],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ describe('upgrading', () => {
|
|||||||
version: oldVersion,
|
version: oldVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
oldVersion,
|
oldVersion,
|
||||||
)
|
)
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||||
|
|
||||||
this.application.setLaunchCallback({
|
this.application.setLaunchCallback({
|
||||||
receiveChallenge: this.receiveChallenge,
|
receiveChallenge: this.receiveChallenge,
|
||||||
@@ -104,15 +104,15 @@ describe('upgrading', () => {
|
|||||||
const result = await this.application.upgradeProtocolVersion()
|
const result = await this.application.upgradeProtocolVersion()
|
||||||
expect(result).to.deep.equal({ success: true })
|
expect(result).to.deep.equal({ success: true })
|
||||||
|
|
||||||
const wrappedRootKey = await this.application.protocolService.rootKeyEncryption.getWrappedRootKey()
|
const wrappedRootKey = await this.application.encryptionService.rootKeyManager.getWrappedRootKey()
|
||||||
const payload = new EncryptedPayload(wrappedRootKey)
|
const payload = new EncryptedPayload(wrappedRootKey)
|
||||||
expect(payload.version).to.equal(newVersion)
|
expect(payload.version).to.equal(newVersion)
|
||||||
|
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
newVersion,
|
newVersion,
|
||||||
)
|
)
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(newVersion)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(newVersion)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(newVersion)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(newVersion)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediately logging out ensures we don't rely on subsequent
|
* Immediately logging out ensures we don't rely on subsequent
|
||||||
@@ -172,7 +172,7 @@ describe('upgrading', () => {
|
|||||||
|
|
||||||
it('protocol version should be upgraded on password change', async function () {
|
it('protocol version should be upgraded on password change', async function () {
|
||||||
/** Delete default items key that is created on launch */
|
/** Delete default items key that is created on launch */
|
||||||
const itemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
await this.application.mutator.setItemToBeDeleted(itemsKey)
|
await this.application.mutator.setItemToBeDeleted(itemsKey)
|
||||||
expect(Uuids(this.application.itemManager.getDisplayableItemsKeys()).includes(itemsKey.uuid)).to.equal(false)
|
expect(Uuids(this.application.itemManager.getDisplayableItemsKeys()).includes(itemsKey.uuid)).to.equal(false)
|
||||||
|
|
||||||
@@ -188,8 +188,8 @@ describe('upgrading', () => {
|
|||||||
|
|
||||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||||
|
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(ProtocolVersion.V003)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(ProtocolVersion.V003)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(ProtocolVersion.V003)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(ProtocolVersion.V003)
|
||||||
|
|
||||||
/** Ensure note is encrypted with 003 */
|
/** Ensure note is encrypted with 003 */
|
||||||
const notePayloads = await Factory.getStoragePayloadsOfType(this.application, ContentType.Note)
|
const notePayloads = await Factory.getStoragePayloadsOfType(this.application, ContentType.Note)
|
||||||
@@ -199,11 +199,11 @@ describe('upgrading', () => {
|
|||||||
const { error } = await this.application.changePassword(this.password, 'foobarfoo')
|
const { error } = await this.application.changePassword(this.password, 'foobarfoo')
|
||||||
expect(error).to.not.exist
|
expect(error).to.not.exist
|
||||||
|
|
||||||
const latestVersion = this.application.protocolService.getLatestVersion()
|
const latestVersion = this.application.encryptionService.getLatestVersion()
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(latestVersion)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(latestVersion)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(latestVersion)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(latestVersion)
|
||||||
|
|
||||||
const defaultItemsKey = await this.application.protocolService.getSureDefaultItemsKey()
|
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||||
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
||||||
|
|
||||||
/** After change, note should now be encrypted with latest protocol version */
|
/** After change, note should now be encrypted with latest protocol version */
|
||||||
@@ -247,19 +247,19 @@ describe('upgrading', () => {
|
|||||||
this.application.setLaunchCallback({
|
this.application.setLaunchCallback({
|
||||||
receiveChallenge: this.receiveChallenge,
|
receiveChallenge: this.receiveChallenge,
|
||||||
})
|
})
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
oldVersion,
|
oldVersion,
|
||||||
)
|
)
|
||||||
const errors = await this.application.upgradeProtocolVersion()
|
const errors = await this.application.upgradeProtocolVersion()
|
||||||
expect(errors).to.not.be.empty
|
expect(errors).to.not.be.empty
|
||||||
|
|
||||||
/** Ensure we're still on 003 */
|
/** Ensure we're still on 003 */
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
oldVersion,
|
oldVersion,
|
||||||
)
|
)
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||||
expect((await this.application.protocolService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('rolls back the local protocol upgrade if the server responds with an error', async function () {
|
it('rolls back the local protocol upgrade if the server responds with an error', async function () {
|
||||||
@@ -268,19 +268,19 @@ describe('upgrading', () => {
|
|||||||
this.application.setLaunchCallback({
|
this.application.setLaunchCallback({
|
||||||
receiveChallenge: this.receiveChallenge,
|
receiveChallenge: this.receiveChallenge,
|
||||||
})
|
})
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
oldVersion,
|
oldVersion,
|
||||||
)
|
)
|
||||||
const errors = await this.application.upgradeProtocolVersion()
|
const errors = await this.application.upgradeProtocolVersion()
|
||||||
expect(errors).to.not.be.empty
|
expect(errors).to.not.be.empty
|
||||||
|
|
||||||
/** Ensure we're still on 003 */
|
/** Ensure we're still on 003 */
|
||||||
expect((await this.application.protocolService.rootKeyEncryption.getRootKeyWrapperKeyParams()).version).to.equal(
|
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||||
oldVersion,
|
oldVersion,
|
||||||
)
|
)
|
||||||
expect((await this.application.protocolService.getRootKeyParams()).version).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||||
expect((await this.application.protocolService.getRootKey()).keyVersion).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||||
expect((await this.application.protocolService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
expect((await this.application.encryptionService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const DataBackups = ({ application, viewControllerManager }: Props) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application.protocolService.supportedVersions().includes(version)) {
|
if (application.encryptionService.supportedVersions().includes(version)) {
|
||||||
await performImport(data)
|
await performImport(data)
|
||||||
} else {
|
} else {
|
||||||
setIsImportDataLoading(false)
|
setIsImportDataLoading(false)
|
||||||
|
|||||||
Reference in New Issue
Block a user