feat(encryption): refactor circular dependencies on services

This commit is contained in:
Karol Sójko
2022-08-05 11:59:02 +02:00
parent 183f68c9c1
commit ffb2193924
40 changed files with 502 additions and 380 deletions

View File

@@ -39,7 +39,6 @@
"@standardnotes/common": "^1.23.1",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/services": "workspace:*",
"@standardnotes/sncrypto-common": "workspace:*",
"@standardnotes/utils": "workspace:*",
"reflect-metadata": "^0.1.13"

View File

@@ -1,4 +1,10 @@
import * as Models from '@standardnotes/models'
import {
DecryptedPayloadInterface,
ItemsKeyInterface,
RootKeyInterface,
ItemContent,
EncryptedPayloadInterface,
} from '@standardnotes/models'
import {
DecryptedParameters,
EncryptedParameters,
@@ -9,8 +15,8 @@ import { isAsyncOperator } from './Functions'
import { OperatorManager } from './OperatorManager'
export async function encryptPayload(
payload: Models.DecryptedPayloadInterface,
key: Models.ItemsKeyInterface | Models.RootKeyInterface,
payload: DecryptedPayloadInterface,
key: ItemsKeyInterface | RootKeyInterface,
operatorManager: OperatorManager,
): Promise<EncryptedParameters> {
const operator = operatorManager.operatorForVersion(key.keyVersion)
@@ -29,9 +35,9 @@ export async function encryptPayload(
return encryptionParameters
}
export async function decryptPayload<C extends Models.ItemContent = Models.ItemContent>(
payload: Models.EncryptedPayloadInterface,
key: Models.ItemsKeyInterface | Models.RootKeyInterface,
export async function decryptPayload<C extends ItemContent = ItemContent>(
payload: EncryptedPayloadInterface,
key: ItemsKeyInterface | RootKeyInterface,
operatorManager: OperatorManager,
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
const operator = operatorManager.operatorForVersion(payload.version)

View File

@@ -0,0 +1,3 @@
export enum RootKeyServiceEvent {
RootKeyStatusChanged = 'RootKeyStatusChanged',
}

View File

@@ -0,0 +1,22 @@
import { ProtocolVersion } from '@standardnotes/common';
import { EncryptedPayloadInterface, ItemContent } from '@standardnotes/models';
export declare type EncryptedParameters = {
uuid: string;
content: string;
items_key_id: string | undefined;
enc_item_key: string;
version: ProtocolVersion;
/** @deprecated */
auth_hash?: string;
};
export declare type DecryptedParameters<C extends ItemContent = ItemContent> = {
uuid: string;
content: C;
};
export declare type ErrorDecryptingParameters = {
uuid: string;
errorDecrypting: true;
waitingForKey?: boolean;
};
export declare function isErrorDecryptingParameters(x: EncryptedParameters | DecryptedParameters | ErrorDecryptingParameters): x is ErrorDecryptingParameters;
export declare function encryptedParametersFromPayload(payload: EncryptedPayloadInterface): EncryptedParameters;

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encryptedParametersFromPayload = exports.isErrorDecryptingParameters = void 0;
function isErrorDecryptingParameters(x) {
return x.errorDecrypting;
}
exports.isErrorDecryptingParameters = isErrorDecryptingParameters;
function encryptedParametersFromPayload(payload) {
return {
uuid: payload.uuid,
content: payload.content,
items_key_id: payload.items_key_id,
enc_item_key: payload.enc_item_key,
version: payload.version,
auth_hash: payload.auth_hash,
};
}
exports.encryptedParametersFromPayload = encryptedParametersFromPayload;

View File

@@ -1,5 +1,4 @@
export * from './Algorithm'
export * from './Backups/BackupFileDecryptor'
export * from './Backups/BackupFileType'
export * from './Keys/ItemsKey/ItemsKey'
export * from './Keys/ItemsKey/ItemsKeyMutator'
@@ -10,7 +9,6 @@ export * from './Keys/RootKey/ProtocolVersionForKeyParams'
export * from './Keys/RootKey/RootKey'
export * from './Keys/RootKey/RootKeyParams'
export * from './Keys/RootKey/ValidKeyParamsKeys'
export * from './Keys/Utils/DecryptItemsKey'
export * from './Keys/Utils/KeyRecoveryStrings'
export * from './Operator/001/Operator001'
export * from './Operator/002/Operator002'
@@ -21,11 +19,9 @@ export * from './Operator/Operator'
export * from './Operator/OperatorManager'
export * from './Operator/OperatorWrapper'
export * from './Service/Encryption/EncryptionProvider'
export * from './Service/Encryption/EncryptionService'
export * from './Service/Functions'
export * from './Service/Items/ItemsEncryption'
export * from './Service/RootKey/KeyMode'
export * from './Service/RootKey/RootKeyEncryption'
export * from './Service/RootKey/RootKeyServiceEvent'
export * from './Split/AbstractKeySplit'
export * from './Split/EncryptionSplit'
export * from './Split/EncryptionTypeSplit'

View File

@@ -5,4 +5,3 @@ export * from './Streaming/StreamingReader'
export * from './Streaming/StreamingSaver'
export * from './Streaming/StreamingApi'
export * from './utils'
export * from './Cache/FileMemoryCache'

View File

@@ -1,5 +1,4 @@
import { EncryptedBytes } from '@standardnotes/files'
import { EncryptedBytes } from '../Types/EncryptedBytes'
import { FileMemoryCache } from './FileMemoryCache'
describe('file memory cache', () => {

View File

@@ -1,6 +1,7 @@
import { removeFromArray } from '@standardnotes/utils'
import { Uuid } from '@standardnotes/common'
import { EncryptedBytes } from '@standardnotes/files'
import { EncryptedBytes } from '../Types/EncryptedBytes'
export class FileMemoryCache {
private cache: Record<Uuid, EncryptedBytes> = {}

View File

@@ -5,6 +5,7 @@ export * from './Api/FileSystemApi'
export * from './Api/FileSystemNoSelection'
export * from './Api/FileSystemResult'
export * from './Api/FilesApiInterface'
export * from './Cache/FileMemoryCache'
export * from './Chunker/ByteChunker'
export * from './Chunker/OnChunkCallback'
export * from './Chunker/OrderedByteChunker'

View File

@@ -25,6 +25,7 @@
"dependencies": {
"@standardnotes/auth": "^3.19.4",
"@standardnotes/common": "^1.30.0",
"@standardnotes/encryption": "workspace:^",
"@standardnotes/files": "workspace:^",
"@standardnotes/models": "workspace:^",
"@standardnotes/responses": "workspace:*",

View File

@@ -2,8 +2,7 @@ import { ContentType, Uuid } from '@standardnotes/common'
import { EncryptionProvider } from '@standardnotes/encryption'
import { PayloadEmitSource, FileItem, CreateEncryptedBackupFileContextPayload } from '@standardnotes/models'
import { ClientDisplayableError } from '@standardnotes/responses'
import { FileBackupMetadataFile, FileBackupsDevice, FileBackupsMapping } from '../Device/FileBackupsDevice'
import { FilesApiInterface } from '@standardnotes/files'
import { FilesApiInterface, FileBackupMetadataFile, FileBackupsDevice, FileBackupsMapping } from '@standardnotes/files'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { AbstractService } from '../Service/AbstractService'

View File

@@ -1,5 +1,5 @@
import { DecryptedTransferPayload } from '@standardnotes/models'
import { FileBackupsDevice } from './FileBackupsDevice'
import { FileBackupsDevice } from '@standardnotes/files'
export interface WebClientRequiresDesktopMethods extends FileBackupsDevice {
localBackupsCount(): Promise<number>

View File

@@ -5,6 +5,15 @@ import {
leftVersionGreaterThanOrEqualToRight,
ProtocolVersion,
} from '@standardnotes/common'
import {
BackupFileType,
ContentTypeUsesRootKeyEncryption,
CreateAnyKeyParams,
isItemsKey,
SNItemsKey,
SNRootKey,
SNRootKeyParams,
} from '@standardnotes/encryption'
import {
BackupFile,
CreateDecryptedItemFromPayload,
@@ -23,13 +32,7 @@ import {
} from '@standardnotes/models'
import { ClientDisplayableError } from '@standardnotes/responses'
import { extendArray } from '@standardnotes/utils'
import { isItemsKey, SNItemsKey } from '../Keys/ItemsKey/ItemsKey'
import { ContentTypeUsesRootKeyEncryption } from '../Keys/RootKey/Functions'
import { CreateAnyKeyParams } from '../Keys/RootKey/KeyParamsFunctions'
import { SNRootKey } from '../Keys/RootKey/RootKey'
import { SNRootKeyParams } from '../Keys/RootKey/RootKeyParams'
import { EncryptionService } from '../Service/Encryption/EncryptionService'
import { BackupFileType } from './BackupFileType'
import { EncryptionService } from './EncryptionService'
export async function DecryptBackupFile(
file: BackupFile,

View File

@@ -1,53 +1,77 @@
import * as Common from '@standardnotes/common'
import * as Models from '@standardnotes/models'
import {
CreateAnyKeyParams,
CreateEncryptionSplitWithKeyLookup,
DecryptedParameters,
EncryptedParameters,
encryptedParametersFromPayload,
EncryptionProvider,
ErrorDecryptingParameters,
findDefaultItemsKey,
FindPayloadInDecryptionSplit,
FindPayloadInEncryptionSplit,
isErrorDecryptingParameters,
ItemAuthenticatedData,
KeyedDecryptionSplit,
KeyedEncryptionSplit,
KeyMode,
LegacyAttachedData,
OperatorManager,
RootKeyEncryptedAuthenticatedData,
RootKeyServiceEvent,
SNRootKey,
SNRootKeyParams,
SplitPayloadsByEncryptionType,
V001Algorithm,
V002Algorithm,
} from '@standardnotes/encryption'
import {
BackupFile,
CreateDecryptedBackupFileContextPayload,
CreateEncryptedBackupFileContextPayload,
DecryptedPayload,
DecryptedPayloadInterface,
EncryptedPayload,
EncryptedPayloadInterface,
isDecryptedPayload,
isEncryptedPayload,
ItemContent,
ItemsKeyInterface,
RootKeyInterface,
} from '@standardnotes/models'
import { ClientDisplayableError } from '@standardnotes/responses'
import * as Services from '@standardnotes/services'
import { DiagnosticInfo } from '@standardnotes/services'
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
import * as Utils from '@standardnotes/utils'
import { isNotUndefined } from '@standardnotes/utils'
import { V001Algorithm, V002Algorithm } from '../../Algorithm'
import { DecryptBackupFile } from '../../Backups/BackupFileDecryptor'
import { CreateAnyKeyParams } from '../../Keys/RootKey/KeyParamsFunctions'
import { SNRootKey } from '../../Keys/RootKey/RootKey'
import { SNRootKeyParams } from '../../Keys/RootKey/RootKeyParams'
import { OperatorManager } from '../../Operator/OperatorManager'
import {
CreateEncryptionSplitWithKeyLookup,
FindPayloadInDecryptionSplit,
FindPayloadInEncryptionSplit,
} from '../../Split/EncryptionSplit'
import { SplitPayloadsByEncryptionType } from '../../Split/Functions'
import { KeyedDecryptionSplit } from '../../Split/KeyedDecryptionSplit'
import { KeyedEncryptionSplit } from '../../Split/KeyedEncryptionSplit'
extendArray,
isNotUndefined,
isNullOrUndefined,
isReactNativeEnvironment,
isWebCryptoAvailable,
UuidGenerator,
} from '@standardnotes/utils'
import {
DecryptedParameters,
EncryptedParameters,
encryptedParametersFromPayload,
ErrorDecryptingParameters,
isErrorDecryptingParameters,
} from '../../Types/EncryptedParameters'
import { ItemAuthenticatedData } from '../../Types/ItemAuthenticatedData'
import { LegacyAttachedData } from '../../Types/LegacyAttachedData'
import { RootKeyEncryptedAuthenticatedData } from '../../Types/RootKeyEncryptedAuthenticatedData'
import { findDefaultItemsKey } from '../Functions'
import { ItemsEncryptionService } from '../Items/ItemsEncryption'
import { KeyMode } from '../RootKey/KeyMode'
import * as RootKeyEncryption from '../RootKey/RootKeyEncryption'
import { EncryptionProvider } from './EncryptionProvider'
AnyKeyParamsContent,
ApplicationIdentifier,
compareVersions,
ContentType,
isVersionLessThanOrEqualTo,
KeyParamsOrigination,
ProtocolVersion,
ProtocolVersionLastNonrootItemsKey,
ProtocolVersionLatest,
} from '@standardnotes/common'
export enum EncryptionServiceEvent {
RootKeyStatusChanged = 'RootKeyStatusChanged',
}
import { AbstractService } from '../Service/AbstractService'
import { ItemsEncryptionService } from './ItemsEncryption'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { PayloadManagerInterface } from '../Payloads/PayloadManagerInterface'
import { DeviceInterface } from '../Device/DeviceInterface'
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { SyncEvent } from '../Event/SyncEvent'
import { DiagnosticInfo } from '../Diagnostics/ServiceDiagnostics'
import { RootKeyEncryptionService } from './RootKeyEncryption'
import { DecryptBackupFile } from './BackupFileDecryptor'
import { EncryptionServiceEvent } from './EncryptionServiceEvent'
/**
* The encryption service is responsible for the encryption and decryption of payloads, and
@@ -76,20 +100,20 @@ export enum EncryptionServiceEvent {
* It also exposes public methods that allows consumers to retrieve an items key
* for a particular payload, and also retrieve all available items keys.
*/
export class EncryptionService extends Services.AbstractService<EncryptionServiceEvent> implements EncryptionProvider {
export class EncryptionService extends AbstractService<EncryptionServiceEvent> implements EncryptionProvider {
private operatorManager: OperatorManager
private readonly itemsEncryption: ItemsEncryptionService
private readonly rootKeyEncryption: RootKeyEncryption.RootKeyEncryptionService
private readonly rootKeyEncryption: RootKeyEncryptionService
private rootKeyObserverDisposer: () => void
constructor(
private itemManager: Services.ItemManagerInterface,
private payloadManager: Services.PayloadManagerInterface,
public deviceInterface: Services.DeviceInterface,
private storageService: Services.StorageServiceInterface,
private identifier: Common.ApplicationIdentifier,
private itemManager: ItemManagerInterface,
private payloadManager: PayloadManagerInterface,
public deviceInterface: DeviceInterface,
private storageService: StorageServiceInterface,
private identifier: ApplicationIdentifier,
public crypto: PureCryptoInterface,
protected override internalEventBus: Services.InternalEventBusInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
this.crypto = crypto
@@ -104,7 +128,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
internalEventBus,
)
this.rootKeyEncryption = new RootKeyEncryption.RootKeyEncryptionService(
this.rootKeyEncryption = new RootKeyEncryptionService(
this.itemManager,
this.operatorManager,
this.deviceInterface,
@@ -114,12 +138,12 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
)
this.rootKeyObserverDisposer = this.rootKeyEncryption.addEventObserver((event) => {
this.itemsEncryption.userVersion = this.getUserVersion()
if (event === RootKeyEncryption.RootKeyServiceEvent.RootKeyStatusChanged) {
if (event === RootKeyServiceEvent.RootKeyStatusChanged) {
void this.notifyEvent(EncryptionServiceEvent.RootKeyStatusChanged)
}
})
Utils.UuidGenerator.SetGenerator(this.crypto.generateUUID)
UuidGenerator.SetGenerator(this.crypto.generateUUID)
}
public override deinit(): void {
@@ -160,7 +184,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
}
public getLatestVersion() {
return Common.ProtocolVersionLatest
return ProtocolVersionLatest
}
public hasAccount() {
@@ -171,7 +195,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return this.rootKeyEncryption.hasRootKeyEncryptionSource()
}
public getUserVersion(): Common.ProtocolVersion | undefined {
public getUserVersion(): ProtocolVersion | undefined {
return this.rootKeyEncryption.getUserVersion()
}
@@ -181,8 +205,8 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return accountUpgradeAvailable || passcodeUpgradeAvailable
}
public getSureDefaultItemsKey(): Models.ItemsKeyInterface {
return this.itemsEncryption.getDefaultItemsKey() as Models.ItemsKeyInterface
public getSureDefaultItemsKey(): ItemsKeyInterface {
return this.itemsEncryption.getDefaultItemsKey() as ItemsKeyInterface
}
async repersistAllItems(): Promise<void> {
@@ -201,22 +225,22 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
await this.itemsEncryption.decryptErroredPayloads()
}
public itemsKeyForPayload(payload: Models.EncryptedPayloadInterface): Models.ItemsKeyInterface | undefined {
public itemsKeyForPayload(payload: EncryptedPayloadInterface): ItemsKeyInterface | undefined {
return this.itemsEncryption.itemsKeyForPayload(payload)
}
public defaultItemsKeyForItemVersion(
version: Common.ProtocolVersion,
fromKeys?: Models.ItemsKeyInterface[],
): Models.ItemsKeyInterface | undefined {
version: ProtocolVersion,
fromKeys?: ItemsKeyInterface[],
): ItemsKeyInterface | undefined {
return this.itemsEncryption.defaultItemsKeyForItemVersion(version, fromKeys)
}
public async encryptSplitSingle(split: KeyedEncryptionSplit): Promise<Models.EncryptedPayloadInterface> {
public async encryptSplitSingle(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface> {
return (await this.encryptSplit(split))[0]
}
public async encryptSplit(split: KeyedEncryptionSplit): Promise<Models.EncryptedPayloadInterface[]> {
public async encryptSplit(split: KeyedEncryptionSplit): Promise<EncryptedPayloadInterface[]> {
const allEncryptedParams: EncryptedParameters[] = []
if (split.usesRootKey) {
@@ -224,7 +248,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
split.usesRootKey.items,
split.usesRootKey.key,
)
Utils.extendArray(allEncryptedParams, rootKeyEncrypted)
extendArray(allEncryptedParams, rootKeyEncrypted)
}
if (split.usesItemsKey) {
@@ -232,21 +256,21 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
split.usesItemsKey.items,
split.usesItemsKey.key,
)
Utils.extendArray(allEncryptedParams, itemsKeyEncrypted)
extendArray(allEncryptedParams, itemsKeyEncrypted)
}
if (split.usesRootKeyWithKeyLookup) {
const rootKeyEncrypted = await this.rootKeyEncryption.encryptPayloadsWithKeyLookup(
split.usesRootKeyWithKeyLookup.items,
)
Utils.extendArray(allEncryptedParams, rootKeyEncrypted)
extendArray(allEncryptedParams, rootKeyEncrypted)
}
if (split.usesItemsKeyWithKeyLookup) {
const itemsKeyEncrypted = await this.itemsEncryption.encryptPayloadsWithKeyLookup(
split.usesItemsKeyWithKeyLookup.items,
)
Utils.extendArray(allEncryptedParams, itemsKeyEncrypted)
extendArray(allEncryptedParams, itemsKeyEncrypted)
}
const packagedEncrypted = allEncryptedParams.map((encryptedParams) => {
@@ -263,17 +287,17 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
}
public async decryptSplitSingle<
C extends Models.ItemContent = Models.ItemContent,
P extends Models.DecryptedPayloadInterface<C> = Models.DecryptedPayloadInterface<C>,
>(split: KeyedDecryptionSplit): Promise<P | Models.EncryptedPayloadInterface> {
C extends ItemContent = ItemContent,
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
>(split: KeyedDecryptionSplit): Promise<P | EncryptedPayloadInterface> {
const results = await this.decryptSplit<C, P>(split)
return results[0]
}
public async decryptSplit<
C extends Models.ItemContent = Models.ItemContent,
P extends Models.DecryptedPayloadInterface<C> = Models.DecryptedPayloadInterface<C>,
>(split: KeyedDecryptionSplit): Promise<(P | Models.EncryptedPayloadInterface)[]> {
C extends ItemContent = ItemContent,
P extends DecryptedPayloadInterface<C> = DecryptedPayloadInterface<C>,
>(split: KeyedDecryptionSplit): Promise<(P | EncryptedPayloadInterface)[]> {
const resultParams: (DecryptedParameters<C> | ErrorDecryptingParameters)[] = []
if (split.usesRootKey) {
@@ -281,14 +305,14 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
split.usesRootKey.items,
split.usesRootKey.key,
)
Utils.extendArray(resultParams, rootKeyDecrypted)
extendArray(resultParams, rootKeyDecrypted)
}
if (split.usesRootKeyWithKeyLookup) {
const rootKeyDecrypted = await this.rootKeyEncryption.decryptPayloadsWithKeyLookup<C>(
split.usesRootKeyWithKeyLookup.items,
)
Utils.extendArray(resultParams, rootKeyDecrypted)
extendArray(resultParams, rootKeyDecrypted)
}
if (split.usesItemsKey) {
@@ -296,26 +320,26 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
split.usesItemsKey.items,
split.usesItemsKey.key,
)
Utils.extendArray(resultParams, itemsKeyDecrypted)
extendArray(resultParams, itemsKeyDecrypted)
}
if (split.usesItemsKeyWithKeyLookup) {
const itemsKeyDecrypted = await this.itemsEncryption.decryptPayloadsWithKeyLookup<C>(
split.usesItemsKeyWithKeyLookup.items,
)
Utils.extendArray(resultParams, itemsKeyDecrypted)
extendArray(resultParams, itemsKeyDecrypted)
}
const packagedResults = resultParams.map((params) => {
const original = FindPayloadInDecryptionSplit(params.uuid, split)
if (isErrorDecryptingParameters(params)) {
return new Models.EncryptedPayload({
return new EncryptedPayload({
...original.ejected(),
...params,
})
} else {
return new Models.DecryptedPayload<C>({
return new DecryptedPayload<C>({
...original.ejected(),
...params,
}) as P
@@ -333,7 +357,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
if (!userVersion) {
return false
}
return userVersion !== Common.ProtocolVersionLatest
return userVersion !== ProtocolVersionLatest
}
/**
@@ -354,29 +378,24 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
*
* Versions 004 and above are always supported.
*/
if (Common.compareVersions(keyParams.version, Common.ProtocolVersion.V004) >= 0) {
if (compareVersions(keyParams.version, ProtocolVersion.V004) >= 0) {
/* keyParams.version >= 004 */
return true
} else {
return !!Utils.isWebCryptoAvailable() || Utils.isReactNativeEnvironment()
return !!isWebCryptoAvailable() || isReactNativeEnvironment()
}
}
public supportedVersions(): Common.ProtocolVersion[] {
return [
Common.ProtocolVersion.V001,
Common.ProtocolVersion.V002,
Common.ProtocolVersion.V003,
Common.ProtocolVersion.V004,
]
public supportedVersions(): ProtocolVersion[] {
return [ProtocolVersion.V001, ProtocolVersion.V002, ProtocolVersion.V003, ProtocolVersion.V004]
}
/**
* Determines whether the input version is greater than the latest supported library version.
*/
public isVersionNewerThanLibraryVersion(version: Common.ProtocolVersion) {
const libraryVersion = Common.ProtocolVersionLatest
return Common.compareVersions(version, libraryVersion) === 1
public isVersionNewerThanLibraryVersion(version: ProtocolVersion) {
const libraryVersion = ProtocolVersionLatest
return compareVersions(version, libraryVersion) === 1
}
/**
@@ -384,13 +403,13 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
* This function returns the client-enforced minimum cost, to prevent the server from
* overwhelmingly under-reporting the cost.
*/
public costMinimumForVersion(version: Common.ProtocolVersion) {
if (Common.compareVersions(version, Common.ProtocolVersion.V003) >= 0) {
public costMinimumForVersion(version: ProtocolVersion) {
if (compareVersions(version, ProtocolVersion.V003) >= 0) {
throw 'Cost minimums only apply to versions <= 002'
}
if (version === Common.ProtocolVersion.V001) {
if (version === ProtocolVersion.V001) {
return V001Algorithm.PbkdfMinCost
} else if (version === Common.ProtocolVersion.V002) {
} else if (version === ProtocolVersion.V002) {
return V002Algorithm.PbkdfMinCost
} else {
throw `Invalid version for cost minimum: ${version}`
@@ -411,8 +430,8 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
public async createRootKey(
identifier: string,
password: string,
origination: Common.KeyParamsOrigination,
version?: Common.ProtocolVersion,
origination: KeyParamsOrigination,
version?: ProtocolVersion,
) {
return this.rootKeyEncryption.createRootKey(identifier, password, origination, version)
}
@@ -420,9 +439,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
public async decryptBackupFile(
file: BackupFile,
password?: string,
): Promise<
ClientDisplayableError | (Models.EncryptedPayloadInterface | Models.DecryptedPayloadInterface<Models.ItemContent>)[]
> {
): Promise<ClientDisplayableError | (EncryptedPayloadInterface | DecryptedPayloadInterface<ItemContent>)[]> {
const result = await DecryptBackupFile(file, this, password)
return result
}
@@ -431,7 +448,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
* Creates a key params object from a raw object
* @param keyParams - The raw key params object to create a KeyParams object from
*/
public createKeyParams(keyParams: Common.AnyKeyParamsContent) {
public createKeyParams(keyParams: AnyKeyParamsContent) {
return CreateAnyKeyParams(keyParams)
}
@@ -447,7 +464,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
const ejected = result.map((payload) => CreateEncryptedBackupFileContextPayload(payload))
const data: BackupFile = {
version: Common.ProtocolVersionLatest,
version: ProtocolVersionLatest,
items: ejected,
}
@@ -457,12 +474,10 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
}
public createDecryptedBackupFile(): BackupFile {
const payloads = this.payloadManager.nonDeletedItems.filter(
(item) => item.content_type !== Common.ContentType.ItemsKey,
)
const payloads = this.payloadManager.nonDeletedItems.filter((item) => item.content_type !== ContentType.ItemsKey)
const data: BackupFile = {
version: Common.ProtocolVersionLatest,
version: ProtocolVersionLatest,
items: payloads
.map((payload) => {
if (isDecryptedPayload(payload)) {
@@ -557,7 +572,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
}
public getEmbeddedPayloadAuthenticatedData(
payload: Models.EncryptedPayloadInterface,
payload: EncryptedPayloadInterface,
): RootKeyEncryptedAuthenticatedData | ItemAuthenticatedData | LegacyAttachedData | undefined {
const version = payload.version
if (!version) {
@@ -569,12 +584,12 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
}
/** Returns the key params attached to this key's encrypted payload */
public getKeyEmbeddedKeyParams(key: Models.EncryptedPayloadInterface): SNRootKeyParams | undefined {
public getKeyEmbeddedKeyParams(key: EncryptedPayloadInterface): SNRootKeyParams | undefined {
const authenticatedData = this.getEmbeddedPayloadAuthenticatedData(key)
if (!authenticatedData) {
return undefined
}
if (Common.isVersionLessThanOrEqualTo(key.version, Common.ProtocolVersion.V003)) {
if (isVersionLessThanOrEqualTo(key.version, ProtocolVersion.V003)) {
const rawKeyParams = authenticatedData as LegacyAttachedData
return this.createKeyParams(rawKeyParams)
} else {
@@ -597,7 +612,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return false
}
if (Common.compareVersions(rootKey.keyVersion, Common.ProtocolVersionLastNonrootItemsKey) > 0) {
if (compareVersions(rootKey.keyVersion, ProtocolVersionLastNonrootItemsKey) > 0) {
/** Is >= 004, not needed */
return false
}
@@ -616,7 +631,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return defaultItemsKey.itemsKey !== rootKey.itemsKey
}
public async createNewDefaultItemsKey(): Promise<Models.ItemsKeyInterface> {
public async createNewDefaultItemsKey(): Promise<ItemsKeyInterface> {
return this.rootKeyEncryption.createNewDefaultItemsKey()
}
@@ -625,11 +640,11 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return rootKey ? rootKey.keyParams.createdDate : undefined
}
public async onSyncEvent(eventName: Services.SyncEvent) {
if (eventName === Services.SyncEvent.SyncCompletedWithAllItemsUploaded) {
public async onSyncEvent(eventName: SyncEvent) {
if (eventName === SyncEvent.SyncCompletedWithAllItemsUploaded) {
await this.handleFullSyncCompletion()
}
if (eventName === Services.SyncEvent.DownloadFirstSyncCompleted) {
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
await this.handleDownloadFirstSyncCompletion()
}
}
@@ -665,7 +680,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
return key.isDefault
})
const hasSyncedItemsKey = !Utils.isNullOrUndefined(defaultSyncedKey)
const hasSyncedItemsKey = !isNullOrUndefined(defaultSyncedKey)
if (hasSyncedItemsKey) {
/** Delete all never synced keys */
await this.itemManager.setItemsToBeDeleted(neverSyncedKeys)
@@ -695,7 +710,7 @@ export class EncryptionService extends Services.AbstractService<EncryptionServic
/** If we do not have an items key for our current account version, create one */
const userVersion = this.getUserVersion()
const accountVersionedKey = this.itemsEncryption.getItemsKeys().find((key) => key.keyVersion === userVersion)
if (Utils.isNullOrUndefined(accountVersionedKey)) {
if (isNullOrUndefined(accountVersionedKey)) {
await this.rootKeyEncryption.createNewDefaultItemsKey()
}

View File

@@ -0,0 +1,3 @@
export enum EncryptionServiceEvent {
RootKeyStatusChanged = 'RootKeyStatusChanged',
}

View File

@@ -5,15 +5,11 @@ import {
ItemsKeyContent,
RootKeyInterface,
} from '@standardnotes/models'
import {
ChallengePrompt,
ChallengeReason,
ChallengeServiceInterface,
ChallengeValidation,
} from '@standardnotes/services'
import { EncryptionProvider } from '../../Service/Encryption/EncryptionProvider'
import { SNRootKeyParams } from '../RootKey/RootKeyParams'
import { KeyRecoveryStrings } from './KeyRecoveryStrings'
import { EncryptionProvider, KeyRecoveryStrings, SNRootKeyParams } from '@standardnotes/encryption'
import { ChallengeServiceInterface } from '../Challenge/ChallengeServiceInterface'
import { ChallengePrompt } from '../Challenge/Prompt/ChallengePrompt'
import { ChallengeReason } from '../Challenge/Types/ChallengeReason'
import { ChallengeValidation } from '../Challenge/Types/ChallengeValidation'
export async function DecryptItemsKeyWithUserFallback(
itemsKey: EncryptedPayloadInterface,

View File

@@ -1,30 +1,45 @@
import { ContentType, ProtocolVersion } from '@standardnotes/common'
import * as Models from '@standardnotes/models'
import { isEncryptedPayload } from '@standardnotes/models'
import * as Services from '@standardnotes/services'
import { DiagnosticInfo } from '@standardnotes/services'
import { Uuids } from '@standardnotes/utils'
import { OperatorManager } from '../../Operator/OperatorManager'
import * as OperatorWrapper from '../../Operator/OperatorWrapper'
import { StandardException } from '../../StandardException'
import {
DecryptedParameters,
EncryptedParameters,
ErrorDecryptingParameters,
findDefaultItemsKey,
isErrorDecryptingParameters,
} from '../../Types/EncryptedParameters'
import { findDefaultItemsKey } from '../Functions'
OperatorManager,
StandardException,
encryptPayload,
decryptPayload,
} from '@standardnotes/encryption'
import {
DecryptedPayload,
DecryptedPayloadInterface,
EncryptedPayload,
EncryptedPayloadInterface,
isEncryptedPayload,
ItemContent,
ItemsKeyInterface,
PayloadEmitSource,
SureFindPayload,
} from '@standardnotes/models'
import { Uuids } from '@standardnotes/utils'
export class ItemsEncryptionService extends Services.AbstractService {
import { DiagnosticInfo } from '../Diagnostics/ServiceDiagnostics'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { PayloadManagerInterface } from '../Payloads/PayloadManagerInterface'
import { AbstractService } from '../Service/AbstractService'
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
export class ItemsEncryptionService extends AbstractService {
private removeItemsObserver!: () => void
public userVersion?: ProtocolVersion
constructor(
private itemManager: Services.ItemManagerInterface,
private payloadManager: Services.PayloadManagerInterface,
private storageService: Services.StorageServiceInterface,
private itemManager: ItemManagerInterface,
private payloadManager: PayloadManagerInterface,
private storageService: StorageServiceInterface,
private operatorManager: OperatorManager,
protected override internalEventBus: Services.InternalEventBusInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
@@ -59,19 +74,19 @@ export class ItemsEncryptionService extends Services.AbstractService {
return this.itemManager.getDisplayableItemsKeys()
}
public itemsKeyForPayload(payload: Models.EncryptedPayloadInterface): Models.ItemsKeyInterface | undefined {
public itemsKeyForPayload(payload: EncryptedPayloadInterface): ItemsKeyInterface | undefined {
return this.getItemsKeys().find(
(key) => key.uuid === payload.items_key_id || key.duplicateOf === payload.items_key_id,
)
}
public getDefaultItemsKey(): Models.ItemsKeyInterface | undefined {
public getDefaultItemsKey(): ItemsKeyInterface | undefined {
return findDefaultItemsKey(this.getItemsKeys())
}
private keyToUseForItemEncryption(): Models.ItemsKeyInterface | StandardException {
private keyToUseForItemEncryption(): ItemsKeyInterface | StandardException {
const defaultKey = this.getDefaultItemsKey()
let result: Models.ItemsKeyInterface | undefined = undefined
let result: ItemsKeyInterface | undefined = undefined
if (this.userVersion && this.userVersion !== defaultKey?.keyVersion) {
/**
@@ -92,9 +107,7 @@ export class ItemsEncryptionService extends Services.AbstractService {
return result
}
private keyToUseForDecryptionOfPayload(
payload: Models.EncryptedPayloadInterface,
): Models.ItemsKeyInterface | undefined {
private keyToUseForDecryptionOfPayload(payload: EncryptedPayloadInterface): ItemsKeyInterface | undefined {
if (payload.items_key_id) {
const itemsKey = this.itemsKeyForPayload(payload)
return itemsKey
@@ -104,7 +117,7 @@ export class ItemsEncryptionService extends Services.AbstractService {
return defaultKey
}
public async encryptPayloadWithKeyLookup(payload: Models.DecryptedPayloadInterface): Promise<EncryptedParameters> {
public async encryptPayloadWithKeyLookup(payload: DecryptedPayloadInterface): Promise<EncryptedParameters> {
const key = this.keyToUseForItemEncryption()
if (key instanceof StandardException) {
@@ -115,8 +128,8 @@ export class ItemsEncryptionService extends Services.AbstractService {
}
public async encryptPayload(
payload: Models.DecryptedPayloadInterface,
key: Models.ItemsKeyInterface,
payload: DecryptedPayloadInterface,
key: ItemsKeyInterface,
): Promise<EncryptedParameters> {
if (isEncryptedPayload(payload)) {
throw Error('Attempting to encrypt already encrypted payload.')
@@ -128,24 +141,22 @@ export class ItemsEncryptionService extends Services.AbstractService {
throw Error('Attempting to encrypt payload with no UuidGenerator.')
}
return OperatorWrapper.encryptPayload(payload, key, this.operatorManager)
return encryptPayload(payload, key, this.operatorManager)
}
public async encryptPayloads(
payloads: Models.DecryptedPayloadInterface[],
key: Models.ItemsKeyInterface,
payloads: DecryptedPayloadInterface[],
key: ItemsKeyInterface,
): Promise<EncryptedParameters[]> {
return Promise.all(payloads.map((payload) => this.encryptPayload(payload, key)))
}
public async encryptPayloadsWithKeyLookup(
payloads: Models.DecryptedPayloadInterface[],
): Promise<EncryptedParameters[]> {
public async encryptPayloadsWithKeyLookup(payloads: DecryptedPayloadInterface[]): Promise<EncryptedParameters[]> {
return Promise.all(payloads.map((payload) => this.encryptPayloadWithKeyLookup(payload)))
}
public async decryptPayloadWithKeyLookup<C extends Models.ItemContent = Models.ItemContent>(
payload: Models.EncryptedPayloadInterface,
public async decryptPayloadWithKeyLookup<C extends ItemContent = ItemContent>(
payload: EncryptedPayloadInterface,
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
const key = this.keyToUseForDecryptionOfPayload(payload)
@@ -160,9 +171,9 @@ export class ItemsEncryptionService extends Services.AbstractService {
return this.decryptPayload(payload, key)
}
public async decryptPayload<C extends Models.ItemContent = Models.ItemContent>(
payload: Models.EncryptedPayloadInterface,
key: Models.ItemsKeyInterface,
public async decryptPayload<C extends ItemContent = ItemContent>(
payload: EncryptedPayloadInterface,
key: ItemsKeyInterface,
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
if (!payload.content) {
return {
@@ -171,18 +182,18 @@ export class ItemsEncryptionService extends Services.AbstractService {
}
}
return OperatorWrapper.decryptPayload(payload, key, this.operatorManager)
return decryptPayload(payload, key, this.operatorManager)
}
public async decryptPayloadsWithKeyLookup<C extends Models.ItemContent = Models.ItemContent>(
payloads: Models.EncryptedPayloadInterface[],
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 Models.ItemContent = Models.ItemContent>(
payloads: Models.EncryptedPayloadInterface[],
key: Models.ItemsKeyInterface,
public async decryptPayloads<C extends ItemContent = ItemContent>(
payloads: EncryptedPayloadInterface[],
key: ItemsKeyInterface,
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
return Promise.all(payloads.map((payload) => this.decryptPayload<C>(payload, key)))
}
@@ -196,21 +207,21 @@ export class ItemsEncryptionService extends Services.AbstractService {
const resultParams = await this.decryptPayloadsWithKeyLookup(payloads)
const decryptedPayloads = resultParams.map((params) => {
const original = Models.SureFindPayload(payloads, params.uuid)
const original = SureFindPayload(payloads, params.uuid)
if (isErrorDecryptingParameters(params)) {
return new Models.EncryptedPayload({
return new EncryptedPayload({
...original.ejected(),
...params,
})
} else {
return new Models.DecryptedPayload({
return new DecryptedPayload({
...original.ejected(),
...params,
})
}
})
await this.payloadManager.emitPayloads(decryptedPayloads, Models.PayloadEmitSource.LocalChanged)
await this.payloadManager.emitPayloads(decryptedPayloads, PayloadEmitSource.LocalChanged)
}
/**
@@ -222,8 +233,8 @@ export class ItemsEncryptionService extends Services.AbstractService {
*/
public defaultItemsKeyForItemVersion(
version: ProtocolVersion,
fromKeys?: Models.ItemsKeyInterface[],
): Models.ItemsKeyInterface | undefined {
fromKeys?: ItemsKeyInterface[],
): ItemsKeyInterface | undefined {
/** Try to find one marked default first */
const searchKeys = fromKeys || this.getItemsKeys()
const priorityKey = searchKeys.find((key) => {

View File

@@ -1,49 +1,71 @@
import * as Common from '@standardnotes/common'
import * as Models from '@standardnotes/models'
import {
ApplicationIdentifier,
ProtocolVersionLatest,
ProtocolVersion,
AnyKeyParamsContent,
KeyParamsOrigination,
compareVersions,
ProtocolVersionLastNonrootItemsKey,
ContentType,
} from '@standardnotes/common'
import {
RootKeyServiceEvent,
KeyMode,
SNRootKeyParams,
OperatorManager,
CreateNewRootKey,
CreateAnyKeyParams,
SNRootKey,
isErrorDecryptingParameters,
EncryptedParameters,
DecryptedParameters,
ErrorDecryptingParameters,
findDefaultItemsKey,
ItemsKeyMutator,
encryptPayload,
decryptPayload,
} from '@standardnotes/encryption'
import {
CreateDecryptedItemFromPayload,
DecryptedPayload,
DecryptedPayloadInterface,
DecryptedTransferPayload,
EncryptedPayload,
EncryptedPayloadInterface,
EncryptedTransferPayload,
FillItemContentSpecialized,
ItemContent,
ItemsKeyContent,
ItemsKeyContentSpecialized,
ItemsKeyInterface,
NamespacedRootKeyInKeychain,
PayloadTimestampDefaults,
RootKeyContent,
RootKeyInterface,
} from '@standardnotes/models'
import * as Services from '@standardnotes/services'
import { UuidGenerator } from '@standardnotes/utils'
import { ItemsKeyMutator } from '../../Keys/ItemsKey/ItemsKeyMutator'
import { CreateNewRootKey } from '../../Keys/RootKey/Functions'
import { CreateAnyKeyParams } from '../../Keys/RootKey/KeyParamsFunctions'
import { SNRootKey } from '../../Keys/RootKey/RootKey'
import { SNRootKeyParams } from '../../Keys/RootKey/RootKeyParams'
import { OperatorManager } from '../../Operator/OperatorManager'
import * as OperatorWrapper from '../../Operator/OperatorWrapper'
import {
DecryptedParameters,
EncryptedParameters,
ErrorDecryptingParameters,
isErrorDecryptingParameters,
} from '../../Types/EncryptedParameters'
import { findDefaultItemsKey } from '../Functions'
import { KeyMode } from './KeyMode'
export enum RootKeyServiceEvent {
RootKeyStatusChanged = 'RootKeyStatusChanged',
}
import { DeviceInterface } from '../Device/DeviceInterface'
import { DiagnosticInfo } from '../Diagnostics/ServiceDiagnostics'
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'
export class RootKeyEncryptionService extends Services.AbstractService<RootKeyServiceEvent> {
export class RootKeyEncryptionService extends AbstractService<RootKeyServiceEvent> {
private rootKey?: RootKeyInterface
public keyMode = KeyMode.RootKeyNone
public memoizedRootKeyParams?: SNRootKeyParams
constructor(
private itemManager: Services.ItemManagerInterface,
private itemManager: ItemManagerInterface,
private operatorManager: OperatorManager,
public deviceInterface: Services.DeviceInterface,
private storageService: Services.StorageServiceInterface,
private identifier: Common.ApplicationIdentifier,
protected override internalEventBus: Services.InternalEventBusInterface,
public deviceInterface: DeviceInterface,
private storageService: StorageServiceInterface,
private identifier: ApplicationIdentifier,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
}
@@ -89,7 +111,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
if (!passcodeParams) {
return false
}
return passcodeParams.version !== Common.ProtocolVersionLatest
return passcodeParams.version !== ProtocolVersionLatest
}
public async hasRootKeyWrapper() {
@@ -118,7 +140,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
return this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper
}
public async getEncryptionSourceVersion(): Promise<Common.ProtocolVersion> {
public async getEncryptionSourceVersion(): Promise<ProtocolVersion> {
if (this.hasAccount()) {
return this.getSureUserVersion()
} else if (this.hasPasscode()) {
@@ -129,12 +151,12 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
throw Error('Attempting to access encryption source version without source')
}
public getUserVersion(): Common.ProtocolVersion | undefined {
public getUserVersion(): ProtocolVersion | undefined {
const keyParams = this.memoizedRootKeyParams
return keyParams?.version
}
private getSureUserVersion(): Common.ProtocolVersion {
private getSureUserVersion(): ProtocolVersion {
const keyParams = this.memoizedRootKeyParams as SNRootKeyParams
return keyParams.version
}
@@ -173,15 +195,15 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
public async getRootKeyWrapperKeyParams(): Promise<SNRootKeyParams | undefined> {
const rawKeyParams = await this.storageService.getValue(
Services.StorageKey.RootKeyWrapperKeyParams,
Services.StorageValueModes.Nonwrapped,
StorageKey.RootKeyWrapperKeyParams,
StorageValueModes.Nonwrapped,
)
if (!rawKeyParams) {
return undefined
}
return CreateAnyKeyParams(rawKeyParams as Common.AnyKeyParamsContent)
return CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
}
public async getSureRootKeyWrapperKeyParams() {
@@ -213,8 +235,8 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
public async createRootKey(
identifier: string,
password: string,
origination: Common.KeyParamsOrigination,
version?: Common.ProtocolVersion,
origination: KeyParamsOrigination,
version?: ProtocolVersion,
) {
const operator = version ? this.operatorManager.operatorForVersion(version) : this.operatorManager.defaultOperator()
return operator.createRootKey(identifier, password, origination)
@@ -261,7 +283,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
* account keys are encrypted with wrappingKey. Here we validate
* by attempting to decrypt account keys.
*/
const wrappedKeyPayload = new Models.EncryptedPayload(wrappedRootKey)
const wrappedKeyPayload = new EncryptedPayload(wrappedRootKey)
const decrypted = await this.decryptPayload(wrappedKeyPayload, wrappingKey)
return !isErrorDecryptingParameters(decrypted)
} else {
@@ -270,16 +292,13 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
}
private async recomputeAccountKeyParams(): Promise<SNRootKeyParams | undefined> {
const rawKeyParams = await this.storageService.getValue(
Services.StorageKey.RootKeyParams,
Services.StorageValueModes.Nonwrapped,
)
const rawKeyParams = await this.storageService.getValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
if (!rawKeyParams) {
return
}
this.memoizedRootKeyParams = CreateAnyKeyParams(rawKeyParams as Common.AnyKeyParamsContent)
this.memoizedRootKeyParams = CreateAnyKeyParams(rawKeyParams as AnyKeyParamsContent)
return this.memoizedRootKeyParams
}
@@ -289,25 +308,21 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
*/
private async wrapAndPersistRootKey(wrappingKey: SNRootKey) {
const rootKey = this.getSureRootKey()
const value: Models.DecryptedTransferPayload = {
const value: DecryptedTransferPayload = {
...rootKey.payload.ejected(),
content: FillItemContentSpecialized(rootKey.persistableValueWhenWrapping()),
}
const payload = new Models.DecryptedPayload(value)
const payload = new DecryptedPayload(value)
const wrappedKey = await this.encryptPayload(payload, wrappingKey)
const wrappedKeyPayload = new Models.EncryptedPayload({
const wrappedKeyPayload = new EncryptedPayload({
...payload.ejected(),
...wrappedKey,
errorDecrypting: false,
waitingForKey: false,
})
this.storageService.setValue(
Services.StorageKey.WrappedRootKey,
wrappedKeyPayload.ejected(),
Services.StorageValueModes.Nonwrapped,
)
this.storageService.setValue(StorageKey.WrappedRootKey, wrappedKeyPayload.ejected(), StorageValueModes.Nonwrapped)
}
public async unwrapRootKey(wrappingKey: RootKeyInterface) {
@@ -321,8 +336,8 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
}
const wrappedKey = this.getWrappedRootKey()
const payload = new Models.EncryptedPayload(wrappedKey)
const decrypted = await this.decryptPayload<Models.RootKeyContent>(payload, wrappingKey)
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.')
@@ -362,9 +377,9 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
}
this.storageService.setValue(
Services.StorageKey.RootKeyWrapperKeyParams,
StorageKey.RootKeyWrapperKeyParams,
wrappingKey.keyParams.getPortableValue(),
Services.StorageValueModes.Nonwrapped,
StorageValueModes.Nonwrapped,
)
await this.handleKeyStatusChange()
@@ -388,11 +403,8 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
this.keyMode = KeyMode.RootKeyOnly
}
await this.storageService.removeValue(Services.StorageKey.WrappedRootKey, Services.StorageValueModes.Nonwrapped)
await this.storageService.removeValue(
Services.StorageKey.RootKeyWrapperKeyParams,
Services.StorageValueModes.Nonwrapped,
)
await this.storageService.removeValue(StorageKey.WrappedRootKey, StorageValueModes.Nonwrapped)
await this.storageService.removeValue(StorageKey.RootKeyWrapperKeyParams, StorageValueModes.Nonwrapped)
if (this.keyMode === KeyMode.RootKeyOnly) {
await this.saveRootKeyToKeychain()
@@ -424,9 +436,9 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
this.setRootKeyInstance(key)
this.storageService.setValue(
Services.StorageKey.RootKeyParams,
StorageKey.RootKeyParams,
key.keyParams.getPortableValue(),
Services.StorageValueModes.Nonwrapped,
StorageValueModes.Nonwrapped,
)
if (this.keyMode === KeyMode.RootKeyOnly) {
@@ -446,12 +458,9 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
*/
public async deleteWorkspaceSpecificKeyStateFromDevice() {
await this.deviceInterface.clearNamespacedKeychainValue(this.identifier)
await this.storageService.removeValue(Services.StorageKey.WrappedRootKey, Services.StorageValueModes.Nonwrapped)
await this.storageService.removeValue(
Services.StorageKey.RootKeyWrapperKeyParams,
Services.StorageValueModes.Nonwrapped,
)
await this.storageService.removeValue(Services.StorageKey.RootKeyParams, Services.StorageValueModes.Nonwrapped)
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)
@@ -459,9 +468,9 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
}
private getWrappedRootKey() {
return this.storageService.getValue<Models.EncryptedTransferPayload>(
Services.StorageKey.WrappedRootKey,
Services.StorageValueModes.Nonwrapped,
return this.storageService.getValue<EncryptedTransferPayload>(
StorageKey.WrappedRootKey,
StorageValueModes.Nonwrapped,
)
}
@@ -481,7 +490,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
return this.itemManager.getDisplayableItemsKeys()
}
public async encrypPayloadWithKeyLookup(payload: Models.DecryptedPayloadInterface): Promise<EncryptedParameters> {
public async encrypPayloadWithKeyLookup(payload: DecryptedPayloadInterface): Promise<EncryptedParameters> {
const key = this.getRootKey()
if (key == undefined) {
@@ -491,25 +500,20 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
return this.encryptPayload(payload, key)
}
public async encryptPayloadsWithKeyLookup(
payloads: Models.DecryptedPayloadInterface[],
): Promise<EncryptedParameters[]> {
public async encryptPayloadsWithKeyLookup(payloads: DecryptedPayloadInterface[]): Promise<EncryptedParameters[]> {
return Promise.all(payloads.map((payload) => this.encrypPayloadWithKeyLookup(payload)))
}
public async encryptPayload(
payload: Models.DecryptedPayloadInterface,
key: RootKeyInterface,
): Promise<EncryptedParameters> {
return OperatorWrapper.encryptPayload(payload, key, this.operatorManager)
public async encryptPayload(payload: DecryptedPayloadInterface, key: RootKeyInterface): Promise<EncryptedParameters> {
return encryptPayload(payload, key, this.operatorManager)
}
public async encryptPayloads(payloads: Models.DecryptedPayloadInterface[], key: RootKeyInterface) {
public async encryptPayloads(payloads: DecryptedPayloadInterface[], key: RootKeyInterface) {
return Promise.all(payloads.map((payload) => this.encryptPayload(payload, key)))
}
public async decryptPayloadWithKeyLookup<C extends Models.ItemContent = Models.ItemContent>(
payload: Models.EncryptedPayloadInterface,
public async decryptPayloadWithKeyLookup<C extends ItemContent = ItemContent>(
payload: EncryptedPayloadInterface,
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
const key = this.getRootKey()
@@ -524,21 +528,21 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
return this.decryptPayload(payload, key)
}
public async decryptPayload<C extends Models.ItemContent = Models.ItemContent>(
payload: Models.EncryptedPayloadInterface,
public async decryptPayload<C extends ItemContent = ItemContent>(
payload: EncryptedPayloadInterface,
key: RootKeyInterface,
): Promise<DecryptedParameters<C> | ErrorDecryptingParameters> {
return OperatorWrapper.decryptPayload(payload, key, this.operatorManager)
return decryptPayload(payload, key, this.operatorManager)
}
public async decryptPayloadsWithKeyLookup<C extends Models.ItemContent = Models.ItemContent>(
payloads: Models.EncryptedPayloadInterface[],
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 Models.ItemContent = Models.ItemContent>(
payloads: Models.EncryptedPayloadInterface[],
public async decryptPayloads<C extends ItemContent = ItemContent>(
payloads: EncryptedPayloadInterface[],
key: RootKeyInterface,
): Promise<(DecryptedParameters<C> | ErrorDecryptingParameters)[]> {
return Promise.all(payloads.map((payload) => this.decryptPayload<C>(payload, key)))
@@ -566,24 +570,24 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
* 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<Models.ItemsKeyInterface> {
public async createNewDefaultItemsKey(): Promise<ItemsKeyInterface> {
const rootKey = this.getSureRootKey()
const operatorVersion = rootKey ? rootKey.keyVersion : Common.ProtocolVersionLatest
let itemTemplate: Models.ItemsKeyInterface
const operatorVersion = rootKey ? rootKey.keyVersion : ProtocolVersionLatest
let itemTemplate: ItemsKeyInterface
if (Common.compareVersions(operatorVersion, Common.ProtocolVersionLastNonrootItemsKey) <= 0) {
if (compareVersions(operatorVersion, ProtocolVersionLastNonrootItemsKey) <= 0) {
/** Create root key based items key */
const payload = new DecryptedPayload<ItemsKeyContent>({
uuid: UuidGenerator.GenerateUuid(),
content_type: Common.ContentType.ItemsKey,
content: Models.FillItemContentSpecialized<ItemsKeyContentSpecialized, ItemsKeyContent>({
content_type: ContentType.ItemsKey,
content: FillItemContentSpecialized<ItemsKeyContentSpecialized, ItemsKeyContent>({
itemsKey: rootKey.masterKey,
dataAuthenticationKey: rootKey.dataAuthenticationKey,
version: operatorVersion,
}),
...PayloadTimestampDefaults(),
})
itemTemplate = Models.CreateDecryptedItemFromPayload(payload)
itemTemplate = CreateDecryptedItemFromPayload(payload)
} else {
/** Create independent items key */
itemTemplate = this.operatorManager.operatorForVersion(operatorVersion).createItemsKey()
@@ -600,7 +604,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
})
}
const itemsKey = (await this.itemManager.insertItem(itemTemplate)) as Models.ItemsKeyInterface
const itemsKey = (await this.itemManager.insertItem(itemTemplate)) as ItemsKeyInterface
await this.itemManager.changeItemsKey(itemsKey, (mutator) => {
mutator.isDefault = true
@@ -626,7 +630,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
return rollback
}
override async getDiagnostics(): Promise<Services.DiagnosticInfo | undefined> {
override async getDiagnostics(): Promise<DiagnosticInfo | undefined> {
return {
rootKeyEncryption: {
hasRootKey: this.rootKey != undefined,

View File

@@ -1,4 +1,3 @@
import { DecryptedBytes, EncryptedBytes, FileMemoryCache, OrderedByteChunker } from '@standardnotes/filepicker'
import { ClientDisplayableError } from '@standardnotes/responses'
import { ContentType } from '@standardnotes/common'
import {
@@ -13,21 +12,7 @@ import {
} from '@standardnotes/models'
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
import { UuidGenerator } from '@standardnotes/utils'
import {
AbstractService,
InternalEventBusInterface,
ItemManagerInterface,
SyncServiceInterface,
AlertService,
FileSystemApi,
FilesApiInterface,
FileBackupMetadataFile,
FileHandleRead,
FileSystemNoSelection,
ChallengeServiceInterface,
FileBackupsConstantsV1,
} from '@standardnotes/services'
import { DecryptItemsKeyWithUserFallback, EncryptionProvider, SNItemsKey } from '@standardnotes/encryption'
import { EncryptionProvider, SNItemsKey } from '@standardnotes/encryption'
import {
DownloadAndDecryptFileOperation,
EncryptAndUploadFileOperation,
@@ -35,8 +20,26 @@ import {
FileDownloadProgress,
FilesClientInterface,
readAndDecryptBackupFile,
FilesApiInterface,
FileBackupsConstantsV1,
FileBackupMetadataFile,
FileSystemApi,
FileHandleRead,
FileSystemNoSelection,
EncryptedBytes,
DecryptedBytes,
OrderedByteChunker,
FileMemoryCache,
} from '@standardnotes/files'
import { AlertService } from '../Alert/AlertService'
import { ChallengeServiceInterface } from '../Challenge'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { AbstractService } from '../Service/AbstractService'
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
import { DecryptItemsKeyWithUserFallback } from '../Encryption/Functions'
const OneHundredMb = 100 * 1_000_000
export class FileService extends AbstractService implements FilesClientInterface {

View File

@@ -18,11 +18,16 @@ export * from './Device/DesktopManagerInterface'
export * from './Device/DesktopWebCommunication'
export * from './Device/DeviceInterface'
export * from './Device/Environments'
export * from './Device/FileBackupsDevice'
export * from './Device/MobileDeviceInterface'
export * from './Device/TypeCheck'
export * from './Device/WebOrDesktopDeviceInterface'
export * from './Diagnostics/ServiceDiagnostics'
export * from './Encryption/BackupFileDecryptor'
export * from './Encryption/EncryptionService'
export * from './Encryption/EncryptionServiceEvent'
export * from './Encryption/Functions'
export * from './Encryption/ItemsEncryption'
export * from './Encryption/RootKeyEncryption'
export * from './Event/ApplicationEvent'
export * from './Event/ApplicationEventCallback'
export * from './Event/EventObserver'
@@ -34,6 +39,7 @@ export * from './Feature/FeaturesClientInterface'
export * from './Feature/FeaturesEvent'
export * from './Feature/OfflineSubscriptionEntitlements'
export * from './Feature/SetOfflineFeaturesFunctionResponse'
export * from './Files/FileService'
export * from './Integrity/IntegrityApiInterface'
export * from './Integrity/IntegrityEvent'
export * from './Integrity/IntegrityEventPayload'

View File

@@ -1,4 +1,3 @@
import { SnjsVersion } from './../Version'
import {
HttpService,
HttpServiceInterface,
@@ -10,13 +9,11 @@ import {
} from '@standardnotes/api'
import * as Common from '@standardnotes/common'
import * as ExternalServices from '@standardnotes/services'
import * as Encryption from '@standardnotes/encryption'
import * as Models from '@standardnotes/models'
import * as Responses from '@standardnotes/responses'
import * as InternalServices from '../Services'
import * as Utils from '@standardnotes/utils'
import * as Settings from '@standardnotes/settings'
import * as Files from '@standardnotes/files'
import { Subscription } from '@standardnotes/security'
import { UuidString, ApplicationEventPayload } from '../Types'
import { applicationEventForSyncEvent } from '@Lib/Application/Event'
@@ -36,11 +33,19 @@ import {
DeinitSource,
AppGroupManagedApplication,
ApplicationInterface,
EncryptionService,
EncryptionServiceEvent,
FilesBackupService,
FileService,
} from '@standardnotes/services'
import { SNLog } from '../Log'
import { FilesClientInterface } from '@standardnotes/files'
import { ComputePrivateWorkspaceIdentifier } from '@standardnotes/encryption'
import { useBoolean } from '@standardnotes/utils'
import { BackupFile, DecryptedItemInterface, EncryptedItemInterface, ItemStream } from '@standardnotes/models'
import { ClientDisplayableError } from '@standardnotes/responses'
import { SnjsVersion } from './../Version'
import { SNLog } from '../Log'
import { Challenge, ChallengeResponse } from '../Services'
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
import { ApplicationOptionsDefaults } from './Options/Defaults'
@@ -78,7 +83,7 @@ export class SNApplication
private deprecatedHttpService!: InternalServices.SNHttpService
private declare httpService: HttpServiceInterface
private payloadManager!: InternalServices.PayloadManager
public protocolService!: Encryption.EncryptionService
public protocolService!: EncryptionService
private diskStorageService!: InternalServices.DiskStorageService
private inMemoryStore!: ExternalServices.KeyValueStoreInterface<string>
/**
@@ -104,11 +109,11 @@ export class SNApplication
private settingsService!: InternalServices.SNSettingsService
private mfaService!: InternalServices.SNMfaService
private listedService!: InternalServices.ListedService
private fileService!: Files.FileService
private fileService!: FileService
private mutatorService!: InternalServices.MutatorService
private integrityService!: ExternalServices.IntegrityService
private statusService!: ExternalServices.StatusService
private filesBackupService?: Files.FilesBackupService
private filesBackupService?: FilesBackupService
private internalEventBus!: ExternalServices.InternalEventBusInterface
@@ -182,7 +187,7 @@ export class SNApplication
this.defineInternalEventHandlers()
}
public get files(): Files.FilesClientInterface {
public get files(): FilesClientInterface {
return this.fileService
}
@@ -222,7 +227,7 @@ export class SNApplication
return this.statusService
}
public get fileBackups(): Files.FilesBackupService | undefined {
public get fileBackups(): FilesBackupService | undefined {
return this.filesBackupService
}
@@ -231,7 +236,7 @@ export class SNApplication
}
public computePrivateWorkspaceIdentifier(userphrase: string, name: string): Promise<string | undefined> {
return Encryption.ComputePrivateWorkspaceIdentifier(this.options.crypto, userphrase, name)
return ComputePrivateWorkspaceIdentifier(this.options.crypto, userphrase, name)
}
/**
@@ -1117,7 +1122,7 @@ export class SNApplication
}
private createFileService() {
this.fileService = new Files.FileService(
this.fileService = new FileService(
this.apiService,
this.itemManager,
this.syncService,
@@ -1328,7 +1333,7 @@ export class SNApplication
}
private createProtocolService() {
this.protocolService = new Encryption.EncryptionService(
this.protocolService = new EncryptionService(
this.itemManager,
this.payloadManager,
this.deviceInterface,
@@ -1339,7 +1344,7 @@ export class SNApplication
)
this.serviceObservers.push(
this.protocolService.addEventObserver(async (event) => {
if (event === Encryption.EncryptionServiceEvent.RootKeyStatusChanged) {
if (event === EncryptionServiceEvent.RootKeyStatusChanged) {
await this.notifyEvent(ApplicationEvent.KeyStatusChanged)
}
}),
@@ -1539,7 +1544,7 @@ export class SNApplication
}
private createFilesBackupService(device: ExternalServices.DesktopDeviceInterface): void {
this.filesBackupService = new Files.FilesBackupService(
this.filesBackupService = new FilesBackupService(
this.itemManager,
this.apiService,
this.protocolService,

View File

@@ -1,8 +1,7 @@
import { SNSessionManager } from '../Services/Session/SessionManager'
import { ApplicationIdentifier } from '@standardnotes/common'
import { ItemManager } from '@Lib/Services/Items/ItemManager'
import { EncryptionService } from '@standardnotes/encryption'
import { DeviceInterface, InternalEventBusInterface, Environment } from '@standardnotes/services'
import { DeviceInterface, InternalEventBusInterface, Environment, EncryptionService } from '@standardnotes/services'
import { ChallengeService, SNSingletonManager, SNFeaturesService, DiskStorageService } from '@Lib/Services'
export type MigrationServices = {

View File

@@ -1,4 +1,4 @@
import { EncryptionService, SNRootKey } from '@standardnotes/encryption'
import { SNRootKey } from '@standardnotes/encryption'
import { Challenge, ChallengeService } from '../Challenge'
import { ListedService } from '../Listed/ListedService'
import { ActionResponse, HttpResponse } from '@standardnotes/responses'
@@ -30,6 +30,7 @@ import {
ChallengeValidation,
ChallengeReason,
ChallengePrompt,
EncryptionService,
} from '@standardnotes/services'
/**

View File

@@ -12,9 +12,10 @@ import {
ApiServiceEvent,
MetaReceivedData,
DiagnosticInfo,
FilesApiInterface,
KeyValueStoreInterface,
} from '@standardnotes/services'
import { FilesApiInterface } from '@standardnotes/files'
import { ServerSyncPushContextualPayload, SNFeatureRepo, FileContent } from '@standardnotes/models'
import * as Responses from '@standardnotes/responses'
import { API_MESSAGE_FAILED_OFFLINE_ACTIVATION } from '@Lib/Services/Api/Messages'

View File

@@ -1,5 +1,4 @@
import { RootKeyInterface } from '@standardnotes/models'
import { EncryptionService } from '@standardnotes/encryption'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { removeFromArray } from '@standardnotes/utils'
import { isValidProtectionSessionLength } from '../Protection/ProtectionService'
@@ -14,6 +13,7 @@ import {
ChallengeInterface,
ChallengePromptInterface,
ChallengePrompt,
EncryptionService,
} from '@standardnotes/services'
import { ChallengeResponse } from './ChallengeResponse'
import { ChallengeOperation } from './ChallengeOperation'

View File

@@ -1,5 +1,4 @@
import { ContentType, Uuid } from '@standardnotes/common'
import { EncryptionService } from '@standardnotes/encryption'
import { isNullOrUndefined, removeFromArray } from '@standardnotes/utils'
import { ItemManager } from '@Lib/Services/Items/ItemManager'
import { SNApiService } from '@Lib/Services/Api/ApiService'
@@ -7,8 +6,8 @@ import { DiskStorageService } from '@Lib/Services/Storage/DiskStorageService'
import { UuidString } from '../../Types/UuidString'
import * as Models from '@standardnotes/models'
import * as Responses from '@standardnotes/responses'
import * as Services from '@standardnotes/services'
import { isErrorDecryptingPayload, PayloadTimestampDefaults, SNNote } from '@standardnotes/models'
import { AbstractService, EncryptionService, DeviceInterface, InternalEventBusInterface } from '@standardnotes/services'
/** The amount of revisions per item above which should call for an optimization. */
const DefaultItemRevisionsThreshold = 20
@@ -28,7 +27,7 @@ const LargeEntryDeltaThreshold = 25
* 2. Remote server history. Entries are automatically added by the server and must be
* retrieved per item via an API call.
*/
export class SNHistoryManager extends Services.AbstractService {
export class SNHistoryManager extends AbstractService {
private removeChangeObserver: () => void
/**
@@ -49,8 +48,8 @@ export class SNHistoryManager extends Services.AbstractService {
private storageService: DiskStorageService,
private apiService: SNApiService,
private protocolService: EncryptionService,
public deviceInterface: Services.DeviceInterface,
protected override internalEventBus: Services.InternalEventBusInterface,
public deviceInterface: DeviceInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
this.removeChangeObserver = this.itemManager.addObserver(ContentType.Note, ({ changed, inserted }) => {

View File

@@ -1,10 +1,10 @@
import { ContentType } from '@standardnotes/common'
import { ItemsKeyInterface } from '@standardnotes/models'
import { dateSorted } from '@standardnotes/utils'
import { SNRootKeyParams, DecryptItemsKeyByPromptingUser, EncryptionProvider } from '@standardnotes/encryption'
import { SNRootKeyParams, EncryptionProvider } from '@standardnotes/encryption'
import { DecryptionQueueItem, KeyRecoveryOperationResult } from './Types'
import { serverKeyParamsAreSafe } from './Utils'
import { ChallengeServiceInterface } from '@standardnotes/services'
import { ChallengeServiceInterface, DecryptItemsKeyByPromptingUser } from '@standardnotes/services'
import { ItemManager } from '../Items'
export class KeyRecoveryOperation {

View File

@@ -1,11 +1,5 @@
import { KeyRecoveryOperation } from './KeyRecoveryOperation'
import {
SNRootKeyParams,
EncryptionService,
SNRootKey,
KeyParamsFromApiResponse,
KeyRecoveryStrings,
} from '@standardnotes/encryption'
import { SNRootKeyParams, SNRootKey, KeyParamsFromApiResponse, KeyRecoveryStrings } from '@standardnotes/encryption'
import { UserService } from '../User/UserService'
import {
isErrorDecryptingPayload,
@@ -37,6 +31,7 @@ import {
ChallengeValidation,
ChallengeReason,
ChallengePrompt,
EncryptionService,
} from '@standardnotes/services'
import {
UndecryptableItemsStorage,

View File

@@ -1,8 +1,7 @@
import { SNHistoryManager } from './../History/HistoryManager'
import { NoteContent, SNNote, FillItemContent, DecryptedPayload, PayloadTimestampDefaults } from '@standardnotes/models'
import { EncryptionService } from '@standardnotes/encryption'
import { ContentType } from '@standardnotes/common'
import { InternalEventBusInterface } from '@standardnotes/services'
import { EncryptionService, InternalEventBusInterface } from '@standardnotes/services'
import {
ChallengeService,
MutatorService,

View File

@@ -1,8 +1,12 @@
import { ChallengeService } from '../Challenge'
import { EncryptionService } from '@standardnotes/encryption'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { SNProtectionService } from './ProtectionService'
import { InternalEventBus, InternalEventBusInterface, ChallengeReason } from '@standardnotes/services'
import {
InternalEventBus,
InternalEventBusInterface,
ChallengeReason,
EncryptionService,
} from '@standardnotes/services'
import { UuidGenerator } from '@standardnotes/utils'
import {
DecryptedPayload,

View File

@@ -2,7 +2,6 @@ import { Challenge } from './../Challenge/Challenge'
import { ChallengeService } from './../Challenge/ChallengeService'
import { SNLog } from '@Lib/Log'
import { DecryptedItem } from '@standardnotes/models'
import { EncryptionService } from '@standardnotes/encryption'
import { DiskStorageService } from '@Lib/Services/Storage/DiskStorageService'
import { isNullOrUndefined } from '@standardnotes/utils'
import {
@@ -15,6 +14,7 @@ import {
ChallengeReason,
ChallengePrompt,
ChallengeValidation,
EncryptionService,
} from '@standardnotes/services'
import { ProtectionsClientInterface } from './ClientInterface'
import { ContentType } from '@standardnotes/common'

View File

@@ -9,19 +9,14 @@ import {
ChallengeKeyboardType,
ChallengeReason,
ChallengePromptTitle,
EncryptionService,
} from '@standardnotes/services'
import { Base64String } from '@standardnotes/sncrypto-common'
import { ClientDisplayableError } from '@standardnotes/responses'
import { CopyPayloadWithContentOverride } from '@standardnotes/models'
import { isNullOrUndefined } from '@standardnotes/utils'
import { JwtSession } from './Sessions/JwtSession'
import {
KeyParamsFromApiResponse,
SNRootKeyParams,
SNRootKey,
EncryptionService,
CreateNewRootKey,
} from '@standardnotes/encryption'
import { KeyParamsFromApiResponse, SNRootKeyParams, SNRootKey, CreateNewRootKey } from '@standardnotes/encryption'
import { SessionStrings, SignInStrings } from '../Api/Messages'
import { RemoteSession, RawStorageValue } from './Sessions/Types'
import { Session } from './Sessions/Session'

View File

@@ -26,7 +26,6 @@ import { ServerSyncResponse } from '@Lib/Services/Sync/Account/Response'
import { ServerSyncResponseResolver } from '@Lib/Services/Sync/Account/ResponseResolver'
import { SyncSignal, SyncStats } from '@Lib/Services/Sync/Signals'
import { UuidString } from '../../Types/UuidString'
import * as Encryption from '@standardnotes/encryption'
import {
PayloadSource,
CreateDecryptedItemFromPayload,
@@ -73,9 +72,15 @@ import {
SyncQueueStrategy,
SyncServiceInterface,
DiagnosticInfo,
EncryptionService,
} from '@standardnotes/services'
import { OfflineSyncResponse } from './Offline/Response'
import { KeyedDecryptionSplit, SplitPayloadsByEncryptionType } from '@standardnotes/encryption'
import {
CreateDecryptionSplitWithKeyLookup,
CreateEncryptionSplitWithKeyLookup,
KeyedDecryptionSplit,
SplitPayloadsByEncryptionType,
} from '@standardnotes/encryption'
import { CreatePayloadFromRawServerItem } from './Account/Utilities'
import { ApplicationSyncOptions } from '@Lib/Application/Options/OptionalOptions'
@@ -131,7 +136,7 @@ export class SNSyncService
constructor(
private itemManager: ItemManager,
private sessionManager: SNSessionManager,
private protocolService: Encryption.EncryptionService,
private protocolService: EncryptionService,
private storageService: DiskStorageService,
private payloadManager: PayloadManager,
private apiService: SNApiService,
@@ -226,7 +231,7 @@ export class SNSyncService
isDecryptedPayload,
) as DecryptedPayloadInterface<ItemsKeyContent>[]
const itemsKeysSplit: Encryption.KeyedDecryptionSplit = {
const itemsKeysSplit: KeyedDecryptionSplit = {
usesRootKeyWithKeyLookup: {
items: encryptedItemsKeysPayloads,
},
@@ -301,7 +306,7 @@ export class SNSyncService
}
}
const split: Encryption.KeyedDecryptionSplit = {
const split: KeyedDecryptionSplit = {
usesItemsKeyWithKeyLookup: {
items: encrypted,
},
@@ -440,9 +445,9 @@ export class SNSyncService
): Promise<ServerSyncPushContextualPayload[]> {
const payloadSplit = CreatePayloadSplit(payloads)
const encryptionSplit = Encryption.SplitPayloadsByEncryptionType(payloadSplit.decrypted)
const encryptionSplit = SplitPayloadsByEncryptionType(payloadSplit.decrypted)
const keyLookupSplit = Encryption.CreateEncryptionSplitWithKeyLookup(encryptionSplit)
const keyLookupSplit = CreateEncryptionSplitWithKeyLookup(encryptionSplit)
const encryptedResults = await this.protocolService.encryptSplit(keyLookupSplit)
@@ -973,7 +978,7 @@ export class SNSyncService
? (CreateDecryptedItemFromPayload(previouslyProcessedItemsKey) as ItemsKeyInterface)
: undefined
const keyedSplit: Encryption.KeyedDecryptionSplit = {}
const keyedSplit: KeyedDecryptionSplit = {}
if (itemsKey) {
keyedSplit.usesItemsKey = {
items: [encrypted],
@@ -1162,9 +1167,9 @@ export class SNSyncService
const payloadSplit = CreateNonDecryptedPayloadSplit(receivedPayloads)
const encryptionSplit = Encryption.SplitPayloadsByEncryptionType(payloadSplit.encrypted)
const encryptionSplit = SplitPayloadsByEncryptionType(payloadSplit.encrypted)
const keyedSplit = Encryption.CreateDecryptionSplitWithKeyLookup(encryptionSplit)
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
const decryptionResults = await this.protocolService.decryptSplit(keyedSplit)

View File

@@ -1,6 +1,6 @@
import { Challenge } from '../Challenge'
import { ChallengeService } from '../Challenge/ChallengeService'
import { EncryptionService, SNRootKey, SNRootKeyParams } from '@standardnotes/encryption'
import { SNRootKey, SNRootKeyParams } from '@standardnotes/encryption'
import { HttpResponse, SignInResponse, User } from '@standardnotes/responses'
import { ItemManager } from '@Lib/Services/Items/ItemManager'
import { KeyParamsOrigination } from '@standardnotes/common'
@@ -14,6 +14,7 @@ import {
InternalEventBusInterface,
UserClientInterface,
StoragePersistencePolicies,
EncryptionService,
} from '@standardnotes/services'
import { SNApiService } from './../Api/ApiService'
import { SNProtectionService } from '../Protection/ProtectionService'

View File

@@ -8,31 +8,40 @@ import {
SNTheme,
} from '@standardnotes/models'
import { removeFromArray } from '@standardnotes/utils'
import { ApplicationEvent, ApplicationService, FeatureStatus, InternalEventBus, StorageValueModes, WebApplicationInterface } from '@standardnotes/snjs'
import {
AbstractService,
WebApplicationInterface,
InternalEventBusInterface,
ApplicationEvent,
StorageValueModes,
FeatureStatus,
} from '@standardnotes/services'
const CachedThemesKey = 'cachedThemes'
const TimeBeforeApplyingColorScheme = 5
const DefaultThemeIdentifier = 'Default'
export class ThemeManager extends ApplicationService {
export class ThemeManager extends AbstractService {
private activeThemes: Uuid[] = []
private unregisterDesktop?: () => void
private unregisterStream!: () => void
private lastUseDeviceThemeSettings = false
private unsubApp!: () => void
constructor(application: WebApplicationInterface) {
super(application, new InternalEventBus())
constructor(
protected application: WebApplicationInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
this.addAppEventObserverAfterSubclassesFinishConstructing()
this.colorSchemeEventHandler = this.colorSchemeEventHandler.bind(this)
}
override async onAppStart() {
super.onAppStart().catch(console.error)
async onAppStart() {
this.registerObservers()
}
override async onAppEvent(event: ApplicationEvent) {
super.onAppEvent(event).catch(console.error)
async onAppEvent(event: ApplicationEvent) {
switch (event) {
case ApplicationEvent.SignedOut: {
this.deactivateAllThemes()
@@ -59,6 +68,25 @@ export class ThemeManager extends ApplicationService {
}
}
addAppEventObserverAfterSubclassesFinishConstructing() {
setTimeout(() => {
this.addAppEventObserver()
}, 0)
}
addAppEventObserver() {
if (this.application.isStarted()) {
void this.onAppStart()
}
this.unsubApp = this.application.addEventObserver(async (event: ApplicationEvent) => {
await this.onAppEvent(event)
if (event === ApplicationEvent.Started) {
void this.onAppStart()
}
})
}
private handlePreferencesChangeEvent(): void {
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
@@ -86,6 +114,10 @@ export class ThemeManager extends ApplicationService {
;(this.unregisterStream as unknown) = undefined
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this.colorSchemeEventHandler)
;(this.application as unknown) = undefined
this.unsubApp()
;(this.unsubApp as unknown) = undefined
super.deinit()
}

View File

@@ -4,3 +4,4 @@ export * from './Archive/ArchiveManager'
export * from './IO/IOService'
export * from './Security/AutolockService'
export * from './Storage/LocalStorage'
export * from './Theme/ThemeManager'

View File

@@ -22,8 +22,7 @@ import { makeObservable, observable } from 'mobx'
import { PanelResizedData } from '@/Types/PanelResizedData'
import { isDesktopApplication } from '@/Utils'
import { DesktopManager } from './Device/DesktopManager'
import { ArchiveManager, AutolockService, IOService, WebAlertService } from '@standardnotes/ui-services'
import { ThemeManager } from '@/Theme/ThemeManager'
import { ArchiveManager, AutolockService, IOService, WebAlertService, ThemeManager } from '@standardnotes/ui-services'
type WebServices = {
viewControllerManager: ViewControllerManager

View File

@@ -33,8 +33,9 @@ const createApplication = (
const viewControllerManager = new ViewControllerManager(application, device)
const archiveService = new ArchiveManager(application)
const io = new IOService(platform === Platform.MacWeb || platform === Platform.MacDesktop)
const autolockService = new AutolockService(application, new InternalEventBus())
const themeService = new ThemeManager(application)
const internalEventBus = new InternalEventBus()
const autolockService = new AutolockService(application, internalEventBus)
const themeService = new ThemeManager(application, internalEventBus)
application.setWebServices({
viewControllerManager,

View File

@@ -6576,7 +6576,7 @@ __metadata:
languageName: node
linkType: hard
"@standardnotes/encryption@workspace:*, @standardnotes/encryption@workspace:packages/encryption":
"@standardnotes/encryption@workspace:*, @standardnotes/encryption@workspace:^, @standardnotes/encryption@workspace:packages/encryption":
version: 0.0.0-use.local
resolution: "@standardnotes/encryption@workspace:packages/encryption"
dependencies:
@@ -6584,7 +6584,6 @@ __metadata:
"@standardnotes/config": 2.4.3
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
"@standardnotes/services": "workspace:*"
"@standardnotes/sncrypto-common": "workspace:*"
"@standardnotes/utils": "workspace:*"
"@types/jest": ^28.1.5
@@ -7179,6 +7178,7 @@ __metadata:
dependencies:
"@standardnotes/auth": ^3.19.4
"@standardnotes/common": ^1.30.0
"@standardnotes/encryption": "workspace:^"
"@standardnotes/files": "workspace:^"
"@standardnotes/models": "workspace:^"
"@standardnotes/responses": "workspace:*"