refactor: application dependency management (#2363)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
1211
packages/snjs/lib/Application/Dependencies/Dependencies.ts
Normal file
1211
packages/snjs/lib/Application/Dependencies/Dependencies.ts
Normal file
File diff suppressed because it is too large
Load Diff
147
packages/snjs/lib/Application/Dependencies/Types.ts
Normal file
147
packages/snjs/lib/Application/Dependencies/Types.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
export const TYPES = {
|
||||
// System
|
||||
DeviceInterface: Symbol.for('DeviceInterface'),
|
||||
AlertService: Symbol.for('AlertService'),
|
||||
Crypto: Symbol.for('Crypto'),
|
||||
|
||||
// Services
|
||||
InternalEventBus: Symbol.for('InternalEventBus'),
|
||||
PayloadManager: Symbol.for('PayloadManager'),
|
||||
ItemManager: Symbol.for('ItemManager'),
|
||||
MutatorService: Symbol.for('MutatorService'),
|
||||
DiskStorageService: Symbol.for('DiskStorageService'),
|
||||
UserEventService: Symbol.for('UserEventService'),
|
||||
InMemoryStore: Symbol.for('InMemoryStore'),
|
||||
KeySystemKeyManager: Symbol.for('KeySystemKeyManager'),
|
||||
EncryptionService: Symbol.for('EncryptionService'),
|
||||
ChallengeService: Symbol.for('ChallengeService'),
|
||||
DeprecatedHttpService: Symbol.for('DeprecatedHttpService'),
|
||||
HttpService: Symbol.for('HttpService'),
|
||||
LegacyApiService: Symbol.for('LegacyApiService'),
|
||||
UserServer: Symbol.for('UserServer'),
|
||||
UserRequestServer: Symbol.for('UserRequestServer'),
|
||||
UserApiService: Symbol.for('UserApiService'),
|
||||
SubscriptionServer: Symbol.for('SubscriptionServer'),
|
||||
SubscriptionApiService: Symbol.for('SubscriptionApiService'),
|
||||
WebSocketServer: Symbol.for('WebSocketServer'),
|
||||
WebSocketApiService: Symbol.for('WebSocketApiService'),
|
||||
WebSocketsService: Symbol.for('WebSocketsService'),
|
||||
SessionManager: Symbol.for('SessionManager'),
|
||||
SubscriptionManager: Symbol.for('SubscriptionManager'),
|
||||
HistoryManager: Symbol.for('HistoryManager'),
|
||||
SyncService: Symbol.for('SyncService'),
|
||||
ProtectionService: Symbol.for('ProtectionService'),
|
||||
UserService: Symbol.for('UserService'),
|
||||
KeyRecoveryService: Symbol.for('KeyRecoveryService'),
|
||||
SingletonManager: Symbol.for('SingletonManager'),
|
||||
PreferencesService: Symbol.for('PreferencesService'),
|
||||
SettingsService: Symbol.for('SettingsService'),
|
||||
FeaturesService: Symbol.for('FeaturesService'),
|
||||
ComponentManager: Symbol.for('ComponentManager'),
|
||||
MfaService: Symbol.for('MfaService'),
|
||||
StatusService: Symbol.for('StatusService'),
|
||||
MigrationService: Symbol.for('MigrationService'),
|
||||
FileService: Symbol.for('FileService'),
|
||||
IntegrityService: Symbol.for('IntegrityService'),
|
||||
ListedService: Symbol.for('ListedService'),
|
||||
ActionsService: Symbol.for('ActionsService'),
|
||||
AuthenticatorApiService: Symbol.for('AuthenticatorApiService'),
|
||||
AuthenticatorManager: Symbol.for('AuthenticatorManager'),
|
||||
AuthApiService: Symbol.for('AuthApiService'),
|
||||
AuthManager: Symbol.for('AuthManager'),
|
||||
RevisionApiService: Symbol.for('RevisionApiService'),
|
||||
RevisionManager: Symbol.for('RevisionManager'),
|
||||
ContactService: Symbol.for('ContactService'),
|
||||
VaultService: Symbol.for('VaultService'),
|
||||
SharedVaultService: Symbol.for('SharedVaultService'),
|
||||
AsymmetricMessageService: Symbol.for('AsymmetricMessageService'),
|
||||
SelfContactManager: Symbol.for('SelfContactManager'),
|
||||
EncryptionOperators: Symbol.for('EncryptionOperators'),
|
||||
RootKeyManager: Symbol.for('RootKeyManager'),
|
||||
ItemsEncryptionService: Symbol.for('ItemsEncryptionService'),
|
||||
|
||||
// Servers
|
||||
RevisionServer: Symbol.for('RevisionServer'),
|
||||
AuthenticatorServer: Symbol.for('AuthenticatorServer'),
|
||||
AuthServer: Symbol.for('AuthServer'),
|
||||
SharedVaultInvitesServer: Symbol.for('SharedVaultInvitesServer'),
|
||||
SharedVaultServer: Symbol.for('SharedVaultServer'),
|
||||
SharedVaultUsersServer: Symbol.for('SharedVaultUsersServer'),
|
||||
AsymmetricMessageServer: Symbol.for('AsymmetricMessageServer'),
|
||||
|
||||
// Desktop Services
|
||||
FilesBackupService: Symbol.for('FilesBackupService'),
|
||||
HomeServerService: Symbol.for('HomeServerService'),
|
||||
|
||||
// Usecases
|
||||
SignInWithRecoveryCodes: Symbol.for('SignInWithRecoveryCodes'),
|
||||
GetRecoveryCodes: Symbol.for('GetRecoveryCodes'),
|
||||
AddAuthenticator: Symbol.for('AddAuthenticator'),
|
||||
ListAuthenticators: Symbol.for('ListAuthenticators'),
|
||||
DeleteAuthenticator: Symbol.for('DeleteAuthenticator'),
|
||||
GetAuthenticatorAuthenticationOptions: Symbol.for('GetAuthenticatorAuthenticationOptions'),
|
||||
GetAuthenticatorAuthenticationResponse: Symbol.for('GetAuthenticatorAuthenticationResponse'),
|
||||
ListRevisions: Symbol.for('ListRevisions'),
|
||||
GetRevision: Symbol.for('GetRevision'),
|
||||
DeleteRevision: Symbol.for('DeleteRevision'),
|
||||
ImportDataUseCase: Symbol.for('ImportDataUseCase'),
|
||||
RemoveItemsLocally: Symbol.for('RemoveItemsLocally'),
|
||||
FindContact: Symbol.for('FindContact'),
|
||||
GetAllContacts: Symbol.for('GetAllContacts'),
|
||||
CreateOrEditContact: Symbol.for('CreateOrEditContact'),
|
||||
EditContact: Symbol.for('EditContact'),
|
||||
ValidateItemSigner: Symbol.for('ValidateItemSigner'),
|
||||
GetVault: Symbol.for('GetVault'),
|
||||
ChangeVaultKeyOptions: Symbol.for('ChangeVaultKeyOptions'),
|
||||
MoveItemsToVault: Symbol.for('MoveItemsToVault'),
|
||||
CreateVault: Symbol.for('CreateVault'),
|
||||
RemoveItemFromVault: Symbol.for('RemoveItemFromVault'),
|
||||
DeleteVault: Symbol.for('DeleteVault'),
|
||||
RotateVaultKey: Symbol.for('RotateVaultKey'),
|
||||
CreateSharedVault: Symbol.for('CreateSharedVault'),
|
||||
HandleKeyPairChange: Symbol.for('HandleKeyPairChange'),
|
||||
NotifyVaultUsersOfKeyRotation: Symbol.for('NotifyVaultUsersOfKeyRotation'),
|
||||
SendVaultDataChangedMessage: Symbol.for('SendVaultDataChangedMessage'),
|
||||
SendVaultKeyChangedMessage: Symbol.for('SendVaultKeyChangedMessage'),
|
||||
GetTrustedPayload: Symbol.for('GetTrustedPayload'),
|
||||
GetUntrustedPayload: Symbol.for('GetUntrustedPayload'),
|
||||
GetVaultContacts: Symbol.for('GetVaultContacts'),
|
||||
AcceptVaultInvite: Symbol.for('AcceptVaultInvite'),
|
||||
InviteToVault: Symbol.for('InviteToVault'),
|
||||
LeaveVault: Symbol.for('LeaveVault'),
|
||||
DeleteThirdPartyVault: Symbol.for('DeleteThirdPartyVault'),
|
||||
ShareContactWithVault: Symbol.for('ShareContactWithVault'),
|
||||
ConvertToSharedVault: Symbol.for('ConvertToSharedVault'),
|
||||
DeleteSharedVault: Symbol.for('DeleteSharedVault'),
|
||||
RemoveVaultMember: Symbol.for('RemoveVaultMember'),
|
||||
GetVaultUsers: Symbol.for('GetSharedVaultUsers'),
|
||||
ResendAllMessages: Symbol.for('ResendAllMessages'),
|
||||
ReuploadAllInvites: Symbol.for('ReuploadAllInvites'),
|
||||
ReuploadInvite: Symbol.for('ReuploadInvite'),
|
||||
GetInboundMessages: Symbol.for('GetInboundMessages'),
|
||||
GetOutboundMessages: Symbol.for('GetOutboundMessages'),
|
||||
HandleRootKeyChangedMessage: Symbol.for('HandleRootKeyChangedMessage'),
|
||||
ProcessAcceptedVaultInvite: Symbol.for('ProcessAcceptedVaultInvite'),
|
||||
ResendMessage: Symbol.for('ResendMessage'),
|
||||
SendMessage: Symbol.for('SendMessage'),
|
||||
SendOwnContactChangeMessage: Symbol.for('SendOwnContactChangeMessage'),
|
||||
DecryptMessage: Symbol.for('DecryptMessage'),
|
||||
DecryptOwnMessage: Symbol.for('DecryptOwnMessage'),
|
||||
EncryptMessage: Symbol.for('EncryptMessage'),
|
||||
GetMessageAdditionalData: Symbol.for('GetMessageAdditionalData'),
|
||||
SendVaultInvite: Symbol.for('SendVaultInvite'),
|
||||
ReplaceContactData: Symbol.for('ReplaceContactData'),
|
||||
CreateNewDefaultItemsKey: Symbol.for('CreateNewDefaultItemsKey'),
|
||||
CreateNewItemsKeyWithRollback: Symbol.for('CreateNewItemsKeyWithRollback'),
|
||||
FindDefaultItemsKey: Symbol.for('FindDefaultItemsKey'),
|
||||
DecryptErroredTypeAPayloads: Symbol.for('DecryptErroredTypeAPayloads'),
|
||||
DecryptTypeAPayload: Symbol.for('DecryptTypeAPayload'),
|
||||
DecryptTypeAPayloadWithKeyLookup: Symbol.for('DecryptTypeAPayloadWithKeyLookup'),
|
||||
EncryptTypeAPayload: Symbol.for('EncryptTypeAPayload'),
|
||||
EncryptTypeAPayloadWithKeyLookup: Symbol.for('EncryptTypeAPayloadWithKeyLookup'),
|
||||
DecryptBackupFile: Symbol.for('DecryptBackupFile'),
|
||||
|
||||
// Mappers
|
||||
SessionStorageMapper: Symbol.for('SessionStorageMapper'),
|
||||
LegacySessionStorageMapper: Symbol.for('LegacySessionStorageMapper'),
|
||||
}
|
||||
14
packages/snjs/lib/Application/Dependencies/isDeinitable.ts
Normal file
14
packages/snjs/lib/Application/Dependencies/isDeinitable.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export function isDeinitable(service: unknown): service is { deinit(): void } {
|
||||
if (!service) {
|
||||
throw new Error('Service is undefined')
|
||||
}
|
||||
return typeof (service as { deinit(): void }).deinit === 'function'
|
||||
}
|
||||
|
||||
export function canBlockDeinit(service: unknown): service is { blockDeinit(): Promise<void> } {
|
||||
if (!service) {
|
||||
throw new Error('Service is undefined')
|
||||
}
|
||||
|
||||
return typeof (service as { blockDeinit(): Promise<void> }).blockDeinit === 'function'
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { EncryptedPayloadInterface, HistoryEntry } from '@standardnotes/models'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { RevisionClientInterface } from '@standardnotes/services'
|
||||
import { EncryptionProviderInterface, RevisionClientInterface } from '@standardnotes/services'
|
||||
jest.mock('@standardnotes/models', () => {
|
||||
const original = jest.requireActual('@standardnotes/models')
|
||||
|
||||
@@ -32,11 +31,13 @@ describe('GetRevision', () => {
|
||||
enc_item_key: 'foobar',
|
||||
auth_hash: 'foobar',
|
||||
created_at: '2021-01-01T00:00:00.000Z',
|
||||
updated_at: '2021-01-01T00:00:00.000Z'
|
||||
updated_at: '2021-01-01T00:00:00.000Z',
|
||||
} as jest.Mocked<Revision>)
|
||||
|
||||
encryptionService = {} as jest.Mocked<EncryptionProviderInterface>
|
||||
encryptionService.getEmbeddedPayloadAuthenticatedData = jest.fn().mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
|
||||
encryptionService.getEmbeddedPayloadAuthenticatedData = jest
|
||||
.fn()
|
||||
.mockReturnValue({ u: '00000000-0000-0000-0000-000000000000' })
|
||||
const encryptedPayload = {
|
||||
content: 'foobar',
|
||||
} as jest.Mocked<EncryptedPayloadInterface>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ServerItemResponse } from '@standardnotes/responses'
|
||||
import { RevisionClientInterface } from '@standardnotes/services'
|
||||
import { EncryptionProviderInterface, RevisionClientInterface } from '@standardnotes/services'
|
||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import {
|
||||
EncryptedPayload,
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
NoteContent,
|
||||
PayloadTimestampDefaults,
|
||||
} from '@standardnotes/models'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
|
||||
import { GetRevisionDTO } from './GetRevisionDTO'
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {
|
||||
AuthClientInterface,
|
||||
EncryptionProviderInterface,
|
||||
InternalEventBusInterface,
|
||||
KeyValueStoreInterface,
|
||||
SessionsClientInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { AnyKeyParamsContent } from '@standardnotes/common'
|
||||
import { DecryptedPayloadInterface, RootKeyContent, RootKeyInterface } from '@standardnotes/models'
|
||||
@@ -20,14 +20,8 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
let sessionManager: SessionsClientInterface
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
|
||||
const createUseCase = () => new SignInWithRecoveryCodes(
|
||||
authManager,
|
||||
encryptionService,
|
||||
inMemoryStore,
|
||||
crypto,
|
||||
sessionManager,
|
||||
internalEventBus,
|
||||
)
|
||||
const createUseCase = () =>
|
||||
new SignInWithRecoveryCodes(authManager, encryptionService, inMemoryStore, crypto, sessionManager, internalEventBus)
|
||||
|
||||
beforeEach(() => {
|
||||
authManager = {} as jest.Mocked<AuthClientInterface>
|
||||
@@ -54,12 +48,7 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
encryptionService.hasAccount = jest.fn()
|
||||
encryptionService.computeRootKey = jest.fn().mockReturnValue(rootKey)
|
||||
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(true)
|
||||
encryptionService.supportedVersions = jest.fn().mockReturnValue([
|
||||
'001',
|
||||
'002',
|
||||
'003',
|
||||
'004',
|
||||
])
|
||||
encryptionService.supportedVersions = jest.fn().mockReturnValue(['001', '002', '003', '004'])
|
||||
encryptionService.isVersionNewerThanLibraryVersion = jest.fn()
|
||||
|
||||
inMemoryStore = {} as jest.Mocked<KeyValueStoreInterface<string>>
|
||||
@@ -82,7 +71,11 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
encryptionService.hasAccount = jest.fn().mockReturnValue(true)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('Tried to sign in when an account already exists.')
|
||||
@@ -92,7 +85,11 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
authManager.recoveryKeyParams = jest.fn().mockReturnValue(false)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('Could not retrieve recovery key params')
|
||||
@@ -102,10 +99,16 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('Your account was created on a platform with higher security capabilities than this browser supports. If we attempted to generate your login keys here, it would take hours. Please use a browser with more up to date security capabilities, like Google Chrome or Firefox, to log in.')
|
||||
expect(result.getError()).toEqual(
|
||||
'Your account was created on a platform with higher security capabilities than this browser supports. If we attempted to generate your login keys here, it would take hours. Please use a browser with more up to date security capabilities, like Google Chrome or Firefox, to log in.',
|
||||
)
|
||||
})
|
||||
|
||||
it('should fail if key params has unsupported version', async () => {
|
||||
@@ -123,10 +126,16 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('This version of the application does not support your newer account type. Please upgrade to the latest version of Standard Notes to sign in.')
|
||||
expect(result.getError()).toEqual(
|
||||
'This version of the application does not support your newer account type. Please upgrade to the latest version of Standard Notes to sign in.',
|
||||
)
|
||||
})
|
||||
|
||||
it('should fail if key params has expired version', async () => {
|
||||
@@ -144,17 +153,27 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
encryptionService.platformSupportsKeyDerivation = jest.fn().mockReturnValue(false)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('The protocol version associated with your account is outdated and no longer supported by this application. Please visit standardnotes.com/help/security for more information.')
|
||||
expect(result.getError()).toEqual(
|
||||
'The protocol version associated with your account is outdated and no longer supported by this application. Please visit standardnotes.com/help/security for more information.',
|
||||
)
|
||||
})
|
||||
|
||||
it('should fail if the sign in with recovery code fails', async () => {
|
||||
authManager.signInWithRecoveryCodes = jest.fn().mockReturnValue(false)
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
expect(result.getError()).toEqual('Could not sign in with recovery code')
|
||||
@@ -168,11 +187,15 @@ describe('SignInWithRecoveryCodes', () => {
|
||||
uuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
protocolVersion: '004',
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
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',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(false)
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
AccountEvent,
|
||||
AuthClientInterface,
|
||||
EXPIRED_PROTOCOL_VERSION,
|
||||
EncryptionProviderInterface,
|
||||
InternalEventBusInterface,
|
||||
InternalEventPublishStrategy,
|
||||
KeyValueStoreInterface,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
UNSUPPORTED_KEY_DERIVATION,
|
||||
UNSUPPORTED_PROTOCOL_VERSION,
|
||||
} from '@standardnotes/services'
|
||||
import { CreateAnyKeyParams, EncryptionProviderInterface, SNRootKey } from '@standardnotes/encryption'
|
||||
import { CreateAnyKeyParams, SNRootKey } from '@standardnotes/encryption'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
|
||||
import { SignInWithRecoveryCodesDTO } from './SignInWithRecoveryCodesDTO'
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
MutatorClientInterface,
|
||||
PreferenceServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { SNSessionManager } from '../Services/Session/SessionManager'
|
||||
import { SessionManager } from '../Services/Session/SessionManager'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { ChallengeService, SNSingletonManager, SNFeaturesService, DiskStorageService } from '@Lib/Services'
|
||||
import { ChallengeService, SingletonManager, FeaturesService, DiskStorageService } from '@Lib/Services'
|
||||
import { LegacySession, MapperInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export type MigrationServices = {
|
||||
@@ -18,12 +18,12 @@ export type MigrationServices = {
|
||||
deviceInterface: DeviceInterface
|
||||
storageService: DiskStorageService
|
||||
challengeService: ChallengeService
|
||||
sessionManager: SNSessionManager
|
||||
sessionManager: SessionManager
|
||||
backups?: BackupServiceInterface
|
||||
itemManager: ItemManager
|
||||
mutator: MutatorClientInterface
|
||||
singletonManager: SNSingletonManager
|
||||
featuresService: SNFeaturesService
|
||||
singletonManager: SingletonManager
|
||||
featuresService: FeaturesService
|
||||
preferences: PreferenceServiceInterface
|
||||
environment: Environment
|
||||
platform: Platform
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import { SNRootKey } from '@standardnotes/encryption'
|
||||
import { ChallengeService } from '../Challenge'
|
||||
import { ListedService } from '../Listed/ListedService'
|
||||
import { ActionResponse, DeprecatedHttpResponse } from '@standardnotes/responses'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import {
|
||||
@@ -21,8 +20,6 @@ import {
|
||||
TransferPayload,
|
||||
ItemContent,
|
||||
} from '@standardnotes/models'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||
import { DeprecatedHttpService } from '../Api/DeprecatedHttpService'
|
||||
import {
|
||||
AbstractService,
|
||||
@@ -53,20 +50,17 @@ type PayloadRequestHandler = (uuid: string) => TransferPayload | undefined
|
||||
* `post`: sends an item's data to a remote service. This is used for example by Listed
|
||||
* to allow publishing a note to a user's blog.
|
||||
*/
|
||||
export class SNActionsService extends AbstractService {
|
||||
export class ActionsService extends AbstractService {
|
||||
private previousPasswords: string[] = []
|
||||
private payloadRequestHandlers: PayloadRequestHandler[] = []
|
||||
|
||||
constructor(
|
||||
private itemManager: ItemManager,
|
||||
private alertService: AlertService,
|
||||
public deviceInterface: DeviceInterface,
|
||||
private device: DeviceInterface,
|
||||
private httpService: DeprecatedHttpService,
|
||||
private payloadManager: PayloadManager,
|
||||
private encryptionService: EncryptionService,
|
||||
private syncService: SNSyncService,
|
||||
private challengeService: ChallengeService,
|
||||
private listedService: ListedService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -76,13 +70,10 @@ export class SNActionsService extends AbstractService {
|
||||
public override deinit(): void {
|
||||
;(this.itemManager as unknown) = undefined
|
||||
;(this.alertService as unknown) = undefined
|
||||
;(this.deviceInterface as unknown) = undefined
|
||||
;(this.device as unknown) = undefined
|
||||
;(this.httpService as unknown) = undefined
|
||||
;(this.payloadManager as unknown) = undefined
|
||||
;(this.listedService as unknown) = undefined
|
||||
;(this.challengeService as unknown) = undefined
|
||||
;(this.encryptionService as unknown) = undefined
|
||||
;(this.syncService as unknown) = undefined
|
||||
this.payloadRequestHandlers.length = 0
|
||||
this.previousPasswords.length = 0
|
||||
super.deinit()
|
||||
@@ -323,7 +314,7 @@ export class SNActionsService extends AbstractService {
|
||||
}
|
||||
|
||||
private handleShowAction(action: Action) {
|
||||
void this.deviceInterface.openUrl(action.url)
|
||||
void this.device.openUrl(action.url)
|
||||
return {} as ActionResponse
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { joinPaths } from '@standardnotes/utils'
|
||||
import {
|
||||
AbstractService,
|
||||
ApiServiceInterface,
|
||||
LegacyApiServiceInterface,
|
||||
InternalEventBusInterface,
|
||||
IntegrityApiInterface,
|
||||
ItemsServerInterface,
|
||||
@@ -86,10 +86,10 @@ const V0_API_VERSION = '20200115'
|
||||
|
||||
type InvalidSessionObserver = (revoked: boolean) => void
|
||||
|
||||
export class SNApiService
|
||||
export class LegacyApiService
|
||||
extends AbstractService<ApiServiceEvent, ApiServiceEventData>
|
||||
implements
|
||||
ApiServiceInterface,
|
||||
LegacyApiServiceInterface,
|
||||
FilesApiInterface,
|
||||
IntegrityApiInterface,
|
||||
ItemsServerInterface,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { WebSocketApiServiceInterface } from '@standardnotes/api'
|
||||
|
||||
import { StorageKey, DiskStorageService } from '@Lib/index'
|
||||
import { SNWebSocketsService } from './WebsocketsService'
|
||||
import { WebSocketsService } from './WebsocketsService'
|
||||
|
||||
describe('webSocketsService', () => {
|
||||
const webSocketUrl = ''
|
||||
@@ -12,7 +12,7 @@ describe('webSocketsService', () => {
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
|
||||
const createService = () => {
|
||||
return new SNWebSocketsService(storageService, webSocketUrl, webSocketApiService, internalEventBus)
|
||||
return new WebSocketsService(storageService, webSocketUrl, webSocketApiService, internalEventBus)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { WebSocketApiServiceInterface } from '@standardnotes/api'
|
||||
import { WebSocketsServiceEvent } from './WebSocketsServiceEvent'
|
||||
|
||||
export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent, UserRolesChangedEvent> {
|
||||
export class WebSocketsService extends AbstractService<WebSocketsServiceEvent, UserRolesChangedEvent> {
|
||||
private webSocket?: WebSocket
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -158,7 +158,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
||||
return { wrappingKey }
|
||||
}
|
||||
|
||||
public isPasscodeLocked() {
|
||||
public isPasscodeLocked(): Promise<boolean> {
|
||||
return this.encryptionService.isPasscodeLocked()
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
||||
delete this.challengeOperations[challenge.id]
|
||||
}
|
||||
|
||||
public cancelChallenge(challenge: Challenge) {
|
||||
public cancelChallenge(challenge: Challenge): void {
|
||||
const operation = this.challengeOperations[challenge.id]
|
||||
operation.cancel()
|
||||
|
||||
@@ -274,7 +274,7 @@ export class ChallengeService extends AbstractService implements ChallengeServic
|
||||
this.deleteChallengeOperation(operation)
|
||||
}
|
||||
|
||||
public async submitValuesForChallenge(challenge: Challenge, values: ChallengeValue[]) {
|
||||
public async submitValuesForChallenge(challenge: Challenge, values: ChallengeValue[]): Promise<void> {
|
||||
if (values.length === 0) {
|
||||
throw Error('Attempting to submit 0 values for challenge')
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@ import {
|
||||
PreferenceServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { FeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { SNComponentManager } from './ComponentManager'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { SyncService } from '../Sync/SyncService'
|
||||
|
||||
describe('featuresService', () => {
|
||||
let items: ItemManagerInterface
|
||||
let mutator: MutatorClientInterface
|
||||
let features: SNFeaturesService
|
||||
let features: FeaturesService
|
||||
let alerts: AlertService
|
||||
let sync: SyncServiceInterface
|
||||
let prefs: PreferenceServiceInterface
|
||||
@@ -47,7 +47,7 @@ describe('featuresService', () => {
|
||||
attachEvent: jest.fn(),
|
||||
} as unknown as Window & typeof globalThis
|
||||
|
||||
sync = {} as jest.Mocked<SNSyncService>
|
||||
sync = {} as jest.Mocked<SyncService>
|
||||
sync.sync = jest.fn()
|
||||
|
||||
items = {} as jest.Mocked<ItemManager>
|
||||
@@ -61,7 +61,7 @@ describe('featuresService', () => {
|
||||
mutator.changeItem = jest.fn()
|
||||
mutator.changeFeatureRepo = jest.fn()
|
||||
|
||||
features = {} as jest.Mocked<SNFeaturesService>
|
||||
features = {} as jest.Mocked<FeaturesService>
|
||||
|
||||
prefs = {} as jest.Mocked<SNPreferencesService>
|
||||
prefs.addEventObserver = jest.fn()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { FeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import {
|
||||
ActionObserver,
|
||||
@@ -94,7 +94,7 @@ export class SNComponentManager
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
private features: SNFeaturesService,
|
||||
private features: FeaturesService,
|
||||
private preferences: PreferenceServiceInterface,
|
||||
protected alerts: AlertService,
|
||||
private environment: Environment,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
ItemManagerInterface,
|
||||
SyncServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { SNFeaturesService } from '@Lib/Services'
|
||||
import { FeaturesService } from '@Lib/Services'
|
||||
import {
|
||||
ActionObserver,
|
||||
ComponentEventObserver,
|
||||
@@ -100,7 +100,7 @@ export class ComponentViewer implements ComponentViewerInterface {
|
||||
sync: SyncServiceInterface
|
||||
alerts: AlertService
|
||||
preferences: PreferenceServiceInterface
|
||||
features: SNFeaturesService
|
||||
features: FeaturesService
|
||||
},
|
||||
private options: {
|
||||
item: ComponentViewerItem
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { ItemInterface, SNFeatureRepo } from '@standardnotes/models'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { SyncService } from '../Sync/SyncService'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features'
|
||||
import { FeaturesService } from '@Lib/Services/Features'
|
||||
import { RoleName, ContentType } from '@standardnotes/domain-core'
|
||||
import { FeatureIdentifier, GetFeatures } from '@standardnotes/features'
|
||||
import { SNWebSocketsService } from '../Api/WebsocketsService'
|
||||
import { SNSettingsService } from '../Settings'
|
||||
import { WebSocketsService } from '../Api/WebsocketsService'
|
||||
import { SettingsService } from '../Settings'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import {
|
||||
AlertService,
|
||||
ApiServiceInterface,
|
||||
LegacyApiServiceInterface,
|
||||
FeaturesEvent,
|
||||
FeatureStatus,
|
||||
InternalEventBusInterface,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
UserClientInterface,
|
||||
UserService,
|
||||
} from '@standardnotes/services'
|
||||
import { SNApiService, SNSessionManager } from '../Api'
|
||||
import { LegacyApiService, SessionManager } from '../Api'
|
||||
import { ItemManager } from '../Items'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { SettingsClientInterface } from '../Settings/SettingsClientInterface'
|
||||
@@ -33,8 +33,8 @@ describe('FeaturesService', () => {
|
||||
let itemManager: ItemManagerInterface
|
||||
let mutator: MutatorClientInterface
|
||||
let subscriptions: SubscriptionManagerInterface
|
||||
let apiService: ApiServiceInterface
|
||||
let webSocketsService: SNWebSocketsService
|
||||
let apiService: LegacyApiServiceInterface
|
||||
let webSocketsService: WebSocketsService
|
||||
let settingsService: SettingsClientInterface
|
||||
let userService: UserClientInterface
|
||||
let syncService: SyncServiceInterface
|
||||
@@ -46,7 +46,7 @@ describe('FeaturesService', () => {
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
|
||||
const createService = () => {
|
||||
return new SNFeaturesService(
|
||||
return new FeaturesService(
|
||||
storageService,
|
||||
itemManager,
|
||||
mutator,
|
||||
@@ -72,7 +72,7 @@ describe('FeaturesService', () => {
|
||||
storageService.setValue = jest.fn()
|
||||
storageService.getValue = jest.fn()
|
||||
|
||||
apiService = {} as jest.Mocked<SNApiService>
|
||||
apiService = {} as jest.Mocked<LegacyApiService>
|
||||
apiService.addEventObserver = jest.fn()
|
||||
apiService.isThirdPartyHostUsed = jest.fn().mockReturnValue(false)
|
||||
|
||||
@@ -92,23 +92,23 @@ describe('FeaturesService', () => {
|
||||
subscriptions.getOnlineSubscription = jest.fn()
|
||||
subscriptions.addEventObserver = jest.fn()
|
||||
|
||||
webSocketsService = {} as jest.Mocked<SNWebSocketsService>
|
||||
webSocketsService = {} as jest.Mocked<WebSocketsService>
|
||||
webSocketsService.addEventObserver = jest.fn()
|
||||
|
||||
settingsService = {} as jest.Mocked<SNSettingsService>
|
||||
settingsService = {} as jest.Mocked<SettingsService>
|
||||
settingsService.updateSetting = jest.fn()
|
||||
|
||||
userService = {} as jest.Mocked<UserService>
|
||||
userService.addEventObserver = jest.fn()
|
||||
|
||||
syncService = {} as jest.Mocked<SNSyncService>
|
||||
syncService = {} as jest.Mocked<SyncService>
|
||||
syncService.sync = jest.fn()
|
||||
|
||||
alertService = {} as jest.Mocked<AlertService>
|
||||
alertService.confirm = jest.fn().mockReturnValue(true)
|
||||
alertService.alert = jest.fn()
|
||||
|
||||
sessionManager = {} as jest.Mocked<SNSessionManager>
|
||||
sessionManager = {} as jest.Mocked<SessionManager>
|
||||
sessionManager.isSignedIntoFirstPartyServer = jest.fn()
|
||||
sessionManager.getUser = jest.fn()
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { RoleName, ContentType } from '@standardnotes/domain-core'
|
||||
import { PROD_OFFLINE_FEATURES_URL } from '../../Hosts'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { SNWebSocketsService } from '../Api/WebsocketsService'
|
||||
import { WebSocketsService } from '../Api/WebsocketsService'
|
||||
import { WebSocketsServiceEvent } from '../Api/WebSocketsServiceEvent'
|
||||
import { TRUSTED_CUSTOM_EXTENSIONS_HOSTS, TRUSTED_FEATURE_HOSTS } from '@Lib/Hosts'
|
||||
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
StorageKey,
|
||||
MutatorClientInterface,
|
||||
StorageServiceInterface,
|
||||
ApiServiceInterface,
|
||||
LegacyApiServiceInterface,
|
||||
ItemManagerInterface,
|
||||
SyncServiceInterface,
|
||||
SessionsClientInterface,
|
||||
@@ -47,6 +47,8 @@ import {
|
||||
SubscriptionManagerInterface,
|
||||
AccountEvent,
|
||||
SubscriptionManagerEvent,
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
import { DownloadRemoteThirdPartyFeatureUseCase } from './UseCase/DownloadRemoteThirdPartyFeature'
|
||||
@@ -56,7 +58,7 @@ import { SettingsClientInterface } from '../Settings/SettingsClientInterface'
|
||||
|
||||
type GetOfflineSubscriptionDetailsResponse = OfflineSubscriptionEntitlements | ClientDisplayableError
|
||||
|
||||
export class SNFeaturesService
|
||||
export class FeaturesService
|
||||
extends AbstractService<FeaturesEvent>
|
||||
implements FeaturesClientInterface, InternalEventHandlerInterface
|
||||
{
|
||||
@@ -71,8 +73,8 @@ export class SNFeaturesService
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private subscriptions: SubscriptionManagerInterface,
|
||||
private api: ApiServiceInterface,
|
||||
sockets: SNWebSocketsService,
|
||||
private api: LegacyApiServiceInterface,
|
||||
sockets: WebSocketsService,
|
||||
private settings: SettingsClientInterface,
|
||||
private user: UserClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
@@ -152,20 +154,19 @@ export class SNFeaturesService
|
||||
const { userRoles } = event.payload as MetaReceivedData
|
||||
void this.updateOnlineRolesWithNewValues(userRoles.map((role) => role.name))
|
||||
}
|
||||
}
|
||||
|
||||
override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
if (stage === ApplicationStage.FullSyncCompleted_13) {
|
||||
if (!this.hasFirstPartyOnlineSubscription()) {
|
||||
const offlineRepo = this.getOfflineRepo()
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.FullSyncCompleted_13) {
|
||||
if (!this.hasFirstPartyOnlineSubscription()) {
|
||||
const offlineRepo = this.getOfflineRepo()
|
||||
|
||||
if (offlineRepo) {
|
||||
void this.downloadOfflineRoles(offlineRepo)
|
||||
if (offlineRepo) {
|
||||
void this.downloadOfflineRoles(offlineRepo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.handleApplicationStage(stage)
|
||||
}
|
||||
|
||||
public enableExperimentalFeature(identifier: FeatureIdentifier): void {
|
||||
|
||||
@@ -9,13 +9,17 @@ import {
|
||||
import {
|
||||
AlertService,
|
||||
API_MESSAGE_FAILED_DOWNLOADING_EXTENSION,
|
||||
ApiServiceInterface,
|
||||
LegacyApiServiceInterface,
|
||||
ItemManagerInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { isString } from '@standardnotes/utils'
|
||||
|
||||
export class DownloadRemoteThirdPartyFeatureUseCase {
|
||||
constructor(private api: ApiServiceInterface, private items: ItemManagerInterface, private alerts: AlertService) {}
|
||||
constructor(
|
||||
private api: LegacyApiServiceInterface,
|
||||
private items: ItemManagerInterface,
|
||||
private alerts: AlertService,
|
||||
) {}
|
||||
|
||||
async execute(url: string): Promise<ComponentInterface | undefined> {
|
||||
const response = await this.api.downloadFeatureUrl(url)
|
||||
|
||||
@@ -30,7 +30,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 AbstractService implements HistoryServiceInterface {
|
||||
export class HistoryManager extends AbstractService implements HistoryServiceInterface {
|
||||
private removeChangeObserver: () => void
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { ItemsKeyInterface } from '@standardnotes/models'
|
||||
import { dateSorted } from '@standardnotes/utils'
|
||||
import { SNRootKeyParams, EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { SNRootKeyParams } from '@standardnotes/encryption'
|
||||
import { DecryptionQueueItem, KeyRecoveryOperationResult } from './Types'
|
||||
import { serverKeyParamsAreSafe } from './Utils'
|
||||
import { ChallengeServiceInterface, DecryptItemsKeyByPromptingUser } from '@standardnotes/services'
|
||||
import {
|
||||
ChallengeServiceInterface,
|
||||
DecryptItemsKeyByPromptingUser,
|
||||
EncryptionProviderInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { ItemManager } from '../Items'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
getIncrementedDirtyIndex,
|
||||
ContentTypeUsesRootKeyEncryption,
|
||||
} from '@standardnotes/models'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { SyncService } from '../Sync/SyncService'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||
import { ChallengeService } from '../Challenge'
|
||||
import { SNApiService } from '@Lib/Services/Api/ApiService'
|
||||
import { LegacyApiService } from '@Lib/Services/Api/ApiService'
|
||||
import { ItemManager } from '../Items/ItemManager'
|
||||
import { removeFromArray, Uuids } from '@standardnotes/utils'
|
||||
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
||||
@@ -33,6 +33,10 @@ import {
|
||||
EncryptionService,
|
||||
Challenge,
|
||||
UserService,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
} from '@standardnotes/services'
|
||||
import {
|
||||
UndecryptableItemsStorage,
|
||||
@@ -79,7 +83,10 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
* but our current copy is not, we will ignore the incoming value until we can properly
|
||||
* decrypt it.
|
||||
*/
|
||||
export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, DecryptedPayloadInterface[]> {
|
||||
export class KeyRecoveryService
|
||||
extends AbstractService<KeyRecoveryEvent, DecryptedPayloadInterface[]>
|
||||
implements InternalEventHandlerInterface
|
||||
{
|
||||
private removeItemObserver: () => void
|
||||
private decryptionQueue: DecryptionQueueItem[] = []
|
||||
private isProcessingQueue = false
|
||||
@@ -87,12 +94,12 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
||||
constructor(
|
||||
private itemManager: ItemManager,
|
||||
private payloadManager: PayloadManager,
|
||||
private apiService: SNApiService,
|
||||
private apiService: LegacyApiService,
|
||||
private encryptionService: EncryptionService,
|
||||
private challengeService: ChallengeService,
|
||||
private alertService: AlertService,
|
||||
private storageService: DiskStorageService,
|
||||
private syncService: SNSyncService,
|
||||
private sync: SyncService,
|
||||
private userService: UserService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
@@ -126,7 +133,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
||||
;(this.challengeService as unknown) = undefined
|
||||
;(this.alertService as unknown) = undefined
|
||||
;(this.storageService as unknown) = undefined
|
||||
;(this.syncService as unknown) = undefined
|
||||
;(this.sync as unknown) = undefined
|
||||
;(this.userService as unknown) = undefined
|
||||
|
||||
this.removeItemObserver()
|
||||
@@ -135,11 +142,12 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
void super.handleApplicationStage(stage)
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
void this.processPersistedUndecryptables()
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
void this.processPersistedUndecryptables()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,8 +391,8 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
||||
await this.potentiallyPerformFallbackSignInToUpdateOutdatedLocalRootKey(serverParams)
|
||||
}
|
||||
|
||||
if (this.syncService.isOutOfSync()) {
|
||||
void this.syncService.sync({ checkIntegrity: true })
|
||||
if (this.sync.isOutOfSync()) {
|
||||
void this.sync.sync({ checkIntegrity: true })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +508,7 @@ export class SNKeyRecoveryService extends AbstractService<KeyRecoveryEvent, Decr
|
||||
}
|
||||
|
||||
if (decryptedMatching.some((p) => p.dirty)) {
|
||||
await this.syncService.sync()
|
||||
await this.sync.sync()
|
||||
}
|
||||
|
||||
await this.notifyEvent(KeyRecoveryEvent.KeysRecovered, decryptedMatching)
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import { SyncClientInterface } from './../Sync/SyncClientInterface'
|
||||
import { isString, lastElement, sleep } from '@standardnotes/utils'
|
||||
import { UuidString } from '@Lib/Types/UuidString'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { DeprecatedHttpService } from '../Api/DeprecatedHttpService'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { SNSettingsService } from '../Settings/SNSettingsService'
|
||||
import { SettingsService } from '../Settings/SNSettingsService'
|
||||
import { ListedClientInterface } from './ListedClientInterface'
|
||||
import { SNApiService } from '../Api/ApiService'
|
||||
import { LegacyApiService } from '../Api/ApiService'
|
||||
import { isErrorResponse, ListedAccount, ListedAccountInfo, ListedAccountInfoResponse } from '@standardnotes/responses'
|
||||
import { NoteMutator, SNActionsExtension, SNNote } from '@standardnotes/models'
|
||||
import { AbstractService, InternalEventBusInterface, MutatorClientInterface } from '@standardnotes/services'
|
||||
import {
|
||||
AbstractService,
|
||||
InternalEventBusInterface,
|
||||
MutatorClientInterface,
|
||||
SyncServiceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { SNProtectionService } from '../Protection'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
export class ListedService extends AbstractService implements ListedClientInterface {
|
||||
constructor(
|
||||
private apiService: SNApiService,
|
||||
private apiService: LegacyApiService,
|
||||
private itemManager: ItemManager,
|
||||
private settingsService: SNSettingsService,
|
||||
private settingsService: SettingsService,
|
||||
private httpSerivce: DeprecatedHttpService,
|
||||
private protectionService: SNProtectionService,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
|
||||
import { SNSettingsService } from '../Settings'
|
||||
import { SettingsService } from '../Settings'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { SNFeaturesService } from '../Features/FeaturesService'
|
||||
import { FeaturesService } from '../Features/FeaturesService'
|
||||
import { AbstractService, InternalEventBusInterface, SignInStrings } from '@standardnotes/services'
|
||||
|
||||
export class SNMfaService extends AbstractService {
|
||||
constructor(
|
||||
private settingsService: SNSettingsService,
|
||||
private settingsService: SettingsService,
|
||||
private crypto: PureCryptoInterface,
|
||||
private featuresService: SNFeaturesService,
|
||||
private featuresService: FeaturesService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
ApplicationStage,
|
||||
AbstractService,
|
||||
DiagnosticInfo,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
ApplicationStageChangedEventPayload,
|
||||
} from '@standardnotes/services'
|
||||
import { SnjsVersion, isRightVersionGreaterThanLeft } from '../../Version'
|
||||
import { SNLog } from '@Lib/Log'
|
||||
@@ -23,7 +26,7 @@ import { MigrationClasses } from '@Lib/Migrations/Versions'
|
||||
* first launches, and also other steps after the application is unlocked, or after the
|
||||
* first sync completes. Migrations live under /migrations and inherit from the base Migration class.
|
||||
*/
|
||||
export class SNMigrationService extends AbstractService {
|
||||
export class MigrationService extends AbstractService implements InternalEventHandlerInterface {
|
||||
private activeMigrations?: Migration[]
|
||||
private baseMigration!: BaseMigration
|
||||
|
||||
@@ -44,7 +47,7 @@ export class SNMigrationService extends AbstractService {
|
||||
public async initialize(): Promise<void> {
|
||||
await this.runBaseMigrationPreRun()
|
||||
|
||||
const requiredMigrations = SNMigrationService.getRequiredMigrations(await this.getStoredSnjsVersion())
|
||||
const requiredMigrations = MigrationService.getRequiredMigrations(await this.getStoredSnjsVersion())
|
||||
|
||||
this.activeMigrations = this.instantiateMigrationClasses(requiredMigrations)
|
||||
|
||||
@@ -70,13 +73,11 @@ export class SNMigrationService extends AbstractService {
|
||||
await this.baseMigration.preRun()
|
||||
}
|
||||
|
||||
/**
|
||||
* Application instances will call this function directly when they arrive
|
||||
* at a certain migratory state.
|
||||
*/
|
||||
public override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
await super.handleApplicationStage(stage)
|
||||
await this.handleStage(stage)
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
await this.handleStage(stage)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +90,7 @@ export class SNMigrationService extends AbstractService {
|
||||
}
|
||||
|
||||
public async hasPendingMigrations(): Promise<boolean> {
|
||||
const requiredMigrations = SNMigrationService.getRequiredMigrations(await this.getStoredSnjsVersion())
|
||||
const requiredMigrations = MigrationService.getRequiredMigrations(await this.getStoredSnjsVersion())
|
||||
return requiredMigrations.length > 0 || (await this.baseMigration.needsKeychainRepair())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SNUserPrefs, PrefKey, PrefValue, UserPrefsMutator, ItemContent, FillItemContent } from '@standardnotes/models'
|
||||
import { ItemManager } from '../Items/ItemManager'
|
||||
import { SNSingletonManager } from '../Singleton/SingletonManager'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { SingletonManager } from '../Singleton/SingletonManager'
|
||||
import { SyncService } from '../Sync/SyncService'
|
||||
import {
|
||||
AbstractService,
|
||||
InternalEventBusInterface,
|
||||
@@ -10,12 +10,16 @@ import {
|
||||
PreferenceServiceInterface,
|
||||
PreferencesServiceEvent,
|
||||
MutatorClientInterface,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
} from '@standardnotes/services'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
export class SNPreferencesService
|
||||
extends AbstractService<PreferencesServiceEvent>
|
||||
implements PreferenceServiceInterface
|
||||
implements PreferenceServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private shouldReload = true
|
||||
private reloading = false
|
||||
@@ -24,10 +28,10 @@ export class SNPreferencesService
|
||||
private removeSyncObserver?: () => void
|
||||
|
||||
constructor(
|
||||
private singletons: SNSingletonManager,
|
||||
private singletons: SingletonManager,
|
||||
items: ItemManager,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SNSyncService,
|
||||
private sync: SyncService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -52,18 +56,19 @@ export class SNPreferencesService
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
public override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
await super.handleApplicationStage(stage)
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
/** Try to read preferences singleton from storage */
|
||||
this.preferences = this.singletons.findSingleton<SNUserPrefs>(
|
||||
ContentType.TYPES.UserPrefs,
|
||||
SNUserPrefs.singletonPredicate,
|
||||
)
|
||||
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
/** Try to read preferences singleton from storage */
|
||||
this.preferences = this.singletons.findSingleton<SNUserPrefs>(
|
||||
ContentType.TYPES.UserPrefs,
|
||||
SNUserPrefs.singletonPredicate,
|
||||
)
|
||||
|
||||
if (this.preferences) {
|
||||
void this.notifyEvent(PreferencesServiceEvent.PreferencesChanged)
|
||||
if (this.preferences) {
|
||||
void this.notifyEvent(PreferencesServiceEvent.PreferencesChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ import {
|
||||
TimingDisplayOption,
|
||||
ProtectionsClientInterface,
|
||||
MutatorClientInterface,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
} from '@standardnotes/services'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
@@ -70,7 +74,10 @@ export const ProtectionSessionDurations = [
|
||||
* like viewing a protected note, as well as managing how long that
|
||||
* authentication should be valid for.
|
||||
*/
|
||||
export class SNProtectionService extends AbstractService<ProtectionEvent> implements ProtectionsClientInterface {
|
||||
export class SNProtectionService
|
||||
extends AbstractService<ProtectionEvent>
|
||||
implements ProtectionsClientInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private sessionExpiryTimeout = -1
|
||||
private mobilePasscodeTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
|
||||
private mobileBiometricsTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
|
||||
@@ -93,13 +100,15 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
override handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
|
||||
this.mobilePasscodeTiming = this.getMobilePasscodeTiming()
|
||||
this.mobileBiometricsTiming = this.getMobileBiometricsTiming()
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
|
||||
this.mobilePasscodeTiming = this.getMobilePasscodeTiming()
|
||||
this.mobileBiometricsTiming = this.getMobileBiometricsTiming()
|
||||
}
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
public hasProtectionSources(): boolean {
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
InternalFeatureService,
|
||||
InternalFeature,
|
||||
} from '@standardnotes/services'
|
||||
import { Base64String, PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||
import { Base64String, PkcKeyPair, PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import {
|
||||
SessionBody,
|
||||
ErrorTag,
|
||||
@@ -52,9 +52,9 @@ import * as Common from '@standardnotes/common'
|
||||
|
||||
import { RawStorageValue } from './Sessions/Types'
|
||||
import { ShareToken } from './ShareToken'
|
||||
import { SNApiService } from '../Api/ApiService'
|
||||
import { LegacyApiService } from '../Api/ApiService'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { SNWebSocketsService } from '../Api/WebsocketsService'
|
||||
import { WebSocketsService } from '../Api/WebsocketsService'
|
||||
import { Strings } from '@Lib/Strings'
|
||||
import { UuidString } from '@Lib/Types/UuidString'
|
||||
import { ChallengeResponse, ChallengeService } from '../Challenge'
|
||||
@@ -78,7 +78,7 @@ const cleanedEmailString = (email: string) => {
|
||||
* server credentials, such as the session token. It also exposes methods for registering
|
||||
* for a new account, signing into an existing one, or changing an account password.
|
||||
*/
|
||||
export class SNSessionManager
|
||||
export class SessionManager
|
||||
extends AbstractService<SessionEvent>
|
||||
implements SessionsClientInterface, InternalEventHandlerInterface
|
||||
{
|
||||
@@ -87,13 +87,14 @@ export class SNSessionManager
|
||||
private session?: Session | LegacySession
|
||||
|
||||
constructor(
|
||||
private diskStorageService: DiskStorageService,
|
||||
private apiService: SNApiService,
|
||||
private storage: DiskStorageService,
|
||||
private apiService: LegacyApiService,
|
||||
private userApiService: UserApiServiceInterface,
|
||||
private alertService: AlertService,
|
||||
private encryptionService: EncryptionService,
|
||||
private crypto: PureCryptoInterface,
|
||||
private challengeService: ChallengeService,
|
||||
private webSocketsService: SNWebSocketsService,
|
||||
private webSocketsService: WebSocketsService,
|
||||
private httpService: HttpServiceInterface,
|
||||
private sessionStorageMapper: MapperInterface<Session, Record<string, unknown>>,
|
||||
private legacySessionStorageMapper: MapperInterface<LegacySession, Record<string, unknown>>,
|
||||
@@ -118,7 +119,7 @@ export class SNSessionManager
|
||||
|
||||
override deinit(): void {
|
||||
;(this.encryptionService as unknown) = undefined
|
||||
;(this.diskStorageService as unknown) = undefined
|
||||
;(this.storage as unknown) = undefined
|
||||
;(this.apiService as unknown) = undefined
|
||||
;(this.alertService as unknown) = undefined
|
||||
;(this.challengeService as unknown) = undefined
|
||||
@@ -141,17 +142,17 @@ export class SNSessionManager
|
||||
this.apiService.setUser(user)
|
||||
}
|
||||
|
||||
async initializeFromDisk() {
|
||||
this.memoizeUser(this.diskStorageService.getValue(StorageKey.User))
|
||||
async initializeFromDisk(): Promise<void> {
|
||||
this.memoizeUser(this.storage.getValue(StorageKey.User))
|
||||
|
||||
if (!this.user) {
|
||||
const legacyUuidLookup = this.diskStorageService.getValue<string>(StorageKey.LegacyUuid)
|
||||
const legacyUuidLookup = this.storage.getValue<string>(StorageKey.LegacyUuid)
|
||||
if (legacyUuidLookup) {
|
||||
this.memoizeUser({ uuid: legacyUuidLookup, email: legacyUuidLookup })
|
||||
}
|
||||
}
|
||||
|
||||
const rawSession = this.diskStorageService.getValue<RawStorageValue>(StorageKey.Session)
|
||||
const rawSession = this.storage.getValue<RawStorageValue>(StorageKey.Session)
|
||||
if (rawSession) {
|
||||
try {
|
||||
const session =
|
||||
@@ -286,7 +287,7 @@ export class SNSessionManager
|
||||
email,
|
||||
password,
|
||||
false,
|
||||
this.diskStorageService.isEphemeralSession(),
|
||||
this.storage.isEphemeralSession(),
|
||||
currentKeyParams?.version,
|
||||
)
|
||||
if (isErrorResponse(response)) {
|
||||
@@ -630,10 +631,17 @@ export class SNSessionManager
|
||||
if (!isErrorResponse(rawResponse)) {
|
||||
if (InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)) {
|
||||
const eventData: UserKeyPairChangedEventData = {
|
||||
oldKeyPair,
|
||||
oldSigningKeyPair,
|
||||
newKeyPair: parameters.newRootKey.encryptionKeyPair,
|
||||
newSigningKeyPair: parameters.newRootKey.signingKeyPair,
|
||||
previous:
|
||||
oldKeyPair && oldSigningKeyPair
|
||||
? {
|
||||
encryption: oldKeyPair,
|
||||
signing: oldSigningKeyPair,
|
||||
}
|
||||
: undefined,
|
||||
current: {
|
||||
encryption: parameters.newRootKey.encryptionKeyPair,
|
||||
signing: parameters.newRootKey.signingKeyPair,
|
||||
},
|
||||
}
|
||||
|
||||
void this.notifyEvent(SessionEvent.UserKeyPairChanged, eventData)
|
||||
@@ -692,7 +700,7 @@ export class SNSessionManager
|
||||
}
|
||||
|
||||
private decodeDemoShareToken(token: Base64String): ShareToken {
|
||||
const jsonString = this.encryptionService.crypto.base64Decode(token)
|
||||
const jsonString = this.crypto.base64Decode(token)
|
||||
return JSON.parse(jsonString)
|
||||
}
|
||||
|
||||
@@ -712,7 +720,7 @@ export class SNSessionManager
|
||||
await this.encryptionService.setRootKey(rootKey, wrappingKey)
|
||||
|
||||
this.memoizeUser(user)
|
||||
this.diskStorageService.setValue(StorageKey.User, user)
|
||||
this.storage.setValue(StorageKey.User, user)
|
||||
|
||||
void this.apiService.setHost(host)
|
||||
this.httpService.setHost(host)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SNApiService } from '../Api/ApiService'
|
||||
import { LegacyApiService } from '../Api/ApiService'
|
||||
import { SettingsGateway } from './SettingsGateway'
|
||||
import { SNSessionManager } from '../Session/SessionManager'
|
||||
import { SessionManager } from '../Session/SessionManager'
|
||||
import { EmailBackupFrequency, SettingName } from '@standardnotes/settings'
|
||||
import { AbstractService, InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { SettingsClientInterface } from './SettingsClientInterface'
|
||||
|
||||
export class SNSettingsService extends AbstractService implements SettingsClientInterface {
|
||||
export class SettingsService extends AbstractService implements SettingsClientInterface {
|
||||
private provider!: SettingsGateway
|
||||
private frequencyOptionsLabels = {
|
||||
[EmailBackupFrequency.Disabled]: 'No email backups',
|
||||
@@ -14,8 +14,8 @@ export class SNSettingsService extends AbstractService implements SettingsClient
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly sessionManager: SNSessionManager,
|
||||
private readonly apiService: SNApiService,
|
||||
private readonly sessionManager: SessionManager,
|
||||
private readonly apiService: LegacyApiService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Predicate,
|
||||
} from '@standardnotes/models'
|
||||
import { arrayByRemovingFromIndex, extendArray, UuidGenerator } from '@standardnotes/utils'
|
||||
import { SNSyncService } from '../Sync/SyncService'
|
||||
import { SyncService } from '../Sync/SyncService'
|
||||
import {
|
||||
AbstractService,
|
||||
InternalEventBusInterface,
|
||||
@@ -33,7 +33,7 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
* 2. Items can override isSingleton, singletonPredicate, and strategyWhenConflictingWithItem (optional)
|
||||
* to automatically gain singleton resolution.
|
||||
*/
|
||||
export class SNSingletonManager extends AbstractService implements SingletonManagerInterface {
|
||||
export class SingletonManager extends AbstractService implements SingletonManagerInterface {
|
||||
private resolveQueue: DecryptedItemInterface[] = []
|
||||
|
||||
private removeItemObserver!: () => void
|
||||
@@ -43,7 +43,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
private itemManager: ItemManager,
|
||||
private mutator: MutatorClientInterface,
|
||||
private payloadManager: PayloadManager,
|
||||
private syncService: SNSyncService,
|
||||
private sync: SyncService,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -51,7 +51,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
|
||||
public override deinit(): void {
|
||||
;(this.syncService as unknown) = undefined
|
||||
;(this.sync as unknown) = undefined
|
||||
;(this.mutator as unknown) = undefined
|
||||
;(this.itemManager as unknown) = undefined
|
||||
;(this.payloadManager as unknown) = undefined
|
||||
@@ -93,7 +93,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
})
|
||||
|
||||
this.removeSyncObserver = this.syncService.addEventObserver(async (eventName) => {
|
||||
this.removeSyncObserver = this.sync.addEventObserver(async (eventName) => {
|
||||
if (
|
||||
eventName === SyncEvent.DownloadFirstSyncCompleted ||
|
||||
eventName === SyncEvent.SyncCompletedWithAllItemsUploaded
|
||||
@@ -142,7 +142,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
* of a download-first request.
|
||||
*/
|
||||
if (handled.length > 0 && eventSource === SyncEvent.SyncCompletedWithAllItemsUploaded) {
|
||||
await this.syncService?.sync({ sourceDescription: 'Resolve singletons for items' })
|
||||
await this.sync?.sync({ sourceDescription: 'Resolve singletons for items' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
|
||||
/** Item not found, safe to create after full sync has completed */
|
||||
if (!this.syncService.getLastSyncDate()) {
|
||||
if (!this.sync.getLastSyncDate()) {
|
||||
/**
|
||||
* Add a temporary observer in case of long-running sync request, where
|
||||
* the item we're looking for ends up resolving early or in the middle.
|
||||
@@ -199,7 +199,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
})
|
||||
|
||||
await this.syncService.sync({ sourceDescription: 'Find or create singleton, before any sync has completed' })
|
||||
await this.sync.sync({ sourceDescription: 'Find or create singleton, before any sync has completed' })
|
||||
|
||||
removeObserver()
|
||||
|
||||
@@ -233,7 +233,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
|
||||
const item = await this.mutator.emitItemFromPayload(dirtyPayload, PayloadEmitSource.LocalInserted)
|
||||
|
||||
void this.syncService.sync({ sourceDescription: 'After find or create singleton' })
|
||||
void this.sync.sync({ sourceDescription: 'After find or create singleton' })
|
||||
|
||||
return item as T
|
||||
}
|
||||
@@ -248,7 +248,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
|
||||
/** Item not found, safe to create after full sync has completed */
|
||||
if (!this.syncService.getLastSyncDate()) {
|
||||
if (!this.sync.getLastSyncDate()) {
|
||||
/**
|
||||
* Add a temporary observer in case of long-running sync request, where
|
||||
* the item we're looking for ends up resolving early or in the middle.
|
||||
@@ -265,7 +265,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
}
|
||||
})
|
||||
|
||||
await this.syncService.sync({ sourceDescription: 'Find or create singleton, before any sync has completed' })
|
||||
await this.sync.sync({ sourceDescription: 'Find or create singleton, before any sync has completed' })
|
||||
|
||||
removeObserver()
|
||||
|
||||
@@ -292,7 +292,7 @@ export class SNSingletonManager extends AbstractService implements SingletonMana
|
||||
|
||||
const item = await this.mutator.emitItemFromPayload(dirtyPayload, PayloadEmitSource.LocalInserted)
|
||||
|
||||
void this.syncService.sync({ sourceDescription: 'After find or create singleton' })
|
||||
void this.sync.sync({ sourceDescription: 'After find or create singleton' })
|
||||
|
||||
return item as T
|
||||
}
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
import { Copy, extendArray, UuidGenerator, Uuids } from '@standardnotes/utils'
|
||||
import { SNLog } from '../../Log'
|
||||
import { isErrorDecryptingParameters, SNRootKey } from '@standardnotes/encryption'
|
||||
import * as Encryption from '@standardnotes/encryption'
|
||||
import * as Services from '@standardnotes/services'
|
||||
import {
|
||||
KeyedDecryptionSplit,
|
||||
KeyedEncryptionSplit,
|
||||
SplitPayloadsByEncryptionType,
|
||||
CreateEncryptionSplitWithKeyLookup,
|
||||
isErrorDecryptingParameters,
|
||||
SNRootKey,
|
||||
} from '@standardnotes/encryption'
|
||||
import {
|
||||
AbstractService,
|
||||
StorageServiceInterface,
|
||||
InternalEventHandlerInterface,
|
||||
StoragePersistencePolicies,
|
||||
StorageValuesObject,
|
||||
DeviceInterface,
|
||||
InternalEventBusInterface,
|
||||
InternalEventInterface,
|
||||
ApplicationEvent,
|
||||
ApplicationStageChangedEventPayload,
|
||||
ApplicationStage,
|
||||
ValueModesKeys,
|
||||
StorageValueModes,
|
||||
namespacedKey,
|
||||
RawStorageKey,
|
||||
WrappedStorageValue,
|
||||
ValuesObjectRecord,
|
||||
EncryptionProviderInterface,
|
||||
} from '@standardnotes/services'
|
||||
import {
|
||||
CreateDecryptedLocalStorageContextPayload,
|
||||
CreateDeletedLocalStorageContextPayload,
|
||||
@@ -31,25 +56,28 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
* decrypt the persisted key/values, and also a method to determine whether a particular
|
||||
* key can decrypt wrapped storage.
|
||||
*/
|
||||
export class DiskStorageService extends Services.AbstractService implements Services.StorageServiceInterface {
|
||||
private encryptionProvider!: Encryption.EncryptionProviderInterface
|
||||
export class DiskStorageService
|
||||
extends AbstractService
|
||||
implements StorageServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private encryptionProvider!: EncryptionProviderInterface
|
||||
private storagePersistable = false
|
||||
private persistencePolicy!: Services.StoragePersistencePolicies
|
||||
private persistencePolicy!: StoragePersistencePolicies
|
||||
private needsPersist = false
|
||||
private currentPersistPromise?: Promise<Services.StorageValuesObject>
|
||||
private currentPersistPromise?: Promise<StorageValuesObject>
|
||||
|
||||
private values!: Services.StorageValuesObject
|
||||
private values!: StorageValuesObject
|
||||
|
||||
constructor(
|
||||
private deviceInterface: Services.DeviceInterface,
|
||||
private deviceInterface: DeviceInterface,
|
||||
private identifier: string,
|
||||
protected override internalEventBus: Services.InternalEventBusInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
void this.setPersistencePolicy(Services.StoragePersistencePolicies.Default)
|
||||
void this.setPersistencePolicy(StoragePersistencePolicies.Default)
|
||||
}
|
||||
|
||||
public provideEncryptionProvider(provider: Encryption.EncryptionProviderInterface): void {
|
||||
public provideEncryptionProvider(provider: EncryptionProviderInterface): void {
|
||||
this.encryptionProvider = provider
|
||||
}
|
||||
|
||||
@@ -60,21 +88,22 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
override async handleApplicationStage(stage: Services.ApplicationStage) {
|
||||
await super.handleApplicationStage(stage)
|
||||
|
||||
if (stage === Services.ApplicationStage.Launched_10) {
|
||||
this.storagePersistable = true
|
||||
if (this.needsPersist) {
|
||||
void this.persistValuesToDisk()
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
if (stage === ApplicationStage.Launched_10) {
|
||||
this.storagePersistable = true
|
||||
if (this.needsPersist) {
|
||||
void this.persistValuesToDisk()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async setPersistencePolicy(persistencePolicy: Services.StoragePersistencePolicies) {
|
||||
public async setPersistencePolicy(persistencePolicy: StoragePersistencePolicies) {
|
||||
this.persistencePolicy = persistencePolicy
|
||||
|
||||
if (this.persistencePolicy === Services.StoragePersistencePolicies.Ephemeral) {
|
||||
if (this.persistencePolicy === StoragePersistencePolicies.Ephemeral) {
|
||||
await this.deviceInterface.clearNamespacedKeychainValue(this.identifier)
|
||||
await this.deviceInterface.removeAllDatabaseEntries(this.identifier)
|
||||
await this.deviceInterface.removeRawStorageValuesForIdentifier(this.identifier)
|
||||
@@ -82,42 +111,42 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
}
|
||||
}
|
||||
|
||||
public isEphemeralSession() {
|
||||
return this.persistencePolicy === Services.StoragePersistencePolicies.Ephemeral
|
||||
public isEphemeralSession(): boolean {
|
||||
return this.persistencePolicy === StoragePersistencePolicies.Ephemeral
|
||||
}
|
||||
|
||||
public async initializeFromDisk() {
|
||||
public async initializeFromDisk(): Promise<void> {
|
||||
const value = await this.deviceInterface.getRawStorageValue(this.getPersistenceKey())
|
||||
const values = value ? JSON.parse(value as string) : undefined
|
||||
|
||||
await this.setInitialValues(values)
|
||||
}
|
||||
|
||||
private async setInitialValues(values?: Services.StorageValuesObject) {
|
||||
private async setInitialValues(values?: StorageValuesObject) {
|
||||
const sureValues = values || this.defaultValuesObject()
|
||||
|
||||
if (!sureValues[Services.ValueModesKeys.Unwrapped]) {
|
||||
sureValues[Services.ValueModesKeys.Unwrapped] = {}
|
||||
if (!sureValues[ValueModesKeys.Unwrapped]) {
|
||||
sureValues[ValueModesKeys.Unwrapped] = {}
|
||||
}
|
||||
|
||||
this.values = sureValues
|
||||
|
||||
if (!this.isStorageWrapped()) {
|
||||
this.values[Services.ValueModesKeys.Unwrapped] = {
|
||||
...(this.values[Services.ValueModesKeys.Wrapped].content as object),
|
||||
...this.values[Services.ValueModesKeys.Unwrapped],
|
||||
this.values[ValueModesKeys.Unwrapped] = {
|
||||
...(this.values[ValueModesKeys.Wrapped].content as object),
|
||||
...this.values[ValueModesKeys.Unwrapped],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public isStorageWrapped(): boolean {
|
||||
const wrappedValue = this.values[Services.ValueModesKeys.Wrapped]
|
||||
const wrappedValue = this.values[ValueModesKeys.Wrapped]
|
||||
|
||||
return wrappedValue != undefined && isEncryptedLocalStoragePayload(wrappedValue)
|
||||
}
|
||||
|
||||
public async canDecryptWithKey(key: SNRootKey): Promise<boolean> {
|
||||
const wrappedValue = this.values[Services.ValueModesKeys.Wrapped]
|
||||
const wrappedValue = this.values[ValueModesKeys.Wrapped]
|
||||
|
||||
if (!isEncryptedLocalStoragePayload(wrappedValue)) {
|
||||
throw Error('Attempting to decrypt non decrypted storage value')
|
||||
@@ -143,7 +172,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
content_type: ContentType.TYPES.EncryptedStorage,
|
||||
})
|
||||
|
||||
const split: Encryption.KeyedDecryptionSplit = key
|
||||
const split: KeyedDecryptionSplit = key
|
||||
? {
|
||||
usesRootKey: {
|
||||
items: [payload],
|
||||
@@ -161,8 +190,8 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
return decryptedPayload
|
||||
}
|
||||
|
||||
public async decryptStorage() {
|
||||
const wrappedValue = this.values[Services.ValueModesKeys.Wrapped]
|
||||
public async decryptStorage(): Promise<void> {
|
||||
const wrappedValue = this.values[ValueModesKeys.Wrapped]
|
||||
|
||||
if (!isEncryptedLocalStoragePayload(wrappedValue)) {
|
||||
throw Error('Attempting to decrypt already decrypted storage')
|
||||
@@ -174,7 +203,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
throw SNLog.error(Error('Unable to decrypt storage.'))
|
||||
}
|
||||
|
||||
this.values[Services.ValueModesKeys.Unwrapped] = Copy(decryptedPayload.content)
|
||||
this.values[ValueModesKeys.Unwrapped] = Copy(decryptedPayload.content)
|
||||
}
|
||||
|
||||
/** @todo This function should be debounced. */
|
||||
@@ -184,7 +213,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
return
|
||||
}
|
||||
|
||||
if (this.persistencePolicy === Services.StoragePersistencePolicies.Ephemeral) {
|
||||
if (this.persistencePolicy === StoragePersistencePolicies.Ephemeral) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -195,18 +224,18 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
const values = await this.immediatelyPersistValuesToDisk()
|
||||
|
||||
/** Save the persisted value so we have access to it in memory (for unit tests afawk) */
|
||||
this.values[Services.ValueModesKeys.Wrapped] = values[Services.ValueModesKeys.Wrapped]
|
||||
this.values[ValueModesKeys.Wrapped] = values[ValueModesKeys.Wrapped]
|
||||
}
|
||||
|
||||
public async awaitPersist(): Promise<void> {
|
||||
await this.currentPersistPromise
|
||||
}
|
||||
|
||||
private async immediatelyPersistValuesToDisk(): Promise<Services.StorageValuesObject> {
|
||||
private async immediatelyPersistValuesToDisk(): Promise<StorageValuesObject> {
|
||||
this.currentPersistPromise = this.executeCriticalFunction(async () => {
|
||||
const values = await this.generatePersistableValues()
|
||||
|
||||
const persistencePolicySuddenlyChanged = this.persistencePolicy === Services.StoragePersistencePolicies.Ephemeral
|
||||
const persistencePolicySuddenlyChanged = this.persistencePolicy === StoragePersistencePolicies.Ephemeral
|
||||
if (persistencePolicySuddenlyChanged) {
|
||||
return values
|
||||
}
|
||||
@@ -224,10 +253,10 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
* either as a plain object, or an encrypted item.
|
||||
*/
|
||||
private async generatePersistableValues() {
|
||||
const rawContent = <Partial<Services.StorageValuesObject>>Copy(this.values)
|
||||
const rawContent = <Partial<StorageValuesObject>>Copy(this.values)
|
||||
|
||||
const valuesToWrap = rawContent[Services.ValueModesKeys.Unwrapped]
|
||||
rawContent[Services.ValueModesKeys.Unwrapped] = undefined
|
||||
const valuesToWrap = rawContent[ValueModesKeys.Unwrapped]
|
||||
rawContent[ValueModesKeys.Unwrapped] = undefined
|
||||
|
||||
const payload = new DecryptedPayload({
|
||||
uuid: UuidGenerator.GenerateUuid(),
|
||||
@@ -237,7 +266,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
})
|
||||
|
||||
if (this.encryptionProvider.hasRootKeyEncryptionSource()) {
|
||||
const split: Encryption.KeyedEncryptionSplit = {
|
||||
const split: KeyedEncryptionSplit = {
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -245,31 +274,27 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
|
||||
const encryptedPayload = await this.encryptionProvider.encryptSplitSingle(split)
|
||||
|
||||
rawContent[Services.ValueModesKeys.Wrapped] = CreateEncryptedLocalStorageContextPayload(encryptedPayload)
|
||||
rawContent[ValueModesKeys.Wrapped] = CreateEncryptedLocalStorageContextPayload(encryptedPayload)
|
||||
} else {
|
||||
rawContent[Services.ValueModesKeys.Wrapped] = CreateDecryptedLocalStorageContextPayload(payload)
|
||||
rawContent[ValueModesKeys.Wrapped] = CreateDecryptedLocalStorageContextPayload(payload)
|
||||
}
|
||||
|
||||
return rawContent as Services.StorageValuesObject
|
||||
return rawContent as StorageValuesObject
|
||||
}
|
||||
|
||||
public setValue<T>(key: string, value: T, mode = Services.StorageValueModes.Default): void {
|
||||
public setValue<T>(key: string, value: T, mode = StorageValueModes.Default): void {
|
||||
this.setValueWithNoPersist(key, value, mode)
|
||||
|
||||
void this.persistValuesToDisk()
|
||||
}
|
||||
|
||||
public async setValueAndAwaitPersist(
|
||||
key: string,
|
||||
value: unknown,
|
||||
mode = Services.StorageValueModes.Default,
|
||||
): Promise<void> {
|
||||
public async setValueAndAwaitPersist(key: string, value: unknown, mode = StorageValueModes.Default): Promise<void> {
|
||||
this.setValueWithNoPersist(key, value, mode)
|
||||
|
||||
await this.persistValuesToDisk()
|
||||
}
|
||||
|
||||
private setValueWithNoPersist(key: string, value: unknown, mode = Services.StorageValueModes.Default): void {
|
||||
private setValueWithNoPersist(key: string, value: unknown, mode = StorageValueModes.Default): void {
|
||||
if (!this.values) {
|
||||
throw Error(`Attempting to set storage key ${key} before loading local storage.`)
|
||||
}
|
||||
@@ -279,7 +304,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
domainStorage[key] = value
|
||||
}
|
||||
|
||||
public getValue<T>(key: string, mode = Services.StorageValueModes.Default, defaultValue?: T): T {
|
||||
public getValue<T>(key: string, mode = StorageValueModes.Default, defaultValue?: T): T {
|
||||
if (!this.values) {
|
||||
throw Error(`Attempting to get storage key ${key} before loading local storage.`)
|
||||
}
|
||||
@@ -293,7 +318,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
return value != undefined ? (value as T) : (defaultValue as T)
|
||||
}
|
||||
|
||||
public getAllKeys(mode = Services.StorageValueModes.Default): string[] {
|
||||
public getAllKeys(mode = StorageValueModes.Default): string[] {
|
||||
if (!this.values) {
|
||||
throw Error('Attempting to get all keys before loading local storage.')
|
||||
}
|
||||
@@ -301,7 +326,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
return Object.keys(this.values[this.domainKeyForMode(mode)])
|
||||
}
|
||||
|
||||
public async removeValue(key: string, mode = Services.StorageValueModes.Default): Promise<void> {
|
||||
public async removeValue(key: string, mode = StorageValueModes.Default): Promise<void> {
|
||||
if (!this.values) {
|
||||
throw Error(`Attempting to remove storage key ${key} before loading local storage.`)
|
||||
}
|
||||
@@ -318,34 +343,34 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
* Default persistence key. Platforms can override as needed.
|
||||
*/
|
||||
private getPersistenceKey() {
|
||||
return Services.namespacedKey(this.identifier, Services.RawStorageKey.StorageObject)
|
||||
return namespacedKey(this.identifier, RawStorageKey.StorageObject)
|
||||
}
|
||||
|
||||
private defaultValuesObject(
|
||||
wrapped?: Services.WrappedStorageValue,
|
||||
unwrapped?: Services.ValuesObjectRecord,
|
||||
nonwrapped?: Services.ValuesObjectRecord,
|
||||
wrapped?: WrappedStorageValue,
|
||||
unwrapped?: ValuesObjectRecord,
|
||||
nonwrapped?: ValuesObjectRecord,
|
||||
) {
|
||||
return DiskStorageService.DefaultValuesObject(wrapped, unwrapped, nonwrapped)
|
||||
}
|
||||
|
||||
public static DefaultValuesObject(
|
||||
wrapped: Services.WrappedStorageValue = {} as Services.WrappedStorageValue,
|
||||
unwrapped: Services.ValuesObjectRecord = {},
|
||||
nonwrapped: Services.ValuesObjectRecord = {},
|
||||
wrapped: WrappedStorageValue = {} as WrappedStorageValue,
|
||||
unwrapped: ValuesObjectRecord = {},
|
||||
nonwrapped: ValuesObjectRecord = {},
|
||||
) {
|
||||
return {
|
||||
[Services.ValueModesKeys.Wrapped]: wrapped,
|
||||
[Services.ValueModesKeys.Unwrapped]: unwrapped,
|
||||
[Services.ValueModesKeys.Nonwrapped]: nonwrapped,
|
||||
} as Services.StorageValuesObject
|
||||
[ValueModesKeys.Wrapped]: wrapped,
|
||||
[ValueModesKeys.Unwrapped]: unwrapped,
|
||||
[ValueModesKeys.Nonwrapped]: nonwrapped,
|
||||
} as StorageValuesObject
|
||||
}
|
||||
|
||||
private domainKeyForMode(mode: Services.StorageValueModes) {
|
||||
if (mode === Services.StorageValueModes.Default) {
|
||||
return Services.ValueModesKeys.Unwrapped
|
||||
} else if (mode === Services.StorageValueModes.Nonwrapped) {
|
||||
return Services.ValueModesKeys.Nonwrapped
|
||||
private domainKeyForMode(mode: StorageValueModes) {
|
||||
if (mode === StorageValueModes.Default) {
|
||||
return ValueModesKeys.Unwrapped
|
||||
} else if (mode === StorageValueModes.Nonwrapped) {
|
||||
return ValueModesKeys.Nonwrapped
|
||||
} else {
|
||||
throw Error('Invalid mode')
|
||||
}
|
||||
@@ -368,7 +393,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
}
|
||||
|
||||
public async savePayloads(payloads: FullyFormedPayloadInterface[]): Promise<void> {
|
||||
if (this.persistencePolicy === Services.StoragePersistencePolicies.Ephemeral) {
|
||||
if (this.persistencePolicy === StoragePersistencePolicies.Ephemeral) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -380,7 +405,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
const unencryptable: DecryptedPayloadInterface[] = []
|
||||
|
||||
const { rootKeyEncryption, keySystemRootKeyEncryption, itemsKeyEncryption } =
|
||||
Encryption.SplitPayloadsByEncryptionType(decrypted)
|
||||
SplitPayloadsByEncryptionType(decrypted)
|
||||
|
||||
if (itemsKeyEncryption) {
|
||||
extendArray(encryptable, itemsKeyEncryption)
|
||||
@@ -402,9 +427,9 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
await this.deletePayloads(discardable)
|
||||
}
|
||||
|
||||
const encryptableSplit = Encryption.SplitPayloadsByEncryptionType(encryptable)
|
||||
const encryptableSplit = SplitPayloadsByEncryptionType(encryptable)
|
||||
|
||||
const keyLookupSplit = Encryption.CreateEncryptionSplitWithKeyLookup(encryptableSplit)
|
||||
const keyLookupSplit = CreateEncryptionSplitWithKeyLookup(encryptableSplit)
|
||||
|
||||
const encryptedResults = await this.encryptionProvider.encryptSplit(keyLookupSplit)
|
||||
|
||||
@@ -449,9 +474,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
await this.clearValues()
|
||||
await this.clearAllPayloads()
|
||||
|
||||
await this.deviceInterface.removeRawStorageValue(
|
||||
Services.namespacedKey(this.identifier, Services.RawStorageKey.SnjsVersion),
|
||||
)
|
||||
await this.deviceInterface.removeRawStorageValue(namespacedKey(this.identifier, RawStorageKey.SnjsVersion))
|
||||
|
||||
await this.deviceInterface.removeRawStorageValue(this.getPersistenceKey())
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ServerSyncPushContextualPayload } from '@standardnotes/models'
|
||||
import { arrayByDifference, nonSecureRandomIdentifier, subtractFromArray } from '@standardnotes/utils'
|
||||
import { ServerSyncResponse } from '@Lib/Services/Sync/Account/Response'
|
||||
import { ResponseSignalReceiver, SyncSignal } from '@Lib/Services/Sync/Signals'
|
||||
import { SNApiService } from '../../Api/ApiService'
|
||||
import { LegacyApiService } from '../../Api/ApiService'
|
||||
|
||||
export const SyncUpDownLimit = 150
|
||||
|
||||
@@ -23,7 +23,7 @@ export class AccountSyncOperation {
|
||||
constructor(
|
||||
public readonly payloads: ServerSyncPushContextualPayload[],
|
||||
private receiver: ResponseSignalReceiver<ServerSyncResponse>,
|
||||
private apiService: SNApiService,
|
||||
private apiService: LegacyApiService,
|
||||
public readonly options: {
|
||||
syncToken?: string
|
||||
paginationToken?: string
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SyncOpStatus } from './SyncOpStatus'
|
||||
import { AbstractService, SyncEvent, SyncOptions } from '@standardnotes/services'
|
||||
|
||||
export interface SyncClientInterface extends AbstractService<SyncEvent> {
|
||||
setLaunchPriorityUuids(launchPriorityUuids: string[]): void
|
||||
sync(options?: Partial<SyncOptions>): Promise<unknown>
|
||||
isOutOfSync(): boolean
|
||||
getLastSyncDate(): Date | undefined
|
||||
getSyncStatus(): SyncOpStatus
|
||||
lockSyncing(): void
|
||||
unlockSyncing(): void
|
||||
|
||||
completedOnlineDownloadFirstSync: boolean
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
import { SyncEvent, SyncEventReceiver } from '@standardnotes/services'
|
||||
|
||||
const HEALTHY_SYNC_DURATION_THRESHOLD_S = 5
|
||||
const TIMING_MONITOR_POLL_FREQUENCY_MS = 500
|
||||
|
||||
export class SyncOpStatus {
|
||||
error?: any
|
||||
private interval: any
|
||||
private receiver: SyncEventReceiver
|
||||
private completedUpload = 0
|
||||
private totalUpload = 0
|
||||
private downloaded = 0
|
||||
private databaseLoadCurrent = 0
|
||||
private databaseLoadTotal = 0
|
||||
private databaseLoadDone = false
|
||||
private syncing = false
|
||||
private syncStart!: Date
|
||||
private timingMonitor?: any
|
||||
|
||||
constructor(interval: any, receiver: SyncEventReceiver) {
|
||||
this.interval = interval
|
||||
this.receiver = receiver
|
||||
}
|
||||
|
||||
public deinit() {
|
||||
this.stopTimingMonitor()
|
||||
}
|
||||
|
||||
public setUploadStatus(completed: number, total: number) {
|
||||
this.completedUpload = completed
|
||||
this.totalUpload = total
|
||||
this.receiver(SyncEvent.StatusChanged)
|
||||
}
|
||||
|
||||
public setDownloadStatus(downloaded: number) {
|
||||
this.downloaded += downloaded
|
||||
this.receiver(SyncEvent.StatusChanged)
|
||||
}
|
||||
|
||||
public setDatabaseLoadStatus(current: number, total: number, done: boolean) {
|
||||
this.databaseLoadCurrent = current
|
||||
this.databaseLoadTotal = total
|
||||
this.databaseLoadDone = done
|
||||
if (done) {
|
||||
this.receiver(SyncEvent.LocalDataLoaded)
|
||||
} else {
|
||||
this.receiver(SyncEvent.LocalDataIncrementalLoad)
|
||||
}
|
||||
}
|
||||
|
||||
public getStats() {
|
||||
return {
|
||||
uploadCompletionCount: this.completedUpload,
|
||||
uploadTotalCount: this.totalUpload,
|
||||
downloadCount: this.downloaded,
|
||||
localDataDone: this.databaseLoadDone,
|
||||
localDataCurrent: this.databaseLoadCurrent,
|
||||
localDataTotal: this.databaseLoadTotal,
|
||||
}
|
||||
}
|
||||
|
||||
public setDidBegin() {
|
||||
this.syncing = true
|
||||
this.syncStart = new Date()
|
||||
}
|
||||
|
||||
public setDidEnd() {
|
||||
this.syncing = false
|
||||
}
|
||||
|
||||
get syncInProgress() {
|
||||
return this.syncing === true
|
||||
}
|
||||
|
||||
get secondsSinceSyncStart() {
|
||||
return (new Date().getTime() - this.syncStart.getTime()) / 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies receiver if current sync request is taking too long to complete.
|
||||
*/
|
||||
startTimingMonitor(): void {
|
||||
if (this.timingMonitor) {
|
||||
this.stopTimingMonitor()
|
||||
}
|
||||
|
||||
this.timingMonitor = this.interval(() => {
|
||||
if (this.secondsSinceSyncStart > HEALTHY_SYNC_DURATION_THRESHOLD_S) {
|
||||
this.receiver(SyncEvent.SyncTakingTooLong)
|
||||
this.stopTimingMonitor()
|
||||
}
|
||||
}, TIMING_MONITOR_POLL_FREQUENCY_MS)
|
||||
}
|
||||
|
||||
stopTimingMonitor(): void {
|
||||
if (Object.prototype.hasOwnProperty.call(this.interval, 'cancel')) {
|
||||
this.interval.cancel(this.timingMonitor)
|
||||
} else {
|
||||
clearInterval(this.timingMonitor)
|
||||
}
|
||||
this.timingMonitor = null
|
||||
}
|
||||
|
||||
hasError(): boolean {
|
||||
return !!this.error
|
||||
}
|
||||
|
||||
setError(error: any): void {
|
||||
this.error = error
|
||||
}
|
||||
|
||||
clearError() {
|
||||
this.error = null
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.downloaded = 0
|
||||
this.completedUpload = 0
|
||||
this.totalUpload = 0
|
||||
this.syncing = false
|
||||
this.error = null
|
||||
this.stopTimingMonitor()
|
||||
this.receiver(SyncEvent.StatusChanged)
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,12 @@ import {
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { OfflineSyncOperation } from '@Lib/Services/Sync/Offline/Operation'
|
||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||
import { SNApiService } from '../Api/ApiService'
|
||||
import { SNHistoryManager } from '../History/HistoryManager'
|
||||
import { LegacyApiService } from '../Api/ApiService'
|
||||
import { HistoryManager } from '../History/HistoryManager'
|
||||
import { SNLog } from '@Lib/Log'
|
||||
import { SNSessionManager } from '../Session/SessionManager'
|
||||
import { SessionManager } from '../Session/SessionManager'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { SyncClientInterface } from './SyncClientInterface'
|
||||
import { SyncPromise } from './Types'
|
||||
import { SyncOpStatus } from '@Lib/Services/Sync/SyncOpStatus'
|
||||
import { ServerSyncResponse } from '@Lib/Services/Sync/Account/Response'
|
||||
import { ServerSyncResponseResolver } from '@Lib/Services/Sync/Account/ResponseResolver'
|
||||
import { SyncSignal, SyncStats } from '@Lib/Services/Sync/Signals'
|
||||
@@ -84,6 +82,7 @@ import {
|
||||
SyncEventReceivedRemoteSharedVaultsData,
|
||||
SyncEventReceivedUserEventsData,
|
||||
SyncEventReceivedAsymmetricMessagesData,
|
||||
SyncOpStatus,
|
||||
} from '@standardnotes/services'
|
||||
import { OfflineSyncResponse } from './Offline/Response'
|
||||
import {
|
||||
@@ -121,9 +120,9 @@ const ContentTypeLocalLoadPriorty = [
|
||||
* After each sync request, any changes made or retrieved are also persisted locally.
|
||||
* The sync service largely does not perform any task unless it is called upon.
|
||||
*/
|
||||
export class SNSyncService
|
||||
export class SyncService
|
||||
extends AbstractService<SyncEvent>
|
||||
implements SyncServiceInterface, InternalEventHandlerInterface, SyncClientInterface
|
||||
implements SyncServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private dirtyIndexAtLastPresyncSave?: number
|
||||
private lastSyncDate?: Date
|
||||
@@ -152,12 +151,12 @@ export class SNSyncService
|
||||
|
||||
constructor(
|
||||
private itemManager: ItemManager,
|
||||
private sessionManager: SNSessionManager,
|
||||
private sessionManager: SessionManager,
|
||||
private encryptionService: EncryptionService,
|
||||
private storageService: DiskStorageService,
|
||||
private payloadManager: PayloadManager,
|
||||
private apiService: SNApiService,
|
||||
private historyService: SNHistoryManager,
|
||||
private apiService: LegacyApiService,
|
||||
private historyService: HistoryManager,
|
||||
private device: DeviceInterface,
|
||||
private identifier: string,
|
||||
private readonly options: ApplicationSyncOptions,
|
||||
@@ -968,25 +967,25 @@ export class SNSyncService
|
||||
|
||||
const historyMap = this.historyService.getHistoryMapCopy()
|
||||
|
||||
if (response.userEvents) {
|
||||
if (response.userEvents && response.userEvents.length > 0) {
|
||||
await this.notifyEventSync(SyncEvent.ReceivedUserEvents, response.userEvents as SyncEventReceivedUserEventsData)
|
||||
}
|
||||
|
||||
if (response.asymmetricMessages) {
|
||||
if (response.asymmetricMessages && response.asymmetricMessages.length > 0) {
|
||||
await this.notifyEventSync(
|
||||
SyncEvent.ReceivedAsymmetricMessages,
|
||||
response.asymmetricMessages as SyncEventReceivedAsymmetricMessagesData,
|
||||
)
|
||||
}
|
||||
|
||||
if (response.vaults) {
|
||||
if (response.vaults && response.vaults.length > 0) {
|
||||
await this.notifyEventSync(
|
||||
SyncEvent.ReceivedRemoteSharedVaults,
|
||||
response.vaults as SyncEventReceivedRemoteSharedVaultsData,
|
||||
)
|
||||
}
|
||||
|
||||
if (response.vaultInvites) {
|
||||
if (response.vaultInvites && response.vaultInvites.length > 0) {
|
||||
await this.notifyEventSync(
|
||||
SyncEvent.ReceivedSharedVaultInvites,
|
||||
response.vaultInvites as SyncEventReceivedSharedVaultInvitesData,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
export * from './SyncService'
|
||||
export * from './Types'
|
||||
export * from './SyncOpStatus'
|
||||
export * from './SyncClientInterface'
|
||||
export * from './Account/Operation'
|
||||
export * from './Account/ResponseResolver'
|
||||
export * from './Offline/Operation'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './Application'
|
||||
export * from './Application/Dependencies/Types'
|
||||
export * from './ApplicationGroup'
|
||||
export * from './Client'
|
||||
export * from './Domain'
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('001 protocol operations', () => {
|
||||
})
|
||||
|
||||
it('cost minimum', () => {
|
||||
expect(application.encryptionService.costMinimumForVersion('001')).to.equal(3000)
|
||||
expect(application.encryption.costMinimumForVersion('001')).to.equal(3000)
|
||||
})
|
||||
|
||||
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 () => {
|
||||
const password = 'password'
|
||||
const keyParams = await application.encryptionService.createKeyParams({
|
||||
const keyParams = await application.encryption.createKeyParams({
|
||||
pw_func: 'pbkdf2',
|
||||
pw_alg: 'sha512',
|
||||
pw_key_size: 512,
|
||||
@@ -67,7 +67,7 @@ describe('001 protocol operations', () => {
|
||||
'sVuHmG0XAp1PRDE8r8XqFXijjP8Pqdwal9YFRrXK4hKLt1yyq8MwQU+1Z95Tz/b7ajYdidwFE0iDwd8Iu8281VtJsQ4yhh2tJiAzBy6newyHfhA5nH93yZ3iXRJaG87bgNQE9lsXzTV/OHAvqMuQtw/QVSWI3Qy1Pyu1Tn72q7FPKKhRRkzEEZ+Ax0BA1fHg',
|
||||
uuid: '54001a6f-7c22-4b34-8316-fadf9b1fc255',
|
||||
})
|
||||
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||
const decrypted = await application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [payload],
|
||||
key: key,
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('002 protocol operations', () => {
|
||||
})
|
||||
|
||||
it('cost minimum', () => {
|
||||
expect(application.encryptionService.costMinimumForVersion('002')).to.equal(3000)
|
||||
expect(application.encryption.costMinimumForVersion('002')).to.equal(3000)
|
||||
})
|
||||
|
||||
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 () => {
|
||||
const password = 'password'
|
||||
const keyParams = await application.encryptionService.createKeyParams({
|
||||
const keyParams = await application.encryption.createKeyParams({
|
||||
pw_salt: '8d381ef44cdeab1489194f87066b747b46053a833ee24956e846e7b40440f5f4',
|
||||
pw_cost: 101000,
|
||||
version: '002',
|
||||
@@ -64,7 +64,7 @@ describe('002 protocol operations', () => {
|
||||
'002:24a8e8f7728bbe06605d8209d87ad338d3d15ef81154bb64d3967c77daa01333:959b042a-3892-461e-8c50-477c10c7c40a:f1d294388742dca34f6f266a01483a4e:VdlEDyjhZ35GbJDg8ruSZv3Tp6WtMME3T5LLvcBYLHIMhrMi0RlPK83lK6F0aEaZvY82pZ0ntU+XpAX7JMSEdKdPXsACML7WeFrqKb3z2qHnA7NxgnIC0yVT/Z2mRrvlY3NNrUPGwJbfRcvfS7FVyw87MemT9CSubMZRviXvXETx82t7rsgjV/AIwOOeWhFi',
|
||||
uuid: '959b042a-3892-461e-8c50-477c10c7c40a',
|
||||
})
|
||||
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||
const decrypted = await application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [payload],
|
||||
key: key,
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('003 protocol operations', () => {
|
||||
|
||||
it('cost minimum should throw', () => {
|
||||
expect(() => {
|
||||
sharedApplication.encryptionService.costMinimumForVersion('003')
|
||||
sharedApplication.encryption.costMinimumForVersion('003')
|
||||
}).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 () => {
|
||||
const identifier = 'foo@bar.com'
|
||||
const password = 'very_secure'
|
||||
const keyParams = sharedApplication.encryptionService.createKeyParams({
|
||||
const keyParams = sharedApplication.encryption.createKeyParams({
|
||||
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
||||
identifier: identifier,
|
||||
version: '003',
|
||||
@@ -73,7 +73,7 @@ describe('003 protocol operations', () => {
|
||||
it('can decrypt item generated with web version 3.3.6', async () => {
|
||||
const identifier = 'demo@standardnotes.org'
|
||||
const password = 'password'
|
||||
const keyParams = sharedApplication.encryptionService.createKeyParams({
|
||||
const keyParams = sharedApplication.encryption.createKeyParams({
|
||||
pw_nonce: '31107837b44d86179140b7c602a55d694243e2e9ced0c4c914ac21ad90215055',
|
||||
identifier: identifier,
|
||||
version: '003',
|
||||
|
||||
@@ -25,16 +25,12 @@ describe('004 protocol operations', function () {
|
||||
|
||||
it('cost minimum should throw', function () {
|
||||
expect(function () {
|
||||
application.encryptionService.costMinimumForVersion('004')
|
||||
application.encryption.costMinimumForVersion('004')
|
||||
}).to.throw('Cost minimums only apply to versions <= 002')
|
||||
})
|
||||
|
||||
it('generates valid keys for registration', async function () {
|
||||
const key = await application.encryptionService.createRootKey(
|
||||
_identifier,
|
||||
_password,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
const key = await application.encryption.createRootKey(_identifier, _password, KeyParamsOrigination.Registration)
|
||||
|
||||
expect(key.masterKey).to.be.ok
|
||||
|
||||
@@ -51,7 +47,7 @@ describe('004 protocol operations', function () {
|
||||
it('computes proper keys for sign in', async function () {
|
||||
const identifier = 'foo@bar.com'
|
||||
const password = 'very_secure'
|
||||
const keyParams = application.encryptionService.createKeyParams({
|
||||
const keyParams = application.encryption.createKeyParams({
|
||||
pw_nonce: 'baaec0131d677cf993381367eb082fe377cefe70118c1699cb9b38f0bc850e7b',
|
||||
identifier: identifier,
|
||||
version: '004',
|
||||
@@ -64,7 +60,7 @@ describe('004 protocol operations', function () {
|
||||
|
||||
it('generates random key', async function () {
|
||||
const length = 96
|
||||
const key = await application.encryptionService.crypto.generateRandomKey(length)
|
||||
const key = await application.encryption.crypto.generateRandomKey(length)
|
||||
expect(key.length).to.equal(length / 4)
|
||||
})
|
||||
|
||||
@@ -78,7 +74,7 @@ describe('004 protocol operations', function () {
|
||||
}),
|
||||
})
|
||||
|
||||
const operator = application.encryptionService.operators.operatorForVersion(ProtocolVersion.V004)
|
||||
const operator = application.dependencies.get(TYPES.EncryptionOperators).operatorForVersion(ProtocolVersion.V004)
|
||||
|
||||
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
||||
const decrypted = await operator.generateDecryptedParameters(encrypted, rootKey)
|
||||
@@ -97,7 +93,7 @@ describe('004 protocol operations', function () {
|
||||
}),
|
||||
})
|
||||
|
||||
const operator = application.encryptionService.operators.operatorForVersion(ProtocolVersion.V004)
|
||||
const operator = application.dependencies.get(TYPES.EncryptionOperators).operatorForVersion(ProtocolVersion.V004)
|
||||
|
||||
const encrypted = await operator.generateEncryptedParameters(payload, rootKey)
|
||||
const decrypted = await operator.generateDecryptedParameters(
|
||||
@@ -112,7 +108,7 @@ describe('004 protocol operations', function () {
|
||||
})
|
||||
|
||||
it('generates existing keys for key params', async function () {
|
||||
const key = await application.encryptionService.computeRootKey(_password, rootKeyParams)
|
||||
const key = await application.encryption.computeRootKey(_password, rootKeyParams)
|
||||
expect(key.compare(rootKey)).to.be.true
|
||||
})
|
||||
|
||||
|
||||
@@ -55,4 +55,4 @@ export const BaseTests = [
|
||||
'session.test.js',
|
||||
'subscriptions.test.js',
|
||||
'recovery.test.js',
|
||||
];
|
||||
]
|
||||
|
||||
@@ -5,6 +5,8 @@ export const VaultTests = [
|
||||
'vaults/contacts.test.js',
|
||||
'vaults/crypto.test.js',
|
||||
'vaults/asymmetric-messages.test.js',
|
||||
'vaults/keypair-change.test.js',
|
||||
'vaults/signatures.test.js',
|
||||
'vaults/shared_vaults.test.js',
|
||||
'vaults/invites.test.js',
|
||||
'vaults/items.test.js',
|
||||
|
||||
@@ -14,8 +14,8 @@ describe('actions service', () => {
|
||||
localStorage.clear()
|
||||
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.itemManager = this.application.itemManager
|
||||
this.actionsManager = this.application.actionsManager
|
||||
this.itemManager = this.application.items
|
||||
this.actionsManager = this.application.actions
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('actions service', () => {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const rootKey = await this.application.encryptionService.createRootKey(
|
||||
const rootKey = await this.application.encryption.createRootKey(
|
||||
this.email,
|
||||
this.password,
|
||||
KeyParamsOrigination.Registration,
|
||||
@@ -117,7 +117,7 @@ describe('actions service', () => {
|
||||
})
|
||||
|
||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -170,7 +170,10 @@ describe('actions service', () => {
|
||||
})
|
||||
|
||||
// Extension item
|
||||
const extensionItem = await this.application.mutator.createItem(ContentType.TYPES.ActionsExtension, this.actionsExtension)
|
||||
const extensionItem = await this.application.mutator.createItem(
|
||||
ContentType.TYPES.ActionsExtension,
|
||||
this.actionsExtension,
|
||||
)
|
||||
this.extensionItemUuid = extensionItem.uuid
|
||||
})
|
||||
|
||||
@@ -308,8 +311,8 @@ describe('actions service', () => {
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
this.actionsManager.deviceInterface.openUrl = (url) => url
|
||||
this.deviceInterfaceOpenUrl = sandbox.spy(this.actionsManager.deviceInterface, 'openUrl')
|
||||
this.actionsManager.device.openUrl = (url) => url
|
||||
this.deviceInterfaceOpenUrl = sandbox.spy(this.actionsManager.device, 'openUrl')
|
||||
})
|
||||
|
||||
this.afterEach(async function () {
|
||||
@@ -359,14 +362,14 @@ describe('actions service', () => {
|
||||
const response = await this.actionsManager.runAction(this.encryptedPostAction, this.noteItem)
|
||||
|
||||
expect(response.items[0].enc_item_key).to.satisfy((string) => {
|
||||
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||
return string.startsWith(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
expect(response.items[0].uuid).to.eq(this.noteItem.uuid)
|
||||
expect(response.items[0].auth_hash).to.not.be.ok
|
||||
expect(response.items[0].content_type).to.be.ok
|
||||
expect(response.items[0].created_at).to.be.ok
|
||||
expect(response.items[0].content).to.satisfy((string) => {
|
||||
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||
return string.startsWith(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ describe('application instances', () => {
|
||||
const context2 = await Factory.createAppContext({ identifier: 'app2' })
|
||||
await Promise.all([context1.launch(), context2.launch()])
|
||||
|
||||
expect(context1.application.payloadManager).to.equal(context1.application.payloadManager)
|
||||
expect(context1.application.payloadManager).to.not.equal(context2.application.payloadManager)
|
||||
expect(context1.application.payloads).to.equal(context1.application.payloads)
|
||||
expect(context1.application.payloads).to.not.equal(context2.application.payloads)
|
||||
|
||||
await Factory.createMappedNote(context1.application)
|
||||
expect(context1.application.itemManager.items.length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect(context2.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
expect(context1.application.items.items.length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect(context2.application.items.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
await context1.deinit()
|
||||
await context2.deinit()
|
||||
@@ -40,16 +40,16 @@ describe('application instances', () => {
|
||||
const app2 = await Factory.createAndInitializeApplication('app2')
|
||||
|
||||
await Factory.createMappedNote(app1)
|
||||
await app1.syncService.sync(syncOptions)
|
||||
await app1.sync.sync(syncOptions)
|
||||
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems)
|
||||
expect((await app1.storage.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.storage.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
await Factory.createMappedNote(app2)
|
||||
await app2.syncService.sync(syncOptions)
|
||||
await app2.sync.sync(syncOptions)
|
||||
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app1.storage.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.storage.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
await Factory.safeDeinit(app1)
|
||||
await Factory.safeDeinit(app2)
|
||||
})
|
||||
@@ -58,7 +58,7 @@ describe('application instances', () => {
|
||||
/** This test will always succeed but should be observed for console exceptions */
|
||||
const app = await Factory.createAndInitializeApplication('app')
|
||||
/** Don't await */
|
||||
app.diskStorageService.persistValuesToDisk()
|
||||
app.storage.persistValuesToDisk()
|
||||
await app.prepareForDeinit()
|
||||
await Factory.safeDeinit(app)
|
||||
})
|
||||
@@ -101,13 +101,13 @@ describe('application instances', () => {
|
||||
const app = await Factory.createAndInitializeApplication('app')
|
||||
/** Don't await */
|
||||
const MaximumWaitTime = 0.5
|
||||
app.diskStorageService.executeCriticalFunction(async () => {
|
||||
app.storage.executeCriticalFunction(async () => {
|
||||
/** If we sleep less than the maximum, locking should occur safely.
|
||||
* If we sleep more than the maximum, locking should occur with exception on
|
||||
* app deinit. */
|
||||
await Factory.sleep(MaximumWaitTime - 0.05)
|
||||
/** Access any deviceInterface function */
|
||||
app.diskStorageService.deviceInterface.getAllDatabaseEntries(app.identifier)
|
||||
app.device.getAllDatabaseEntries(app.identifier)
|
||||
})
|
||||
await app.lock()
|
||||
})
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('auth fringe cases', () => {
|
||||
console.warn("Expecting errors 'Unable to find operator for version undefined'")
|
||||
|
||||
const restartedApplication = await Factory.restartApplication(context.application)
|
||||
const refreshedNote = restartedApplication.payloadManager.findOne(note.uuid)
|
||||
const refreshedNote = restartedApplication.payloads.findOne(note.uuid)
|
||||
expect(refreshedNote.errorDecrypting).to.equal(true)
|
||||
|
||||
await Factory.safeDeinit(restartedApplication)
|
||||
@@ -67,9 +67,9 @@ describe('auth fringe cases', () => {
|
||||
)
|
||||
|
||||
await restartedApplication.signIn(context.email, context.password, undefined, undefined, undefined, awaitSync)
|
||||
const refreshedNote = restartedApplication.itemManager.findItem(note.uuid)
|
||||
const refreshedNote = restartedApplication.items.findItem(note.uuid)
|
||||
expect(isDecryptedItem(refreshedNote)).to.equal(true)
|
||||
expect(restartedApplication.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(restartedApplication.items.getDisplayableNotes().length).to.equal(1)
|
||||
await Factory.safeDeinit(restartedApplication)
|
||||
}).timeout(10000)
|
||||
})
|
||||
@@ -97,15 +97,13 @@ describe('auth fringe cases', () => {
|
||||
/** Sign in and merge local data */
|
||||
await newApplication.signIn(context.email, context.password, undefined, undefined, true, true)
|
||||
|
||||
expect(newApplication.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(newApplication.items.getDisplayableNotes().length).to.equal(2)
|
||||
|
||||
expect(
|
||||
newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text,
|
||||
).to.equal(staleText)
|
||||
expect(newApplication.items.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text).to.equal(
|
||||
staleText,
|
||||
)
|
||||
|
||||
const conflictedCopy = newApplication.itemManager
|
||||
.getDisplayableNotes()
|
||||
.find((n) => n.uuid !== firstVersionOfNote.uuid)
|
||||
const conflictedCopy = newApplication.items.getDisplayableNotes().find((n) => n.uuid !== firstVersionOfNote.uuid)
|
||||
expect(conflictedCopy.text).to.equal(serverText)
|
||||
expect(conflictedCopy.duplicate_of).to.equal(firstVersionOfNote.uuid)
|
||||
await Factory.safeDeinit(newApplication)
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('basic auth', function () {
|
||||
it('successfully register new account', async function () {
|
||||
const response = await this.application.register(this.email, this.password)
|
||||
expect(response).to.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
})
|
||||
|
||||
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.',
|
||||
)
|
||||
|
||||
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.not.be.ok
|
||||
})
|
||||
|
||||
it('successfully signs out of account', async function () {
|
||||
await this.application.register(this.email, this.password)
|
||||
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
|
||||
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(this.application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyNone)
|
||||
expect(await this.application.encryption.getRootKey()).to.not.be.ok
|
||||
expect(this.application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyNone)
|
||||
})
|
||||
|
||||
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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
}).timeout(20000)
|
||||
|
||||
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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
|
||||
let error
|
||||
try {
|
||||
@@ -99,7 +99,7 @@ describe('basic auth', function () {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
}).timeout(20000)
|
||||
|
||||
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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
})(),
|
||||
(async () => {
|
||||
/** 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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
})(),
|
||||
(async () => {
|
||||
/** Make sure the first function runs first */
|
||||
@@ -185,7 +185,7 @@ describe('basic auth', function () {
|
||||
*/
|
||||
await this.application.register(uppercase, this.password)
|
||||
|
||||
const response = await this.application.sessionManager.retrieveKeyParams(lowercase)
|
||||
const response = await this.application.sessions.retrieveKeyParams(lowercase)
|
||||
const keyParams = response.keyParams
|
||||
expect(keyParams.identifier).to.equal(lowercase)
|
||||
expect(keyParams.identifier).to.not.equal(uppercase)
|
||||
@@ -204,7 +204,7 @@ describe('basic auth', function () {
|
||||
const response = await this.application.signIn(uppercase, this.password, undefined, undefined, undefined, true)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
}).timeout(20000)
|
||||
|
||||
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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
}).timeout(20000)
|
||||
|
||||
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)
|
||||
expect(response).to.be.ok
|
||||
expect(response.data.error).to.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.not.be.ok
|
||||
}).timeout(20000)
|
||||
|
||||
it('fails to change to short password', async function () {
|
||||
@@ -255,7 +255,7 @@ describe('basic auth', function () {
|
||||
let outOfSync = true
|
||||
let didCompletePostDownloadFirstSync = false
|
||||
let didCompleteDownloadFirstSync = false
|
||||
this.application.syncService.addEventObserver((eventName) => {
|
||||
this.application.sync.addEventObserver((eventName) => {
|
||||
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
|
||||
didCompleteDownloadFirstSync = true
|
||||
}
|
||||
@@ -265,7 +265,7 @@ describe('basic auth', function () {
|
||||
if (!didCompletePostDownloadFirstSync && eventName === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
didCompletePostDownloadFirstSync = true
|
||||
/** Should be in sync */
|
||||
outOfSync = this.application.syncService.isOutOfSync()
|
||||
outOfSync = this.application.sync.isOutOfSync()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -289,9 +289,9 @@ describe('basic auth', function () {
|
||||
|
||||
this.expectedItemCount += noteCount
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const newPassword = 'newpassword'
|
||||
const response = await this.application.changePassword(this.password, newPassword)
|
||||
@@ -299,18 +299,18 @@ describe('basic auth', function () {
|
||||
/** New items key */
|
||||
this.expectedItemCount++
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
expect(response.error).to.not.be.ok
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const note = this.application.items.getDisplayableNotes()[0]
|
||||
|
||||
/**
|
||||
* Create conflict for a note. First modify the item without saving so that
|
||||
@@ -339,10 +339,10 @@ describe('basic auth', function () {
|
||||
expect(signinResponse).to.be.ok
|
||||
expect(signinResponse.data.error).to.not.be.ok
|
||||
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
}
|
||||
|
||||
it('successfully changes password', changePassword).timeout(40000)
|
||||
@@ -383,7 +383,7 @@ describe('basic auth', function () {
|
||||
const noteCount = 10
|
||||
await Factory.createManyMappedNotes(this.application, noteCount)
|
||||
this.expectedItemCount += noteCount
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const numTimesToChangePw = 3
|
||||
let newPassword = Factory.randomString()
|
||||
@@ -398,16 +398,16 @@ describe('basic auth', function () {
|
||||
currentPassword = newPassword
|
||||
newPassword = Factory.randomString()
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
this.application = await this.context.signout()
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
|
||||
/** Should login with new password */
|
||||
const signinResponse = await this.application.signIn(
|
||||
@@ -421,7 +421,7 @@ describe('basic auth', function () {
|
||||
|
||||
expect(signinResponse).to.be.ok
|
||||
expect(signinResponse.data.error).to.not.be.ok
|
||||
expect(await this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.be.ok
|
||||
}
|
||||
}).timeout(80000)
|
||||
|
||||
@@ -432,7 +432,7 @@ describe('basic auth', function () {
|
||||
password: this.password,
|
||||
})
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
const performSignIn = sinon.spy(this.application.sessionManager, 'performSignIn')
|
||||
const performSignIn = sinon.spy(this.application.sessions, 'performSignIn')
|
||||
await this.application.signIn(this.email, 'wrong password', undefined, undefined, undefined, true)
|
||||
expect(performSignIn.callCount).to.equal(1)
|
||||
})
|
||||
@@ -441,8 +441,8 @@ describe('basic auth', function () {
|
||||
/** Should delete the new items key locally without marking it as deleted so that it doesn't sync */
|
||||
await this.context.register()
|
||||
|
||||
const originalImpl = this.application.encryptionService.getSureDefaultItemsKey
|
||||
this.application.encryptionService.getSureDefaultItemsKey = () => {
|
||||
const originalImpl = this.application.encryption.getSureDefaultItemsKey
|
||||
this.application.encryption.getSureDefaultItemsKey = () => {
|
||||
return {
|
||||
neverSynced: true,
|
||||
}
|
||||
@@ -454,7 +454,7 @@ describe('basic auth', function () {
|
||||
|
||||
await this.context.changePassword('new-password')
|
||||
|
||||
this.application.encryptionService.getSureDefaultItemsKey = originalImpl
|
||||
this.application.encryption.getSureDefaultItemsKey = originalImpl
|
||||
|
||||
expect(mutatorSpy.callCount).to.equal(0)
|
||||
expect(removeItemsSpy.callCount).to.equal(1)
|
||||
@@ -518,8 +518,8 @@ describe('basic auth', function () {
|
||||
|
||||
const _response = await this.application.deleteAccount()
|
||||
|
||||
sinon.spy(snApp.challengeService, 'sendChallenge')
|
||||
const spyCall = snApp.challengeService.sendChallenge.getCall(0)
|
||||
sinon.spy(snApp.challenges, 'sendChallenge')
|
||||
const spyCall = snApp.challenges.sendChallenge.getCall(0)
|
||||
const challenge = spyCall.firstArg
|
||||
expect(challenge.prompts).to.have.lengthOf(2)
|
||||
expect(challenge.prompts[0].validation).to.equal(ChallengeValidation.AccountPassword)
|
||||
|
||||
@@ -27,10 +27,10 @@ describe('backups', function () {
|
||||
|
||||
it('backup file should have a version number', async function () {
|
||||
let data = await this.application.createDecryptedBackupFile()
|
||||
expect(data.version).to.equal(this.application.encryptionService.getLatestVersion())
|
||||
expect(data.version).to.equal(this.application.encryption.getLatestVersion())
|
||||
await this.application.addPasscode('passcode')
|
||||
data = await this.application.createEncryptedBackupFileForAutomatedDesktopBackups()
|
||||
expect(data.version).to.equal(this.application.encryptionService.getLatestVersion())
|
||||
expect(data.version).to.equal(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
|
||||
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 encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note.payload],
|
||||
},
|
||||
@@ -153,9 +153,9 @@ describe('backups', function () {
|
||||
errorDecrypting: true,
|
||||
})
|
||||
|
||||
await this.application.payloadManager.emitPayload(errored)
|
||||
await this.application.payloads.emitPayload(errored)
|
||||
|
||||
const erroredItem = this.application.itemManager.findAnyItem(errored.uuid)
|
||||
const erroredItem = this.application.items.findAnyItem(errored.uuid)
|
||||
|
||||
expect(erroredItem.errorDecrypting).to.equal(true)
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ describe('device authentication', function () {
|
||||
const application = await Factory.createAndInitializeApplication(namespace)
|
||||
const passcode = 'foobar'
|
||||
const wrongPasscode = 'barfoo'
|
||||
expect(await application.protectionService.createLaunchChallenge()).to.not.be.ok
|
||||
expect(await application.protections.createLaunchChallenge()).to.not.be.ok
|
||||
await application.addPasscode(passcode)
|
||||
expect(await application.hasPasscode()).to.equal(true)
|
||||
expect(await application.protectionService.createLaunchChallenge()).to.be.ok
|
||||
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
expect(await application.protections.createLaunchChallenge()).to.be.ok
|
||||
expect(application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
await Factory.safeDeinit(application)
|
||||
|
||||
/** Recreate application and initialize */
|
||||
@@ -49,10 +49,10 @@ describe('device authentication', function () {
|
||||
tmpApplication.submitValuesForChallenge(challenge, initialValues)
|
||||
}
|
||||
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.not.be.ok
|
||||
await tmpApplication.launch(true)
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
await Factory.safeDeinit(tmpApplication)
|
||||
}).timeout(10000)
|
||||
|
||||
@@ -64,8 +64,8 @@ describe('device authentication', function () {
|
||||
await application.addPasscode(passcode)
|
||||
await application.protections.enableBiometrics()
|
||||
expect(await application.hasPasscode()).to.equal(true)
|
||||
expect((await application.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
expect((await application.protections.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||
expect(application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
await Factory.safeDeinit(application)
|
||||
|
||||
/** Recreate application and initialize */
|
||||
@@ -98,11 +98,11 @@ describe('device authentication', function () {
|
||||
}
|
||||
|
||||
await tmpApplication.prepareForLaunch({ receiveChallenge })
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect((await tmpApplication.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.not.be.ok
|
||||
expect((await tmpApplication.protections.createLaunchChallenge()).prompts.length).to.equal(2)
|
||||
await tmpApplication.launch(true)
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.WrapperOnly)
|
||||
await Factory.safeDeinit(tmpApplication)
|
||||
}).timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
@@ -118,12 +118,12 @@ describe('device authentication', function () {
|
||||
})
|
||||
const sampleStorageKey = 'foo'
|
||||
const sampleStorageValue = 'bar'
|
||||
await application.diskStorageService.setValue(sampleStorageKey, sampleStorageValue)
|
||||
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyOnly)
|
||||
await application.storage.setValue(sampleStorageKey, sampleStorageValue)
|
||||
expect(application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyOnly)
|
||||
const passcode = 'foobar'
|
||||
Factory.handlePasswordChallenges(application, password)
|
||||
await application.addPasscode(passcode)
|
||||
expect(application.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||
expect(application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||
expect(await application.hasPasscode()).to.equal(true)
|
||||
await Factory.safeDeinit(application)
|
||||
|
||||
@@ -154,11 +154,11 @@ describe('device authentication', function () {
|
||||
await tmpApplication.prepareForLaunch({
|
||||
receiveChallenge: receiveChallenge,
|
||||
})
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.not.be.ok
|
||||
await tmpApplication.launch(true)
|
||||
expect(await tmpApplication.diskStorageService.getValue(sampleStorageKey)).to.equal(sampleStorageValue)
|
||||
expect(await tmpApplication.encryptionService.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryptionService.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||
expect(await tmpApplication.storage.getValue(sampleStorageKey)).to.equal(sampleStorageValue)
|
||||
expect(await tmpApplication.encryption.getRootKey()).to.be.ok
|
||||
expect(tmpApplication.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyPlusWrapper)
|
||||
await Factory.safeDeinit(tmpApplication)
|
||||
}).timeout(Factory.TwentySecondTimeout)
|
||||
})
|
||||
|
||||
@@ -32,8 +32,8 @@ describe('features', () => {
|
||||
|
||||
describe('new user roles received on api response meta', () => {
|
||||
it('should save roles and features', async () => {
|
||||
expect(application.featuresService.onlineRoles).to.have.lengthOf(1)
|
||||
expect(application.featuresService.onlineRoles[0]).to.equal('CORE_USER')
|
||||
expect(application.features.onlineRoles).to.have.lengthOf(1)
|
||||
expect(application.features.onlineRoles[0]).to.equal('CORE_USER')
|
||||
|
||||
const storedRoles = await application.getValue(StorageKey.UserRoles)
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('features', () => {
|
||||
|
||||
describe('extension repo items observer', () => {
|
||||
it('should migrate to user setting when extension repo is added', async () => {
|
||||
sinon.stub(application.apiService, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
sinon.stub(application.legacyApi, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('features', () => {
|
||||
const extensionKey = UuidGenerator.GenerateUuid().split('-').join('')
|
||||
|
||||
const promise = new Promise((resolve) => {
|
||||
sinon.stub(application.featuresService, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
sinon.stub(application.features, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
})
|
||||
|
||||
await application.mutator.createItem(
|
||||
@@ -71,14 +71,14 @@ describe('features', () => {
|
||||
})
|
||||
|
||||
it('signing into account with ext repo should migrate it', async () => {
|
||||
sinon.stub(application.apiService, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
sinon.stub(application.legacyApi, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
return false
|
||||
})
|
||||
/** Attach an ExtensionRepo object to an account, but prevent it from being migrated.
|
||||
* Then sign out, sign back in, and ensure the item is migrated. */
|
||||
/** Prevent migration from running */
|
||||
sinon
|
||||
.stub(application.featuresService, 'migrateFeatureRepoToUserSetting')
|
||||
.stub(application.features, 'migrateFeatureRepoToUserSetting')
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
.callsFake(() => {})
|
||||
const extensionKey = UuidGenerator.GenerateUuid().split('-').join('')
|
||||
@@ -93,11 +93,11 @@ describe('features', () => {
|
||||
application = await Factory.signOutApplicationAndReturnNew(application)
|
||||
|
||||
sinon.restore()
|
||||
sinon.stub(application.apiService, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
sinon.stub(application.legacyApi, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
return false
|
||||
})
|
||||
const promise = new Promise((resolve) => {
|
||||
sinon.stub(application.featuresService, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
sinon.stub(application.features, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
})
|
||||
await Factory.loginToApplication({
|
||||
application,
|
||||
@@ -109,7 +109,7 @@ describe('features', () => {
|
||||
|
||||
it('having an ext repo with no account, then signing into account, should migrate it', async () => {
|
||||
application = await Factory.signOutApplicationAndReturnNew(application)
|
||||
sinon.stub(application.apiService, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
sinon.stub(application.legacyApi, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
return false
|
||||
})
|
||||
const extensionKey = UuidGenerator.GenerateUuid().split('-').join('')
|
||||
@@ -123,7 +123,7 @@ describe('features', () => {
|
||||
await application.sync.sync()
|
||||
|
||||
const promise = new Promise((resolve) => {
|
||||
sinon.stub(application.featuresService, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
sinon.stub(application.features, 'migrateFeatureRepoToUserSetting').callsFake(resolve)
|
||||
})
|
||||
await Factory.loginToApplication({
|
||||
application,
|
||||
@@ -134,7 +134,7 @@ describe('features', () => {
|
||||
})
|
||||
|
||||
it.skip('migrated ext repo should have property indicating it was migrated', async () => {
|
||||
sinon.stub(application.apiService, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
sinon.stub(application.legacyApi, 'isThirdPartyHostUsed').callsFake(() => {
|
||||
return false
|
||||
})
|
||||
expect(await application.settings.getDoesSensitiveSettingExist(SettingName.ExtensionKey)).to.equal(false)
|
||||
@@ -171,7 +171,7 @@ describe('features', () => {
|
||||
)
|
||||
await application.sync.sync()
|
||||
|
||||
const repo = application.featuresService.getOfflineRepo()
|
||||
const repo = application.features.getOfflineRepo()
|
||||
expect(repo.migratedToOfflineEntitlements).to.equal(true)
|
||||
expect(repo.offlineFeaturesUrl).to.equal('https://api.standardnotes.com/v1/offline/features')
|
||||
expect(repo.offlineKey).to.equal(extensionKey)
|
||||
|
||||
@@ -12,7 +12,6 @@ describe('files', function () {
|
||||
let context
|
||||
let fileService
|
||||
let itemManager
|
||||
let subscriptionId = 1001
|
||||
|
||||
beforeEach(function () {
|
||||
localStorage.clear()
|
||||
@@ -28,8 +27,8 @@ describe('files', function () {
|
||||
await context.launch()
|
||||
|
||||
application = context.application
|
||||
fileService = context.application.fileService
|
||||
itemManager = context.application.itemManager
|
||||
fileService = context.application.files
|
||||
itemManager = context.application.items
|
||||
|
||||
await Factory.registerUserToApplication({
|
||||
application: context.application,
|
||||
@@ -51,7 +50,7 @@ describe('files', function () {
|
||||
await setup({ fakeCrypto: true, subscription: true })
|
||||
|
||||
const remoteIdentifier = Utils.generateUuid()
|
||||
const token = await application.apiService.createUserFileValetToken(remoteIdentifier, ValetTokenOperation.Write)
|
||||
const token = await application.legacyApi.createUserFileValetToken(remoteIdentifier, ValetTokenOperation.Write)
|
||||
|
||||
expect(token.length).to.be.above(0)
|
||||
})
|
||||
@@ -60,7 +59,7 @@ describe('files', function () {
|
||||
await setup({ fakeCrypto: true, subscription: false })
|
||||
|
||||
const remoteIdentifier = Utils.generateUuid()
|
||||
const tokenOrError = await application.apiService.createUserFileValetToken(
|
||||
const tokenOrError = await application.legacyApi.createUserFileValetToken(
|
||||
remoteIdentifier,
|
||||
ValetTokenOperation.Write,
|
||||
)
|
||||
@@ -79,7 +78,7 @@ describe('files', function () {
|
||||
})
|
||||
|
||||
const remoteIdentifier = Utils.generateUuid()
|
||||
const tokenOrError = await application.apiService.createUserFileValetToken(
|
||||
const tokenOrError = await application.legacyApi.createUserFileValetToken(
|
||||
remoteIdentifier,
|
||||
ValetTokenOperation.Write,
|
||||
)
|
||||
@@ -90,19 +89,19 @@ describe('files', function () {
|
||||
it('creating two upload sessions successively should succeed', async function () {
|
||||
await setup({ fakeCrypto: true, subscription: true })
|
||||
|
||||
const firstToken = await application.apiService.createUserFileValetToken(
|
||||
const firstToken = await application.legacyApi.createUserFileValetToken(
|
||||
Utils.generateUuid(),
|
||||
ValetTokenOperation.Write,
|
||||
)
|
||||
const firstSession = await application.apiService.startUploadSession(firstToken, 'user')
|
||||
const firstSession = await application.legacyApi.startUploadSession(firstToken, 'user')
|
||||
|
||||
expect(firstSession.uploadId).to.be.ok
|
||||
|
||||
const secondToken = await application.apiService.createUserFileValetToken(
|
||||
const secondToken = await application.legacyApi.createUserFileValetToken(
|
||||
Utils.generateUuid(),
|
||||
ValetTokenOperation.Write,
|
||||
)
|
||||
const secondSession = await application.apiService.startUploadSession(secondToken, 'user')
|
||||
const secondSession = await application.legacyApi.startUploadSession(secondToken, 'user')
|
||||
|
||||
expect(secondSession.uploadId).to.be.ok
|
||||
})
|
||||
|
||||
@@ -24,10 +24,10 @@ describe('history manager', () => {
|
||||
describe('session', function () {
|
||||
beforeEach(async function () {
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.historyManager = this.application.historyManager
|
||||
this.payloadManager = this.application.payloadManager
|
||||
this.history = this.application.dependencies.get(TYPES.HistoryManager)
|
||||
this.payloadManager = this.application.payloads
|
||||
/** Automatically optimize after every revision by setting this to 0 */
|
||||
this.historyManager.itemRevisionThreshold = 0
|
||||
this.history.itemRevisionThreshold = 0
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
@@ -52,11 +52,11 @@ describe('history manager', () => {
|
||||
|
||||
it('create basic history entries 1', async function () {
|
||||
const item = await Factory.createSyncedNote(this.application)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(0)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(0)
|
||||
|
||||
/** Sync with same contents, should not create new entry */
|
||||
await Factory.markDirtyAndSyncItem(this.application, item)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(0)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(0)
|
||||
|
||||
/** Sync with different contents, should create new entry */
|
||||
await this.application.changeAndSaveItem(
|
||||
@@ -68,7 +68,7 @@ describe('history manager', () => {
|
||||
undefined,
|
||||
syncOptions,
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(1)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('first change should create revision with previous value', async function () {
|
||||
@@ -78,7 +78,7 @@ describe('history manager', () => {
|
||||
/** Simulate loading new application session */
|
||||
const context = await Factory.createAppContext({ identifier })
|
||||
await context.launch()
|
||||
expect(context.application.historyManager.sessionHistoryForItem(item).length).to.equal(0)
|
||||
expect(context.history.sessionHistoryForItem(item).length).to.equal(0)
|
||||
await context.application.changeAndSaveItem(
|
||||
item,
|
||||
(mutator) => {
|
||||
@@ -88,7 +88,7 @@ describe('history manager', () => {
|
||||
undefined,
|
||||
syncOptions,
|
||||
)
|
||||
const entries = context.application.historyManager.sessionHistoryForItem(item)
|
||||
const entries = context.history.sessionHistoryForItem(item)
|
||||
expect(entries.length).to.equal(1)
|
||||
expect(entries[0].payload.content.title).to.equal(item.content.title)
|
||||
await context.deinit()
|
||||
@@ -101,7 +101,7 @@ describe('history manager', () => {
|
||||
references: [],
|
||||
})
|
||||
await context.application.mutator.insertItem(item)
|
||||
expect(context.application.historyManager.sessionHistoryForItem(item).length).to.equal(0)
|
||||
expect(context.history.sessionHistoryForItem(item).length).to.equal(0)
|
||||
|
||||
await context.application.changeAndSaveItem(
|
||||
item,
|
||||
@@ -112,7 +112,7 @@ describe('history manager', () => {
|
||||
undefined,
|
||||
syncOptions,
|
||||
)
|
||||
expect(context.application.historyManager.sessionHistoryForItem(item).length).to.equal(0)
|
||||
expect(context.history.sessionHistoryForItem(item).length).to.equal(0)
|
||||
await context.deinit()
|
||||
})
|
||||
|
||||
@@ -123,14 +123,14 @@ describe('history manager', () => {
|
||||
* won't here because it's the first change, which we want to keep.
|
||||
*/
|
||||
await setTextAndSync(this.application, item, item.content.text + '1')
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(1)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(1)
|
||||
|
||||
/**
|
||||
* Changing it by one character should keep this entry,
|
||||
* since it's now the last (and will keep the first)
|
||||
*/
|
||||
item = await setTextAndSync(this.application, item, item.content.text + '2')
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(2)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(2)
|
||||
/**
|
||||
* Change it over the largeCharacterChange threshold. It should keep this
|
||||
* revision, but now remove the previous revision, since it's no longer
|
||||
@@ -141,29 +141,29 @@ describe('history manager', () => {
|
||||
item,
|
||||
item.content.text + Factory.randomString(largeCharacterChange + 1),
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(2)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(2)
|
||||
|
||||
item = await setTextAndSync(
|
||||
this.application,
|
||||
item,
|
||||
item.content.text + Factory.randomString(largeCharacterChange + 1),
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(2)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(2)
|
||||
/** Delete over threshold text. */
|
||||
item = await setTextAndSync(
|
||||
this.application,
|
||||
item,
|
||||
deleteCharsFromString(item.content.text, largeCharacterChange + 1),
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(3)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(3)
|
||||
/**
|
||||
* Delete just 1 character. It should now retain the previous revision, as well as the
|
||||
* one previous to that.
|
||||
*/
|
||||
item = await setTextAndSync(this.application, item, deleteCharsFromString(item.content.text, 1))
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(4)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(4)
|
||||
item = await setTextAndSync(this.application, item, deleteCharsFromString(item.content.text, 1))
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(5)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(5)
|
||||
})
|
||||
|
||||
it('should keep the entry right before a large deletion, regardless of its delta', async function () {
|
||||
@@ -174,25 +174,25 @@ describe('history manager', () => {
|
||||
)
|
||||
let item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
await this.application.mutator.setItemDirty(item)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
/** It should keep the first and last by default */
|
||||
item = await setTextAndSync(this.application, item, item.content.text)
|
||||
item = await setTextAndSync(this.application, item, item.content.text + Factory.randomString(1))
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(2)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(2)
|
||||
item = await setTextAndSync(
|
||||
this.application,
|
||||
item,
|
||||
deleteCharsFromString(item.content.text, largeCharacterChange + 1),
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(2)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(2)
|
||||
item = await setTextAndSync(this.application, item, item.content.text + Factory.randomString(1))
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(3)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(3)
|
||||
item = await setTextAndSync(
|
||||
this.application,
|
||||
item,
|
||||
item.content.text + Factory.randomString(largeCharacterChange + 1),
|
||||
)
|
||||
expect(this.historyManager.sessionHistoryForItem(item).length).to.equal(4)
|
||||
expect(this.history.sessionHistoryForItem(item).length).to.equal(4)
|
||||
})
|
||||
|
||||
it('entries should be ordered from newest to oldest', async function () {
|
||||
@@ -205,7 +205,7 @@ describe('history manager', () => {
|
||||
let item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
|
||||
await this.application.mutator.setItemDirty(item)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
item = await setTextAndSync(this.application, item, item.content.text + Factory.randomString(1))
|
||||
|
||||
@@ -224,10 +224,10 @@ describe('history manager', () => {
|
||||
)
|
||||
|
||||
/** First entry should be the latest revision. */
|
||||
const latestRevision = this.historyManager.sessionHistoryForItem(item)[0]
|
||||
const latestRevision = this.history.sessionHistoryForItem(item)[0]
|
||||
/** Last entry should be the initial revision. */
|
||||
const initialRevision =
|
||||
this.historyManager.sessionHistoryForItem(item)[this.historyManager.sessionHistoryForItem(item).length - 1]
|
||||
this.history.sessionHistoryForItem(item)[this.history.sessionHistoryForItem(item).length - 1]
|
||||
|
||||
expect(latestRevision).to.not.equal(initialRevision)
|
||||
|
||||
@@ -252,7 +252,7 @@ describe('history manager', () => {
|
||||
undefined,
|
||||
syncOptions,
|
||||
)
|
||||
const historyItem = this.historyManager.sessionHistoryForItem(item)[0]
|
||||
const historyItem = this.history.sessionHistoryForItem(item)[0]
|
||||
expect(historyItem.previewTitle()).to.equal(historyItem.payload.created_at.toLocaleString())
|
||||
})
|
||||
})
|
||||
@@ -262,8 +262,8 @@ describe('history manager', () => {
|
||||
|
||||
beforeEach(async function () {
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.historyManager = this.application.historyManager
|
||||
this.payloadManager = this.application.payloadManager
|
||||
this.history = this.application.dependencies.get(TYPES.HistoryManager)
|
||||
this.payloadManager = this.application.payloads
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
await Factory.registerUserToApplication({
|
||||
@@ -280,10 +280,10 @@ describe('history manager', () => {
|
||||
it('response from server should be failed if not signed in', async function () {
|
||||
await this.application.user.signOut()
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.historyManager = this.application.historyManager
|
||||
this.payloadManager = this.application.payloadManager
|
||||
this.history = this.application.dependencies.get(TYPES.HistoryManager)
|
||||
this.payloadManager = this.application.payloads
|
||||
const item = await Factory.createSyncedNote(this.application)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const itemHistoryOrError = await this.application.listRevisions.execute({ itemUuid: item.uuid })
|
||||
|
||||
expect(itemHistoryOrError.isFailed()).to.equal(true)
|
||||
@@ -355,7 +355,7 @@ describe('history manager', () => {
|
||||
expect(payloadFromServer.uuid).to.eq(item.payload.uuid)
|
||||
expect(payloadFromServer.content).to.eql(item.payload.content)
|
||||
|
||||
item = this.application.itemManager.findItem(item.uuid)
|
||||
item = this.application.items.findItem(item.uuid)
|
||||
expect(payloadFromServer.content).to.not.eql(item.payload.content)
|
||||
})
|
||||
|
||||
|
||||
@@ -37,21 +37,21 @@ describe('key recovery service', function () {
|
||||
|
||||
await context.register()
|
||||
|
||||
const randomRootKey = await application.encryptionService.createRootKey(
|
||||
const randomRootKey = await application.encryption.createRootKey(
|
||||
unassociatedIdentifier,
|
||||
unassociatedPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||
const randomItemsKey = await context.operators.defaultOperator().createItemsKey()
|
||||
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [randomItemsKey.payload],
|
||||
key: randomRootKey,
|
||||
},
|
||||
})
|
||||
|
||||
const errored = await application.encryptionService.decryptSplitSingle({
|
||||
const errored = await application.encryption.decryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [encrypted],
|
||||
},
|
||||
@@ -59,13 +59,13 @@ describe('key recovery service', function () {
|
||||
|
||||
expect(errored.errorDecrypting).to.equal(true)
|
||||
|
||||
await application.payloadManager.emitPayload(errored, PayloadEmitSource.LocalInserted)
|
||||
await application.payloads.emitPayload(errored, PayloadEmitSource.LocalInserted)
|
||||
|
||||
await context.resolveWhenKeyRecovered(errored.uuid)
|
||||
|
||||
expect(application.items.findItem(errored.uuid).errorDecrypting).to.not.be.ok
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
await context.deinit()
|
||||
})
|
||||
|
||||
@@ -89,37 +89,37 @@ describe('key recovery service', function () {
|
||||
})
|
||||
await context.register()
|
||||
|
||||
const randomRootKey = await application.encryptionService.createRootKey(
|
||||
const randomRootKey = await application.encryption.createRootKey(
|
||||
unassociatedIdentifier,
|
||||
unassociatedPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
|
||||
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||
const randomItemsKey = await context.operators.defaultOperator().createItemsKey()
|
||||
|
||||
await application.payloadManager.emitPayload(
|
||||
await application.payloads.emitPayload(
|
||||
randomItemsKey.payload.copy({ dirty: true, dirtyIndex: getIncrementedDirtyIndex() }),
|
||||
PayloadEmitSource.LocalInserted,
|
||||
)
|
||||
|
||||
await context.sync()
|
||||
|
||||
const originalSyncTime = application.payloadManager.findOne(randomItemsKey.uuid).lastSyncEnd.getTime()
|
||||
const originalSyncTime = application.payloads.findOne(randomItemsKey.uuid).lastSyncEnd.getTime()
|
||||
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [randomItemsKey.payload],
|
||||
key: randomRootKey,
|
||||
},
|
||||
})
|
||||
|
||||
const errored = await application.encryptionService.decryptSplitSingle({
|
||||
const errored = await application.encryption.decryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [encrypted],
|
||||
},
|
||||
})
|
||||
|
||||
await application.payloadManager.emitPayload(errored, PayloadEmitSource.LocalInserted)
|
||||
await application.payloads.emitPayload(errored, PayloadEmitSource.LocalInserted)
|
||||
|
||||
const recoveryPromise = context.resolveWhenKeyRecovered(errored.uuid)
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('key recovery service', function () {
|
||||
|
||||
await recoveryPromise
|
||||
|
||||
expect(application.payloadManager.findOne(errored.uuid).lastSyncEnd.getTime()).to.be.above(originalSyncTime)
|
||||
expect(application.payloads.findOne(errored.uuid).lastSyncEnd.getTime()).to.be.above(originalSyncTime)
|
||||
|
||||
await context.deinit()
|
||||
})
|
||||
@@ -214,15 +214,15 @@ describe('key recovery service', function () {
|
||||
})
|
||||
|
||||
/** Create items key associated with a random root key */
|
||||
const randomRootKey = await application.encryptionService.createRootKey(
|
||||
const randomRootKey = await application.encryption.createRootKey(
|
||||
unassociatedIdentifier,
|
||||
unassociatedPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
const randomItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||
const randomItemsKey2 = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||
const randomItemsKey = await context.operators.defaultOperator().createItemsKey()
|
||||
const randomItemsKey2 = await context.operators.defaultOperator().createItemsKey()
|
||||
|
||||
const encrypted = await application.encryptionService.encryptSplit({
|
||||
const encrypted = await application.encryption.encryptSplit({
|
||||
usesRootKey: {
|
||||
items: [randomItemsKey.payload, randomItemsKey2.payload],
|
||||
key: randomRootKey,
|
||||
@@ -230,13 +230,13 @@ describe('key recovery service', function () {
|
||||
})
|
||||
|
||||
/** Attempt decryption and insert into rotation in errored state */
|
||||
const decrypted = await application.encryptionService.decryptSplit({
|
||||
const decrypted = await application.encryption.decryptSplit({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: encrypted,
|
||||
},
|
||||
})
|
||||
|
||||
await application.payloadManager.emitPayloads(decrypted, PayloadEmitSource.LocalInserted)
|
||||
await application.payloads.emitPayloads(decrypted, PayloadEmitSource.LocalInserted)
|
||||
|
||||
/** Wait and allow recovery wizard to complete */
|
||||
await Factory.sleep(1.5)
|
||||
@@ -247,7 +247,7 @@ describe('key recovery service', function () {
|
||||
|
||||
expect(totalPromptCount).to.equal(1)
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
await context.deinit()
|
||||
})
|
||||
|
||||
@@ -289,19 +289,19 @@ describe('key recovery service', function () {
|
||||
|
||||
/** Same previously errored key should now no longer be errored, */
|
||||
expect(contextA.application.items.getAnyItems(ContentType.TYPES.ItemsKey).length).to.equal(2)
|
||||
for (const key of contextA.application.itemManager.getDisplayableItemsKeys()) {
|
||||
for (const key of contextA.application.items.getDisplayableItemsKeys()) {
|
||||
expect(key.errorDecrypting).to.not.be.ok
|
||||
}
|
||||
|
||||
const aKey = await contextA.application.encryptionService.getRootKey()
|
||||
const bKey = await contextB.application.encryptionService.getRootKey()
|
||||
const aKey = await contextA.application.encryption.getRootKey()
|
||||
const bKey = await contextB.application.encryption.getRootKey()
|
||||
expect(aKey.compare(bKey)).to.equal(true)
|
||||
|
||||
expect(contextA.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
|
||||
expect(contextB.application.items.findItem(note.uuid).errorDecrypting).to.not.be.ok
|
||||
|
||||
expect(contextA.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(contextB.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(contextA.application.sync.isOutOfSync()).to.equal(false)
|
||||
expect(contextB.application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
await contextA.deinit()
|
||||
await contextB.deinit()
|
||||
@@ -341,7 +341,7 @@ describe('key recovery service', function () {
|
||||
|
||||
/** We expect the item in appA to be errored at this point, but we do not want it to recover */
|
||||
await appA.sync.sync()
|
||||
expect(appA.payloadManager.findOne(note.uuid).waitingForKey).to.equal(true)
|
||||
expect(appA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
|
||||
|
||||
console.warn('Expecting exceptions below as we destroy app during key recovery')
|
||||
await Factory.safeDeinit(appA)
|
||||
@@ -351,8 +351,8 @@ describe('key recovery service', function () {
|
||||
await recreatedAppA.prepareForLaunch({ receiveChallenge: () => {} })
|
||||
await recreatedAppA.launch(true)
|
||||
|
||||
expect(recreatedAppA.payloadManager.findOne(note.uuid).errorDecrypting).to.equal(true)
|
||||
expect(recreatedAppA.payloadManager.findOne(note.uuid).waitingForKey).to.equal(true)
|
||||
expect(recreatedAppA.payloads.findOne(note.uuid).errorDecrypting).to.equal(true)
|
||||
expect(recreatedAppA.payloads.findOne(note.uuid).waitingForKey).to.equal(true)
|
||||
await Factory.safeDeinit(recreatedAppA)
|
||||
})
|
||||
|
||||
@@ -379,7 +379,7 @@ describe('key recovery service', function () {
|
||||
await application.launch(true)
|
||||
await context.register()
|
||||
|
||||
const correctRootKey = await application.encryptionService.getRootKey()
|
||||
const correctRootKey = await application.encryption.getRootKey()
|
||||
|
||||
/**
|
||||
* 1. Change our root key locally so that its keys params doesn't match the server's
|
||||
@@ -390,19 +390,19 @@ describe('key recovery service', function () {
|
||||
const unassociatedIdentifier = 'foorand'
|
||||
|
||||
/** Create items key associated with a random root key */
|
||||
const randomRootKey = await application.encryptionService.createRootKey(
|
||||
const randomRootKey = await application.encryption.createRootKey(
|
||||
unassociatedIdentifier,
|
||||
unassociatedPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
|
||||
const signInFunction = sinon.spy(application.keyRecoveryService, 'performServerSignIn')
|
||||
const signInFunction = sinon.spy(context.keyRecovery, 'performServerSignIn')
|
||||
|
||||
await application.encryptionService.setRootKey(randomRootKey)
|
||||
await application.encryption.setRootKey(randomRootKey)
|
||||
|
||||
const correctItemsKey = await application.encryptionService.operators.defaultOperator().createItemsKey()
|
||||
const correctItemsKey = await context.operators.defaultOperator().createItemsKey()
|
||||
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [correctItemsKey.payload],
|
||||
key: randomRootKey,
|
||||
@@ -414,7 +414,7 @@ describe('key recovery service', function () {
|
||||
context.resolveWhenKeyRecovered(correctItemsKey.uuid),
|
||||
])
|
||||
|
||||
await application.payloadManager.emitPayload(
|
||||
await application.payloads.emitPayload(
|
||||
encrypted.copy({
|
||||
errorDecrypting: true,
|
||||
dirty: true,
|
||||
@@ -428,14 +428,14 @@ describe('key recovery service', function () {
|
||||
|
||||
expect(signInFunction.callCount).to.equal(1)
|
||||
|
||||
const clientRootKey = await application.encryptionService.getRootKey()
|
||||
const clientRootKey = await application.encryption.getRootKey()
|
||||
expect(clientRootKey.compare(correctRootKey)).to.equal(true)
|
||||
|
||||
const decryptedKey = application.items.findItem(correctItemsKey.uuid)
|
||||
expect(decryptedKey).to.be.ok
|
||||
expect(decryptedKey.content.itemsKey).to.equal(correctItemsKey.content.itemsKey)
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
await context.deinit()
|
||||
})
|
||||
@@ -448,8 +448,8 @@ describe('key recovery service', function () {
|
||||
await context.register()
|
||||
|
||||
/** Create and emit errored encrypted items key payload */
|
||||
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const itemsKey = await application.encryption.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [itemsKey.payload],
|
||||
},
|
||||
@@ -474,7 +474,7 @@ describe('key recovery service', function () {
|
||||
/** The timestamp of our current key should be updated however so we do not enter out of sync state */
|
||||
expect(currentItemsKey.serverUpdatedAt.getTime()).to.equal(newUpdated.getTime())
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
await context.deinit()
|
||||
})
|
||||
@@ -485,8 +485,8 @@ describe('key recovery service', function () {
|
||||
await context.launch()
|
||||
await context.register()
|
||||
|
||||
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const itemsKey = await application.encryption.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [itemsKey.payload],
|
||||
},
|
||||
@@ -498,7 +498,7 @@ describe('key recovery service', function () {
|
||||
updated_at: newUpdated,
|
||||
})
|
||||
|
||||
await application.payloadManager.emitDeltaEmit({
|
||||
await application.payloads.emitDeltaEmit({
|
||||
emits: [],
|
||||
ignored: [errored],
|
||||
source: PayloadEmitSource.RemoteRetrieved,
|
||||
@@ -511,7 +511,7 @@ describe('key recovery service', function () {
|
||||
expect(latestItemsKey.errorDecrypting).to.not.be.ok
|
||||
expect(latestItemsKey.itemsKey).to.equal(itemsKey.itemsKey)
|
||||
expect(latestItemsKey.serverUpdatedAt.getTime()).to.equal(newUpdated.getTime())
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
await context.deinit()
|
||||
})
|
||||
@@ -524,8 +524,8 @@ describe('key recovery service', function () {
|
||||
await context.register()
|
||||
|
||||
/** Create and emit errored encrypted items key payload */
|
||||
const itemsKey = await application.encryptionService.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const itemsKey = await application.encryption.getSureDefaultItemsKey()
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [itemsKey.payload],
|
||||
},
|
||||
@@ -533,7 +533,7 @@ describe('key recovery service', function () {
|
||||
|
||||
context.disableKeyRecovery()
|
||||
|
||||
await application.payloadManager.emitDeltaEmit({
|
||||
await application.payloads.emitDeltaEmit({
|
||||
emits: [],
|
||||
ignored: [
|
||||
encrypted.copy({
|
||||
@@ -548,7 +548,7 @@ describe('key recovery service', function () {
|
||||
|
||||
await Factory.sleep(0.1)
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
await context.deinit()
|
||||
|
||||
@@ -589,17 +589,17 @@ describe('key recovery service', function () {
|
||||
})
|
||||
|
||||
/** Create items key associated with a random root key */
|
||||
const randomRootKey = await application.encryptionService.createRootKey(
|
||||
const randomRootKey = await application.encryption.createRootKey(
|
||||
unassociatedIdentifier,
|
||||
unassociatedPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
ProtocolVersion.V003,
|
||||
)
|
||||
const randomItemsKey = await application.encryptionService.operators
|
||||
const randomItemsKey = await context.operators
|
||||
.operatorForVersion(ProtocolVersion.V003)
|
||||
.createItemsKey()
|
||||
|
||||
const encrypted = await application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await application.encryption.encryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [randomItemsKey.payload],
|
||||
key: randomRootKey,
|
||||
@@ -607,7 +607,7 @@ describe('key recovery service', function () {
|
||||
})
|
||||
|
||||
/** Attempt decryption and insert into rotation in errored state */
|
||||
const decrypted = await application.encryptionService.decryptSplitSingle({
|
||||
const decrypted = await application.encryption.decryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [encrypted],
|
||||
},
|
||||
@@ -616,7 +616,7 @@ describe('key recovery service', function () {
|
||||
expect(decrypted.errorDecrypting).to.equal(true)
|
||||
|
||||
/** Insert into rotation */
|
||||
await application.payloadManager.emitPayload(decrypted, PayloadEmitSource.LocalInserted)
|
||||
await application.payloads.emitPayload(decrypted, PayloadEmitSource.LocalInserted)
|
||||
|
||||
/** Wait and allow recovery wizard to complete */
|
||||
await Factory.sleep(0.3)
|
||||
@@ -624,7 +624,7 @@ describe('key recovery service', function () {
|
||||
/** Should be decrypted now */
|
||||
expect(application.items.findItem(encrypted.uuid).errorDecrypting).to.not.be.ok
|
||||
|
||||
expect(application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(application.sync.isOutOfSync()).to.equal(false)
|
||||
await context.deinit()
|
||||
})
|
||||
|
||||
@@ -653,9 +653,9 @@ describe('key recovery service', function () {
|
||||
contextA.password = newPassword
|
||||
await appB.sync.sync()
|
||||
|
||||
const newDefaultKey = appB.encryptionService.getSureDefaultItemsKey()
|
||||
const newDefaultKey = appB.encryption.getSureDefaultItemsKey()
|
||||
|
||||
const encrypted = await appB.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await appB.encryption.encryptSplitSingle({
|
||||
usesRootKeyWithKeyLookup: {
|
||||
items: [newDefaultKey.payload],
|
||||
},
|
||||
@@ -663,28 +663,26 @@ describe('key recovery service', function () {
|
||||
|
||||
/** Insert foreign items key into appA, which shouldn't be able to decrypt it yet */
|
||||
const appA = contextA.application
|
||||
await appA.payloadManager.emitPayload(
|
||||
await appA.payloads.emitPayload(
|
||||
encrypted.copy({
|
||||
errorDecrypting: true,
|
||||
}),
|
||||
PayloadEmitSource.LocalInserted,
|
||||
)
|
||||
|
||||
await Factory.awaitFunctionInvokation(appA.keyRecoveryService, 'handleDecryptionOfAllKeysMatchingCorrectRootKey')
|
||||
await Factory.awaitFunctionInvokation(contextA.keyRecovery, 'handleDecryptionOfAllKeysMatchingCorrectRootKey')
|
||||
|
||||
/** Stored version of items key should use new root key */
|
||||
const stored = (await appA.deviceInterface.getAllDatabaseEntries(appA.identifier)).find(
|
||||
const stored = (await appA.device.getAllDatabaseEntries(appA.identifier)).find(
|
||||
(payload) => payload.uuid === newDefaultKey.uuid,
|
||||
)
|
||||
const storedParams = await appA.encryptionService.getKeyEmbeddedKeyParamsFromItemsKey(new EncryptedPayload(stored))
|
||||
const storedParams = await appA.encryption.getKeyEmbeddedKeyParamsFromItemsKey(new EncryptedPayload(stored))
|
||||
|
||||
const correctStored = (await appB.deviceInterface.getAllDatabaseEntries(appB.identifier)).find(
|
||||
const correctStored = (await appB.device.getAllDatabaseEntries(appB.identifier)).find(
|
||||
(payload) => payload.uuid === newDefaultKey.uuid,
|
||||
)
|
||||
|
||||
const correctParams = await appB.encryptionService.getKeyEmbeddedKeyParamsFromItemsKey(
|
||||
new EncryptedPayload(correctStored),
|
||||
)
|
||||
const correctParams = await appB.encryption.getKeyEmbeddedKeyParamsFromItemsKey(new EncryptedPayload(correctStored))
|
||||
|
||||
expect(storedParams).to.eql(correctParams)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('keys', function () {
|
||||
})
|
||||
|
||||
it('should not have root key by default', async function () {
|
||||
expect(await this.application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await this.application.encryption.getRootKey()).to.not.be.ok
|
||||
})
|
||||
|
||||
it('validates content types requiring root encryption', function () {
|
||||
@@ -43,7 +43,7 @@ describe('keys', function () {
|
||||
/** Items key available by default */
|
||||
const payload = Factory.createNotePayload()
|
||||
const processedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -54,44 +54,44 @@ describe('keys', function () {
|
||||
|
||||
it('has root key and one items key after registering user', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
expect(this.application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.encryption.getRootKey()).to.be.ok
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
})
|
||||
|
||||
it('changing root key with passcode should re-wrap root key', async function () {
|
||||
const email = 'foo'
|
||||
const password = 'bar'
|
||||
const key = await this.application.encryptionService.createRootKey(email, password, KeyParamsOrigination.Registration)
|
||||
await this.application.encryptionService.setRootKey(key)
|
||||
const key = await this.application.encryption.createRootKey(email, password, KeyParamsOrigination.Registration)
|
||||
await this.application.encryption.setRootKey(key)
|
||||
Factory.handlePasswordChallenges(this.application, password)
|
||||
await this.application.addPasscode(password)
|
||||
|
||||
/** We should be able to decrypt wrapped root key with passcode */
|
||||
const wrappingKeyParams = await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()
|
||||
const wrappingKey = await this.application.encryptionService.computeRootKey(password, wrappingKeyParams)
|
||||
await this.application.encryptionService.unwrapRootKey(wrappingKey).catch((error) => {
|
||||
const wrappingKeyParams = await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()
|
||||
const wrappingKey = await this.application.encryption.computeRootKey(password, wrappingKeyParams)
|
||||
await this.application.encryption.unwrapRootKey(wrappingKey).catch((error) => {
|
||||
expect(error).to.not.be.ok
|
||||
})
|
||||
|
||||
const newPassword = 'bar'
|
||||
const newKey = await this.application.encryptionService.createRootKey(
|
||||
const newKey = await this.application.encryption.createRootKey(
|
||||
email,
|
||||
newPassword,
|
||||
KeyParamsOrigination.Registration,
|
||||
)
|
||||
await this.application.encryptionService.setRootKey(newKey, wrappingKey)
|
||||
await this.application.encryptionService.unwrapRootKey(wrappingKey).catch((error) => {
|
||||
await this.application.encryption.setRootKey(newKey, wrappingKey)
|
||||
await this.application.encryption.unwrapRootKey(wrappingKey).catch((error) => {
|
||||
expect(error).to.not.be.ok
|
||||
})
|
||||
})
|
||||
|
||||
it('items key should be encrypted with root key', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const rootKey = await this.application.encryptionService.getRootKey()
|
||||
const itemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
const rootKey = await this.application.encryption.getRootKey()
|
||||
|
||||
/** Encrypt items key */
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [itemsKey.payloadRepresentation()],
|
||||
key: rootKey,
|
||||
@@ -102,7 +102,7 @@ describe('keys', function () {
|
||||
expect(encryptedPayload.items_key_id).to.not.be.ok
|
||||
|
||||
/** Attempt to decrypt with root key. Should succeed. */
|
||||
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decryptedPayload = await this.application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [encryptedPayload],
|
||||
key: rootKey,
|
||||
@@ -114,7 +114,7 @@ describe('keys', function () {
|
||||
})
|
||||
|
||||
it('should create random items key if no account and no passcode', async function () {
|
||||
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
||||
const itemsKeys = this.application.items.getDisplayableItemsKeys()
|
||||
expect(itemsKeys.length).to.equal(1)
|
||||
const notePayload = Factory.createNotePayload()
|
||||
|
||||
@@ -122,55 +122,55 @@ describe('keys', function () {
|
||||
dirty: true,
|
||||
dirtyIndex: getIncrementedDirtyIndex(),
|
||||
})
|
||||
await this.application.payloadManager.emitPayload(dirtied, PayloadEmitSource.LocalChanged)
|
||||
await this.application.payloads.emitPayload(dirtied, PayloadEmitSource.LocalChanged)
|
||||
await this.application.sync.sync()
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const rawNotePayload = rawPayloads.find((r) => r.content_type === ContentType.TYPES.Note)
|
||||
expect(typeof rawNotePayload.content).to.equal('string')
|
||||
})
|
||||
|
||||
it('should keep offline created items key upon registration', async function () {
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
const originalItemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
const originalItemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
await this.application.register(this.email, this.password)
|
||||
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
const newestItemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
const newestItemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
expect(newestItemsKey.uuid).to.equal(originalItemsKey.uuid)
|
||||
})
|
||||
|
||||
it('should use items key for encryption of note', async function () {
|
||||
const notePayload = Factory.createNotePayload()
|
||||
const keyToUse = await this.application.encryptionService.itemsEncryption.keyToUseForItemEncryption(notePayload)
|
||||
const keyToUse = await this.application.encryption.itemsEncryption.keyToUseForItemEncryption(notePayload)
|
||||
expect(keyToUse.content_type).to.equal(ContentType.TYPES.ItemsKey)
|
||||
})
|
||||
|
||||
it('encrypting an item should associate an items key to it', async function () {
|
||||
const note = Factory.createNotePayload()
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note],
|
||||
},
|
||||
})
|
||||
|
||||
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
const itemsKey = this.application.encryption.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
expect(itemsKey).to.be.ok
|
||||
})
|
||||
|
||||
it('decrypt encrypted item with associated key', async function () {
|
||||
const note = Factory.createNotePayload()
|
||||
const title = note.content.title
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note],
|
||||
},
|
||||
})
|
||||
|
||||
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
const itemsKey = this.application.encryption.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
expect(itemsKey).to.be.ok
|
||||
|
||||
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decryptedPayload = await this.application.encryption.decryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [encryptedPayload],
|
||||
},
|
||||
@@ -182,17 +182,17 @@ describe('keys', function () {
|
||||
it('decrypts items waiting for keys', async function () {
|
||||
const notePayload = Factory.createNotePayload()
|
||||
const title = notePayload.content.title
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [notePayload],
|
||||
},
|
||||
})
|
||||
|
||||
const itemsKey = this.application.encryptionService.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
const itemsKey = this.application.encryption.itemsKeyForEncryptedPayload(encryptedPayload)
|
||||
|
||||
await this.application.itemManager.removeItemLocally(itemsKey)
|
||||
await this.application.items.removeItemLocally(itemsKey)
|
||||
|
||||
const erroredPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||
const erroredPayload = await this.application.encryption.decryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [encryptedPayload],
|
||||
},
|
||||
@@ -200,7 +200,7 @@ describe('keys', function () {
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([erroredPayload], PayloadEmitSource.LocalChanged)
|
||||
|
||||
const note = this.application.itemManager.findAnyItem(notePayload.uuid)
|
||||
const note = this.application.items.findAnyItem(notePayload.uuid)
|
||||
expect(note.errorDecrypting).to.equal(true)
|
||||
expect(note.waitingForKey).to.equal(true)
|
||||
|
||||
@@ -213,7 +213,7 @@ describe('keys', function () {
|
||||
*/
|
||||
await Factory.sleep(0.2)
|
||||
|
||||
const updatedNote = this.application.itemManager.findItem(note.uuid)
|
||||
const updatedNote = this.application.items.findItem(note.uuid)
|
||||
|
||||
expect(updatedNote.errorDecrypting).to.not.be.ok
|
||||
expect(updatedNote.waitingForKey).to.not.be.ok
|
||||
@@ -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 () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
|
||||
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const itemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
|
||||
expect(itemsKey.errorDecrypting).to.not.be.ok
|
||||
|
||||
@@ -239,9 +239,9 @@ describe('keys', function () {
|
||||
},
|
||||
})
|
||||
|
||||
await this.application.syncService.handleSuccessServerResponse({ payloadsSavedOrSaving: [], options: {} }, response)
|
||||
await this.application.sync.handleSuccessServerResponse({ payloadsSavedOrSaving: [], options: {} }, response)
|
||||
|
||||
const refreshedKey = this.application.payloadManager.findOne(itemsKey.uuid)
|
||||
const refreshedKey = this.application.payloads.findOne(itemsKey.uuid)
|
||||
|
||||
expect(refreshedKey.errorDecrypting).to.not.be.ok
|
||||
expect(refreshedKey.content.itemsKey).to.be.ok
|
||||
@@ -250,19 +250,19 @@ describe('keys', function () {
|
||||
it('generating export params with logged in account should produce encrypted payload', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const payload = Factory.createNotePayload()
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
})
|
||||
expect(typeof encryptedPayload.content).to.equal('string')
|
||||
expect(encryptedPayload.content.substring(0, 3)).to.equal(this.application.encryptionService.getLatestVersion())
|
||||
expect(encryptedPayload.content.substring(0, 3)).to.equal(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
|
||||
it('When setting passcode, should encrypt items keys', async function () {
|
||||
await this.application.addPasscode('foo')
|
||||
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const itemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const itemsKeyRawPayload = rawPayloads.find((p) => p.uuid === itemsKey.uuid)
|
||||
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
||||
expect(itemsKeyPayload.enc_item_key).to.be.ok
|
||||
@@ -270,13 +270,13 @@ describe('keys', function () {
|
||||
|
||||
it('items key encrypted payload should contain root key params', async function () {
|
||||
await this.application.addPasscode('foo')
|
||||
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const itemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const itemsKeyRawPayload = rawPayloads.find((p) => p.uuid === itemsKey.uuid)
|
||||
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
||||
|
||||
const authenticatedData = this.context.encryption.getEmbeddedPayloadAuthenticatedData(itemsKeyPayload)
|
||||
const rootKeyParams = await this.application.encryptionService.getRootKeyParams()
|
||||
const rootKeyParams = await this.application.encryption.getRootKeyParams()
|
||||
|
||||
expect(authenticatedData.kp).to.be.ok
|
||||
expect(authenticatedData.kp).to.eql(rootKeyParams.getPortableValue())
|
||||
@@ -286,8 +286,8 @@ describe('keys', function () {
|
||||
it('correctly validates local passcode', async function () {
|
||||
const passcode = 'foo'
|
||||
await this.application.addPasscode('foo')
|
||||
expect((await this.application.encryptionService.validatePasscode('wrong')).valid).to.equal(false)
|
||||
expect((await this.application.encryptionService.validatePasscode(passcode)).valid).to.equal(true)
|
||||
expect((await this.application.encryption.validatePasscode('wrong')).valid).to.equal(false)
|
||||
expect((await this.application.encryption.validatePasscode(passcode)).valid).to.equal(true)
|
||||
})
|
||||
|
||||
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,
|
||||
* and create a new default items key that is the default for a given protocol version.
|
||||
*/
|
||||
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const latestVersion = this.application.encryptionService.getLatestVersion()
|
||||
const defaultItemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
const latestVersion = this.application.encryption.getLatestVersion()
|
||||
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
||||
|
||||
/** Register with 003 version */
|
||||
@@ -308,11 +308,11 @@ describe('keys', function () {
|
||||
version: ProtocolVersion.V003,
|
||||
})
|
||||
|
||||
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
||||
const itemsKeys = this.application.items.getDisplayableItemsKeys()
|
||||
expect(itemsKeys.length).to.equal(1)
|
||||
const newestItemsKey = itemsKeys[0]
|
||||
expect(newestItemsKey.keyVersion).to.equal(ProtocolVersion.V003)
|
||||
const rootKey = await this.application.encryptionService.getRootKey()
|
||||
const rootKey = await this.application.encryption.getRootKey()
|
||||
expect(newestItemsKey.itemsKey).to.equal(rootKey.masterKey)
|
||||
expect(newestItemsKey.dataAuthenticationKey).to.equal(rootKey.dataAuthenticationKey)
|
||||
})
|
||||
@@ -326,33 +326,33 @@ describe('keys', function () {
|
||||
version: ProtocolVersion.V003,
|
||||
})
|
||||
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys()[0].dirty).to.equal(false)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableItemsKeys()[0].dirty).to.equal(false)
|
||||
|
||||
/** Sign out and back in */
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(10)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(10)
|
||||
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
|
||||
})
|
||||
|
||||
it('When root key changes, all items keys must be re-encrypted', async function () {
|
||||
const passcode = 'foo'
|
||||
await this.application.addPasscode(passcode)
|
||||
await Factory.createSyncedNote(this.application)
|
||||
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
||||
const itemsKeys = this.application.items.getDisplayableItemsKeys()
|
||||
expect(itemsKeys.length).to.equal(1)
|
||||
const originalItemsKey = itemsKeys[0]
|
||||
|
||||
const originalRootKey = await this.application.encryptionService.getRootKey()
|
||||
const originalRootKey = await this.application.encryption.getRootKey()
|
||||
/** Expect that we can decrypt raw payload with current root key */
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const itemsKeyRawPayload = rawPayloads.find((p) => p.uuid === originalItemsKey.uuid)
|
||||
const itemsKeyPayload = new EncryptedPayload(itemsKeyRawPayload)
|
||||
const decrypted = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decrypted = await this.application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [itemsKeyPayload],
|
||||
key: originalRootKey,
|
||||
@@ -366,7 +366,7 @@ describe('keys', function () {
|
||||
Factory.handlePasswordChallenges(this.application, passcode)
|
||||
await this.application.changePasscode('bar')
|
||||
|
||||
const newRootKey = await this.application.encryptionService.getRootKey()
|
||||
const newRootKey = await this.application.encryption.getRootKey()
|
||||
expect(newRootKey).to.not.equal(originalRootKey)
|
||||
expect(newRootKey.masterKey).to.not.equal(originalRootKey.masterKey)
|
||||
|
||||
@@ -374,12 +374,12 @@ describe('keys', function () {
|
||||
* Expect that originalRootKey can no longer decrypt originalItemsKey
|
||||
* as items key has been re-encrypted with new root key
|
||||
*/
|
||||
const rawPayloads2 = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads2 = await this.application.storage.getAllRawPayloads()
|
||||
const itemsKeyRawPayload2 = rawPayloads2.find((p) => p.uuid === originalItemsKey.uuid)
|
||||
expect(itemsKeyRawPayload2.content).to.not.equal(itemsKeyRawPayload.content)
|
||||
|
||||
const itemsKeyPayload2 = new EncryptedPayload(itemsKeyRawPayload2)
|
||||
const decrypted2 = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decrypted2 = await this.application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [itemsKeyPayload2],
|
||||
key: originalRootKey,
|
||||
@@ -388,7 +388,7 @@ describe('keys', function () {
|
||||
expect(decrypted2.errorDecrypting).to.equal(true)
|
||||
|
||||
/** Should be able to decrypt with new root key */
|
||||
const decrypted3 = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decrypted3 = await this.application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [itemsKeyPayload2],
|
||||
key: newRootKey,
|
||||
@@ -403,19 +403,19 @@ describe('keys', function () {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
})
|
||||
const itemsKeys = this.application.itemManager.getDisplayableItemsKeys()
|
||||
const itemsKeys = this.application.items.getDisplayableItemsKeys()
|
||||
expect(itemsKeys.length).to.equal(1)
|
||||
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const defaultItemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
|
||||
const result = await this.application.changePassword(this.password, 'foobarfoo')
|
||||
expect(result.error).to.not.be.ok
|
||||
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||
const newDefaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(2)
|
||||
const newDefaultItemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
||||
|
||||
const note = await Factory.createSyncedNote(this.application)
|
||||
const payload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const payload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note.payload],
|
||||
},
|
||||
@@ -430,20 +430,20 @@ describe('keys', function () {
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
const itemsKeys = application.itemManager.getDisplayableItemsKeys()
|
||||
const itemsKeys = application.items.getDisplayableItemsKeys()
|
||||
expect(itemsKeys.length).to.equal(1)
|
||||
const defaultItemsKey = application.encryptionService.getSureDefaultItemsKey()
|
||||
const defaultItemsKey = application.encryption.getSureDefaultItemsKey()
|
||||
|
||||
const newEmail = UuidGenerator.GenerateUuid()
|
||||
const result = await application.changeEmail(newEmail, password)
|
||||
expect(result.error).to.not.be.ok
|
||||
|
||||
expect(application.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||
const newDefaultItemsKey = application.encryptionService.getSureDefaultItemsKey()
|
||||
expect(application.items.getDisplayableItemsKeys().length).to.equal(2)
|
||||
const newDefaultItemsKey = application.encryption.getSureDefaultItemsKey()
|
||||
expect(newDefaultItemsKey.uuid).to.not.equal(defaultItemsKey.uuid)
|
||||
|
||||
const note = await Factory.createSyncedNote(application)
|
||||
const payload = await application.encryptionService.encryptSplitSingle({
|
||||
const payload = await application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note.payload],
|
||||
},
|
||||
@@ -480,34 +480,28 @@ describe('keys', function () {
|
||||
|
||||
it('loading the keychain root key should also load its key params', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const rootKey = await this.application.encryptionService.rootKeyManager.getRootKeyFromKeychain()
|
||||
const rootKey = await this.application.encryption.rootKeyManager.getRootKeyFromKeychain()
|
||||
expect(rootKey.keyParams).to.be.ok
|
||||
})
|
||||
|
||||
it('key params should be persisted separately and not as part of root key', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const rawKey = await this.application.deviceInterface.getNamespacedKeychainValue(this.application.identifier)
|
||||
const rawKey = await this.application.device.getNamespacedKeychainValue(this.application.identifier)
|
||||
expect(rawKey.keyParams).to.not.be.ok
|
||||
const rawKeyParams = await this.application.diskStorageService.getValue(
|
||||
StorageKey.RootKeyParams,
|
||||
StorageValueModes.Nonwrapped,
|
||||
)
|
||||
const rawKeyParams = await this.application.storage.getValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
||||
expect(rawKeyParams).to.be.ok
|
||||
})
|
||||
|
||||
it('persisted key params should exactly equal in memory rootKey.keyParams', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const rootKey = await this.application.encryptionService.getRootKey()
|
||||
const rawKeyParams = await this.application.diskStorageService.getValue(
|
||||
StorageKey.RootKeyParams,
|
||||
StorageValueModes.Nonwrapped,
|
||||
)
|
||||
const rootKey = await this.application.encryption.getRootKey()
|
||||
const rawKeyParams = await this.application.storage.getValue(StorageKey.RootKeyParams, StorageValueModes.Nonwrapped)
|
||||
expect(rootKey.keyParams.content).to.eql(rawKeyParams)
|
||||
})
|
||||
|
||||
it('key params should have expected values', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||
const keyParamsObject = await this.application.encryption.getRootKeyParams()
|
||||
const keyParams = keyParamsObject.content
|
||||
expect(keyParams.identifier).to.be.ok
|
||||
expect(keyParams.pw_nonce).to.be.ok
|
||||
@@ -533,7 +527,7 @@ describe('keys', function () {
|
||||
email,
|
||||
password,
|
||||
})
|
||||
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||
const keyParamsObject = await this.application.encryption.getRootKeyParams()
|
||||
const keyParams = keyParamsObject.content
|
||||
|
||||
expect(keyParams.created).to.be.ok
|
||||
@@ -551,7 +545,7 @@ describe('keys', function () {
|
||||
password: this.password,
|
||||
version: ProtocolVersion.V003,
|
||||
})
|
||||
const keyParamsObject = await this.application.encryptionService.getRootKeyParams()
|
||||
const keyParamsObject = await this.application.encryption.getRootKeyParams()
|
||||
const keyParams = keyParamsObject.content
|
||||
|
||||
expect(keyParams.created).to.be.ok
|
||||
@@ -566,12 +560,12 @@ describe('keys', function () {
|
||||
password: this.password,
|
||||
version: ProtocolVersion.V003,
|
||||
})
|
||||
expect(await this.application.encryptionService.getEncryptionDisplayName()).to.equal('AES-256')
|
||||
expect(await this.application.encryption.getEncryptionDisplayName()).to.equal('AES-256')
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
/** Register with 004 account */
|
||||
await this.application.register(this.email + 'new', this.password)
|
||||
expect(await this.application.encryptionService.getEncryptionDisplayName()).to.equal('XChaCha20-Poly1305')
|
||||
expect(await this.application.encryption.getEncryptionDisplayName()).to.equal('XChaCha20-Poly1305')
|
||||
})
|
||||
|
||||
it('when launching app with no keychain but data, should present account recovery challenge', async function () {
|
||||
@@ -587,7 +581,7 @@ describe('keys', function () {
|
||||
password: this.password,
|
||||
})
|
||||
/** Simulate empty keychain */
|
||||
await this.application.deviceInterface.clearRawKeychainValue()
|
||||
await this.application.device.clearRawKeychainValue()
|
||||
|
||||
const recreatedApp = await Factory.createApplicationWithFakeCrypto(id)
|
||||
let totalChallenges = 0
|
||||
@@ -599,7 +593,7 @@ describe('keys', function () {
|
||||
await recreatedApp.prepareForLaunch({ receiveChallenge })
|
||||
await recreatedApp.launch(true)
|
||||
|
||||
expect(recreatedApp.encryptionService.getRootKey()).to.be.ok
|
||||
expect(recreatedApp.encryption.getRootKey()).to.be.ok
|
||||
expect(totalChallenges).to.equal(expectedChallenges)
|
||||
await Factory.safeDeinit(recreatedApp)
|
||||
})
|
||||
@@ -630,7 +624,7 @@ describe('keys', function () {
|
||||
|
||||
const newPassword = Utils.generateUuid()
|
||||
|
||||
await contextA.application.userService.changeCredentials({
|
||||
await contextA.application.user.changeCredentials({
|
||||
currentPassword: password,
|
||||
newPassword: newPassword,
|
||||
origination: KeyParamsOrigination.PasswordChange,
|
||||
@@ -639,8 +633,8 @@ describe('keys', function () {
|
||||
await contextB.syncWithIntegrityCheck()
|
||||
await contextA.syncWithIntegrityCheck()
|
||||
|
||||
const clientAUndecryptables = contextA.application.keyRecoveryService.getUndecryptables()
|
||||
const clientBUndecryptables = contextB.application.keyRecoveryService.getUndecryptables()
|
||||
const clientAUndecryptables = contextA.keyRecovery.getUndecryptables()
|
||||
const clientBUndecryptables = contextB.keyRecovery.getUndecryptables()
|
||||
|
||||
expect(Object.keys(clientBUndecryptables).length).to.equal(1)
|
||||
expect(Object.keys(clientAUndecryptables).length).to.equal(0)
|
||||
@@ -684,13 +678,13 @@ describe('keys', function () {
|
||||
|
||||
/** Change password through session manager directly instead of application,
|
||||
* as not to create any items key (to simulate 003 client behavior) */
|
||||
const currentRootKey = await oldClient.encryptionService.computeRootKey(
|
||||
const currentRootKey = await oldClient.encryption.computeRootKey(
|
||||
this.password,
|
||||
await oldClient.encryptionService.getRootKeyParams(),
|
||||
await oldClient.encryption.getRootKeyParams(),
|
||||
)
|
||||
const operator = oldClient.encryptionService.operators.operatorForVersion(ProtocolVersion.V003)
|
||||
const operator = this.context.operators.operatorForVersion(ProtocolVersion.V003)
|
||||
const newRootKey = await operator.createRootKey(this.email, this.password)
|
||||
Object.defineProperty(oldClient.apiService, 'apiVersion', {
|
||||
Object.defineProperty(oldClient.legacyApi, 'apiVersion', {
|
||||
get: function () {
|
||||
return '20190520'
|
||||
},
|
||||
@@ -701,7 +695,7 @@ describe('keys', function () {
|
||||
*/
|
||||
await newClient.signIn(this.email, this.password)
|
||||
|
||||
await oldClient.sessionManager.changeCredentials({
|
||||
await oldClient.sessions.changeCredentials({
|
||||
currentServerPassword: currentRootKey.serverPassword,
|
||||
newRootKey,
|
||||
})
|
||||
@@ -711,7 +705,7 @@ describe('keys', function () {
|
||||
await Factory.sleep(1)
|
||||
|
||||
/** Expect a new items key to be created based on the new root key */
|
||||
expect(newClient.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||
expect(newClient.items.getDisplayableItemsKeys().length).to.equal(2)
|
||||
|
||||
await Factory.safeDeinit(newClient)
|
||||
await Factory.safeDeinit(oldClient)
|
||||
@@ -734,11 +728,11 @@ describe('keys', function () {
|
||||
|
||||
/** Change password through session manager directly instead of application,
|
||||
* as not to create any items key (to simulate 003 client behavior) */
|
||||
const currentRootKey = await this.application.encryptionService.computeRootKey(
|
||||
const currentRootKey = await this.application.encryption.computeRootKey(
|
||||
this.password,
|
||||
await this.application.encryptionService.getRootKeyParams(),
|
||||
await this.application.encryption.getRootKeyParams(),
|
||||
)
|
||||
const operator = this.application.encryptionService.operators.operatorForVersion(ProtocolVersion.V003)
|
||||
const operator = this.context.operators.operatorForVersion(ProtocolVersion.V003)
|
||||
const newRootKeyTemplate = await operator.createRootKey(this.email, this.password)
|
||||
const newRootKey = CreateNewRootKey({
|
||||
...newRootKeyTemplate.content,
|
||||
@@ -748,7 +742,7 @@ describe('keys', function () {
|
||||
},
|
||||
})
|
||||
|
||||
Object.defineProperty(this.application.apiService, 'apiVersion', {
|
||||
Object.defineProperty(this.application.legacyApi, 'apiVersion', {
|
||||
get: function () {
|
||||
return '20190520'
|
||||
},
|
||||
@@ -757,25 +751,25 @@ describe('keys', function () {
|
||||
/** Renew session to prevent timeouts */
|
||||
this.application = await Factory.signOutAndBackIn(this.application, this.email, this.password)
|
||||
|
||||
await this.application.sessionManager.changeCredentials({
|
||||
await this.application.sessions.changeCredentials({
|
||||
currentServerPassword: currentRootKey.serverPassword,
|
||||
newRootKey,
|
||||
})
|
||||
await this.application.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||
await this.application.encryption.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||
/** Note: this may result in a deadlock if features_service syncs and results in an error */
|
||||
await this.application.sync.sync({ awaitAll: true })
|
||||
|
||||
/** Relaunch application and expect new items key to be created */
|
||||
const identifier = this.application.identifier
|
||||
/** Set to pre 2.0.15 version so migration runs */
|
||||
await this.application.deviceInterface.setRawStorageValue(`${identifier}-snjs_version`, '2.0.14')
|
||||
await this.application.device.setRawStorageValue(`${identifier}-snjs_version`, '2.0.14')
|
||||
await Factory.safeDeinit(this.application)
|
||||
|
||||
const refreshedApp = await Factory.createApplicationWithFakeCrypto(identifier)
|
||||
await Factory.initializeApplication(refreshedApp)
|
||||
|
||||
/** Expect a new items key to be created based on the new root key */
|
||||
expect(refreshedApp.itemManager.getDisplayableItemsKeys().length).to.equal(2)
|
||||
expect(refreshedApp.items.getDisplayableItemsKeys().length).to.equal(2)
|
||||
await Factory.safeDeinit(refreshedApp)
|
||||
})
|
||||
})
|
||||
@@ -793,8 +787,8 @@ describe('keys', function () {
|
||||
await this.context.sync()
|
||||
await promise
|
||||
|
||||
await this.application.itemManager.removeAllItemsFromMemory()
|
||||
expect(this.application.encryptionService.getSureDefaultItemsKey()).to.not.be.ok
|
||||
await this.application.items.removeAllItemsFromMemory()
|
||||
expect(this.application.encryption.getSureDefaultItemsKey()).to.not.be.ok
|
||||
|
||||
const protocol003 = new SNProtocolOperator003(new SNWebCrypto())
|
||||
const key = await protocol003.createItemsKey()
|
||||
@@ -810,19 +804,19 @@ describe('keys', function () {
|
||||
}),
|
||||
)
|
||||
|
||||
const defaultKey = this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const defaultKey = this.application.encryption.getSureDefaultItemsKey()
|
||||
expect(defaultKey.keyVersion).to.equal(ProtocolVersion.V003)
|
||||
expect(defaultKey.uuid).to.equal(key.uuid)
|
||||
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
|
||||
const notePayload = Factory.createNotePayload()
|
||||
expect(await this.application.encryptionService.itemsEncryption.keyToUseForItemEncryption(notePayload)).to.be.ok
|
||||
expect(await this.application.encryption.itemsEncryption.keyToUseForItemEncryption(notePayload)).to.be.ok
|
||||
})
|
||||
|
||||
it('having unsynced items keys should resync them upon download first sync completion', async function () {
|
||||
await Factory.registerUserToApplication({ application: this.application })
|
||||
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
const itemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
await this.application.mutator.emitItemFromPayload(
|
||||
itemsKey.payload.copy({
|
||||
dirty: false,
|
||||
@@ -830,7 +824,7 @@ describe('keys', function () {
|
||||
deleted: false,
|
||||
}),
|
||||
)
|
||||
await this.application.syncService.sync({
|
||||
await this.application.sync.sync({
|
||||
mode: SyncMode.DownloadFirst,
|
||||
})
|
||||
const updatedKey = this.application.items.findItem(itemsKey.uuid)
|
||||
@@ -840,7 +834,7 @@ describe('keys', function () {
|
||||
it('having key while offline then signing into account with key should only have 1 default items key', async function () {
|
||||
const otherClient = await Factory.createInitAppWithFakeCrypto()
|
||||
/** Invert order of keys */
|
||||
otherClient.itemManager.itemsKeyDisplayController.setDisplayOptions({ sortBy: 'dsc' })
|
||||
otherClient.items.itemsKeyDisplayController.setDisplayOptions({ sortBy: 'dsc' })
|
||||
/** On client A, create account and note */
|
||||
await Factory.registerUserToApplication({
|
||||
application: this.application,
|
||||
@@ -856,12 +850,12 @@ describe('keys', function () {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
})
|
||||
const defaultKeys = otherClient.encryptionService.itemsEncryption.getItemsKeys().filter((key) => {
|
||||
const defaultKeys = otherClient.encryption.itemsEncryption.getItemsKeys().filter((key) => {
|
||||
return key.isDefault
|
||||
})
|
||||
expect(defaultKeys.length).to.equal(1)
|
||||
|
||||
const rawPayloads = await otherClient.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await otherClient.storage.getAllRawPayloads()
|
||||
const notePayload = rawPayloads.find((p) => p.content_type === ContentType.TYPES.Note)
|
||||
|
||||
expect(notePayload.items_key_id).to.equal(itemsKey.uuid)
|
||||
|
||||
@@ -26,17 +26,16 @@ export class AppContext {
|
||||
}
|
||||
|
||||
enableLogging() {
|
||||
const syncService = this.application.syncService
|
||||
const payloadManager = this.application.payloadManager
|
||||
const payloadManager = this.application.payloads
|
||||
|
||||
syncService.getServiceName = () => {
|
||||
this.application.sync.getServiceName = () => {
|
||||
return `${this.identifier}—SyncService`
|
||||
}
|
||||
payloadManager.getServiceName = () => {
|
||||
return `${this.identifier}-PayloadManager`
|
||||
}
|
||||
|
||||
syncService.loggingEnabled = true
|
||||
this.application.sync.loggingEnabled = true
|
||||
payloadManager.loggingEnabled = true
|
||||
}
|
||||
|
||||
@@ -51,7 +50,7 @@ export class AppContext {
|
||||
}
|
||||
|
||||
get vaults() {
|
||||
return this.application.vaultService
|
||||
return this.application.vaults
|
||||
}
|
||||
|
||||
get sessions() {
|
||||
@@ -67,31 +66,51 @@ export class AppContext {
|
||||
}
|
||||
|
||||
get payloads() {
|
||||
return this.application.payloadManager
|
||||
return this.application.payloads
|
||||
}
|
||||
|
||||
get encryption() {
|
||||
return this.application.encryptionService
|
||||
return this.application.encryption
|
||||
}
|
||||
|
||||
get keyRecovery() {
|
||||
return this.application.dependencies.get(TYPES.KeyRecoveryService)
|
||||
}
|
||||
|
||||
get singletons() {
|
||||
return this.application.dependencies.get(TYPES.SingletonManager)
|
||||
}
|
||||
|
||||
get history() {
|
||||
return this.application.dependencies.get(TYPES.HistoryManager)
|
||||
}
|
||||
|
||||
get subscriptions() {
|
||||
return this.application.dependencies.get(TYPES.SubscriptionManager)
|
||||
}
|
||||
|
||||
get contacts() {
|
||||
return this.application.contactService
|
||||
return this.application.contacts
|
||||
}
|
||||
|
||||
get sharedVaults() {
|
||||
return this.application.sharedVaultService
|
||||
return this.application.sharedVaults
|
||||
}
|
||||
|
||||
get files() {
|
||||
return this.application.fileService
|
||||
return this.application.files
|
||||
}
|
||||
|
||||
get keys() {
|
||||
return this.application.keySystemKeyManager
|
||||
return this.application.dependencies.get(TYPES.KeySystemKeyManager)
|
||||
}
|
||||
|
||||
get operators() {
|
||||
return this.application.dependencies.get(TYPES.EncryptionOperators)
|
||||
}
|
||||
|
||||
get asymmetric() {
|
||||
return this.application.asymmetricMessageService
|
||||
return this.application.asymmetric
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
@@ -115,20 +134,20 @@ export class AppContext {
|
||||
}
|
||||
|
||||
disableIntegrityAutoHeal() {
|
||||
this.application.syncService.emitOutOfSyncRemotePayloads = () => {
|
||||
this.application.sync.emitOutOfSyncRemotePayloads = () => {
|
||||
console.warn('Integrity self-healing is disabled for this test')
|
||||
}
|
||||
}
|
||||
|
||||
disableKeyRecovery() {
|
||||
this.application.keyRecoveryService.beginKeyRecovery = () => {
|
||||
this.keyRecovery.beginKeyRecovery = () => {
|
||||
console.warn('Key recovery is disabled for this test')
|
||||
}
|
||||
}
|
||||
|
||||
handleChallenge = (challenge) => {
|
||||
if (this.ignoringChallenges) {
|
||||
this.application.challengeService.cancelChallenge(challenge)
|
||||
this.application.challenges.cancelChallenge(challenge)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -178,15 +197,12 @@ export class AppContext {
|
||||
},
|
||||
})
|
||||
|
||||
return this.application.syncService.handleSuccessServerResponse(
|
||||
{ payloadsSavedOrSaving: [], options: {} },
|
||||
response,
|
||||
)
|
||||
return this.application.sync.handleSuccessServerResponse({ payloadsSavedOrSaving: [], options: {} }, response)
|
||||
}
|
||||
|
||||
resolveWhenKeyRecovered(uuid) {
|
||||
return new Promise((resolve) => {
|
||||
this.application.keyRecoveryService.addEventObserver((_eventName, keys) => {
|
||||
this.keyRecovery.addEventObserver((_eventName, keys) => {
|
||||
if (Uuids(keys).includes(uuid)) {
|
||||
resolve()
|
||||
}
|
||||
@@ -196,7 +212,7 @@ export class AppContext {
|
||||
|
||||
resolveWhenSharedVaultUserKeysResolved() {
|
||||
return new Promise((resolve) => {
|
||||
this.application.vaultService.collaboration.addEventObserver((eventName) => {
|
||||
this.application.vaults.collaboration.addEventObserver((eventName) => {
|
||||
if (eventName === SharedVaultServiceEvent.SharedVaultStatusChanged) {
|
||||
resolve()
|
||||
}
|
||||
@@ -206,7 +222,7 @@ export class AppContext {
|
||||
|
||||
async awaitSignInEvent() {
|
||||
return new Promise((resolve) => {
|
||||
this.application.userService.addEventObserver((eventName) => {
|
||||
this.application.user.addEventObserver((eventName) => {
|
||||
if (eventName === AccountEvent.SignedInOrRegistered) {
|
||||
resolve()
|
||||
}
|
||||
@@ -235,7 +251,7 @@ export class AppContext {
|
||||
|
||||
awaitNextSucessfulSync() {
|
||||
return new Promise((resolve) => {
|
||||
const removeObserver = this.application.syncService.addEventObserver((event) => {
|
||||
const removeObserver = this.application.sync.addEventObserver((event) => {
|
||||
if (event === SyncEvent.SyncCompletedWithAllItemsUploadedAndDownloaded) {
|
||||
removeObserver()
|
||||
resolve()
|
||||
@@ -246,7 +262,7 @@ export class AppContext {
|
||||
|
||||
awaitNextSyncEvent(eventName) {
|
||||
return new Promise((resolve) => {
|
||||
const removeObserver = this.application.syncService.addEventObserver((event, data) => {
|
||||
const removeObserver = this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === eventName) {
|
||||
removeObserver()
|
||||
resolve(data)
|
||||
@@ -257,7 +273,7 @@ export class AppContext {
|
||||
|
||||
awaitNextSyncSharedVaultFromScratchEvent() {
|
||||
return new Promise((resolve) => {
|
||||
const removeObserver = this.application.syncService.addEventObserver((event, data) => {
|
||||
const removeObserver = this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted && data?.options?.sharedVaultUuids) {
|
||||
removeObserver()
|
||||
resolve(data)
|
||||
@@ -268,7 +284,7 @@ export class AppContext {
|
||||
|
||||
resolveWithUploadedPayloads() {
|
||||
return new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver((event, data) => {
|
||||
this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
resolve(data.uploadedPayloads)
|
||||
}
|
||||
@@ -278,7 +294,7 @@ export class AppContext {
|
||||
|
||||
resolveWithConflicts() {
|
||||
return new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver((event, response) => {
|
||||
this.application.sync.addEventObserver((event, response) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
resolve(response.rawConflictObjects)
|
||||
}
|
||||
@@ -288,7 +304,7 @@ export class AppContext {
|
||||
|
||||
resolveWhenSavedSyncPayloadsIncludesItemUuid(uuid) {
|
||||
return new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver((event, response) => {
|
||||
this.application.sync.addEventObserver((event, response) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
const savedPayload = response.savedPayloads.find((payload) => payload.uuid === uuid)
|
||||
if (savedPayload) {
|
||||
@@ -301,7 +317,7 @@ export class AppContext {
|
||||
|
||||
resolveWhenSavedSyncPayloadsIncludesItemThatIsDuplicatedOf(uuid) {
|
||||
return new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver((event, response) => {
|
||||
this.application.sync.addEventObserver((event, response) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
const savedPayload = response.savedPayloads.find((payload) => payload.duplicate_of === uuid)
|
||||
if (savedPayload) {
|
||||
@@ -354,7 +370,7 @@ export class AppContext {
|
||||
|
||||
resolveWhenUserMessagesProcessingCompletes() {
|
||||
return new Promise((resolve) => {
|
||||
const objectToSpy = this.application.userEventService
|
||||
const objectToSpy = this.application.dependencies.get(TYPES.UserEventService)
|
||||
sinon.stub(objectToSpy, 'handleReceivedUserEvents').callsFake(async (params) => {
|
||||
objectToSpy.handleReceivedUserEvents.restore()
|
||||
const result = await objectToSpy.handleReceivedUserEvents(params)
|
||||
@@ -364,12 +380,36 @@ export class AppContext {
|
||||
})
|
||||
}
|
||||
|
||||
resolveWhenAllInboundAsymmetricMessagesAreDeleted() {
|
||||
return new Promise((resolve) => {
|
||||
const objectToSpy = this.application.dependencies.get(TYPES.AsymmetricMessageServer)
|
||||
sinon.stub(objectToSpy, 'deleteAllInboundMessages').callsFake(async (params) => {
|
||||
objectToSpy.deleteAllInboundMessages.restore()
|
||||
const result = await objectToSpy.deleteAllInboundMessages(params)
|
||||
resolve()
|
||||
return result
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
resolveWhenAllInboundSharedVaultInvitesAreDeleted() {
|
||||
return new Promise((resolve) => {
|
||||
const objectToSpy = this.application.sharedVaults.invitesServer
|
||||
sinon.stub(objectToSpy, 'deleteAllInboundInvites').callsFake(async (params) => {
|
||||
objectToSpy.deleteAllInboundInvites.restore()
|
||||
const result = await objectToSpy.deleteAllInboundInvites(params)
|
||||
resolve()
|
||||
return result
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
resolveWhenSharedVaultServiceSendsContactShareMessage() {
|
||||
return new Promise((resolve) => {
|
||||
const objectToSpy = this.sharedVaults
|
||||
sinon.stub(objectToSpy, 'shareContactWithUserAdministeredSharedVaults').callsFake(async (contact) => {
|
||||
objectToSpy.shareContactWithUserAdministeredSharedVaults.restore()
|
||||
const result = await objectToSpy.shareContactWithUserAdministeredSharedVaults(contact)
|
||||
sinon.stub(objectToSpy, 'shareContactWithVaults').callsFake(async (contact) => {
|
||||
objectToSpy.shareContactWithVaults.restore()
|
||||
const result = await objectToSpy.shareContactWithVaults(contact)
|
||||
resolve()
|
||||
return result
|
||||
})
|
||||
@@ -405,14 +445,14 @@ export class AppContext {
|
||||
}
|
||||
|
||||
awaitUserPrefsSingletonCreation() {
|
||||
const preferences = this.application.preferencesService.preferences
|
||||
const preferences = this.application.preferences.preferences
|
||||
if (preferences) {
|
||||
return
|
||||
}
|
||||
|
||||
let didCompleteRelevantSync = false
|
||||
return new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver((eventName, data) => {
|
||||
this.application.sync.addEventObserver((eventName, data) => {
|
||||
if (!didCompleteRelevantSync) {
|
||||
if (data?.savedPayloads) {
|
||||
const matching = data.savedPayloads.find((p) => {
|
||||
@@ -430,7 +470,7 @@ export class AppContext {
|
||||
|
||||
awaitUserPrefsSingletonResolution() {
|
||||
return new Promise((resolve) => {
|
||||
this.application.preferencesService.addEventObserver((eventName) => {
|
||||
this.application.preferences.addEventObserver((eventName) => {
|
||||
if (eventName === PreferencesServiceEvent.PreferencesChanged) {
|
||||
resolve()
|
||||
}
|
||||
@@ -473,7 +513,7 @@ export class AppContext {
|
||||
}
|
||||
|
||||
findPayload(uuid) {
|
||||
return this.application.payloadManager.findPayload(uuid)
|
||||
return this.application.payloads.findPayload(uuid)
|
||||
}
|
||||
|
||||
get itemsKeys() {
|
||||
@@ -491,15 +531,15 @@ export class AppContext {
|
||||
}
|
||||
|
||||
disableKeyRecoveryServerSignIn() {
|
||||
this.application.keyRecoveryService.performServerSignIn = () => {
|
||||
console.warn('application.keyRecoveryService.performServerSignIn has been stubbed with an empty implementation')
|
||||
this.keyRecovery.performServerSignIn = () => {
|
||||
console.warn('application.keyRecovery.performServerSignIn has been stubbed with an empty implementation')
|
||||
}
|
||||
}
|
||||
|
||||
preventKeyRecoveryOfKeys(ids) {
|
||||
const originalImpl = this.application.keyRecoveryService.handleUndecryptableItemsKeys
|
||||
const originalImpl = this.keyRecovery.handleUndecryptableItemsKeys
|
||||
|
||||
this.application.keyRecoveryService.handleUndecryptableItemsKeys = function (keys) {
|
||||
this.keyRecovery.handleUndecryptableItemsKeys = function (keys) {
|
||||
const filtered = keys.filter((k) => !ids.includes(k.uuid))
|
||||
|
||||
originalImpl.apply(this, [filtered])
|
||||
@@ -520,18 +560,18 @@ export class AppContext {
|
||||
const payload = createNotePayload(title, text)
|
||||
const item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
await this.application.mutator.setItemDirty(item)
|
||||
await this.application.syncService.sync(MaximumSyncOptions)
|
||||
await this.application.sync.sync(MaximumSyncOptions)
|
||||
const note = this.application.items.findItem(payload.uuid)
|
||||
|
||||
return note
|
||||
}
|
||||
|
||||
lockSyncing() {
|
||||
this.application.syncService.lockSyncing()
|
||||
this.application.sync.lockSyncing()
|
||||
}
|
||||
|
||||
unlockSyncing() {
|
||||
this.application.syncService.unlockSyncing()
|
||||
this.application.sync.unlockSyncing()
|
||||
}
|
||||
|
||||
async deleteItemAndSync(item) {
|
||||
@@ -624,7 +664,9 @@ export class AppContext {
|
||||
|
||||
await Utils.sleep(2)
|
||||
} catch (error) {
|
||||
console.warn(`Mock events service not available. You are probalby running a test suite for home server: ${error.message}`)
|
||||
console.warn(
|
||||
`Mock events service not available. You are probalby running a test suite for home server: ${error.message}`,
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -632,7 +674,9 @@ export class AppContext {
|
||||
|
||||
await Utils.sleep(1)
|
||||
} catch (error) {
|
||||
console.warn(`Home server not available. You are probalby running a test suite for self hosted setup: ${error.message}`)
|
||||
console.warn(
|
||||
`Home server not available. You are probalby running a test suite for self hosted setup: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export const createTrustedContactForUserOfContext = async (
|
||||
contextAddingNewContact,
|
||||
contextImportingContactInfoFrom,
|
||||
) => {
|
||||
const contact = await contextAddingNewContact.application.contactService.createOrEditTrustedContact({
|
||||
const contact = await contextAddingNewContact.contacts.createOrEditTrustedContact({
|
||||
name: 'John Doe',
|
||||
publicKey: contextImportingContactInfoFrom.publicKey,
|
||||
signingPublicKey: contextImportingContactInfoFrom.signingPublicKey,
|
||||
@@ -27,6 +27,10 @@ export const createTrustedContactForUserOfContext = async (
|
||||
|
||||
export const acceptAllInvites = async (context) => {
|
||||
const inviteRecords = context.sharedVaults.getCachedPendingInviteRecords()
|
||||
if (inviteRecords.length === 0) {
|
||||
throw new Error('No pending invites to accept')
|
||||
}
|
||||
|
||||
for (const record of inviteRecords) {
|
||||
await context.sharedVaults.acceptPendingSharedVaultInvite(record)
|
||||
}
|
||||
@@ -72,7 +76,7 @@ export const createSharedVaultWithUnacceptedButTrustedInvite = async (
|
||||
const contact = await createTrustedContactForUserOfContext(context, contactContext)
|
||||
await createTrustedContactForUserOfContext(contactContext, context)
|
||||
|
||||
const invite = await context.sharedVaults.inviteContactToSharedVault(sharedVault, contact, permissions)
|
||||
const invite = (await context.sharedVaults.inviteContactToSharedVault(sharedVault, contact, permissions)).getValue()
|
||||
await contactContext.sync()
|
||||
|
||||
return { sharedVault, contact, contactContext, deinitContactContext, invite }
|
||||
@@ -87,7 +91,7 @@ export const createSharedVaultWithUnacceptedAndUntrustedInvite = async (
|
||||
const { contactContext, deinitContactContext } = await createContactContext()
|
||||
const contact = await createTrustedContactForUserOfContext(context, contactContext)
|
||||
|
||||
const invite = await context.sharedVaults.inviteContactToSharedVault(sharedVault, contact, permissions)
|
||||
const invite = (await context.sharedVaults.inviteContactToSharedVault(sharedVault, contact, permissions)).getValue()
|
||||
await contactContext.sync()
|
||||
|
||||
return { sharedVault, contact, contactContext, deinitContactContext, invite }
|
||||
|
||||
@@ -8,10 +8,10 @@ export async function safeDeinit(application) {
|
||||
return
|
||||
}
|
||||
|
||||
await application.diskStorageService.awaitPersist()
|
||||
await application.storage.awaitPersist()
|
||||
|
||||
/** Limit waiting to 1s */
|
||||
await Promise.race([sleep(1), application.syncService?.awaitCurrentSyncs()])
|
||||
await Promise.race([sleep(1), application.sync?.awaitCurrentSyncs()])
|
||||
|
||||
await application.prepareForDeinit()
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export async function createAppContext({ identifier, crypto, email, password, ho
|
||||
}
|
||||
|
||||
export function disableIntegrityAutoHeal(application) {
|
||||
application.syncService.emitOutOfSyncRemotePayloads = () => {
|
||||
application.sync.emitOutOfSyncRemotePayloads = () => {
|
||||
console.warn('Integrity self-healing is disabled for this test')
|
||||
}
|
||||
}
|
||||
@@ -112,12 +112,12 @@ export function registerUserToApplication({ application, email, password, epheme
|
||||
}
|
||||
|
||||
export async function setOldVersionPasscode({ application, passcode, version }) {
|
||||
const identifier = await application.encryptionService.crypto.generateUUID()
|
||||
const operator = application.encryptionService.operators.operatorForVersion(version)
|
||||
const identifier = await application.encryption.crypto.generateUUID()
|
||||
const operator = application.dependencies.get(TYPES.EncryptionOperators).operatorForVersion(version)
|
||||
const key = await operator.createRootKey(identifier, passcode, KeyParamsOrigination.PasscodeCreate)
|
||||
await application.encryptionService.setNewRootKeyWrapper(key)
|
||||
await application.userService.rewriteItemsKeys()
|
||||
await application.syncService.sync(syncOptions)
|
||||
await application.encryption.setNewRootKeyWrapper(key)
|
||||
await application.user.rewriteItemsKeys()
|
||||
await application.sync.sync(syncOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,25 +127,26 @@ export async function setOldVersionPasscode({ application, passcode, version })
|
||||
export async function registerOldUser({ application, email, password, version }) {
|
||||
if (!email) email = Utils.generateUuid()
|
||||
if (!password) password = Utils.generateUuid()
|
||||
const operator = application.encryptionService.operators.operatorForVersion(version)
|
||||
const operator = application.dependencies.get(TYPES.EncryptionOperators).operatorForVersion(version)
|
||||
const accountKey = await operator.createRootKey(email, password, KeyParamsOrigination.Registration)
|
||||
|
||||
const response = await application.userApiService.register({
|
||||
const response = await application.dependencies.get(TYPES.UserApiService).register({
|
||||
email: email,
|
||||
serverPassword: accountKey.serverPassword,
|
||||
keyParams: accountKey.keyParams,
|
||||
})
|
||||
|
||||
/** Mark all existing items as dirty. */
|
||||
await application.mutator.changeItems(application.itemManager.items, (m) => {
|
||||
await application.mutator.changeItems(application.items.items, (m) => {
|
||||
m.dirty = true
|
||||
})
|
||||
await application.sessionManager.handleSuccessAuthResponse(response, accountKey)
|
||||
await application.sessions.handleSuccessAuthResponse(response, accountKey)
|
||||
application.notifyEvent(ApplicationEvent.SignedIn)
|
||||
await application.syncService.sync({
|
||||
await application.sync.sync({
|
||||
mode: SyncMode.DownloadFirst,
|
||||
...syncOptions,
|
||||
})
|
||||
await application.encryptionService.decryptErroredPayloads()
|
||||
await application.encryption.decryptErroredPayloads()
|
||||
}
|
||||
|
||||
export function createStorageItemPayload(contentType) {
|
||||
@@ -182,13 +183,13 @@ export async function createSyncedNote(application, title, text) {
|
||||
const payload = createNotePayload(title, text)
|
||||
const item = await application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
await application.mutator.setItemDirty(item)
|
||||
await application.syncService.sync(syncOptions)
|
||||
await application.sync.sync(syncOptions)
|
||||
const note = application.items.findItem(payload.uuid)
|
||||
return note
|
||||
}
|
||||
|
||||
export async function getStoragePayloadsOfType(application, type) {
|
||||
const rawPayloads = await application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await application.storage.getAllRawPayloads()
|
||||
return rawPayloads
|
||||
.filter((rp) => rp.content_type === type)
|
||||
.map((rp) => {
|
||||
@@ -263,7 +264,7 @@ export async function restartApplication(application) {
|
||||
}
|
||||
|
||||
export async function storagePayloadCount(application) {
|
||||
const payloads = await application.diskStorageService.getAllRawPayloads()
|
||||
const payloads = await application.storage.getAllRawPayloads()
|
||||
return payloads.length
|
||||
}
|
||||
|
||||
@@ -397,28 +398,28 @@ export async function insertItemWithOverride(application, contentType, content,
|
||||
errorDecrypting,
|
||||
})
|
||||
|
||||
await application.payloadManager.emitPayload(encrypted)
|
||||
await application.payloads.emitPayload(encrypted)
|
||||
} else {
|
||||
const decrypted = new DecryptedPayload({
|
||||
...item.payload.ejected(),
|
||||
})
|
||||
await application.payloadManager.emitPayload(decrypted)
|
||||
await application.payloads.emitPayload(decrypted)
|
||||
}
|
||||
|
||||
return application.itemManager.findAnyItem(item.uuid)
|
||||
return application.items.findAnyItem(item.uuid)
|
||||
}
|
||||
|
||||
export async function alternateUuidForItem(application, uuid) {
|
||||
const item = application.itemManager.findItem(uuid)
|
||||
const item = application.items.findItem(uuid)
|
||||
const payload = new DecryptedPayload(item)
|
||||
const results = await PayloadsByAlternatingUuid(payload, application.payloadManager.getMasterCollection())
|
||||
await application.payloadManager.emitPayloads(results, PayloadEmitSource.LocalChanged)
|
||||
await application.syncService.persistPayloads(results)
|
||||
return application.itemManager.findItem(results[0].uuid)
|
||||
const results = await PayloadsByAlternatingUuid(payload, application.payloads.getMasterCollection())
|
||||
await application.payloads.emitPayloads(results, PayloadEmitSource.LocalChanged)
|
||||
await application.sync.persistPayloads(results)
|
||||
return application.items.findItem(results[0].uuid)
|
||||
}
|
||||
|
||||
export async function markDirtyAndSyncItem(application, itemToLookupUuidFor) {
|
||||
const item = application.itemManager.findItem(itemToLookupUuidFor.uuid)
|
||||
const item = application.items.findItem(itemToLookupUuidFor.uuid)
|
||||
if (!item) {
|
||||
throw Error('Attempting to save non-inserted item')
|
||||
}
|
||||
@@ -433,11 +434,11 @@ export async function changePayloadTimeStampAndSync(application, payload, timest
|
||||
|
||||
await application.sync.sync(syncOptions)
|
||||
|
||||
return application.itemManager.findAnyItem(payload.uuid)
|
||||
return application.items.findAnyItem(payload.uuid)
|
||||
}
|
||||
|
||||
export async function changePayloadTimeStamp(application, payload, timestamp, contentOverride) {
|
||||
payload = application.payloadManager.collection.find(payload.uuid)
|
||||
payload = application.payloads.collection.find(payload.uuid)
|
||||
const changedPayload = new DecryptedPayload({
|
||||
...payload,
|
||||
dirty: true,
|
||||
@@ -451,11 +452,11 @@ export async function changePayloadTimeStamp(application, payload, timestamp, co
|
||||
|
||||
await application.mutator.emitItemFromPayload(changedPayload)
|
||||
|
||||
return application.itemManager.findAnyItem(payload.uuid)
|
||||
return application.items.findAnyItem(payload.uuid)
|
||||
}
|
||||
|
||||
export async function changePayloadUpdatedAt(application, payload, updatedAt) {
|
||||
const latestPayload = application.payloadManager.collection.find(payload.uuid)
|
||||
const latestPayload = application.payloads.collection.find(payload.uuid)
|
||||
|
||||
const changedPayload = new DecryptedPayload({
|
||||
...latestPayload.ejected(),
|
||||
@@ -468,7 +469,7 @@ export async function changePayloadUpdatedAt(application, payload, updatedAt) {
|
||||
}
|
||||
|
||||
export async function changePayloadTimeStampDeleteAndSync(application, payload, timestamp, syncOptions) {
|
||||
payload = application.payloadManager.collection.find(payload.uuid)
|
||||
payload = application.payloads.collection.find(payload.uuid)
|
||||
const changedPayload = new DeletedPayload({
|
||||
...payload,
|
||||
content: undefined,
|
||||
@@ -478,6 +479,6 @@ export async function changePayloadTimeStampDeleteAndSync(application, payload,
|
||||
updated_at_timestamp: timestamp,
|
||||
})
|
||||
|
||||
await application.payloadManager.emitPayload(changedPayload)
|
||||
await application.payloads.emitPayload(changedPayload)
|
||||
await application.sync.sync(syncOptions)
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ export default class FakeWebCrypto {
|
||||
const data = {
|
||||
message,
|
||||
nonce,
|
||||
senderSecretKey,
|
||||
recipientPublicKey,
|
||||
senderSecretKey,
|
||||
}
|
||||
return btoa(JSON.stringify(data))
|
||||
}
|
||||
|
||||
@@ -54,11 +54,11 @@ describe('mfa service', () => {
|
||||
const secret = await snApp.generateMfaSecret()
|
||||
const token = await snApp.getOtpToken(secret)
|
||||
|
||||
sinon.spy(snApp.challengeService, 'sendChallenge')
|
||||
sinon.spy(snApp.challenges, 'sendChallenge')
|
||||
await snApp.enableMfa(secret, token)
|
||||
await snApp.disableMfa()
|
||||
|
||||
const spyCall = snApp.challengeService.sendChallenge.getCall(0)
|
||||
const spyCall = snApp.challenges.sendChallenge.getCall(0)
|
||||
const challenge = spyCall.firstArg
|
||||
expect(challenge.prompts).to.have.lengthOf(2)
|
||||
expect(challenge.prompts[0].validation).to.equal(ChallengeValidation.AccountPassword)
|
||||
|
||||
@@ -15,39 +15,39 @@ describe('migrations', () => {
|
||||
|
||||
it('version number is stored as string', async function () {
|
||||
const application = await Factory.createInitAppWithFakeCrypto()
|
||||
const version = await application.migrationService.getStoredSnjsVersion()
|
||||
const version = await application.migrations.getStoredSnjsVersion()
|
||||
expect(typeof version).to.equal('string')
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
|
||||
it('should return correct required migrations if stored version is 1.0.0', async function () {
|
||||
expect((await SNMigrationService.getRequiredMigrations('1.0.0')).length).to.equal(allMigrationsLength)
|
||||
expect((await MigrationService.getRequiredMigrations('1.0.0')).length).to.equal(allMigrationsLength)
|
||||
})
|
||||
|
||||
it('should return correct required migrations if stored version is 2.0.0', async function () {
|
||||
expect((await SNMigrationService.getRequiredMigrations('2.0.0')).length).to.equal(allMigrationsLength)
|
||||
expect((await MigrationService.getRequiredMigrations('2.0.0')).length).to.equal(allMigrationsLength)
|
||||
})
|
||||
|
||||
it('should return 0 required migrations if stored version is futuristic', async function () {
|
||||
expect((await SNMigrationService.getRequiredMigrations('100.0.1')).length).to.equal(0)
|
||||
expect((await MigrationService.getRequiredMigrations('100.0.1')).length).to.equal(0)
|
||||
})
|
||||
|
||||
it('after running base migration with no present storage values, should set version to current', async function () {
|
||||
const application = await Factory.createAppWithRandNamespace()
|
||||
await application.migrationService.runBaseMigrationPreRun()
|
||||
expect(await application.migrationService.getStoredSnjsVersion()).to.equal(SnjsVersion)
|
||||
await application.migrations.runBaseMigrationPreRun()
|
||||
expect(await application.migrations.getStoredSnjsVersion()).to.equal(SnjsVersion)
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
|
||||
it('after running all migrations from a 2.0.0 installation, should set stored version to current', async function () {
|
||||
const application = await Factory.createAppWithRandNamespace()
|
||||
/** Set up 2.0.0 structure with tell-tale storage key */
|
||||
await application.deviceInterface.setRawStorageValue('last_migration_timestamp', JSON.stringify(['anything']))
|
||||
await application.device.setRawStorageValue('last_migration_timestamp', JSON.stringify(['anything']))
|
||||
await application.prepareForLaunch({
|
||||
receiveChallenge: () => {},
|
||||
})
|
||||
await application.launch(true)
|
||||
expect(await application.migrationService.getStoredSnjsVersion()).to.equal(SnjsVersion)
|
||||
expect(await application.migrations.getStoredSnjsVersion()).to.equal(SnjsVersion)
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
|
||||
@@ -72,18 +72,18 @@ describe('migrations', () => {
|
||||
await application.sync.sync()
|
||||
|
||||
expect(application.items.getItems('SF|MFA').length).to.equal(1)
|
||||
expect(
|
||||
(await application.diskStorageService.getAllRawPayloads()).filter((p) => p.content_type === 'SF|MFA').length,
|
||||
).to.equal(1)
|
||||
expect((await application.storage.getAllRawPayloads()).filter((p) => p.content_type === 'SF|MFA').length).to.equal(
|
||||
1,
|
||||
)
|
||||
|
||||
/** Run migration */
|
||||
const migration = new Migration2_20_0(application.migrationService.services)
|
||||
const migration = new Migration2_20_0(application.migrations.services)
|
||||
await migration.handleStage(ApplicationStage.LoadedDatabase_12)
|
||||
|
||||
expect(application.items.getItems('SF|MFA').length).to.equal(0)
|
||||
expect(
|
||||
(await application.diskStorageService.getAllRawPayloads()).filter((p) => p.content_type === 'SF|MFA').length,
|
||||
).to.equal(0)
|
||||
expect((await application.storage.getAllRawPayloads()).filter((p) => p.content_type === 'SF|MFA').length).to.equal(
|
||||
0,
|
||||
)
|
||||
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
@@ -113,7 +113,7 @@ describe('migrations', () => {
|
||||
expect(application.items.getItems(ContentType.TYPES.Theme).length).to.equal(1)
|
||||
|
||||
/** Run migration */
|
||||
const migration = new Migration2_42_0(application.migrationService.services)
|
||||
const migration = new Migration2_42_0(application.migrations.services)
|
||||
await migration.handleStage(ApplicationStage.FullSyncCompleted_13)
|
||||
await application.sync.sync()
|
||||
|
||||
@@ -156,7 +156,7 @@ describe('migrations', () => {
|
||||
expect(application.items.getItems(ContentType.TYPES.Component).length).to.equal(1)
|
||||
|
||||
/** Run migration */
|
||||
const migration = new Migration2_202_1(application.migrationService.services)
|
||||
const migration = new Migration2_202_1(application.migrations.services)
|
||||
await migration.handleStage(ApplicationStage.FullSyncCompleted_13)
|
||||
await application.sync.sync()
|
||||
|
||||
@@ -181,7 +181,7 @@ describe('migrations', () => {
|
||||
expect(application.items.getItems(ContentType.TYPES.Component).length).to.equal(1)
|
||||
|
||||
/** Run migration */
|
||||
const migration = new Migration2_202_1(application.migrationService.services)
|
||||
const migration = new Migration2_202_1(application.migrations.services)
|
||||
await migration.handleStage(ApplicationStage.FullSyncCompleted_13)
|
||||
await application.sync.sync()
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ const makeTags = async (application, titles) => {
|
||||
|
||||
const extractTagHierarchy = (application) => {
|
||||
const result = {}
|
||||
const roots = application.itemManager.getRootTags()
|
||||
const roots = application.items.getRootTags()
|
||||
|
||||
const constructHierarchy = (currentTag, result) => {
|
||||
result[currentTag.title] = { _uuid: currentTag.uuid }
|
||||
|
||||
@@ -30,8 +30,8 @@ describe('app models', () => {
|
||||
await Factory.safeDeinit(this.application)
|
||||
})
|
||||
|
||||
it('payloadManager should be defined', () => {
|
||||
expect(sharedApplication.payloadManager).to.be.ok
|
||||
it('payloads should be defined', () => {
|
||||
expect(sharedApplication.payloads).to.be.ok
|
||||
})
|
||||
|
||||
it('item should be defined', () => {
|
||||
@@ -75,14 +75,14 @@ describe('app models', () => {
|
||||
await this.application.mutator.emitItemsFromPayloads([mutated], PayloadEmitSource.LocalChanged)
|
||||
await this.application.mutator.emitItemsFromPayloads([params2], PayloadEmitSource.LocalChanged)
|
||||
|
||||
const item1 = this.application.itemManager.findItem(params1.uuid)
|
||||
const item2 = this.application.itemManager.findItem(params2.uuid)
|
||||
const item1 = this.application.items.findItem(params1.uuid)
|
||||
const item2 = this.application.items.findItem(params2.uuid)
|
||||
|
||||
expect(item1.content.references.length).to.equal(1)
|
||||
expect(item2.content.references.length).to.equal(0)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('mapping an item twice shouldnt cause problems', async function () {
|
||||
@@ -103,7 +103,7 @@ describe('app models', () => {
|
||||
item = items[0]
|
||||
|
||||
expect(item.content.foo).to.equal('bar')
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
})
|
||||
|
||||
it('mapping item twice should preserve references', async function () {
|
||||
@@ -117,7 +117,7 @@ describe('app models', () => {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(item1)
|
||||
})
|
||||
|
||||
const refreshedItem = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem = this.application.items.findItem(item1.uuid)
|
||||
expect(refreshedItem.content.references.length).to.equal(1)
|
||||
})
|
||||
|
||||
@@ -132,8 +132,8 @@ describe('app models', () => {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(item1)
|
||||
})
|
||||
|
||||
const refreshedItem1 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem2 = this.application.itemManager.findItem(item2.uuid)
|
||||
const refreshedItem1 = this.application.items.findItem(item1.uuid)
|
||||
const refreshedItem2 = this.application.items.findItem(item2.uuid)
|
||||
|
||||
expect(refreshedItem1.content.references.length).to.equal(1)
|
||||
expect(refreshedItem2.content.references.length).to.equal(1)
|
||||
@@ -147,8 +147,8 @@ describe('app models', () => {
|
||||
})
|
||||
await this.application.mutator.emitItemsFromPayloads([damagedPayload], PayloadEmitSource.LocalChanged)
|
||||
|
||||
const refreshedItem1_2 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem2_2 = this.application.itemManager.findItem(item2.uuid)
|
||||
const refreshedItem1_2 = this.application.items.findItem(item1.uuid)
|
||||
const refreshedItem2_2 = this.application.items.findItem(item2.uuid)
|
||||
|
||||
expect(refreshedItem1_2.content.references.length).to.equal(0)
|
||||
expect(refreshedItem2_2.content.references.length).to.equal(1)
|
||||
@@ -164,14 +164,14 @@ describe('app models', () => {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(item1)
|
||||
})
|
||||
|
||||
const refreshedItem1 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem2 = this.application.itemManager.findItem(item2.uuid)
|
||||
const refreshedItem1 = this.application.items.findItem(item1.uuid)
|
||||
const refreshedItem2 = this.application.items.findItem(item2.uuid)
|
||||
|
||||
expect(refreshedItem1.content.references.length).to.equal(1)
|
||||
expect(refreshedItem2.content.references.length).to.equal(1)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item1)).to.include(refreshedItem2)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2)).to.include(refreshedItem1)
|
||||
expect(this.application.items.itemsReferencingItem(item1)).to.include(refreshedItem2)
|
||||
expect(this.application.items.itemsReferencingItem(item2)).to.include(refreshedItem1)
|
||||
|
||||
await this.application.mutator.changeItem(item1, (mutator) => {
|
||||
mutator.removeItemAsRelationship(item2)
|
||||
@@ -180,14 +180,14 @@ describe('app models', () => {
|
||||
mutator.removeItemAsRelationship(item1)
|
||||
})
|
||||
|
||||
const refreshedItem1_2 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem2_2 = this.application.itemManager.findItem(item2.uuid)
|
||||
const refreshedItem1_2 = this.application.items.findItem(item1.uuid)
|
||||
const refreshedItem2_2 = this.application.items.findItem(item2.uuid)
|
||||
|
||||
expect(refreshedItem1_2.content.references.length).to.equal(0)
|
||||
expect(refreshedItem2_2.content.references.length).to.equal(0)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(0)
|
||||
})
|
||||
|
||||
it('properly duplicates item with no relationships', async function () {
|
||||
@@ -213,10 +213,10 @@ describe('app models', () => {
|
||||
expect(duplicate.uuid).to.not.equal(item1.uuid)
|
||||
expect(duplicate.content.references.length).to.equal(1)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(2)
|
||||
expect(this.application.items.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(2)
|
||||
|
||||
const refreshedItem1_2 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem1_2 = this.application.items.findItem(item1.uuid)
|
||||
expect(refreshedItem1_2.isItemContentEqualWith(duplicate)).to.equal(true)
|
||||
expect(refreshedItem1_2.created_at.toISOString()).to.equal(duplicate.created_at.toISOString())
|
||||
expect(refreshedItem1_2.content_type).to.equal(duplicate.content_type)
|
||||
@@ -240,8 +240,8 @@ describe('app models', () => {
|
||||
PayloadEmitSource.LocalChanged,
|
||||
)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(item1).length).to.equal(0)
|
||||
expect(refreshedItem1_2.content.references.length).to.equal(0)
|
||||
})
|
||||
|
||||
@@ -254,18 +254,18 @@ describe('app models', () => {
|
||||
})
|
||||
|
||||
expect(refreshedItem1.content.references.length).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(1)
|
||||
|
||||
const alternatedItem = await Factory.alternateUuidForItem(this.application, item1.uuid)
|
||||
const refreshedItem1_2 = this.application.itemManager.findItem(item1.uuid)
|
||||
const refreshedItem1_2 = this.application.items.findItem(item1.uuid)
|
||||
expect(refreshedItem1_2).to.not.be.ok
|
||||
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(2)
|
||||
|
||||
expect(alternatedItem.content.references.length).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(alternatedItem.uuid).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(alternatedItem.uuid).length).to.equal(0)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(1)
|
||||
|
||||
expect(alternatedItem.isReferencingItem(item2)).to.equal(true)
|
||||
expect(alternatedItem.dirty).to.equal(true)
|
||||
@@ -279,10 +279,10 @@ describe('app models', () => {
|
||||
|
||||
it('alterating itemskey uuid should update errored items encrypted with that key', async function () {
|
||||
const item1 = await Factory.createMappedNote(this.application)
|
||||
const itemsKey = this.application.itemManager.getDisplayableItemsKeys()[0]
|
||||
const itemsKey = this.application.items.getDisplayableItemsKeys()[0]
|
||||
|
||||
/** Encrypt item1 and emit as errored so it persists with items_key_id */
|
||||
const encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [item1.payload],
|
||||
},
|
||||
@@ -292,17 +292,17 @@ describe('app models', () => {
|
||||
waitingForKey: true,
|
||||
})
|
||||
|
||||
await this.application.payloadManager.emitPayload(errored)
|
||||
await this.application.payloads.emitPayload(errored)
|
||||
|
||||
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.payloads.findOne(item1.uuid).errorDecrypting).to.equal(true)
|
||||
expect(this.application.payloads.findOne(item1.uuid).items_key_id).to.equal(itemsKey.uuid)
|
||||
|
||||
sinon.stub(this.application.encryptionService.itemsEncryption, 'decryptErroredItemPayloads').callsFake(() => {
|
||||
sinon.stub(this.application.encryption.itemsEncryption, 'decryptErroredItemPayloads').callsFake(() => {
|
||||
// prevent auto decryption
|
||||
})
|
||||
|
||||
const alternatedKey = await Factory.alternateUuidForItem(this.application, itemsKey.uuid)
|
||||
const updatedPayload = this.application.payloadManager.findOne(item1.uuid)
|
||||
const updatedPayload = this.application.payloads.findOne(item1.uuid)
|
||||
|
||||
expect(updatedPayload.items_key_id).to.equal(alternatedKey.uuid)
|
||||
})
|
||||
@@ -316,22 +316,22 @@ describe('app models', () => {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(item2)
|
||||
})
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(item2).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(item2).length).to.equal(1)
|
||||
|
||||
const alternatedItem1 = await Factory.alternateUuidForItem(this.application, item1.uuid)
|
||||
const alternatedItem2 = await Factory.alternateUuidForItem(this.application, item2.uuid)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
expect(item1.uuid).to.not.equal(alternatedItem1.uuid)
|
||||
expect(item2.uuid).to.not.equal(alternatedItem2.uuid)
|
||||
|
||||
const refreshedAltItem1 = this.application.itemManager.findItem(alternatedItem1.uuid)
|
||||
const refreshedAltItem1 = this.application.items.findItem(alternatedItem1.uuid)
|
||||
expect(refreshedAltItem1.content.references.length).to.equal(1)
|
||||
expect(refreshedAltItem1.content.references[0].uuid).to.equal(alternatedItem2.uuid)
|
||||
expect(alternatedItem2.content.references.length).to.equal(0)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(alternatedItem2).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(alternatedItem2).length).to.equal(1)
|
||||
|
||||
expect(refreshedAltItem1.isReferencingItem(alternatedItem2)).to.equal(true)
|
||||
expect(alternatedItem2.isReferencingItem(refreshedAltItem1)).to.equal(false)
|
||||
@@ -350,12 +350,12 @@ describe('app models', () => {
|
||||
const noteCopy = await this.application.mutator.duplicateItem(note)
|
||||
expect(note.uuid).to.not.equal(noteCopy.uuid)
|
||||
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(1)
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(noteCopy.content.references.length).to.equal(0)
|
||||
const refreshedTag_2 = this.application.itemManager.findItem(tag.uuid)
|
||||
const refreshedTag_2 = this.application.items.findItem(tag.uuid)
|
||||
expect(refreshedTag_2.content.references.length).to.equal(2)
|
||||
})
|
||||
|
||||
|
||||
@@ -73,14 +73,14 @@ describe('importing', function () {
|
||||
|
||||
await application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
expectedItemCount += 2
|
||||
const note = application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
const note = application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
|
||||
await application.importData(
|
||||
{
|
||||
@@ -89,13 +89,13 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
|
||||
expect(application.itemManager.items.length).to.equal(expectedItemCount)
|
||||
expect(application.items.items.length).to.equal(expectedItemCount)
|
||||
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('importing same note many times should create only one duplicate', async function () {
|
||||
@@ -121,8 +121,8 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
expectedItemCount++
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
const imported = application.itemManager.getDisplayableNotes().find((n) => n.uuid !== notePayload.uuid)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(2)
|
||||
const imported = application.items.getDisplayableNotes().find((n) => n.uuid !== notePayload.uuid)
|
||||
expect(imported.content.title).to.equal(mutatedNote.content.title)
|
||||
})
|
||||
|
||||
@@ -144,8 +144,8 @@ describe('importing', function () {
|
||||
},
|
||||
true,
|
||||
)
|
||||
expect(application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.itemManager.findItem(tagPayload.uuid).content.references.length).to.equal(1)
|
||||
expect(application.items.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.findItem(tagPayload.uuid).content.references.length).to.equal(1)
|
||||
})
|
||||
|
||||
it('importing data with differing content should create duplicates', async function () {
|
||||
@@ -155,8 +155,8 @@ describe('importing', function () {
|
||||
const tagPayload = pair[1]
|
||||
await application.mutator.emitItemsFromPayloads(pair, PayloadEmitSource.LocalChanged)
|
||||
expectedItemCount += 2
|
||||
const note = application.itemManager.getDisplayableNotes()[0]
|
||||
const tag = application.itemManager.getDisplayableTags()[0]
|
||||
const note = application.items.getDisplayableNotes()[0]
|
||||
const tag = application.items.getDisplayableTags()[0]
|
||||
const mutatedNote = new DecryptedPayload({
|
||||
...notePayload,
|
||||
content: {
|
||||
@@ -178,27 +178,27 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
expectedItemCount += 2
|
||||
expect(application.itemManager.items.length).to.equal(expectedItemCount)
|
||||
expect(application.items.items.length).to.equal(expectedItemCount)
|
||||
|
||||
const newNote = application.itemManager.getDisplayableNotes().find((n) => n.uuid !== notePayload.uuid)
|
||||
const newTag = application.itemManager.getDisplayableTags().find((t) => t.uuid !== tagPayload.uuid)
|
||||
const newNote = application.items.getDisplayableNotes().find((n) => n.uuid !== notePayload.uuid)
|
||||
const newTag = application.items.getDisplayableTags().find((t) => t.uuid !== tagPayload.uuid)
|
||||
|
||||
expect(newNote.uuid).to.not.equal(note.uuid)
|
||||
expect(newTag.uuid).to.not.equal(tag.uuid)
|
||||
|
||||
const refreshedTag = application.itemManager.findItem(tag.uuid)
|
||||
const refreshedTag = application.items.findItem(tag.uuid)
|
||||
expect(refreshedTag.content.references.length).to.equal(2)
|
||||
expect(refreshedTag.noteCount).to.equal(2)
|
||||
|
||||
const refreshedNote = application.itemManager.findItem(note.uuid)
|
||||
const refreshedNote = application.items.findItem(note.uuid)
|
||||
expect(refreshedNote.content.references.length).to.equal(0)
|
||||
expect(application.itemManager.itemsReferencingItem(refreshedNote).length).to.equal(2)
|
||||
expect(application.items.itemsReferencingItem(refreshedNote).length).to.equal(2)
|
||||
|
||||
expect(newTag.content.references.length).to.equal(1)
|
||||
expect(newTag.noteCount).to.equal(1)
|
||||
|
||||
expect(newNote.content.references.length).to.equal(0)
|
||||
expect(application.itemManager.itemsReferencingItem(newNote).length).to.equal(1)
|
||||
expect(application.items.itemsReferencingItem(newNote).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('when importing items, imported values should not be used to determine if changed', async function () {
|
||||
@@ -249,9 +249,9 @@ describe('importing', function () {
|
||||
expectedItemCount += 1
|
||||
|
||||
/** We expect now that the total item count is 3, not 4. */
|
||||
expect(application.itemManager.items.length).to.equal(expectedItemCount)
|
||||
expect(application.items.items.length).to.equal(expectedItemCount)
|
||||
|
||||
const refreshedTag = application.itemManager.findItem(tag.uuid)
|
||||
const refreshedTag = application.items.findItem(tag.uuid)
|
||||
/** References from both items have merged. */
|
||||
expect(refreshedTag.content.references.length).to.equal(2)
|
||||
})
|
||||
@@ -286,10 +286,10 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.findItem(note.uuid).deleted).to.not.be.ok
|
||||
|
||||
expect(application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.findItem(tag.uuid).deleted).to.not.be.ok
|
||||
})
|
||||
|
||||
@@ -320,8 +320,8 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.itemManager.getDisplayableNotes()[0].uuid).to.not.equal(note.uuid)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes()[0].uuid).to.not.equal(note.uuid)
|
||||
})
|
||||
|
||||
it('should maintain consistency between storage and PayloadManager after an import with conflicts', async function () {
|
||||
@@ -350,8 +350,8 @@ describe('importing', function () {
|
||||
true,
|
||||
)
|
||||
|
||||
const storedPayloads = await application.diskStorageService.getAllRawPayloads()
|
||||
expect(application.itemManager.items.length).to.equal(storedPayloads.length)
|
||||
const storedPayloads = await application.storage.getAllRawPayloads()
|
||||
expect(application.items.items.length).to.equal(storedPayloads.length)
|
||||
const notes = storedPayloads.filter((p) => p.content_type === ContentType.TYPES.Note)
|
||||
const itemsKeys = storedPayloads.filter((p) => p.content_type === ContentType.TYPES.ItemsKey)
|
||||
expect(notes.length).to.equal(1)
|
||||
@@ -383,10 +383,10 @@ describe('importing', function () {
|
||||
|
||||
await application.importData(backupData, true)
|
||||
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.findItem(note.uuid).deleted).to.not.be.ok
|
||||
|
||||
expect(application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.findItem(tag.uuid).deleted).to.not.be.ok
|
||||
})
|
||||
|
||||
@@ -465,10 +465,10 @@ describe('importing', function () {
|
||||
expect(result.affectedItems.length).to.be.eq(backupData.items.length)
|
||||
expect(result.errorCount).to.be.eq(0)
|
||||
|
||||
const decryptedNote = application.itemManager.findItem(noteItem.uuid)
|
||||
const decryptedNote = application.items.findItem(noteItem.uuid)
|
||||
expect(decryptedNote.title).to.be.eq('Encrypted note')
|
||||
expect(decryptedNote.text).to.be.eq('On protocol version 003.')
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
})
|
||||
|
||||
it('should import data from 003 encrypted payload using server generated backup with 004 key params', async function () {
|
||||
@@ -546,10 +546,10 @@ describe('importing', function () {
|
||||
expect(result.affectedItems.length).to.be.eq(backupData.items.length)
|
||||
expect(result.errorCount).to.be.eq(0)
|
||||
|
||||
const decryptedNote = application.itemManager.findItem(noteItem.uuid)
|
||||
const decryptedNote = application.items.findItem(noteItem.uuid)
|
||||
expect(decryptedNote.title).to.be.eq('Encrypted note')
|
||||
expect(decryptedNote.text).to.be.eq('On protocol version 004.')
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
})
|
||||
|
||||
it('should return correct errorCount', async function () {
|
||||
@@ -624,7 +624,7 @@ describe('importing', function () {
|
||||
|
||||
expect(result.affectedItems.length).to.be.eq(0)
|
||||
expect(result.errorCount).to.be.eq(backupData.items.length)
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(0)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(0)
|
||||
})
|
||||
|
||||
it('should not import data from 004 encrypted payload if an invalid password is provided', async function () {
|
||||
@@ -655,7 +655,7 @@ describe('importing', function () {
|
||||
expect(result).to.not.be.undefined
|
||||
expect(result.affectedItems.length).to.be.eq(0)
|
||||
expect(result.errorCount).to.be.eq(backupData.items.length)
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(0)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(0)
|
||||
})
|
||||
|
||||
it('should not import encrypted data with no keyParams or auth_params', async function () {
|
||||
@@ -710,7 +710,7 @@ describe('importing', function () {
|
||||
expect(result.affectedItems.length).to.equal(BaseItemCounts.BackupFileRootKeyEncryptedItems)
|
||||
|
||||
expect(result.errorCount).to.be.eq(backupData.items.length - BaseItemCounts.BackupFileRootKeyEncryptedItems)
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(0)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(0)
|
||||
})
|
||||
|
||||
it('importing data with no items key should use the root key generated by the file password', async function () {
|
||||
@@ -726,7 +726,7 @@ describe('importing', function () {
|
||||
const identifier = 'standardnotes'
|
||||
const application = await Factory.createApplicationWithRealCrypto(identifier)
|
||||
/** Create legacy migrations value so that base migration detects old app */
|
||||
await application.deviceInterface.setRawStorageValue(
|
||||
await application.device.setRawStorageValue(
|
||||
'keychain',
|
||||
JSON.stringify({
|
||||
[identifier]: {
|
||||
@@ -736,7 +736,7 @@ describe('importing', function () {
|
||||
},
|
||||
}),
|
||||
)
|
||||
await application.deviceInterface.setRawStorageValue(
|
||||
await application.device.setRawStorageValue(
|
||||
'descriptors',
|
||||
JSON.stringify({
|
||||
[identifier]: {
|
||||
@@ -746,8 +746,8 @@ describe('importing', function () {
|
||||
},
|
||||
}),
|
||||
)
|
||||
await application.deviceInterface.setRawStorageValue('standardnotes-snjs_version', '2.0.11')
|
||||
await application.deviceInterface.saveDatabaseEntry(
|
||||
await application.device.setRawStorageValue('standardnotes-snjs_version', '2.0.11')
|
||||
await application.device.saveDatabaseEntry(
|
||||
{
|
||||
content:
|
||||
'003:9f2c7527eb8b2a1f8bfb3ea6b885403b6886bce2640843ebd57a6c479cbf7597:58e3322b-269a-4be3-a658-b035dffcd70f:9140b23a0fa989e224e292049f133154:SESTNOgIGf2+ZqmJdFnGU4EMgQkhKOzpZNoSzx76SJaImsayzctAgbUmJ+UU2gSQAHADS3+Z5w11bXvZgIrStTsWriwvYkNyyKmUPadKHNSBwOk4WeBZpWsA9gtI5zgI04Q5pvb8hS+kNW2j1DjM4YWqd0JQxMOeOrMIrxr/6Awn5TzYE+9wCbXZdYHyvRQcp9ui/G02ZJ67IA86vNEdjTTBAAWipWqTqKH9VDZbSQ2W/IOKfIquB373SFDKZb1S1NmBFvcoG2G7w//fAl/+ehYiL6UdiNH5MhXCDAOTQRFNfOh57HFDWVnz1VIp8X+VAPy6d9zzQH+8aws1JxHq/7BOhXrFE8UCueV6kERt9njgQxKJzd9AH32ShSiUB9X/sPi0fUXbS178xAZMJrNx3w==:eyJwd19ub25jZSI6IjRjYjEwM2FhODljZmY0NTYzYTkxMWQzZjM5NjU4M2NlZmM2ODMzYzY2Zjg4MGZiZWUwNmJkYTk0YzMxZjg2OGIiLCJwd19jb3N0IjoxMTAwMDAsImlkZW50aWZpZXIiOiJub3YyMzIyQGJpdGFyLmlvIiwidmVyc2lvbiI6IjAwMyIsIm9yaWdpbmF0aW9uIjoicmVnaXN0cmF0aW9uIn0=',
|
||||
@@ -763,7 +763,7 @@ describe('importing', function () {
|
||||
/**
|
||||
* Note that this storage contains "sync.standardnotes.org" as the API Host param.
|
||||
*/
|
||||
await application.deviceInterface.setRawStorageValue(
|
||||
await application.device.setRawStorageValue(
|
||||
'standardnotes-storage',
|
||||
JSON.stringify({
|
||||
wrapped: {
|
||||
@@ -874,13 +874,13 @@ describe('importing', function () {
|
||||
|
||||
await application.importData(backupData, true)
|
||||
|
||||
expect(application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(application.items.getDisplayableTags().length).to.equal(1)
|
||||
|
||||
const importedNote = application.itemManager.getDisplayableNotes()[0]
|
||||
const importedTag = application.itemManager.getDisplayableTags()[0]
|
||||
expect(application.itemManager.referencesForItem(importedTag).length).to.equal(1)
|
||||
expect(application.itemManager.itemsReferencingItem(importedNote).length).to.equal(1)
|
||||
const importedNote = application.items.getDisplayableNotes()[0]
|
||||
const importedTag = application.items.getDisplayableTags()[0]
|
||||
expect(application.items.referencesForItem(importedTag).length).to.equal(1)
|
||||
expect(application.items.itemsReferencingItem(importedNote).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('should decrypt backup file which contains a vaulted note without a synced key system root key', async () => {
|
||||
|
||||
@@ -23,11 +23,11 @@ describe('items', () => {
|
||||
it('setting an item as dirty should update its client updated at', async function () {
|
||||
const params = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([params], PayloadEmitSource.LocalChanged)
|
||||
const item = this.application.itemManager.items[0]
|
||||
const item = this.application.items.items[0]
|
||||
const prevDate = item.userModifiedDate.getTime()
|
||||
await Factory.sleep(0.1)
|
||||
await this.application.mutator.setItemDirty(item, true)
|
||||
const refreshedItem = this.application.itemManager.findItem(item.uuid)
|
||||
const refreshedItem = this.application.items.findItem(item.uuid)
|
||||
const newDate = refreshedItem.userModifiedDate.getTime()
|
||||
expect(prevDate).to.not.equal(newDate)
|
||||
})
|
||||
@@ -35,7 +35,7 @@ describe('items', () => {
|
||||
it('setting an item as dirty with option to skip client updated at', async function () {
|
||||
const params = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([params], PayloadEmitSource.LocalChanged)
|
||||
const item = this.application.itemManager.items[0]
|
||||
const item = this.application.items.items[0]
|
||||
const prevDate = item.userModifiedDate.getTime()
|
||||
await Factory.sleep(0.1)
|
||||
await this.application.mutator.setItemDirty(item)
|
||||
@@ -47,7 +47,7 @@ describe('items', () => {
|
||||
const params = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([params], PayloadEmitSource.LocalChanged)
|
||||
|
||||
const item = this.application.itemManager.items[0]
|
||||
const item = this.application.items.items[0]
|
||||
expect(item.pinned).to.not.be.ok
|
||||
|
||||
const refreshedItem = await this.application.changeAndSaveItem(
|
||||
@@ -71,8 +71,8 @@ describe('items', () => {
|
||||
const params2 = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([params1, params2], PayloadEmitSource.LocalChanged)
|
||||
|
||||
let item1 = this.application.itemManager.getDisplayableNotes()[0]
|
||||
let item2 = this.application.itemManager.getDisplayableNotes()[1]
|
||||
let item1 = this.application.items.getDisplayableNotes()[0]
|
||||
let item2 = this.application.items.getDisplayableNotes()[1]
|
||||
|
||||
expect(item1.isItemContentEqualWith(item2)).to.equal(true)
|
||||
|
||||
@@ -176,8 +176,8 @@ describe('items', () => {
|
||||
const params2 = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([params1, params2], PayloadEmitSource.LocalChanged)
|
||||
|
||||
let item1 = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const item2 = this.application.itemManager.getDisplayableNotes()[1]
|
||||
let item1 = this.application.items.getDisplayableNotes()[0]
|
||||
const item2 = this.application.items.getDisplayableNotes()[1]
|
||||
|
||||
item1 = await this.application.changeAndSaveItem(
|
||||
item1,
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('model manager mapping', () => {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([payload], PayloadEmitSource.LocalChanged)
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('mapping nonexistent deleted item doesnt create it', async function () {
|
||||
@@ -31,8 +31,8 @@ describe('model manager mapping', () => {
|
||||
dirty: false,
|
||||
deleted: true,
|
||||
})
|
||||
await this.application.payloadManager.emitPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.payloads.emitPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('mapping and deleting nonexistent item creates and deletes it', async function () {
|
||||
@@ -41,7 +41,7 @@ describe('model manager mapping', () => {
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const changedParams = new DeletedPayload({
|
||||
...payload,
|
||||
@@ -53,7 +53,7 @@ describe('model manager mapping', () => {
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([changedParams], PayloadEmitSource.LocalChanged)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('mapping deleted but dirty item should not delete it', async function () {
|
||||
@@ -63,13 +63,13 @@ describe('model manager mapping', () => {
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.payloadManager.emitPayload(new DeleteItemMutator(item).getDeletedResult())
|
||||
await this.application.payloads.emitPayload(new DeleteItemMutator(item).getDeletedResult())
|
||||
|
||||
const payload2 = new DeletedPayload(this.application.payloadManager.findOne(payload.uuid).ejected())
|
||||
const payload2 = new DeletedPayload(this.application.payloads.findOne(payload.uuid).ejected())
|
||||
|
||||
await this.application.payloadManager.emitPayloads([payload2], PayloadEmitSource.LocalChanged)
|
||||
await this.application.payloads.emitPayloads([payload2], PayloadEmitSource.LocalChanged)
|
||||
|
||||
expect(this.application.payloadManager.collection.all().length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.payloads.collection.all().length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('mapping existing item updates its properties', async function () {
|
||||
@@ -85,7 +85,7 @@ describe('model manager mapping', () => {
|
||||
},
|
||||
})
|
||||
await this.application.mutator.emitItemsFromPayloads([mutated], PayloadEmitSource.LocalChanged)
|
||||
const item = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const item = this.application.items.getDisplayableNotes()[0]
|
||||
|
||||
expect(item.content.title).to.equal(newTitle)
|
||||
})
|
||||
@@ -93,9 +93,9 @@ describe('model manager mapping', () => {
|
||||
it('setting an item dirty should retrieve it in dirty items', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([payload], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const note = this.application.items.getDisplayableNotes()[0]
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
const dirtyItems = this.application.itemManager.getDirtyItems()
|
||||
const dirtyItems = this.application.items.getDirtyItems()
|
||||
expect(Uuids(dirtyItems).includes(note.uuid))
|
||||
})
|
||||
|
||||
@@ -107,18 +107,18 @@ describe('model manager mapping', () => {
|
||||
payloads.push(Factory.createNotePayload())
|
||||
}
|
||||
await this.application.mutator.emitItemsFromPayloads(payloads, PayloadEmitSource.LocalChanged)
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
|
||||
const dirtyItems = this.application.itemManager.getDirtyItems()
|
||||
const dirtyItems = this.application.items.getDirtyItems()
|
||||
expect(dirtyItems.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('sync observers should be notified of changes', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([payload], PayloadEmitSource.LocalChanged)
|
||||
const item = this.application.itemManager.items[0]
|
||||
const item = this.application.items.items[0]
|
||||
return new Promise((resolve) => {
|
||||
this.application.itemManager.addObserver(ContentType.TYPES.Any, ({ changed }) => {
|
||||
this.application.items.addObserver(ContentType.TYPES.Any, ({ changed }) => {
|
||||
expect(changed[0].uuid === item.uuid)
|
||||
resolve()
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('notes and tags', () => {
|
||||
it('uses proper class for note', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
expect(note.constructor === SNNote).to.equal(true)
|
||||
})
|
||||
|
||||
@@ -74,11 +74,11 @@ describe('notes and tags', () => {
|
||||
})
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([mutatedNote, mutatedTag], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
expect(note.content.references.length).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(tag).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(tag).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('creates relationship between note and tag', async function () {
|
||||
@@ -90,8 +90,8 @@ describe('notes and tags', () => {
|
||||
expect(tagPayload.content.references.length).to.equal(1)
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
let tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
let note = this.application.items.getDisplayableNotes()[0]
|
||||
let tag = this.application.items.getDisplayableTags()[0]
|
||||
|
||||
expect(note.dirty).to.not.be.ok
|
||||
expect(tag.dirty).to.not.be.ok
|
||||
@@ -102,26 +102,26 @@ describe('notes and tags', () => {
|
||||
expect(note.isReferencingItem(tag)).to.equal(false)
|
||||
expect(tag.isReferencingItem(note)).to.equal(true)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(note.payload.references.length).to.equal(0)
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
|
||||
await this.application.mutator.setItemToBeDeleted(note)
|
||||
|
||||
tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
tag = this.application.items.getDisplayableTags()[0]
|
||||
|
||||
const deletedNotePayload = this.application.payloadManager.findOne(note.uuid)
|
||||
const deletedNotePayload = this.application.payloads.findOne(note.uuid)
|
||||
expect(deletedNotePayload.dirty).to.be.true
|
||||
expect(tag.dirty).to.be.true
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(tag.content.references.length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(tag.noteCount).to.equal(0)
|
||||
|
||||
tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(0)
|
||||
tag = this.application.items.getDisplayableTags()[0]
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(0)
|
||||
expect(tag.dirty).to.be.false
|
||||
})
|
||||
|
||||
@@ -131,13 +131,13 @@ describe('notes and tags', () => {
|
||||
const tagPayload = pair[1]
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads(pair, PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
let note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const mutatedTag = new DecryptedPayload({
|
||||
...tagPayload,
|
||||
@@ -149,11 +149,11 @@ describe('notes and tags', () => {
|
||||
})
|
||||
await this.application.mutator.emitItemsFromPayloads([mutatedTag], PayloadEmitSource.LocalChanged)
|
||||
|
||||
note = this.application.itemManager.findItem(note.uuid)
|
||||
tag = this.application.itemManager.findItem(tag.uuid)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
tag = this.application.items.findItem(tag.uuid)
|
||||
|
||||
expect(tag.content.references.length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(tag.noteCount).to.equal(0)
|
||||
|
||||
// expect to be false
|
||||
@@ -178,8 +178,8 @@ describe('notes and tags', () => {
|
||||
const tagPayload = pair[1]
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
@@ -194,21 +194,21 @@ describe('notes and tags', () => {
|
||||
syncOptions,
|
||||
)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(0)
|
||||
expect(tag.noteCount).to.equal(0)
|
||||
})
|
||||
|
||||
it('properly handles tag duplication', async function () {
|
||||
const pair = createRelatedNoteTagPairPayload()
|
||||
await this.application.mutator.emitItemsFromPayloads(pair, PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
let tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
let note = this.application.items.getDisplayableNotes()[0]
|
||||
let tag = this.application.items.getDisplayableTags()[0]
|
||||
|
||||
const duplicateTag = await this.application.mutator.duplicateItem(tag, true)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
note = this.application.itemManager.findItem(note.uuid)
|
||||
tag = this.application.itemManager.findItem(tag.uuid)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
tag = this.application.items.findItem(tag.uuid)
|
||||
|
||||
expect(tag.uuid).to.not.equal(duplicateTag.uuid)
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
@@ -216,7 +216,7 @@ describe('notes and tags', () => {
|
||||
expect(duplicateTag.content.references.length).to.equal(1)
|
||||
expect(duplicateTag.noteCount).to.equal(1)
|
||||
|
||||
const noteTags = this.application.itemManager.itemsReferencingItem(note)
|
||||
const noteTags = this.application.items.itemsReferencingItem(note)
|
||||
expect(noteTags.length).to.equal(2)
|
||||
|
||||
const noteTag1 = noteTags[0]
|
||||
@@ -233,12 +233,12 @@ describe('notes and tags', () => {
|
||||
const notePayload = pair[0]
|
||||
const tagPayload = pair[1]
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
const duplicateNote = await this.application.mutator.duplicateItem(note, true)
|
||||
expect(note.uuid).to.not.equal(duplicateNote.uuid)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(duplicateNote).length).to.equal(
|
||||
this.application.itemManager.itemsReferencingItem(note).length,
|
||||
expect(this.application.items.itemsReferencingItem(duplicateNote).length).to.equal(
|
||||
this.application.items.itemsReferencingItem(note).length,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -247,24 +247,24 @@ describe('notes and tags', () => {
|
||||
const notePayload = pair[0]
|
||||
const tagPayload = pair[1]
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
|
||||
await this.application.mutator.setItemToBeDeleted(tag)
|
||||
tag = this.application.itemManager.findItem(tag.uuid)
|
||||
tag = this.application.items.findItem(tag.uuid)
|
||||
expect(tag).to.not.be.ok
|
||||
})
|
||||
|
||||
it('modifying item content should not modify payload content', async function () {
|
||||
const notePayload = Factory.createNotePayload()
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload], PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
let note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
note = await this.application.changeAndSaveItem(
|
||||
note,
|
||||
(mutator) => {
|
||||
@@ -286,14 +286,14 @@ describe('notes and tags', () => {
|
||||
const tagPayload = pair[1]
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
let note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
let tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
await this.application.mutator.setItemToBeDeleted(tag)
|
||||
|
||||
note = this.application.itemManager.findItem(note.uuid)
|
||||
this.application.itemManager.findItem(tag.uuid)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
this.application.items.findItem(tag.uuid)
|
||||
|
||||
expect(note.dirty).to.not.be.ok
|
||||
})
|
||||
@@ -320,7 +320,7 @@ describe('notes and tags', () => {
|
||||
title: 'Foo',
|
||||
})
|
||||
await this.application.mutator.insertItem(note)
|
||||
note = this.application.itemManager.findItem(note.uuid)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
expect(note.content.title).to.equal('Foo')
|
||||
})
|
||||
|
||||
@@ -385,13 +385,13 @@ describe('notes and tags', () => {
|
||||
)
|
||||
}),
|
||||
)
|
||||
const pinnedNote = this.application.itemManager.getDisplayableNotes().find((note) => note.title === 'B')
|
||||
const pinnedNote = this.application.items.getDisplayableNotes().find((note) => note.title === 'B')
|
||||
await this.application.mutator.changeItem(pinnedNote, (mutator) => {
|
||||
mutator.pinned = true
|
||||
})
|
||||
const tag = await this.application.mutator.findOrCreateTag('A')
|
||||
await this.application.mutator.changeItem(tag, (mutator) => {
|
||||
for (const note of this.application.itemManager.getDisplayableNotes()) {
|
||||
for (const note of this.application.items.getDisplayableNotes()) {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(note)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -65,8 +65,8 @@ describe('mapping performance', () => {
|
||||
const expectedRunTime = 3 // seconds
|
||||
expect(seconds).to.be.at.most(expectedRunTime)
|
||||
|
||||
for (const note of application.itemManager.getItems(ContentType.TYPES.Note)) {
|
||||
expect(application.itemManager.itemsReferencingItem(note).length).to.be.above(0)
|
||||
for (const note of application.items.getItems(ContentType.TYPES.Note)) {
|
||||
expect(application.items.itemsReferencingItem(note).length).to.be.above(0)
|
||||
}
|
||||
await Factory.safeDeinit(application)
|
||||
}).timeout(20000)
|
||||
@@ -131,9 +131,9 @@ describe('mapping performance', () => {
|
||||
const MAX_RUN_TIME = 15.0 // seconds
|
||||
expect(seconds).to.be.at.most(MAX_RUN_TIME)
|
||||
|
||||
application.itemManager.getItems(ContentType.TYPES.Tag)[0]
|
||||
for (const note of application.itemManager.getItems(ContentType.TYPES.Note)) {
|
||||
expect(application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
application.items.getItems(ContentType.TYPES.Tag)[0]
|
||||
for (const note of application.items.getItems(ContentType.TYPES.Note)) {
|
||||
expect(application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
}
|
||||
await Factory.safeDeinit(application)
|
||||
}).timeout(20000)
|
||||
|
||||
@@ -155,7 +155,7 @@ describe('mutator service', function () {
|
||||
const sandbox = sinon.createSandbox()
|
||||
|
||||
beforeEach(async function () {
|
||||
this.emitPayloads = sandbox.spy(application.items.payloadManager, 'emitPayloads')
|
||||
this.emitPayloads = sandbox.spy(application.payloads, 'emitPayloads')
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('payload encryption', function () {
|
||||
lastSyncBegan: new Date(),
|
||||
})
|
||||
|
||||
const encryptedPayload = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encryptedPayload = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [notePayload],
|
||||
},
|
||||
@@ -114,7 +114,7 @@ describe('payload encryption', function () {
|
||||
it('returns valid encrypted params for syncing', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -126,7 +126,7 @@ describe('payload encryption', function () {
|
||||
expect(encryptedPayload.content_type).to.be.ok
|
||||
expect(encryptedPayload.created_at).to.be.ok
|
||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||
return string.startsWith(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
}).timeout(5000)
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('payload encryption', function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
|
||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -150,14 +150,14 @@ describe('payload encryption', function () {
|
||||
expect(encryptedPayload.deleted).to.not.be.ok
|
||||
expect(encryptedPayload.errorDecrypting).to.not.be.ok
|
||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||
return string.startsWith(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
})
|
||||
|
||||
it('omits deleted for export file', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -170,7 +170,7 @@ describe('payload encryption', function () {
|
||||
expect(encryptedPayload.created_at).to.be.ok
|
||||
expect(encryptedPayload.deleted).to.not.be.ok
|
||||
expect(encryptedPayload.content).to.satisfy((string) => {
|
||||
return string.startsWith(this.application.encryptionService.getLatestVersion())
|
||||
return string.startsWith(this.application.encryption.getLatestVersion())
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('preferences', function () {
|
||||
Factory.initializeApplication(this.application)
|
||||
await willSyncPromise
|
||||
|
||||
expect(this.application.preferencesService.preferences).to.exist
|
||||
expect(this.application.preferences.preferences).to.exist
|
||||
expect(this.application.getPreference(prefKey)).to.equal(prefValue)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -287,8 +287,8 @@ describe('protections', function () {
|
||||
|
||||
it('handles session length', async function () {
|
||||
application = await Factory.createInitAppWithFakeCrypto()
|
||||
await application.protectionService.setSessionLength(300)
|
||||
const length = await application.protectionService.getLastSessionLength()
|
||||
await application.protections.setSessionLength(300)
|
||||
const length = await application.protections.getLastSessionLength()
|
||||
expect(length).to.equal(300)
|
||||
const expirey = await application.getProtectionSessionExpiryDate()
|
||||
expect(expirey).to.be.ok
|
||||
@@ -296,8 +296,8 @@ describe('protections', function () {
|
||||
|
||||
it('handles session length', async function () {
|
||||
application = await Factory.createInitAppWithFakeCrypto()
|
||||
await application.protectionService.setSessionLength(UnprotectedAccessSecondsDuration.OneMinute)
|
||||
const length = await application.protectionService.getLastSessionLength()
|
||||
await application.protections.setSessionLength(UnprotectedAccessSecondsDuration.OneMinute)
|
||||
const length = await application.protections.getLastSessionLength()
|
||||
expect(length).to.equal(UnprotectedAccessSecondsDuration.OneMinute)
|
||||
const expirey = await application.getProtectionSessionExpiryDate()
|
||||
expect(expirey).to.be.ok
|
||||
@@ -388,7 +388,7 @@ describe('protections', function () {
|
||||
it('should return true when session length has been set', async function () {
|
||||
application = await Factory.createInitAppWithFakeCrypto()
|
||||
await application.addPasscode('passcode')
|
||||
await application.protectionService.setSessionLength(UnprotectedAccessSecondsDuration.OneMinute)
|
||||
await application.protections.setSessionLength(UnprotectedAccessSecondsDuration.OneMinute)
|
||||
expect(application.hasUnprotectedAccessSession()).to.be.true
|
||||
})
|
||||
|
||||
|
||||
@@ -19,43 +19,43 @@ describe('protocol', function () {
|
||||
})
|
||||
|
||||
it('checks version to make sure its 004', function () {
|
||||
expect(this.application.encryptionService.getLatestVersion()).to.equal('004')
|
||||
expect(this.application.encryption.getLatestVersion()).to.equal('004')
|
||||
})
|
||||
|
||||
it('checks supported versions to make sure it includes 001, 002, 003, 004', function () {
|
||||
expect(this.application.encryptionService.supportedVersions()).to.eql(['001', '002', '003', '004'])
|
||||
expect(this.application.encryption.supportedVersions()).to.eql(['001', '002', '003', '004'])
|
||||
})
|
||||
|
||||
it('platform derivation support', function () {
|
||||
expect(
|
||||
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||
this.application.encryption.platformSupportsKeyDerivation({
|
||||
version: '001',
|
||||
}),
|
||||
).to.equal(true)
|
||||
expect(
|
||||
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||
this.application.encryption.platformSupportsKeyDerivation({
|
||||
version: '002',
|
||||
}),
|
||||
).to.equal(true)
|
||||
expect(
|
||||
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||
this.application.encryption.platformSupportsKeyDerivation({
|
||||
version: '003',
|
||||
}),
|
||||
).to.equal(true)
|
||||
expect(
|
||||
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||
this.application.encryption.platformSupportsKeyDerivation({
|
||||
version: '004',
|
||||
}),
|
||||
).to.equal(true)
|
||||
expect(
|
||||
this.application.encryptionService.platformSupportsKeyDerivation({
|
||||
this.application.encryption.platformSupportsKeyDerivation({
|
||||
version: '005',
|
||||
}),
|
||||
).to.equal(true)
|
||||
})
|
||||
|
||||
it('key params versions <= 002 should include pw_cost in portable value', function () {
|
||||
const keyParams002 = this.application.encryptionService.createKeyParams({
|
||||
const keyParams002 = this.application.encryption.createKeyParams({
|
||||
version: '002',
|
||||
pw_cost: 5000,
|
||||
})
|
||||
@@ -63,15 +63,15 @@ describe('protocol', function () {
|
||||
})
|
||||
|
||||
it('version comparison of 002 should be older than library version', function () {
|
||||
expect(this.application.encryptionService.isVersionNewerThanLibraryVersion('002')).to.equal(false)
|
||||
expect(this.application.encryption.isVersionNewerThanLibraryVersion('002')).to.equal(false)
|
||||
})
|
||||
|
||||
it('version comparison of 005 should be newer than library version', function () {
|
||||
expect(this.application.encryptionService.isVersionNewerThanLibraryVersion('005')).to.equal(true)
|
||||
expect(this.application.encryption.isVersionNewerThanLibraryVersion('005')).to.equal(true)
|
||||
})
|
||||
|
||||
it('library version should not be outdated', function () {
|
||||
var currentVersion = this.application.encryptionService.getLatestVersion()
|
||||
var currentVersion = this.application.encryption.getLatestVersion()
|
||||
expect(isProtocolVersionExpired(currentVersion)).to.equal(false)
|
||||
})
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('protocol', function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
let error
|
||||
try {
|
||||
await this.application.encryptionService.decryptSplitSingle({
|
||||
await this.application.encryption.decryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -106,7 +106,7 @@ describe('protocol', function () {
|
||||
await this.application.addPasscode('123')
|
||||
const payload = Factory.createNotePayload()
|
||||
const result = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -121,7 +121,7 @@ describe('protocol', function () {
|
||||
it('encrypted payload for server should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -134,7 +134,7 @@ describe('protocol', function () {
|
||||
it('ejected payload for server should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -147,7 +147,7 @@ describe('protocol', function () {
|
||||
it('encrypted payload for storage should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -160,7 +160,7 @@ describe('protocol', function () {
|
||||
it('ejected payload for storage should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedLocalStorageContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -173,7 +173,7 @@ describe('protocol', function () {
|
||||
it('encrypted payload for file should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
@@ -186,7 +186,7 @@ describe('protocol', function () {
|
||||
it('ejected payload for file should include duplicate_of field', async function () {
|
||||
const payload = Factory.createNotePayload('Test')
|
||||
const encryptedPayload = CreateEncryptedBackupFileContextPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [payload],
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('account recovery', function () {
|
||||
|
||||
application = await context.signout()
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
|
||||
await application.signInWithRecoveryCodes.execute({
|
||||
recoveryCodes: generatedRecoveryCodes.getValue(),
|
||||
@@ -52,7 +52,7 @@ describe('account recovery', function () {
|
||||
password: context.password,
|
||||
})
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.be.ok
|
||||
})
|
||||
|
||||
it('should automatically generate new recovery code after recovery sign in', async () => {
|
||||
@@ -96,7 +96,7 @@ describe('account recovery', function () {
|
||||
|
||||
application = await context.signout()
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
|
||||
await application.signInWithRecoveryCodes.execute({
|
||||
recoveryCodes: generatedRecoveryCodes.getValue(),
|
||||
@@ -104,7 +104,7 @@ describe('account recovery', function () {
|
||||
password: 'foobar',
|
||||
})
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should not allow to sign in with invalid recovery code', async () => {
|
||||
@@ -112,7 +112,7 @@ describe('account recovery', function () {
|
||||
|
||||
application = await context.signout()
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
|
||||
await application.signInWithRecoveryCodes.execute({
|
||||
recoveryCodes: 'invalid recovery code',
|
||||
@@ -120,13 +120,13 @@ describe('account recovery', function () {
|
||||
password: context.paswword,
|
||||
})
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should not allow to sign in with recovery code if user has none', async () => {
|
||||
application = await context.signout()
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
|
||||
await application.signInWithRecoveryCodes.execute({
|
||||
recoveryCodes: 'foo bar',
|
||||
@@ -134,6 +134,6 @@ describe('account recovery', function () {
|
||||
password: context.paswword,
|
||||
})
|
||||
|
||||
expect(await application.encryptionService.getRootKey()).to.not.be.ok
|
||||
expect(await application.encryption.getRootKey()).to.not.be.ok
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('server session', function () {
|
||||
})
|
||||
|
||||
async function sleepUntilSessionExpires(application, basedOnAccessToken = true) {
|
||||
const currentSession = application.apiService.session
|
||||
const currentSession = application.legacyApi.session
|
||||
const timestamp = basedOnAccessToken ? currentSession.accessToken.expiresAt : currentSession.refreshToken.expiresAt
|
||||
const timeRemaining = (timestamp - Date.now()) / 1000 // in ms
|
||||
/*
|
||||
@@ -42,7 +42,7 @@ describe('server session', function () {
|
||||
}
|
||||
|
||||
async function getSessionFromStorage(application) {
|
||||
return application.diskStorageService.getValue(StorageKey.Session)
|
||||
return application.storage.getValue(StorageKey.Session)
|
||||
}
|
||||
|
||||
it('should succeed when a sync request is perfomed with an expired access token', async function () {
|
||||
@@ -56,7 +56,7 @@ describe('server session', function () {
|
||||
|
||||
await sleepUntilSessionExpires(this.application)
|
||||
|
||||
const response = await this.application.apiService.sync([])
|
||||
const response = await this.application.legacyApi.sync([])
|
||||
|
||||
expect(response.status).to.equal(200)
|
||||
})
|
||||
@@ -68,7 +68,7 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const response = await this.application.apiService.refreshSession()
|
||||
const response = await this.application.legacyApi.refreshSession()
|
||||
|
||||
expect(response.status).to.equal(200)
|
||||
expect(response.data.session.access_token).to.be.a('string')
|
||||
@@ -87,7 +87,7 @@ describe('server session', function () {
|
||||
})
|
||||
|
||||
// Saving the current session information for later...
|
||||
const sessionBeforeSync = this.application.apiService.getSession()
|
||||
const sessionBeforeSync = this.application.legacyApi.getSession()
|
||||
|
||||
// Waiting enough time for the access token to expire, before performing a new sync request.
|
||||
await sleepUntilSessionExpires(this.application)
|
||||
@@ -96,7 +96,7 @@ describe('server session', function () {
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// After the above sync request is completed, we obtain the session information.
|
||||
const sessionAfterSync = this.application.apiService.getSession()
|
||||
const sessionAfterSync = this.application.legacyApi.getSession()
|
||||
|
||||
expect(sessionBeforeSync.accessToken.value).to.not.equal(sessionAfterSync.accessToken.value)
|
||||
expect(sessionBeforeSync.refreshToken.value).to.not.equal(sessionAfterSync.refreshToken.value)
|
||||
@@ -119,10 +119,10 @@ describe('server session', function () {
|
||||
// Apply a latency simulation so that ` this.inProgressRefreshSessionPromise = this.refreshSession()` does
|
||||
// not have the chance to complete before it is assigned to the variable. This test came along with a fix
|
||||
// where runHttp does not await a pending refreshSession promise if the request being made is itself a refreshSession request.
|
||||
this.application.httpService.__latencySimulatorMs = 1000
|
||||
this.application.http.__latencySimulatorMs = 1000
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const sessionAfterSync = this.application.apiService.getSession()
|
||||
const sessionAfterSync = this.application.legacyApi.getSession()
|
||||
|
||||
expect(sessionAfterSync.accessToken.expiresAt).to.be.greaterThan(Date.now())
|
||||
})
|
||||
@@ -137,7 +137,7 @@ describe('server session', function () {
|
||||
|
||||
await this.application.signIn(this.email, this.password, false, true)
|
||||
|
||||
const response = await this.application.apiService.sync([])
|
||||
const response = await this.application.legacyApi.sync([])
|
||||
expect(response.status).to.equal(200)
|
||||
})
|
||||
|
||||
@@ -149,7 +149,7 @@ describe('server session', function () {
|
||||
ephemeral: true,
|
||||
})
|
||||
|
||||
const response = await this.application.apiService.sync([])
|
||||
const response = await this.application.legacyApi.sync([])
|
||||
expect(response.status).to.equal(200)
|
||||
})
|
||||
|
||||
@@ -161,7 +161,7 @@ describe('server session', function () {
|
||||
})
|
||||
|
||||
const sessionFromStorage = await getSessionFromStorage(this.application)
|
||||
const sessionFromApiService = this.application.apiService.getSession()
|
||||
const sessionFromApiService = this.application.legacyApi.getSession()
|
||||
|
||||
expect(sessionFromStorage.accessToken).to.equal(sessionFromApiService.accessToken.value)
|
||||
expect(sessionFromStorage.refreshToken).to.equal(sessionFromApiService.refreshToken.value)
|
||||
@@ -169,10 +169,10 @@ describe('server session', function () {
|
||||
expect(sessionFromStorage.refreshExpiration).to.equal(sessionFromApiService.refreshToken.expiresAt)
|
||||
expect(sessionFromStorage.readonlyAccess).to.equal(sessionFromApiService.isReadOnly())
|
||||
|
||||
await this.application.apiService.refreshSession()
|
||||
await this.application.legacyApi.refreshSession()
|
||||
|
||||
const updatedSessionFromStorage = await getSessionFromStorage(this.application)
|
||||
const updatedSessionFromApiService = this.application.apiService.getSession()
|
||||
const updatedSessionFromApiService = this.application.legacyApi.getSession()
|
||||
|
||||
expect(updatedSessionFromStorage.accessToken).to.equal(updatedSessionFromApiService.accessToken.value)
|
||||
expect(updatedSessionFromStorage.refreshToken).to.equal(updatedSessionFromApiService.refreshToken.value)
|
||||
@@ -188,11 +188,11 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const signOutResponse = await this.application.apiService.signOut()
|
||||
const signOutResponse = await this.application.legacyApi.signOut()
|
||||
expect(signOutResponse.status).to.equal(204)
|
||||
|
||||
Factory.ignoreChallenges(this.application)
|
||||
const syncResponse = await this.application.apiService.sync([])
|
||||
const syncResponse = await this.application.legacyApi.sync([])
|
||||
expect(syncResponse.status).to.equal(401)
|
||||
expect(syncResponse.data.error.tag).to.equal('invalid-auth')
|
||||
expect(syncResponse.data.error.message).to.equal('Invalid login credentials.')
|
||||
@@ -210,11 +210,11 @@ describe('server session', function () {
|
||||
// Waiting enough time for the access token to expire, before performing a sign out request.
|
||||
await sleepUntilSessionExpires(this.application)
|
||||
|
||||
const signOutResponse = await this.application.apiService.signOut()
|
||||
const signOutResponse = await this.application.legacyApi.signOut()
|
||||
expect(signOutResponse.status).to.equal(204)
|
||||
|
||||
Factory.ignoreChallenges(this.application)
|
||||
const syncResponse = await this.application.apiService.sync([])
|
||||
const syncResponse = await this.application.legacyApi.sync([])
|
||||
expect(syncResponse.status).to.equal(401)
|
||||
expect(syncResponse.data.error.tag).to.equal('invalid-auth')
|
||||
expect(syncResponse.data.error.message).to.equal('Invalid login credentials.')
|
||||
@@ -250,7 +250,7 @@ describe('server session', function () {
|
||||
registerUser: true,
|
||||
})
|
||||
|
||||
application.diskStorageService.setValue(StorageKey.Session, {
|
||||
application.storage.setValue(StorageKey.Session, {
|
||||
accessToken: 'this-is-a-fake-token-1234',
|
||||
refreshToken: 'this-is-a-fake-token-1234',
|
||||
accessExpiration: 999999999999999,
|
||||
@@ -345,7 +345,7 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
this.application.diskStorageService.setValue(StorageKey.Session, {
|
||||
this.application.storage.setValue(StorageKey.Session, {
|
||||
accessToken: 'this-is-a-fake-token-1234',
|
||||
refreshToken: 'this-is-a-fake-token-1234',
|
||||
accessExpiration: 999999999999999,
|
||||
@@ -385,12 +385,12 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
await this.application.apiService.signOut()
|
||||
this.application.apiService.session = undefined
|
||||
await this.application.legacyApi.signOut()
|
||||
this.application.legacyApi.session = undefined
|
||||
|
||||
await this.application.sessionManager.signIn(this.email, this.password)
|
||||
await this.application.sessions.signIn(this.email, this.password)
|
||||
|
||||
const currentSession = this.application.apiService.getSession()
|
||||
const currentSession = this.application.legacyApi.getSession()
|
||||
|
||||
expect(currentSession).to.be.ok
|
||||
expect(currentSession.accessToken).to.be.ok
|
||||
@@ -409,7 +409,7 @@ describe('server session', function () {
|
||||
|
||||
await sleepUntilSessionExpires(this.application, false)
|
||||
|
||||
const refreshSessionResponse = await this.application.apiService.refreshSession()
|
||||
const refreshSessionResponse = await this.application.legacyApi.refreshSession()
|
||||
|
||||
expect(refreshSessionResponse.status).to.equal(400)
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('expired-refresh-token')
|
||||
@@ -420,7 +420,7 @@ describe('server session', function () {
|
||||
Here we make sure that any subsequent requests will fail.
|
||||
*/
|
||||
Factory.ignoreChallenges(this.application)
|
||||
const syncResponse = await this.application.apiService.sync([])
|
||||
const syncResponse = await this.application.legacyApi.sync([])
|
||||
expect(syncResponse.status).to.equal(401)
|
||||
expect(syncResponse.data.error.tag).to.equal('invalid-auth')
|
||||
expect(syncResponse.data.error.message).to.equal('Invalid login credentials.')
|
||||
@@ -433,9 +433,9 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const originalSession = this.application.apiService.getSession()
|
||||
const originalSession = this.application.legacyApi.getSession()
|
||||
|
||||
this.application.diskStorageService.setValue(StorageKey.Session, {
|
||||
this.application.storage.setValue(StorageKey.Session, {
|
||||
accessToken: originalSession.accessToken.value,
|
||||
refreshToken: 'this-is-a-fake-token-1234',
|
||||
accessExpiration: originalSession.accessToken.expiresAt,
|
||||
@@ -444,14 +444,14 @@ describe('server session', function () {
|
||||
})
|
||||
this.application.sessions.initializeFromDisk()
|
||||
|
||||
const refreshSessionResponse = await this.application.apiService.refreshSession()
|
||||
const refreshSessionResponse = await this.application.legacyApi.refreshSession()
|
||||
|
||||
expect(refreshSessionResponse.status).to.equal(400)
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('invalid-refresh-token')
|
||||
expect(refreshSessionResponse.data.error.message).to.equal('The refresh token is not valid.')
|
||||
|
||||
// Access token should remain valid.
|
||||
const syncResponse = await this.application.apiService.sync([])
|
||||
const syncResponse = await this.application.legacyApi.sync([])
|
||||
expect(syncResponse.status).to.equal(200)
|
||||
})
|
||||
|
||||
@@ -462,8 +462,8 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const refreshPromise = this.application.apiService.refreshSession()
|
||||
const syncResponse = await this.application.apiService.sync([])
|
||||
const refreshPromise = this.application.legacyApi.refreshSession()
|
||||
const syncResponse = await this.application.legacyApi.sync([])
|
||||
|
||||
expect(syncResponse.data.error).to.be.ok
|
||||
|
||||
@@ -485,19 +485,19 @@ describe('server session', function () {
|
||||
const notesBeforeSync = await Factory.createManyMappedNotes(this.application, 5)
|
||||
|
||||
await sleepUntilSessionExpires(this.application)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
|
||||
const expectedNotesUuids = notesBeforeSync.map((n) => n.uuid)
|
||||
const notesResults = await this.application.itemManager.findItems(expectedNotesUuids)
|
||||
const notesResults = await this.application.items.findItems(expectedNotesUuids)
|
||||
|
||||
expect(notesResults.length).to.equal(notesBeforeSync.length)
|
||||
|
||||
for (const aNoteBeforeSync of notesBeforeSync) {
|
||||
const noteResult = await this.application.itemManager.findItem(aNoteBeforeSync.uuid)
|
||||
const noteResult = await this.application.items.findItem(aNoteBeforeSync.uuid)
|
||||
expect(aNoteBeforeSync.isItemContentEqualWith(noteResult)).to.equal(true)
|
||||
}
|
||||
})
|
||||
@@ -574,10 +574,10 @@ describe('server session', function () {
|
||||
password: password,
|
||||
})
|
||||
|
||||
const oldRootKey = await appA.encryptionService.getRootKey()
|
||||
const oldRootKey = await appA.encryption.getRootKey()
|
||||
|
||||
/** Set the session as nonsense */
|
||||
appA.diskStorageService.setValue(StorageKey.Session, {
|
||||
appA.storage.setValue(StorageKey.Session, {
|
||||
accessToken: 'foo',
|
||||
refreshToken: 'bar',
|
||||
accessExpiration: 999999999999999,
|
||||
@@ -593,11 +593,11 @@ describe('server session', function () {
|
||||
await Factory.sleep(5.0)
|
||||
|
||||
expect(didPromptForSignIn).to.equal(true)
|
||||
expect(appA.apiService.session.accessToken.value).to.not.equal('foo')
|
||||
expect(appA.apiService.session.refreshToken.value).to.not.equal('bar')
|
||||
expect(appA.legacyApi.session.accessToken.value).to.not.equal('foo')
|
||||
expect(appA.legacyApi.session.refreshToken.value).to.not.equal('bar')
|
||||
|
||||
/** Expect that the session recovery replaces the global root key */
|
||||
const newRootKey = await appA.encryptionService.getRootKey()
|
||||
const newRootKey = await appA.encryption.getRootKey()
|
||||
expect(oldRootKey).to.not.equal(newRootKey)
|
||||
|
||||
await Factory.safeDeinit(appA)
|
||||
@@ -610,7 +610,7 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const response = await this.application.apiService.getSessionsList()
|
||||
const response = await this.application.legacyApi.getSessionsList()
|
||||
expect(response.data[0].current).to.equal(true)
|
||||
})
|
||||
|
||||
@@ -625,12 +625,12 @@ describe('server session', function () {
|
||||
const app2 = await Factory.createAndInitializeApplication('app2')
|
||||
await app2.signIn(this.email, this.password)
|
||||
|
||||
const response = await this.application.apiService.getSessionsList()
|
||||
const response = await this.application.legacyApi.getSessionsList()
|
||||
expect(response.data.length).to.equal(2)
|
||||
|
||||
await app2.user.signOut()
|
||||
|
||||
const response2 = await this.application.apiService.getSessionsList()
|
||||
const response2 = await this.application.legacyApi.getSessionsList()
|
||||
expect(response2.data.length).to.equal(1)
|
||||
})
|
||||
|
||||
@@ -699,7 +699,7 @@ describe('server session', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
this.application.diskStorageService.setValue(StorageKey.Session, {
|
||||
this.application.storage.setValue(StorageKey.Session, {
|
||||
accessToken: undefined,
|
||||
refreshToken: undefined,
|
||||
accessExpiration: 999999999999999,
|
||||
@@ -708,7 +708,7 @@ describe('server session', function () {
|
||||
})
|
||||
this.application.sessions.initializeFromDisk()
|
||||
|
||||
const storageKey = this.application.diskStorageService.getPersistenceKey()
|
||||
const storageKey = this.application.storage.getPersistenceKey()
|
||||
expect(localStorage.getItem(storageKey)).to.be.ok
|
||||
|
||||
await this.application.user.signOut()
|
||||
|
||||
@@ -151,7 +151,7 @@ describe('settings service', function () {
|
||||
const response = await fetch('/packages/snjs/mocha/assets/small_file.md')
|
||||
const buffer = new Uint8Array(await response.arrayBuffer())
|
||||
|
||||
await Files.uploadFile(application.fileService, buffer, 'my-file', 'md', 1000)
|
||||
await Files.uploadFile(application.files, buffer, 'my-file', 'md', 1000)
|
||||
|
||||
await Factory.sleep(1)
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ describe('singletons', function () {
|
||||
return new DecryptedPayload(params)
|
||||
}
|
||||
|
||||
function findOrCreatePrefsSingleton(application) {
|
||||
return application.singletonManager.findOrCreateContentTypeSingleton(ContentType.TYPES.UserPrefs, FillItemContent({}))
|
||||
function findOrCreatePrefsSingleton(context) {
|
||||
return context.singletons.findOrCreateContentTypeSingleton(ContentType.TYPES.UserPrefs, FillItemContent({}))
|
||||
}
|
||||
|
||||
beforeEach(async function () {
|
||||
@@ -49,7 +49,7 @@ describe('singletons', function () {
|
||||
}
|
||||
|
||||
this.signOut = async () => {
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
this.application = await this.context.signout()
|
||||
}
|
||||
|
||||
this.signIn = async () => {
|
||||
@@ -78,10 +78,10 @@ describe('singletons', function () {
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
|
||||
await Factory.safeDeinit(this.application)
|
||||
@@ -100,8 +100,8 @@ describe('singletons', function () {
|
||||
PayloadEmitSource.LocalChanged,
|
||||
)
|
||||
await this.application.mutator.setItemsDirty(items)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('duplicate components should auto-resolve to 1', async function () {
|
||||
@@ -121,30 +121,30 @@ describe('singletons', function () {
|
||||
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.itemsMatchingPredicate(ContentType.TYPES.Component, this.extPred).length).to.equal(1)
|
||||
expect(this.application.items.itemsMatchingPredicate(ContentType.TYPES.Component, this.extPred).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('resolves via find or create', async function () {
|
||||
/* Set to never synced as singleton manager will attempt to sync before resolving */
|
||||
this.application.syncService.ut_clearLastSyncDate()
|
||||
this.application.syncService.ut_setDatabaseLoaded(false)
|
||||
this.application.sync.ut_clearLastSyncDate()
|
||||
this.application.sync.ut_setDatabaseLoaded(false)
|
||||
const contentType = ContentType.TYPES.UserPrefs
|
||||
const predicate = new Predicate('content_type', '=', contentType)
|
||||
/* Start a sync right after we await singleton resolve below */
|
||||
setTimeout(() => {
|
||||
this.application.syncService.ut_setDatabaseLoaded(true)
|
||||
this.application.sync.ut_setDatabaseLoaded(true)
|
||||
this.application.sync.sync({
|
||||
/* Simulate the first sync occuring as that is handled specially by sync service */
|
||||
mode: SyncMode.DownloadFirst,
|
||||
})
|
||||
})
|
||||
const userPreferences = await this.application.singletonManager.findOrCreateContentTypeSingleton(contentType, {})
|
||||
const userPreferences = await this.context.singletons.findOrCreateContentTypeSingleton(contentType, {})
|
||||
|
||||
expect(userPreferences).to.be.ok
|
||||
const refreshedUserPrefs = this.application.items.findItem(userPreferences.uuid)
|
||||
expect(refreshedUserPrefs).to.be.ok
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.itemManager.itemsMatchingPredicate(contentType, predicate).length).to.equal(1)
|
||||
expect(this.application.items.itemsMatchingPredicate(contentType, predicate).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('resolves registered predicate with signing in/out', async function () {
|
||||
@@ -187,7 +187,7 @@ describe('singletons', function () {
|
||||
|
||||
let didCompleteRelevantSync = false
|
||||
let beginCheckingResponse = false
|
||||
this.application.syncService.addEventObserver(async (eventName, data) => {
|
||||
this.application.sync.addEventObserver(async (eventName, data) => {
|
||||
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
|
||||
beginCheckingResponse = true
|
||||
}
|
||||
@@ -202,7 +202,7 @@ describe('singletons', function () {
|
||||
expect(matching).to.not.be.ok
|
||||
}
|
||||
})
|
||||
await this.application.syncService.sync({ mode: SyncMode.DownloadFirst })
|
||||
await this.application.sync.sync({ mode: SyncMode.DownloadFirst })
|
||||
expect(didCompleteRelevantSync).to.equal(true)
|
||||
}).timeout(10000)
|
||||
|
||||
@@ -210,12 +210,14 @@ describe('singletons', function () {
|
||||
await this.registerUser()
|
||||
|
||||
/** Create prefs */
|
||||
const ogPrefs = await findOrCreatePrefsSingleton(this.application)
|
||||
const ogPrefs = await findOrCreatePrefsSingleton(this.context)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
|
||||
this.application = await this.context.signout()
|
||||
|
||||
/** Create another instance while signed out */
|
||||
await findOrCreatePrefsSingleton(this.application)
|
||||
await findOrCreatePrefsSingleton(this.context)
|
||||
|
||||
await Factory.loginToApplication({
|
||||
application: this.application,
|
||||
email: this.email,
|
||||
@@ -223,36 +225,36 @@ describe('singletons', function () {
|
||||
})
|
||||
|
||||
/** After signing in, the instance retrieved from the server should be the one kept */
|
||||
const latestPrefs = await findOrCreatePrefsSingleton(this.application)
|
||||
const latestPrefs = await findOrCreatePrefsSingleton(this.context)
|
||||
expect(latestPrefs.uuid).to.equal(ogPrefs.uuid)
|
||||
|
||||
const allPrefs = this.application.itemManager.getItems(ogPrefs.content_type)
|
||||
const allPrefs = this.application.items.getItems(ogPrefs.content_type)
|
||||
expect(allPrefs.length).to.equal(1)
|
||||
})
|
||||
|
||||
it('resolving singleton before first sync, then signing in, should result in correct number of instances', async function () {
|
||||
await this.registerUser()
|
||||
/** Create prefs and associate them with account */
|
||||
const ogPrefs = await findOrCreatePrefsSingleton(this.application)
|
||||
const ogPrefs = await findOrCreatePrefsSingleton(this.context)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
this.application = await this.context.signout()
|
||||
|
||||
/** Create another instance while signed out */
|
||||
await findOrCreatePrefsSingleton(this.application)
|
||||
await findOrCreatePrefsSingleton(this.context)
|
||||
await Factory.loginToApplication({
|
||||
application: this.application,
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
})
|
||||
/** After signing in, the instance retrieved from the server should be the one kept */
|
||||
const latestPrefs = await findOrCreatePrefsSingleton(this.application)
|
||||
const latestPrefs = await findOrCreatePrefsSingleton(this.context)
|
||||
expect(latestPrefs.uuid).to.equal(ogPrefs.uuid)
|
||||
const allPrefs = this.application.itemManager.getItems(ogPrefs.content_type)
|
||||
const allPrefs = this.application.items.getItems(ogPrefs.content_type)
|
||||
expect(allPrefs.length).to.equal(1)
|
||||
})
|
||||
|
||||
it('if only result is errorDecrypting, create new item', async function () {
|
||||
const item = this.application.itemManager.items.find((item) => item.content_type === ContentType.TYPES.UserPrefs)
|
||||
const item = this.application.items.items.find((item) => item.content_type === ContentType.TYPES.UserPrefs)
|
||||
|
||||
const erroredPayload = new EncryptedPayload({
|
||||
...item.payload.ejected(),
|
||||
@@ -260,16 +262,13 @@ describe('singletons', function () {
|
||||
errorDecrypting: true,
|
||||
})
|
||||
|
||||
await this.application.payloadManager.emitPayload(erroredPayload)
|
||||
await this.application.payloads.emitPayload(erroredPayload)
|
||||
|
||||
const resolvedItem = await this.application.singletonManager.findOrCreateContentTypeSingleton(
|
||||
item.content_type,
|
||||
item.content,
|
||||
)
|
||||
const resolvedItem = await this.context.singletons.findOrCreateContentTypeSingleton(item.content_type, item.content)
|
||||
|
||||
await this.application.sync.sync({ awaitAll: true })
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
expect(resolvedItem.uuid).to.not.equal(item.uuid)
|
||||
expect(resolvedItem.errorDecrypting).to.not.be.ok
|
||||
})
|
||||
@@ -318,34 +317,34 @@ describe('singletons', function () {
|
||||
errorDecrypting: false,
|
||||
})
|
||||
|
||||
await this.application.payloadManager.emitPayload(notErrored)
|
||||
await this.application.payloads.emitPayload(notErrored)
|
||||
|
||||
/** Item will get decrypted on current tick, so wait one before syncing */
|
||||
await Factory.sleep(0)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.itemsMatchingPredicate(ContentType.TYPES.Component, this.extPred).length).to.equal(1)
|
||||
expect(this.application.items.itemsMatchingPredicate(ContentType.TYPES.Component, this.extPred).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('alternating the uuid of a singleton should return correct result', async function () {
|
||||
const payload = createPrefsPayload()
|
||||
const item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const predicate = new Predicate('content_type', '=', item.content_type)
|
||||
let resolvedItem = await this.application.singletonManager.findOrCreateContentTypeSingleton(
|
||||
let resolvedItem = await this.context.singletons.findOrCreateContentTypeSingleton(
|
||||
payload.content_type,
|
||||
payload.content,
|
||||
)
|
||||
const originalUuid = resolvedItem.uuid
|
||||
await Factory.alternateUuidForItem(this.application, resolvedItem.uuid)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
const resolvedItem2 = await this.application.singletonManager.findOrCreateContentTypeSingleton(
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const resolvedItem2 = await this.context.singletons.findOrCreateContentTypeSingleton(
|
||||
payload.content_type,
|
||||
payload.content,
|
||||
)
|
||||
resolvedItem = this.application.items.findItem(resolvedItem.uuid)
|
||||
expect(resolvedItem).to.not.be.ok
|
||||
expect(resolvedItem2.uuid).to.not.equal(originalUuid)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -31,23 +31,23 @@ describe('storage manager', function () {
|
||||
it('should set and retrieve values', async function () {
|
||||
const key = 'foo'
|
||||
const value = 'bar'
|
||||
await this.application.diskStorageService.setValue(key, value)
|
||||
expect(await this.application.diskStorageService.getValue(key)).to.eql(value)
|
||||
await this.application.storage.setValue(key, value)
|
||||
expect(await this.application.storage.getValue(key)).to.eql(value)
|
||||
})
|
||||
|
||||
it('should set and retrieve items', async function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.diskStorageService.savePayload(payload)
|
||||
const payloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
await this.application.storage.savePayload(payload)
|
||||
const payloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(payloads.length).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
})
|
||||
|
||||
it('should clear values', async function () {
|
||||
const key = 'foo'
|
||||
const value = 'bar'
|
||||
await this.application.diskStorageService.setValue(key, value)
|
||||
await this.application.diskStorageService.clearAllData()
|
||||
expect(await this.application.diskStorageService.getValue(key)).to.not.be.ok
|
||||
await this.application.storage.setValue(key, value)
|
||||
await this.application.storage.clearAllData()
|
||||
expect(await this.application.storage.getValue(key)).to.not.be.ok
|
||||
})
|
||||
|
||||
it('serverPassword should not be saved to keychain', async function () {
|
||||
@@ -57,7 +57,7 @@ describe('storage manager', function () {
|
||||
password: this.password,
|
||||
ephemeral: false,
|
||||
})
|
||||
const keychainValue = await this.application.deviceInterface.getNamespacedKeychainValue(this.application.identifier)
|
||||
const keychainValue = await this.application.device.getNamespacedKeychainValue(this.application.identifier)
|
||||
expect(keychainValue.masterKey).to.be.ok
|
||||
expect(keychainValue.serverPassword).to.not.be.ok
|
||||
})
|
||||
@@ -71,10 +71,10 @@ describe('storage manager', function () {
|
||||
})
|
||||
const key = 'foo'
|
||||
const value = 'bar'
|
||||
await this.application.diskStorageService.setValue(key, value)
|
||||
await this.application.storage.setValue(key, value)
|
||||
/** Items are stored in local storage */
|
||||
expect(Object.keys(localStorage).length).to.equal(this.expectedKeyCount + BaseItemCounts.DefaultItems)
|
||||
const retrievedValue = await this.application.diskStorageService.getValue(key)
|
||||
const retrievedValue = await this.application.storage.getValue(key)
|
||||
expect(retrievedValue).to.equal(value)
|
||||
})
|
||||
|
||||
@@ -88,12 +88,12 @@ describe('storage manager', function () {
|
||||
})
|
||||
const key = 'foo'
|
||||
const value = 'bar'
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist(key, value)
|
||||
await this.application.storage.setValueAndAwaitPersist(key, value)
|
||||
|
||||
const expectedKeys = ['keychain']
|
||||
expect(Object.keys(localStorage).length).to.equal(expectedKeys.length)
|
||||
|
||||
const retrievedValue = await this.application.diskStorageService.getValue(key)
|
||||
const retrievedValue = await this.application.storage.getValue(key)
|
||||
expect(retrievedValue).to.equal(value)
|
||||
})
|
||||
|
||||
@@ -105,21 +105,21 @@ describe('storage manager', function () {
|
||||
ephemeral: true,
|
||||
})
|
||||
await Factory.createSyncedNote(this.application)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(0)
|
||||
})
|
||||
|
||||
it('storage with no account and no passcode should not be encrypted', async function () {
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
const wrappedValue = this.application.diskStorageService.values[ValueModesKeys.Wrapped]
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
const wrappedValue = this.application.storage.values[ValueModesKeys.Wrapped]
|
||||
const payload = new DecryptedPayload(wrappedValue)
|
||||
expect(payload.content).to.be.an.instanceof(Object)
|
||||
})
|
||||
|
||||
it('storage aftering adding passcode should be encrypted', async function () {
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.addPasscode('123')
|
||||
const wrappedValue = this.application.diskStorageService.values[ValueModesKeys.Wrapped]
|
||||
const wrappedValue = this.application.storage.values[ValueModesKeys.Wrapped]
|
||||
const payload = new EncryptedPayload(wrappedValue)
|
||||
expect(payload.content).to.be.a('string')
|
||||
})
|
||||
@@ -127,11 +127,11 @@ describe('storage manager', function () {
|
||||
it('storage after adding passcode then removing passcode should not be encrypted', async function () {
|
||||
const passcode = '123'
|
||||
Factory.handlePasswordChallenges(this.application, passcode)
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.addPasscode(passcode)
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
||||
await this.application.storage.setValueAndAwaitPersist('bar', 'foo')
|
||||
await this.application.removePasscode()
|
||||
const wrappedValue = this.application.diskStorageService.values[ValueModesKeys.Wrapped]
|
||||
const wrappedValue = this.application.storage.values[ValueModesKeys.Wrapped]
|
||||
const payload = new DecryptedPayload(wrappedValue)
|
||||
expect(payload.content).to.be.an.instanceof(Object)
|
||||
})
|
||||
@@ -148,35 +148,35 @@ describe('storage manager', function () {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
})
|
||||
expect(await this.application.deviceInterface.getNamespacedKeychainValue(this.application.identifier)).to.be.ok
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
expect(await this.application.device.getNamespacedKeychainValue(this.application.identifier)).to.be.ok
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
Factory.handlePasswordChallenges(this.application, this.password)
|
||||
await this.application.addPasscode(passcode)
|
||||
expect(await this.application.deviceInterface.getNamespacedKeychainValue(this.application.identifier)).to.not.be.ok
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
||||
expect(await this.application.device.getNamespacedKeychainValue(this.application.identifier)).to.not.be.ok
|
||||
await this.application.storage.setValueAndAwaitPersist('bar', 'foo')
|
||||
Factory.handlePasswordChallenges(this.application, passcode)
|
||||
await this.application.removePasscode()
|
||||
expect(await this.application.deviceInterface.getNamespacedKeychainValue(this.application.identifier)).to.be.ok
|
||||
expect(await this.application.device.getNamespacedKeychainValue(this.application.identifier)).to.be.ok
|
||||
|
||||
const wrappedValue = this.application.diskStorageService.values[ValueModesKeys.Wrapped]
|
||||
const wrappedValue = this.application.storage.values[ValueModesKeys.Wrapped]
|
||||
const payload = new EncryptedPayload(wrappedValue)
|
||||
expect(payload.content).to.be.a('string')
|
||||
})
|
||||
|
||||
it('adding account should encrypt storage with account keys', async function () {
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
await Factory.registerUserToApplication({
|
||||
application: this.application,
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
ephemeral: true,
|
||||
})
|
||||
const accountKey = await this.application.encryptionService.getRootKey()
|
||||
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
||||
const accountKey = await this.application.encryption.getRootKey()
|
||||
expect(await this.application.storage.canDecryptWithKey(accountKey)).to.equal(true)
|
||||
})
|
||||
|
||||
it('signing out of account should decrypt storage', async function () {
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
await Factory.registerUserToApplication({
|
||||
application: this.application,
|
||||
email: this.email,
|
||||
@@ -184,15 +184,15 @@ describe('storage manager', function () {
|
||||
ephemeral: true,
|
||||
})
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
||||
const wrappedValue = this.application.diskStorageService.values[ValueModesKeys.Wrapped]
|
||||
await this.application.storage.setValueAndAwaitPersist('bar', 'foo')
|
||||
const wrappedValue = this.application.storage.values[ValueModesKeys.Wrapped]
|
||||
const payload = new DecryptedPayload(wrappedValue)
|
||||
expect(payload.content).to.be.an.instanceof(Object)
|
||||
})
|
||||
|
||||
it('adding account then passcode should encrypt storage with account keys', async function () {
|
||||
/** Should encrypt storage with account keys and encrypt account keys with passcode */
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('foo', 'bar')
|
||||
await this.application.storage.setValueAndAwaitPersist('foo', 'bar')
|
||||
await Factory.registerUserToApplication({
|
||||
application: this.application,
|
||||
email: this.email,
|
||||
@@ -201,23 +201,23 @@ describe('storage manager', function () {
|
||||
})
|
||||
|
||||
/** Should not be wrapped root key yet */
|
||||
expect(await this.application.encryptionService.rootKeyManager.getWrappedRootKey()).to.not.be.ok
|
||||
expect(await this.application.encryption.rootKeyManager.getWrappedRootKey()).to.not.be.ok
|
||||
|
||||
const passcode = '123'
|
||||
Factory.handlePasswordChallenges(this.application, this.password)
|
||||
await this.application.addPasscode(passcode)
|
||||
await this.application.diskStorageService.setValueAndAwaitPersist('bar', 'foo')
|
||||
await this.application.storage.setValueAndAwaitPersist('bar', 'foo')
|
||||
|
||||
/** Root key should now be wrapped */
|
||||
expect(await this.application.encryptionService.rootKeyManager.getWrappedRootKey()).to.be.ok
|
||||
expect(await this.application.encryption.rootKeyManager.getWrappedRootKey()).to.be.ok
|
||||
|
||||
const accountKey = await this.application.encryptionService.getRootKey()
|
||||
expect(await this.application.diskStorageService.canDecryptWithKey(accountKey)).to.equal(true)
|
||||
const passcodeKey = await this.application.encryptionService.computeWrappingKey(passcode)
|
||||
const wrappedRootKey = await this.application.encryptionService.rootKeyManager.getWrappedRootKey()
|
||||
const accountKey = await this.application.encryption.getRootKey()
|
||||
expect(await this.application.storage.canDecryptWithKey(accountKey)).to.equal(true)
|
||||
const passcodeKey = await this.application.encryption.computeWrappingKey(passcode)
|
||||
const wrappedRootKey = await this.application.encryption.rootKeyManager.getWrappedRootKey()
|
||||
/** Expect that we can decrypt wrapped root key with passcode key */
|
||||
const payload = new EncryptedPayload(wrappedRootKey)
|
||||
const decrypted = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decrypted = await this.application.encryption.decryptSplitSingle({
|
||||
usesRootKey: {
|
||||
items: [payload],
|
||||
key: passcodeKey,
|
||||
@@ -229,7 +229,7 @@ describe('storage manager', function () {
|
||||
it('stored payloads should not contain metadata fields', async function () {
|
||||
await this.application.addPasscode('123')
|
||||
await Factory.createSyncedNote(this.application)
|
||||
const payloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const payloads = await this.application.storage.getAllRawPayloads()
|
||||
const payload = payloads[0]
|
||||
expect(payload.fields).to.not.be.ok
|
||||
expect(payload.source).to.not.be.ok
|
||||
@@ -239,7 +239,7 @@ describe('storage manager', function () {
|
||||
it('storing an offline synced payload should not include dirty flag', async function () {
|
||||
await this.application.addPasscode('123')
|
||||
await Factory.createSyncedNote(this.application)
|
||||
const payloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const payloads = await this.application.storage.getAllRawPayloads()
|
||||
const payload = payloads[0]
|
||||
|
||||
expect(payload.dirty).to.not.be.ok
|
||||
@@ -254,7 +254,7 @@ describe('storage manager', function () {
|
||||
})
|
||||
|
||||
await Factory.createSyncedNote(this.application)
|
||||
const payloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const payloads = await this.application.storage.getAllRawPayloads()
|
||||
const payload = payloads[0]
|
||||
|
||||
expect(payload.dirty).to.not.be.ok
|
||||
@@ -269,7 +269,7 @@ describe('storage manager', function () {
|
||||
})
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
const values = this.application.diskStorageService.values[ValueModesKeys.Unwrapped]
|
||||
const values = this.application.storage.values[ValueModesKeys.Unwrapped]
|
||||
expect(Object.keys(values).length).to.equal(0)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Factory from './lib/factory.js'
|
||||
import * as Events from './lib/Events.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
@@ -9,7 +9,6 @@ describe('subscriptions', function () {
|
||||
let application
|
||||
let context
|
||||
let subscriptionManager
|
||||
let subscriptionId = 3001
|
||||
|
||||
afterEach(async function () {
|
||||
await Factory.safeDeinit(application)
|
||||
@@ -24,9 +23,9 @@ describe('subscriptions', function () {
|
||||
await context.launch()
|
||||
|
||||
application = context.application
|
||||
subscriptionManager = context.application.subscriptionManager
|
||||
subscriptionManager = context.subscriptions
|
||||
|
||||
const result = await Factory.registerUserToApplication({
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: context.email,
|
||||
password: context.password,
|
||||
@@ -40,7 +39,7 @@ describe('subscriptions', function () {
|
||||
|
||||
const existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
const newlyCreatedInvite = existingInvites.find(invite => invite.inviteeIdentifier === 'test@test.te')
|
||||
const newlyCreatedInvite = existingInvites.find((invite) => invite.inviteeIdentifier === 'test@test.te')
|
||||
|
||||
expect(newlyCreatedInvite.status).to.equal('sent')
|
||||
})
|
||||
@@ -69,17 +68,17 @@ describe('subscriptions', function () {
|
||||
|
||||
let existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect (existingInvites.length).to.equal(2)
|
||||
expect(existingInvites.length).to.equal(2)
|
||||
|
||||
const newlyCreatedInvite = existingInvites.find(invite => invite.inviteeIdentifier === 'test@test.te')
|
||||
const newlyCreatedInvite = existingInvites.find((invite) => invite.inviteeIdentifier === 'test@test.te')
|
||||
|
||||
await subscriptionManager.cancelInvitation(newlyCreatedInvite.uuid)
|
||||
|
||||
existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect (existingInvites.length).to.equal(2)
|
||||
expect(existingInvites.length).to.equal(2)
|
||||
|
||||
expect(existingInvites.filter(invite => invite.status === 'canceled').length).to.equal(1)
|
||||
expect(existingInvites.filter((invite) => invite.status === 'canceled').length).to.equal(1)
|
||||
})
|
||||
|
||||
it('should invite a user by email if the limit of shared subscription is restored', async () => {
|
||||
@@ -99,6 +98,6 @@ describe('subscriptions', function () {
|
||||
|
||||
existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect(existingInvites.find(invite => invite.inviteeIdentifier === 'test6@test.te')).not.to.equal(undefined)
|
||||
expect(existingInvites.find((invite) => invite.inviteeIdentifier === 'test6@test.te')).not.to.equal(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,10 +30,10 @@ describe('online conflict handling', function () {
|
||||
await this.context.register()
|
||||
|
||||
this.sharedFinalAssertions = async function () {
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
const items = this.application.itemManager.items
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
const items = this.application.items.items
|
||||
expect(items.length).to.equal(this.expectedItemCount)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
}
|
||||
})
|
||||
@@ -68,7 +68,7 @@ describe('online conflict handling', function () {
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
/** First modify the item without saving so that our local contents digress from the server's */
|
||||
await this.application.mutator.changeItem(item, (mutator) => {
|
||||
@@ -85,7 +85,7 @@ describe('online conflict handling', function () {
|
||||
syncOptions,
|
||||
)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('online conflict handling', function () {
|
||||
const payload = createDirtyPayload(ContentType.TYPES.ItemsKey)
|
||||
const item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged)
|
||||
this.expectedItemCount++
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
/** First modify the item without saving so that
|
||||
* our local contents digress from the server's */
|
||||
await this.application.mutator.changeItem(item, (mutator) => {
|
||||
@@ -110,7 +110,7 @@ describe('online conflict handling', function () {
|
||||
syncOptions,
|
||||
)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -119,9 +119,9 @@ describe('online conflict handling', function () {
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const originalValue = note.title
|
||||
@@ -141,27 +141,27 @@ describe('online conflict handling', function () {
|
||||
})
|
||||
|
||||
// Download all items from the server, which will include this note.
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.syncService.sync({
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.sync.sync({
|
||||
...syncOptions,
|
||||
awaitAll: true,
|
||||
})
|
||||
|
||||
// We expect this item to be duplicated
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(2)
|
||||
|
||||
const allItems = this.application.itemManager.items
|
||||
const allItems = this.application.items.items
|
||||
expect(allItems.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const originalItem = this.application.itemManager.findItem(note.uuid)
|
||||
const originalItem = this.application.items.findItem(note.uuid)
|
||||
const duplicateItem = allItems.find((i) => i.content.conflict_of === note.uuid)
|
||||
|
||||
expect(originalItem.title).to.equal(dirtyValue)
|
||||
expect(duplicateItem.title).to.equal(originalValue)
|
||||
expect(originalItem.title).to.not.equal(duplicateItem.title)
|
||||
|
||||
const newRawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const newRawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(newRawPayloads.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
@@ -172,7 +172,7 @@ describe('online conflict handling', function () {
|
||||
await Factory.markDirtyAndSyncItem(this.application, note)
|
||||
this.expectedItemCount++
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
/** First modify the item without saving so that
|
||||
* our local contents digress from the server's */
|
||||
@@ -192,11 +192,11 @@ describe('online conflict handling', function () {
|
||||
|
||||
// We expect this item to be duplicated
|
||||
this.expectedItemCount++
|
||||
const allItems = this.application.itemManager.items
|
||||
const allItems = this.application.items.items
|
||||
expect(allItems.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const note1 = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const note2 = this.application.itemManager.getDisplayableNotes()[1]
|
||||
const note1 = this.application.items.getDisplayableNotes()[0]
|
||||
const note2 = this.application.items.getDisplayableNotes()[1]
|
||||
expect(note1.content.title).to.not.equal(note2.content.title)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
@@ -222,16 +222,16 @@ describe('online conflict handling', function () {
|
||||
)
|
||||
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
// clear sync token, clear storage, download all items, and ensure none of them have error decrypting
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.diskStorageService.clearAllPayloads()
|
||||
await this.application.payloadManager.resetState()
|
||||
await this.application.itemManager.resetState()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.storage.clearAllPayloads()
|
||||
await this.application.payloads.resetState()
|
||||
await this.application.items.resetState()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -239,7 +239,7 @@ describe('online conflict handling', function () {
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
@@ -263,15 +263,15 @@ describe('online conflict handling', function () {
|
||||
// We expect this item to be duplicated
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
|
||||
// We expect the item title to be the new title, and not rolled back to original value
|
||||
expect(note.content.title).to.equal(newTitle)
|
||||
|
||||
const allItems = this.application.itemManager.items
|
||||
const allItems = this.application.items.items
|
||||
expect(allItems.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
@@ -280,16 +280,16 @@ describe('online conflict handling', function () {
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// keep item as is and set dirty
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
|
||||
// clear sync token so that all items are retrieved on next sync
|
||||
this.application.syncService.clearSyncPositionTokens()
|
||||
this.application.sync.clearSyncPositionTokens()
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -310,7 +310,7 @@ describe('online conflict handling', function () {
|
||||
)
|
||||
|
||||
// client B
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.mutator.changeItem(
|
||||
note,
|
||||
(mutator) => {
|
||||
@@ -323,7 +323,7 @@ describe('online conflict handling', function () {
|
||||
|
||||
// conflict_of is a key to ignore when comparing content, so item should
|
||||
// not be duplicated.
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -348,7 +348,7 @@ describe('online conflict handling', function () {
|
||||
mutator.title = `${Math.random()}`
|
||||
})
|
||||
// client B
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
|
||||
await Factory.changePayloadTimeStampAndSync(
|
||||
this.application,
|
||||
@@ -370,17 +370,17 @@ describe('online conflict handling', function () {
|
||||
const originalPayload = note.payloadRepresentation()
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
// client A
|
||||
await this.application.mutator.setItemToBeDeleted(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.expectedItemCount--
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
// client B
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
// Add the item back and say it's not deleted
|
||||
const mutatedPayload = new DecryptedPayload({
|
||||
...originalPayload,
|
||||
@@ -388,13 +388,13 @@ describe('online conflict handling', function () {
|
||||
updated_at: Factory.yesterday(),
|
||||
})
|
||||
await this.application.mutator.emitItemsFromPayloads([mutatedPayload], PayloadEmitSource.LocalChanged)
|
||||
const resultNote = this.application.itemManager.findItem(note.uuid)
|
||||
const resultNote = this.application.items.findItem(note.uuid)
|
||||
expect(resultNote.uuid).to.equal(note.uuid)
|
||||
await this.application.mutator.setItemDirty(resultNote)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// We expect that this item is now gone for good, and a duplicate has not been created.
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -404,11 +404,11 @@ describe('online conflict handling', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
// client A
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
// client B
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
|
||||
// This client says this item is deleted, but the server is saying its not deleted.
|
||||
// In this case, we want to keep the server copy.
|
||||
@@ -420,14 +420,14 @@ describe('online conflict handling', function () {
|
||||
)
|
||||
|
||||
// We expect that this item maintained.
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
it('should create conflict if syncing an item that is stale', async function () {
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
expect(note.dirty).to.equal(false)
|
||||
this.expectedItemCount++
|
||||
@@ -452,7 +452,7 @@ describe('online conflict handling', function () {
|
||||
// We expect now that the item was conflicted
|
||||
this.expectedItemCount++
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
for (const payload of rawPayloads) {
|
||||
expect(payload.dirty).to.not.be.ok
|
||||
@@ -465,7 +465,7 @@ describe('online conflict handling', function () {
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
await Factory.changePayloadTimeStampAndSync(
|
||||
this.application,
|
||||
@@ -475,7 +475,7 @@ describe('online conflict handling', function () {
|
||||
syncOptions,
|
||||
)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -488,11 +488,11 @@ describe('online conflict handling', function () {
|
||||
await Factory.createManyMappedNotes(this.application, largeItemCount)
|
||||
|
||||
/** Upload */
|
||||
this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.sync(syncOptions)
|
||||
await this.context.awaitNextSucessfulSync()
|
||||
|
||||
this.expectedItemCount += largeItemCount
|
||||
const items = this.application.itemManager.items
|
||||
const items = this.application.items.items
|
||||
expect(items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
/**
|
||||
@@ -500,9 +500,9 @@ describe('online conflict handling', function () {
|
||||
* the server as dirty, with no sync token, so that the server also
|
||||
* gives us everything it has.
|
||||
*/
|
||||
this.application.syncService.lockSyncing()
|
||||
this.application.sync.lockSyncing()
|
||||
const yesterday = Factory.yesterday()
|
||||
for (const note of this.application.itemManager.getDisplayableNotes()) {
|
||||
for (const note of this.application.items.getDisplayableNotes()) {
|
||||
/** First modify the item without saving so that
|
||||
* our local contents digress from the server's */
|
||||
await this.application.mutator.changeItem(note, (mutator) => {
|
||||
@@ -516,13 +516,13 @@ describe('online conflict handling', function () {
|
||||
// We expect all the notes to be duplicated.
|
||||
this.expectedItemCount++
|
||||
}
|
||||
this.application.syncService.unlockSyncing()
|
||||
this.application.sync.unlockSyncing()
|
||||
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
this.application.sync.sync(syncOptions)
|
||||
await this.context.awaitNextSucessfulSync()
|
||||
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(largeItemCount * 2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(largeItemCount * 2)
|
||||
await this.sharedFinalAssertions()
|
||||
}).timeout(60000)
|
||||
|
||||
@@ -532,8 +532,8 @@ describe('online conflict handling', function () {
|
||||
this.expectedItemCount -= 1 /** auto-created user preferences */
|
||||
await this.application.mutator.emitItemsFromPayloads([payload1, payload2], PayloadEmitSource.LocalChanged)
|
||||
this.expectedItemCount += 2
|
||||
let tag = this.application.itemManager.getItems(ContentType.TYPES.Tag)[0]
|
||||
let userPrefs = this.application.itemManager.getItems(ContentType.TYPES.UserPrefs)[0]
|
||||
let tag = this.application.items.getItems(ContentType.TYPES.Tag)[0]
|
||||
let userPrefs = this.application.items.getItems(ContentType.TYPES.UserPrefs)[0]
|
||||
expect(tag).to.be.ok
|
||||
expect(userPrefs).to.be.ok
|
||||
|
||||
@@ -544,11 +544,11 @@ describe('online conflict handling', function () {
|
||||
await this.application.mutator.setItemDirty(userPrefs)
|
||||
userPrefs = this.application.items.findItem(userPrefs.uuid)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(userPrefs).length).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(userPrefs)).to.include(tag)
|
||||
expect(this.application.items.itemsReferencingItem(userPrefs).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(userPrefs)).to.include(tag)
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
tag = await Factory.changePayloadTimeStamp(
|
||||
this.application,
|
||||
@@ -559,32 +559,32 @@ describe('online conflict handling', function () {
|
||||
},
|
||||
)
|
||||
|
||||
await this.application.syncService.sync({ ...syncOptions, awaitAll: true })
|
||||
await this.application.sync.sync({ ...syncOptions, awaitAll: true })
|
||||
|
||||
// fooItem should now be conflicted and a copy created
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const fooItems = this.application.itemManager.getItems(ContentType.TYPES.Tag)
|
||||
const fooItems = this.application.items.getItems(ContentType.TYPES.Tag)
|
||||
const fooItem2 = fooItems[1]
|
||||
|
||||
expect(fooItem2.content.conflict_of).to.equal(tag.uuid)
|
||||
// Two items now link to this original object
|
||||
const referencingItems = this.application.itemManager.itemsReferencingItem(userPrefs)
|
||||
const referencingItems = this.application.items.itemsReferencingItem(userPrefs)
|
||||
expect(referencingItems.length).to.equal(2)
|
||||
expect(referencingItems[0]).to.not.equal(referencingItems[1])
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(tag).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(fooItem2).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(tag).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(fooItem2).length).to.equal(0)
|
||||
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(fooItem2.content.references.length).to.equal(1)
|
||||
expect(userPrefs.content.references.length).to.equal(0)
|
||||
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
for (const item of this.application.itemManager.items) {
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
for (const item of this.application.items.items) {
|
||||
expect(item.dirty).to.not.be.ok
|
||||
}
|
||||
await this.sharedFinalAssertions()
|
||||
@@ -611,7 +611,7 @@ describe('online conflict handling', function () {
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
this.expectedItemCount += 2
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// conflict the note
|
||||
const newText = `${Math.random()}`
|
||||
@@ -645,7 +645,7 @@ describe('online conflict handling', function () {
|
||||
* and not 2 (the note and tag)
|
||||
*/
|
||||
this.expectedItemCount += 1
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
expect(tag.content.references.length).to.equal(2)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
@@ -680,7 +680,7 @@ describe('online conflict handling', function () {
|
||||
await this.application.sync.sync()
|
||||
|
||||
/** Expect that no duplicates have been created, and that the note's title is now finalTitle */
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
const finalNote = this.application.items.findItem(note.uuid)
|
||||
expect(finalNote.title).to.equal(finalTitle)
|
||||
await this.sharedFinalAssertions()
|
||||
@@ -713,8 +713,8 @@ describe('online conflict handling', function () {
|
||||
/**
|
||||
* Retrieve this note from the server by clearing sync token
|
||||
*/
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.syncService.sync({
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.sync.sync({
|
||||
...syncOptions,
|
||||
awaitAll: true,
|
||||
})
|
||||
@@ -724,7 +724,7 @@ describe('online conflict handling', function () {
|
||||
*/
|
||||
const resultNote = await this.application.items.findItem(note.uuid)
|
||||
expect(resultNote.errorDecrypting).to.not.be.ok
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -748,8 +748,8 @@ describe('online conflict handling', function () {
|
||||
/** Create bulk data belonging to another account and sync */
|
||||
const largeItemCount = SyncUpDownLimit + 10
|
||||
await Factory.createManyMappedNotes(this.application, largeItemCount)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
const priorData = this.application.itemManager.items
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const priorData = this.application.items.items
|
||||
|
||||
/** Register new account and import this same data */
|
||||
const newApp = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
@@ -759,9 +759,9 @@ describe('online conflict handling', function () {
|
||||
password: Utils.generateUuid(),
|
||||
})
|
||||
await newApp.mutator.emitItemsFromPayloads(priorData.map((i) => i.payload))
|
||||
await newApp.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await newApp.syncService.sync(syncOptions)
|
||||
expect(newApp.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
await newApp.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
await newApp.sync.sync(syncOptions)
|
||||
expect(newApp.payloads.invalidPayloads.length).to.equal(0)
|
||||
await Factory.safeDeinit(newApp)
|
||||
},
|
||||
).timeout(80000)
|
||||
@@ -787,8 +787,8 @@ describe('online conflict handling', function () {
|
||||
})
|
||||
Factory.handlePasswordChallenges(newApp, password)
|
||||
await newApp.importData(backupFile, true)
|
||||
expect(newApp.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(newApp.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(newApp.items.getDisplayableTags().length).to.equal(1)
|
||||
expect(newApp.items.getDisplayableNotes().length).to.equal(1)
|
||||
await Factory.safeDeinit(newApp)
|
||||
}).timeout(10000)
|
||||
|
||||
@@ -799,7 +799,7 @@ describe('online conflict handling', function () {
|
||||
*/
|
||||
/** Create primary account and export data */
|
||||
await createSyncedNoteWithTag(this.application)
|
||||
const tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
const tag = this.application.items.getDisplayableTags()[0]
|
||||
const note2 = await Factory.createMappedNote(this.application)
|
||||
await this.application.changeAndSaveItem(tag, (mutator) => {
|
||||
mutator.e2ePendingRefactor_addItemAsRelationship(note2)
|
||||
@@ -822,7 +822,7 @@ describe('online conflict handling', function () {
|
||||
})
|
||||
Factory.handlePasswordChallenges(newApp, password)
|
||||
await newApp.importData(backupFile, true)
|
||||
const newTag = newApp.itemManager.getDisplayableTags()[0]
|
||||
const newTag = newApp.items.getDisplayableTags()[0]
|
||||
const notes = newApp.items.referencesForItem(newTag)
|
||||
expect(notes.length).to.equal(2)
|
||||
await Factory.safeDeinit(newApp)
|
||||
@@ -857,7 +857,7 @@ describe('online conflict handling', function () {
|
||||
})
|
||||
await this.application.mutator.emitItemFromPayload(modified)
|
||||
await this.application.sync.sync()
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -881,7 +881,7 @@ describe('online conflict handling', function () {
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.emitItemFromPayload(modified)
|
||||
await this.application.sync.sync()
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(2)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
@@ -913,7 +913,7 @@ describe('online conflict handling', function () {
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.emitItemFromPayload(modified)
|
||||
await this.application.sync.sync()
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(2)
|
||||
await this.sharedFinalAssertions()
|
||||
})
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('sync integrity', () => {
|
||||
|
||||
const awaitSyncEventPromise = (application, targetEvent) => {
|
||||
return new Promise((resolve) => {
|
||||
application.syncService.addEventObserver((event) => {
|
||||
application.sync.addEventObserver((event) => {
|
||||
if (event === targetEvent) {
|
||||
resolve()
|
||||
}
|
||||
@@ -37,8 +37,8 @@ describe('sync integrity', () => {
|
||||
}
|
||||
|
||||
afterEach(async function () {
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
await Factory.safeDeinit(this.application)
|
||||
})
|
||||
@@ -51,10 +51,10 @@ describe('sync integrity', () => {
|
||||
this.expectedItemCount++
|
||||
|
||||
const didEnterOutOfSync = awaitSyncEventPromise(this.application, SyncEvent.EnterOutOfSync)
|
||||
await this.application.syncService.sync({ checkIntegrity: true })
|
||||
await this.application.sync.sync({ checkIntegrity: true })
|
||||
|
||||
await this.application.itemManager.removeItemLocally(item)
|
||||
await this.application.syncService.sync({ checkIntegrity: true, awaitAll: true })
|
||||
await this.application.items.removeItemLocally(item)
|
||||
await this.application.sync.sync({ checkIntegrity: true, awaitAll: true })
|
||||
|
||||
await didEnterOutOfSync
|
||||
})
|
||||
@@ -69,11 +69,11 @@ describe('sync integrity', () => {
|
||||
const didEnterOutOfSync = awaitSyncEventPromise(this.application, SyncEvent.EnterOutOfSync)
|
||||
const didExitOutOfSync = awaitSyncEventPromise(this.application, SyncEvent.ExitOutOfSync)
|
||||
|
||||
await this.application.syncService.sync({ checkIntegrity: true })
|
||||
await this.application.itemManager.removeItemLocally(item)
|
||||
await this.application.syncService.sync({ checkIntegrity: true, awaitAll: true })
|
||||
await this.application.sync.sync({ checkIntegrity: true })
|
||||
await this.application.items.removeItemLocally(item)
|
||||
await this.application.sync.sync({ checkIntegrity: true, awaitAll: true })
|
||||
|
||||
await Promise.all([didEnterOutOfSync, didExitOutOfSync])
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,12 +34,12 @@ describe('notes + tags syncing', function () {
|
||||
it('syncing an item then downloading it should include items_key_id', async function () {
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.payloadManager.resetState()
|
||||
await this.application.itemManager.resetState()
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
const downloadedNote = this.application.itemManager.getDisplayableNotes()[0]
|
||||
await this.application.sync.sync(syncOptions)
|
||||
await this.application.payloads.resetState()
|
||||
await this.application.items.resetState()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const downloadedNote = this.application.items.getDisplayableNotes()[0]
|
||||
expect(downloadedNote.items_key_id).to.not.be.ok
|
||||
// Allow time for waitingForKey
|
||||
await Factory.sleep(0.1)
|
||||
@@ -53,20 +53,20 @@ describe('notes + tags syncing', function () {
|
||||
const tagPayload = pair[1]
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
const note = this.application.itemManager.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = this.application.itemManager.getItems([ContentType.TYPES.Tag])[0]
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
const note = this.application.items.getItems([ContentType.TYPES.Note])[0]
|
||||
const tag = this.application.items.getItems([ContentType.TYPES.Tag])[0]
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(1)
|
||||
|
||||
for (let i = 0; i < 9; i++) {
|
||||
await this.application.mutator.setItemsDirty([note, tag])
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.application.sync.clearSyncPositionTokens()
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(1)
|
||||
console.warn('Waiting 0.1s...')
|
||||
await Factory.sleep(0.1)
|
||||
}
|
||||
@@ -77,32 +77,32 @@ describe('notes + tags syncing', function () {
|
||||
const notePayload = pair[0]
|
||||
const tagPayload = pair[1]
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
const originalNote = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const originalTag = this.application.itemManager.getDisplayableTags()[0]
|
||||
const originalNote = this.application.items.getDisplayableNotes()[0]
|
||||
const originalTag = this.application.items.getDisplayableTags()[0]
|
||||
await this.application.mutator.setItemsDirty([originalNote, originalTag])
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(originalTag.content.references.length).to.equal(1)
|
||||
expect(originalTag.noteCount).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(originalNote).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(originalNote).length).to.equal(1)
|
||||
|
||||
// when signing in, all local items are cleared from storage (but kept in memory; to clear desktop logs),
|
||||
// then resaved with alternated uuids.
|
||||
await this.application.diskStorageService.clearAllPayloads()
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.storage.clearAllPayloads()
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(1)
|
||||
|
||||
const note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
const note = this.application.items.getDisplayableNotes()[0]
|
||||
const tag = this.application.items.getDisplayableTags()[0]
|
||||
|
||||
expect(tag.content.references.length).to.equal(1)
|
||||
expect(note.content.references.length).to.equal(0)
|
||||
|
||||
expect(tag.noteCount).to.equal(1)
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
})
|
||||
|
||||
it('duplicating a tag should maintian its relationships', async function () {
|
||||
@@ -110,22 +110,22 @@ describe('notes + tags syncing', function () {
|
||||
const notePayload = pair[0]
|
||||
const tagPayload = pair[1]
|
||||
await this.application.mutator.emitItemsFromPayloads([notePayload, tagPayload], PayloadEmitSource.LocalChanged)
|
||||
let note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
let tag = this.application.itemManager.getDisplayableTags()[0]
|
||||
expect(this.application.itemManager.itemsReferencingItem(note).length).to.equal(1)
|
||||
let note = this.application.items.getDisplayableNotes()[0]
|
||||
let tag = this.application.items.getDisplayableTags()[0]
|
||||
expect(this.application.items.itemsReferencingItem(note).length).to.equal(1)
|
||||
|
||||
await this.application.mutator.setItemsDirty([note, tag])
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
|
||||
note = this.application.itemManager.findItem(note.uuid)
|
||||
tag = this.application.itemManager.findItem(tag.uuid)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
tag = this.application.items.findItem(tag.uuid)
|
||||
|
||||
expect(note.dirty).to.equal(false)
|
||||
expect(tag.dirty).to.equal(false)
|
||||
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(1)
|
||||
|
||||
await Factory.changePayloadTimeStampAndSync(
|
||||
this.application,
|
||||
@@ -137,13 +137,13 @@ describe('notes + tags syncing', function () {
|
||||
syncOptions,
|
||||
)
|
||||
|
||||
tag = this.application.itemManager.findItem(tag.uuid)
|
||||
tag = this.application.items.findItem(tag.uuid)
|
||||
|
||||
// tag should now be conflicted and a copy created
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableTags().length).to.equal(2)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableTags().length).to.equal(2)
|
||||
|
||||
const tags = this.application.itemManager.getDisplayableTags()
|
||||
const tags = this.application.items.getDisplayableTags()
|
||||
const conflictedTag = tags.find((tag) => {
|
||||
return !!tag.content.conflict_of
|
||||
})
|
||||
@@ -157,11 +157,11 @@ describe('notes + tags syncing', function () {
|
||||
expect(conflictedTag.content.conflict_of).to.equal(originalTag.uuid)
|
||||
expect(conflictedTag.noteCount).to.equal(originalTag.noteCount)
|
||||
|
||||
expect(this.application.itemManager.itemsReferencingItem(conflictedTag).length).to.equal(0)
|
||||
expect(this.application.itemManager.itemsReferencingItem(originalTag).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(conflictedTag).length).to.equal(0)
|
||||
expect(this.application.items.itemsReferencingItem(originalTag).length).to.equal(0)
|
||||
|
||||
// Two tags now link to this note
|
||||
const referencingItems = this.application.itemManager.itemsReferencingItem(note)
|
||||
const referencingItems = this.application.items.itemsReferencingItem(note)
|
||||
expect(referencingItems.length).to.equal(2)
|
||||
expect(referencingItems[0]).to.not.equal(referencingItems[1])
|
||||
}).timeout(10000)
|
||||
|
||||
@@ -19,7 +19,7 @@ describe('offline syncing', () => {
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
await Factory.safeDeinit(this.application)
|
||||
})
|
||||
|
||||
@@ -38,19 +38,19 @@ describe('offline syncing', () => {
|
||||
await Factory.alternateUuidForItem(this.application, note.uuid)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const notes = this.application.itemManager.getDisplayableNotes()
|
||||
const notes = this.application.items.getDisplayableNotes()
|
||||
expect(notes.length).to.equal(1)
|
||||
expect(notes[0].uuid).to.not.equal(note.uuid)
|
||||
|
||||
const items = this.application.itemManager.allTrackedItems()
|
||||
const items = this.application.items.allTrackedItems()
|
||||
expect(items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('should sync item with no passcode', async function () {
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
expect(Uuids(this.application.itemManager.getDirtyItems()).includes(note.uuid))
|
||||
expect(Uuids(this.application.items.getDirtyItems()).includes(note.uuid))
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
|
||||
@@ -59,9 +59,9 @@ describe('offline syncing', () => {
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
|
||||
const rawPayloads2 = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads2 = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads2.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const itemsKeyRaw = (await Factory.getStoragePayloadsOfType(this.application, ContentType.TYPES.ItemsKey))[0]
|
||||
@@ -77,26 +77,26 @@ describe('offline syncing', () => {
|
||||
it('should sync item encrypted with passcode', async function () {
|
||||
await this.application.addPasscode('foobar')
|
||||
await Factory.createMappedNote(this.application)
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(1)
|
||||
const rawPayloads1 = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(1)
|
||||
const rawPayloads1 = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads1.length).to.equal(this.expectedItemCount)
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.expectedItemCount++
|
||||
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
const rawPayloads2 = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
const rawPayloads2 = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads2.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const payload = rawPayloads2[0]
|
||||
expect(typeof payload.content).to.equal('string')
|
||||
expect(payload.content.startsWith(this.application.encryptionService.getLatestVersion())).to.equal(true)
|
||||
expect(payload.content.startsWith(this.application.encryption.getLatestVersion())).to.equal(true)
|
||||
})
|
||||
|
||||
it('signing out while offline should succeed', async function () {
|
||||
await Factory.createMappedNote(this.application)
|
||||
this.expectedItemCount++
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
expect(this.application.noAccount()).to.equal(true)
|
||||
expect(this.application.getUser()).to.not.be.ok
|
||||
|
||||
@@ -42,12 +42,12 @@ describe('online syncing', function () {
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
|
||||
const items = this.application.itemManager.allTrackedItems()
|
||||
const items = this.application.items.allTrackedItems()
|
||||
expect(items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
await Factory.safeDeinit(this.application)
|
||||
localStorage.clear()
|
||||
@@ -60,11 +60,11 @@ describe('online syncing', function () {
|
||||
it('should register and sync basic model online', async function () {
|
||||
let note = await Factory.createSyncedNote(this.application)
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
expect(note.dirty).to.not.be.ok
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const notePayloads = noteObjectsFromObjects(rawPayloads)
|
||||
expect(notePayloads.length).to.equal(1)
|
||||
for (const rawNote of notePayloads) {
|
||||
@@ -83,7 +83,7 @@ describe('online syncing', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
const notes = this.application.itemManager.getDisplayableNotes()
|
||||
const notes = this.application.items.getDisplayableNotes()
|
||||
expect(notes.length).to.equal(1)
|
||||
expect(notes[0].title).to.equal(note.title)
|
||||
})
|
||||
@@ -99,7 +99,7 @@ describe('online syncing', function () {
|
||||
|
||||
this.application = await this.context.signout()
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
expect(this.application.items.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
const promise = Factory.loginToApplication({
|
||||
application: this.application,
|
||||
@@ -132,7 +132,7 @@ describe('online syncing', function () {
|
||||
mergeLocal: true,
|
||||
})
|
||||
|
||||
const notes = this.application.itemManager.getDisplayableNotes()
|
||||
const notes = this.application.items.getDisplayableNotes()
|
||||
expect(notes.length).to.equal(1)
|
||||
/** uuid should have been alternated */
|
||||
expect(notes[0].uuid).to.equal(note.uuid)
|
||||
@@ -143,8 +143,8 @@ describe('online syncing', function () {
|
||||
let successes = 0
|
||||
let events = 0
|
||||
|
||||
this.application.syncService.ut_beginLatencySimulator(250)
|
||||
this.application.syncService.addEventObserver((event, data) => {
|
||||
this.application.sync.ut_beginLatencySimulator(250)
|
||||
this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded) {
|
||||
events++
|
||||
}
|
||||
@@ -153,7 +153,7 @@ describe('online syncing', function () {
|
||||
const promises = []
|
||||
for (let i = 0; i < syncCount; i++) {
|
||||
promises.push(
|
||||
this.application.syncService
|
||||
this.application.sync
|
||||
.sync({
|
||||
queueStrategy: SyncQueueStrategy.ResolveOnNext,
|
||||
})
|
||||
@@ -169,7 +169,7 @@ describe('online syncing', function () {
|
||||
// We don't know how many will execute above.
|
||||
expect(events).to.be.at.least(1)
|
||||
|
||||
this.application.syncService.ut_endLatencySimulator()
|
||||
this.application.sync.ut_endLatencySimulator()
|
||||
// Since the syncs all happen after one another, extra syncs may be queued on that we are not awaiting.
|
||||
await Factory.sleep(0.5)
|
||||
})
|
||||
@@ -179,9 +179,9 @@ describe('online syncing', function () {
|
||||
let successes = 0
|
||||
let events = 0
|
||||
|
||||
this.application.syncService.ut_beginLatencySimulator(250)
|
||||
this.application.sync.ut_beginLatencySimulator(250)
|
||||
|
||||
this.application.syncService.addEventObserver((event, data) => {
|
||||
this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded) {
|
||||
events++
|
||||
}
|
||||
@@ -190,7 +190,7 @@ describe('online syncing', function () {
|
||||
const promises = []
|
||||
for (let i = 0; i < syncCount; i++) {
|
||||
promises.push(
|
||||
this.application.syncService
|
||||
this.application.sync
|
||||
.sync({
|
||||
queueStrategy: SyncQueueStrategy.ForceSpawnNew,
|
||||
})
|
||||
@@ -202,7 +202,7 @@ describe('online syncing', function () {
|
||||
await Promise.all(promises)
|
||||
expect(successes).to.equal(syncCount)
|
||||
expect(events).to.equal(syncCount)
|
||||
this.application.syncService.ut_endLatencySimulator()
|
||||
this.application.sync.ut_endLatencySimulator()
|
||||
})
|
||||
|
||||
it('retrieving new items should not mark them as dirty', async function () {
|
||||
@@ -211,7 +211,7 @@ describe('online syncing', function () {
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
const promise = new Promise((resolve) => {
|
||||
this.application.syncService.addEventObserver(async (event) => {
|
||||
this.application.sync.addEventObserver(async (event) => {
|
||||
if (event === SyncEvent.PaginatedSyncRequestCompleted) {
|
||||
const note = this.application.items.findItem(originalNote.uuid)
|
||||
if (note) {
|
||||
@@ -226,22 +226,22 @@ describe('online syncing', function () {
|
||||
})
|
||||
|
||||
it('allows saving of data after sign out', async function () {
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
this.expectedItemCount++
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const notePayload = noteObjectsFromObjects(rawPayloads)
|
||||
expect(notePayload.length).to.equal(1)
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
|
||||
// set item to be merged for when sign in occurs
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
|
||||
// Sign back in for next tests
|
||||
await Factory.loginToApplication({
|
||||
@@ -250,16 +250,16 @@ describe('online syncing', function () {
|
||||
password: this.password,
|
||||
})
|
||||
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.sync.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
|
||||
for (const item of this.application.itemManager.getDisplayableNotes()) {
|
||||
for (const item of this.application.items.getDisplayableNotes()) {
|
||||
expect(item.content.title).to.be.ok
|
||||
}
|
||||
|
||||
const updatedRawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const updatedRawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
for (const payload of updatedRawPayloads) {
|
||||
// if an item comes back from the server, it is saved to disk immediately without a dirty value.
|
||||
expect(payload.dirty).to.not.be.ok
|
||||
@@ -274,10 +274,10 @@ describe('online syncing', function () {
|
||||
const originalTitle = note.content.title
|
||||
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const encrypted = CreateEncryptedServerSyncPushPayload(
|
||||
await this.application.encryptionService.encryptSplitSingle({
|
||||
await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note.payloadRepresentation()],
|
||||
},
|
||||
@@ -291,11 +291,11 @@ describe('online syncing', function () {
|
||||
|
||||
const items = await this.application.mutator.emitItemsFromPayloads([errorred], PayloadEmitSource.LocalChanged)
|
||||
|
||||
const mappedItem = this.application.itemManager.findAnyItem(errorred.uuid)
|
||||
const mappedItem = this.application.items.findAnyItem(errorred.uuid)
|
||||
|
||||
expect(typeof mappedItem.content).to.equal('string')
|
||||
|
||||
const decryptedPayload = await this.application.encryptionService.decryptSplitSingle({
|
||||
const decryptedPayload = await this.application.encryption.decryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [errorred],
|
||||
},
|
||||
@@ -319,7 +319,7 @@ describe('online syncing', function () {
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('removes item from storage upon deletion', async function () {
|
||||
@@ -327,41 +327,41 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
expect(note.dirty).to.equal(false)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
await this.application.mutator.setItemToBeDeleted(note)
|
||||
note = this.application.items.findAnyItem(note.uuid)
|
||||
expect(note.dirty).to.equal(true)
|
||||
this.expectedItemCount--
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
expect(note).to.not.be.ok
|
||||
|
||||
// We expect that this item is now gone for good, and no duplicate has been created.
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
await Factory.sleep(0.5)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('retrieving item with no content should correctly map local state', async function () {
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const syncToken = await this.application.syncService.getLastSyncToken()
|
||||
const syncToken = await this.application.sync.getLastSyncToken()
|
||||
|
||||
this.expectedItemCount++
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
// client A
|
||||
await this.application.mutator.setItemToBeDeleted(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// Subtract 1
|
||||
this.expectedItemCount--
|
||||
@@ -369,10 +369,10 @@ describe('online syncing', function () {
|
||||
// client B
|
||||
// Clearing sync tokens wont work as server wont return deleted items.
|
||||
// Set saved sync token instead
|
||||
await this.application.syncService.setLastSyncToken(syncToken)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.setLastSyncToken(syncToken)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('changing an item while it is being synced should sync again', async function () {
|
||||
@@ -381,7 +381,7 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Begin syncing it with server but introduce latency so we can sneak in a delete */
|
||||
this.application.syncService.ut_beginLatencySimulator(500)
|
||||
this.application.sync.ut_beginLatencySimulator(500)
|
||||
|
||||
const sync = this.application.sync.sync()
|
||||
|
||||
@@ -395,11 +395,11 @@ describe('online syncing', function () {
|
||||
|
||||
await sync
|
||||
|
||||
this.application.syncService.ut_endLatencySimulator()
|
||||
this.application.sync.ut_endLatencySimulator()
|
||||
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const latestNote = this.application.itemManager.findItem(note.uuid)
|
||||
const latestNote = this.application.items.findItem(note.uuid)
|
||||
expect(latestNote.title).to.equal('latest title')
|
||||
})
|
||||
|
||||
@@ -409,7 +409,7 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Begin syncing it with server but introduce latency so we can sneak in a delete */
|
||||
this.application.syncService.ut_beginLatencySimulator(500)
|
||||
this.application.sync.ut_beginLatencySimulator(500)
|
||||
|
||||
const sync = this.application.sync.sync()
|
||||
|
||||
@@ -423,12 +423,12 @@ describe('online syncing', function () {
|
||||
|
||||
await sync
|
||||
|
||||
this.application.syncService.ut_endLatencySimulator()
|
||||
this.application.sync.ut_endLatencySimulator()
|
||||
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
/** We expect that item has been deleted */
|
||||
const allItems = this.application.itemManager.items
|
||||
const allItems = this.application.items.items
|
||||
expect(allItems.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
@@ -440,7 +440,7 @@ describe('online syncing', function () {
|
||||
let success = true
|
||||
let didCompleteRelevantSync = false
|
||||
let beginCheckingResponse = false
|
||||
this.application.syncService.addEventObserver((eventName, data) => {
|
||||
this.application.sync.addEventObserver((eventName, data) => {
|
||||
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
|
||||
beginCheckingResponse = true
|
||||
}
|
||||
@@ -456,7 +456,7 @@ describe('online syncing', function () {
|
||||
}
|
||||
}
|
||||
})
|
||||
await this.application.syncService.sync({ mode: SyncMode.DownloadFirst })
|
||||
await this.application.sync.sync({ mode: SyncMode.DownloadFirst })
|
||||
expect(didCompleteRelevantSync).to.equal(true)
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
@@ -469,7 +469,7 @@ describe('online syncing', function () {
|
||||
let success = true
|
||||
let didCompleteRelevantSync = false
|
||||
let beginCheckingResponse = false
|
||||
this.application.syncService.addEventObserver(async (eventName, data) => {
|
||||
this.application.sync.addEventObserver(async (eventName, data) => {
|
||||
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
|
||||
await this.application.mutator.setItemToBeDeleted(note)
|
||||
beginCheckingResponse = true
|
||||
@@ -486,7 +486,7 @@ describe('online syncing', function () {
|
||||
}
|
||||
}
|
||||
})
|
||||
await this.application.syncService.sync({ mode: SyncMode.DownloadFirst })
|
||||
await this.application.sync.sync({ mode: SyncMode.DownloadFirst })
|
||||
expect(didCompleteRelevantSync).to.equal(true)
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
@@ -496,16 +496,16 @@ describe('online syncing', function () {
|
||||
|
||||
this.expectedItemCount++
|
||||
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
|
||||
|
||||
this.application.itemManager.resetState()
|
||||
this.application.payloadManager.resetState()
|
||||
this.application.items.resetState()
|
||||
this.application.payloads.resetState()
|
||||
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(0)
|
||||
expect(this.application.items.items.length).to.equal(0)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
|
||||
const encryptedPayloads = rawPayloads.map((rawPayload) => {
|
||||
return new EncryptedPayload(rawPayload)
|
||||
@@ -515,17 +515,17 @@ describe('online syncing', function () {
|
||||
|
||||
const keyedSplit = CreateDecryptionSplitWithKeyLookup(encryptionSplit)
|
||||
|
||||
const decryptionResults = await this.application.encryptionService.decryptSplit(keyedSplit)
|
||||
const decryptionResults = await this.application.encryption.decryptSplit(keyedSplit)
|
||||
|
||||
await this.application.mutator.emitItemsFromPayloads(decryptionResults, PayloadEmitSource.LocalChanged)
|
||||
|
||||
expect(this.application.itemManager.allTrackedItems().length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.allTrackedItems().length).to.equal(this.expectedItemCount)
|
||||
|
||||
const foundNote = this.application.itemManager.findAnyItem(note.uuid)
|
||||
const foundNote = this.application.items.findAnyItem(note.uuid)
|
||||
|
||||
expect(foundNote.dirty).to.equal(true)
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
})
|
||||
|
||||
/** Temporarily skipping due to long run time */
|
||||
@@ -538,8 +538,8 @@ describe('online syncing', function () {
|
||||
|
||||
this.expectedItemCount += largeItemCount
|
||||
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
}).timeout(15000)
|
||||
|
||||
@@ -551,32 +551,32 @@ describe('online syncing', function () {
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
}
|
||||
/** Upload */
|
||||
this.application.syncService.sync({ awaitAll: true, checkIntegrity: false })
|
||||
this.application.sync.sync({ awaitAll: true, checkIntegrity: false })
|
||||
await this.context.awaitNextSucessfulSync()
|
||||
this.expectedItemCount += largeItemCount
|
||||
|
||||
/** Clear local data */
|
||||
await this.application.payloadManager.resetState()
|
||||
await this.application.itemManager.resetState()
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.diskStorageService.clearAllPayloads()
|
||||
expect(this.application.itemManager.items.length).to.equal(0)
|
||||
await this.application.payloads.resetState()
|
||||
await this.application.items.resetState()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.storage.clearAllPayloads()
|
||||
expect(this.application.items.items.length).to.equal(0)
|
||||
|
||||
/** Download all data */
|
||||
this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.sync(syncOptions)
|
||||
await this.context.awaitNextSucessfulSync()
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
}).timeout(30000)
|
||||
|
||||
it('syncing an item should storage it encrypted', async function () {
|
||||
const note = await Factory.createMappedNote(this.application)
|
||||
await this.application.mutator.setItemDirty(note)
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
this.expectedItemCount++
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const notePayload = rawPayloads.find((p) => p.content_type === ContentType.TYPES.Note)
|
||||
expect(typeof notePayload.content).to.equal('string')
|
||||
})
|
||||
@@ -587,12 +587,12 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Simulate database not loaded */
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
this.application.syncService.ut_setDatabaseLoaded(false)
|
||||
this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
this.application.sync.ut_setDatabaseLoaded(false)
|
||||
this.application.sync.sync(syncOptions)
|
||||
await Factory.sleep(0.3)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const notePayload = rawPayloads.find((p) => p.content_type === ContentType.TYPES.Note)
|
||||
expect(typeof notePayload.content).to.equal('string')
|
||||
})
|
||||
@@ -610,18 +610,18 @@ describe('online syncing', function () {
|
||||
syncOptions,
|
||||
)
|
||||
this.expectedItemCount++
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
const notePayload = rawPayloads.find((p) => p.content_type === ContentType.TYPES.Note)
|
||||
expect(typeof notePayload.content).to.equal('string')
|
||||
expect(notePayload.content.length).to.be.above(text.length)
|
||||
})
|
||||
|
||||
it('syncing a new item before local data has loaded should still persist the item to disk', async function () {
|
||||
this.application.syncService.ut_setDatabaseLoaded(false)
|
||||
this.application.sync.ut_setDatabaseLoaded(false)
|
||||
/** You don't want to clear model manager state as we'll lose encrypting items key */
|
||||
// await this.application.payloadManager.resetState();
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(0)
|
||||
// await this.application.payloads.resetState();
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(0)
|
||||
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
note = await this.application.mutator.changeItem(note, (mutator) => {
|
||||
@@ -629,15 +629,15 @@ describe('online syncing', function () {
|
||||
})
|
||||
/** This sync request should exit prematurely as we called ut_setDatabaseNotLoaded */
|
||||
/** Do not await. Sleep instead. */
|
||||
this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.sync(syncOptions)
|
||||
await Factory.sleep(0.3)
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Item should still be dirty */
|
||||
expect(note.dirty).to.equal(true)
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(1)
|
||||
expect(this.application.items.getDirtyItems().length).to.equal(1)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(this.expectedItemCount)
|
||||
const rawPayload = rawPayloads.find((p) => p.uuid === note.uuid)
|
||||
expect(rawPayload.uuid).to.equal(note.uuid)
|
||||
@@ -645,16 +645,16 @@ describe('online syncing', function () {
|
||||
expect(typeof rawPayload.content).to.equal('string')
|
||||
|
||||
/** Clear state data and upload item from storage to server */
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.payloadManager.resetState()
|
||||
await this.application.itemManager.resetState()
|
||||
await this.application.syncService.loadDatabasePayloads()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.payloads.resetState()
|
||||
await this.application.items.resetState()
|
||||
await this.application.sync.loadDatabasePayloads()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const newRawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
const newRawPayloads = await this.application.storage.getAllRawPayloads()
|
||||
expect(newRawPayloads.length).to.equal(this.expectedItemCount)
|
||||
|
||||
const currentItem = this.application.itemManager.findItem(note.uuid)
|
||||
const currentItem = this.application.items.findItem(note.uuid)
|
||||
expect(currentItem.content.text).to.equal(note.content.text)
|
||||
expect(currentItem.text).to.equal(note.text)
|
||||
expect(currentItem.dirty).to.not.be.ok
|
||||
@@ -680,16 +680,16 @@ describe('online syncing', function () {
|
||||
const largeItemCount = 50
|
||||
await Factory.createManyMappedNotes(this.application, largeItemCount)
|
||||
this.expectedItemCount += largeItemCount
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
|
||||
this.application.syncService.ut_setDatabaseLoaded(false)
|
||||
await this.application.syncService.loadDatabasePayloads()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.ut_setDatabaseLoaded(false)
|
||||
await this.application.sync.loadDatabasePayloads()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const items = await this.application.itemManager.items
|
||||
const items = await this.application.items.items
|
||||
expect(items.length).to.equal(this.expectedItemCount)
|
||||
}).timeout(20000)
|
||||
|
||||
@@ -717,7 +717,7 @@ describe('online syncing', function () {
|
||||
it('syncing twice without waiting should only execute 1 online sync', async function () {
|
||||
const expectedEvents = 1
|
||||
let actualEvents = 0
|
||||
this.application.syncService.addEventObserver((event, data) => {
|
||||
this.application.sync.addEventObserver((event, data) => {
|
||||
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded && data.source === SyncSource.External) {
|
||||
actualEvents++
|
||||
}
|
||||
@@ -742,8 +742,8 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
// client A. Don't await, we want to do other stuff.
|
||||
this.application.syncService.ut_beginLatencySimulator(1500)
|
||||
const slowSync = this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.ut_beginLatencySimulator(1500)
|
||||
const slowSync = this.application.sync.sync(syncOptions)
|
||||
await Factory.sleep(0.1)
|
||||
expect(note.dirty).to.equal(true)
|
||||
|
||||
@@ -758,8 +758,8 @@ describe('online syncing', function () {
|
||||
expect(note.payload.dirtyIndex).to.be.above(note.payload.globalDirtyIndexAtLastSync)
|
||||
|
||||
// Now do a regular sync with no latency.
|
||||
this.application.syncService.ut_endLatencySimulator()
|
||||
const midSync = this.application.syncService.sync(syncOptions)
|
||||
this.application.sync.ut_endLatencySimulator()
|
||||
const midSync = this.application.sync.sync(syncOptions)
|
||||
|
||||
await slowSync
|
||||
await midSync
|
||||
@@ -770,14 +770,14 @@ describe('online syncing', function () {
|
||||
expect(note.content.text).to.equal(text)
|
||||
|
||||
// client B
|
||||
await this.application.payloadManager.resetState()
|
||||
await this.application.itemManager.resetState()
|
||||
await this.application.syncService.clearSyncPositionTokens()
|
||||
await this.application.syncService.sync(syncOptions)
|
||||
await this.application.payloads.resetState()
|
||||
await this.application.items.resetState()
|
||||
await this.application.sync.clearSyncPositionTokens()
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
// Expect that the server value and client value match, and no conflicts are created.
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
const foundItem = this.application.itemManager.findItem(note.uuid)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
const foundItem = this.application.items.findItem(note.uuid)
|
||||
expect(foundItem.content.text).to.equal(text)
|
||||
expect(foundItem.text).to.equal(text)
|
||||
})
|
||||
@@ -790,17 +790,17 @@ describe('online syncing', function () {
|
||||
/** Create an item and sync it */
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
|
||||
this.application.itemManager.addObserver(ContentType.TYPES.Note, ({ source }) => {
|
||||
this.application.items.addObserver(ContentType.TYPES.Note, ({ source }) => {
|
||||
if (source === PayloadEmitSource.RemoteSaved) {
|
||||
actualSaveCount++
|
||||
}
|
||||
})
|
||||
|
||||
this.expectedItemCount++
|
||||
this.application.syncService.ut_beginLatencySimulator(150)
|
||||
this.application.sync.ut_beginLatencySimulator(150)
|
||||
|
||||
/** Dont await */
|
||||
const syncRequest = this.application.syncService.sync(syncOptions)
|
||||
const syncRequest = this.application.sync.sync(syncOptions)
|
||||
|
||||
/** Dirty the item 100ms into 150ms request */
|
||||
const newText = `${Math.random()}`
|
||||
@@ -837,7 +837,7 @@ describe('online syncing', function () {
|
||||
/** Create an item and sync it */
|
||||
let note = await Factory.createMappedNote(this.application)
|
||||
|
||||
this.application.itemManager.addObserver(ContentType.TYPES.Note, ({ source }) => {
|
||||
this.application.items.addObserver(ContentType.TYPES.Note, ({ source }) => {
|
||||
if (source === PayloadEmitSource.RemoteSaved) {
|
||||
actualSaveCount++
|
||||
}
|
||||
@@ -845,13 +845,13 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Dont await */
|
||||
const syncRequest = this.application.syncService.sync(syncOptions)
|
||||
const syncRequest = this.application.sync.sync(syncOptions)
|
||||
|
||||
/** Dirty the item before lastSyncBegan is set */
|
||||
let didPerformMutatation = false
|
||||
const newText = `${Math.random()}`
|
||||
|
||||
this.application.syncService.addEventObserver(async (eventName) => {
|
||||
this.application.sync.addEventObserver(async (eventName) => {
|
||||
if (eventName === SyncEvent.SyncDidBeginProcessing && !didPerformMutatation) {
|
||||
didPerformMutatation = true
|
||||
await this.application.mutator.changeItem(note, (mutator) => {
|
||||
@@ -876,7 +876,7 @@ describe('online syncing', function () {
|
||||
let didPerformMutatation = false
|
||||
const newText = `${Math.random()}`
|
||||
|
||||
this.application.itemManager.addObserver(ContentType.TYPES.Note, async ({ changed, source }) => {
|
||||
this.application.items.addObserver(ContentType.TYPES.Note, async ({ changed, source }) => {
|
||||
if (source === PayloadEmitSource.RemoteSaved) {
|
||||
actualSaveCount++
|
||||
} else if (source === PayloadEmitSource.PreSyncSave && !didPerformMutatation) {
|
||||
@@ -895,7 +895,7 @@ describe('online syncing', function () {
|
||||
this.expectedItemCount++
|
||||
|
||||
/** Dont await */
|
||||
const syncRequest = this.application.syncService.sync(syncOptions)
|
||||
const syncRequest = this.application.sync.sync(syncOptions)
|
||||
await syncRequest
|
||||
expect(actualSaveCount).to.equal(expectedSaveCount)
|
||||
note = this.application.items.findItem(note.uuid)
|
||||
@@ -904,12 +904,12 @@ describe('online syncing', function () {
|
||||
|
||||
it('retreiving a remote deleted item should succeed', async function () {
|
||||
const note = await Factory.createSyncedNote(this.application)
|
||||
const preDeleteSyncToken = await this.application.syncService.getLastSyncToken()
|
||||
const preDeleteSyncToken = await this.application.sync.getLastSyncToken()
|
||||
await this.application.mutator.deleteItem(note)
|
||||
await this.application.sync.sync()
|
||||
await this.application.syncService.setLastSyncToken(preDeleteSyncToken)
|
||||
await this.application.sync.setLastSyncToken(preDeleteSyncToken)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
expect(this.application.itemManager.items.length).to.equal(this.expectedItemCount)
|
||||
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
|
||||
})
|
||||
|
||||
it('errored items should not be synced', async function () {
|
||||
@@ -918,7 +918,7 @@ describe('online syncing', function () {
|
||||
const lastSyncBegan = note.lastSyncBegan
|
||||
const lastSyncEnd = note.lastSyncEnd
|
||||
|
||||
const encrypted = await this.application.encryptionService.encryptSplitSingle({
|
||||
const encrypted = await this.application.encryption.encryptSplitSingle({
|
||||
usesItemsKeyWithKeyLookup: {
|
||||
items: [note.payload],
|
||||
},
|
||||
@@ -929,7 +929,7 @@ describe('online syncing', function () {
|
||||
dirty: true,
|
||||
})
|
||||
|
||||
await this.application.payloadManager.emitPayload(errored)
|
||||
await this.application.payloads.emitPayload(errored)
|
||||
await this.application.sync.sync(syncOptions)
|
||||
|
||||
const updatedNote = this.application.items.findAnyItem(note.uuid)
|
||||
@@ -957,10 +957,10 @@ describe('online syncing', function () {
|
||||
},
|
||||
})
|
||||
|
||||
await this.application.syncService.handleSuccessServerResponse({ payloadsSavedOrSaving: [], options: {} }, response)
|
||||
await this.application.sync.handleSuccessServerResponse({ payloadsSavedOrSaving: [], options: {} }, response)
|
||||
|
||||
expect(this.application.payloadManager.findOne(invalidPayload.uuid)).to.not.be.ok
|
||||
expect(this.application.payloadManager.findOne(validPayload.uuid)).to.be.ok
|
||||
expect(this.application.payloads.findOne(invalidPayload.uuid)).to.not.be.ok
|
||||
expect(this.application.payloads.findOne(validPayload.uuid)).to.be.ok
|
||||
})
|
||||
|
||||
it('retrieved items should have both updated_at and updated_at_timestamps', async function () {
|
||||
@@ -996,13 +996,13 @@ describe('online syncing', function () {
|
||||
|
||||
it('should call onPresyncSave before sync begins', async function () {
|
||||
const events = []
|
||||
this.application.syncService.addEventObserver((event) => {
|
||||
this.application.sync.addEventObserver((event) => {
|
||||
if (event === SyncEvent.SyncDidBeginProcessing) {
|
||||
events.push('sync-will-begin')
|
||||
}
|
||||
})
|
||||
|
||||
await this.application.syncService.sync({
|
||||
await this.application.sync.sync({
|
||||
onPresyncSave: () => {
|
||||
events.push('on-presync-save')
|
||||
},
|
||||
|
||||
@@ -92,11 +92,11 @@ describe('upgrading', () => {
|
||||
version: oldVersion,
|
||||
})
|
||||
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
oldVersion,
|
||||
)
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
|
||||
this.application.setLaunchCallback({
|
||||
receiveChallenge: this.receiveChallenge,
|
||||
@@ -104,15 +104,15 @@ describe('upgrading', () => {
|
||||
const result = await this.application.upgradeProtocolVersion()
|
||||
expect(result).to.deep.equal({ success: true })
|
||||
|
||||
const wrappedRootKey = await this.application.encryptionService.rootKeyManager.getWrappedRootKey()
|
||||
const wrappedRootKey = await this.application.encryption.rootKeyManager.getWrappedRootKey()
|
||||
const payload = new EncryptedPayload(wrappedRootKey)
|
||||
expect(payload.version).to.equal(newVersion)
|
||||
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
newVersion,
|
||||
)
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(newVersion)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(newVersion)
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(newVersion)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(newVersion)
|
||||
|
||||
/**
|
||||
* Immediately logging out ensures we don't rely on subsequent
|
||||
@@ -120,8 +120,8 @@ describe('upgrading', () => {
|
||||
*/
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
expect(this.application.itemManager.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.payloadManager.invalidPayloads).to.be.empty
|
||||
expect(this.application.items.getDisplayableNotes().length).to.equal(1)
|
||||
expect(this.application.payloads.invalidPayloads).to.be.empty
|
||||
}).timeout(15000)
|
||||
|
||||
it('upgrading from 003 to 004 with passcode only then reiniting app should create valid state', async function () {
|
||||
@@ -155,7 +155,7 @@ describe('upgrading', () => {
|
||||
await appFirst.launch(true)
|
||||
const result = await appFirst.upgradeProtocolVersion()
|
||||
expect(result).to.deep.equal({ success: true })
|
||||
expect(appFirst.payloadManager.invalidPayloads).to.be.empty
|
||||
expect(appFirst.payloads.invalidPayloads).to.be.empty
|
||||
await Factory.safeDeinit(appFirst)
|
||||
|
||||
/** Recreate the once more */
|
||||
@@ -166,15 +166,15 @@ describe('upgrading', () => {
|
||||
},
|
||||
})
|
||||
await appSecond.launch(true)
|
||||
expect(appSecond.payloadManager.invalidPayloads).to.be.empty
|
||||
expect(appSecond.payloads.invalidPayloads).to.be.empty
|
||||
await Factory.safeDeinit(appSecond)
|
||||
}).timeout(15000)
|
||||
|
||||
it('protocol version should be upgraded on password change', async function () {
|
||||
/** Delete default items key that is created on launch */
|
||||
const itemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const itemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
await this.application.mutator.setItemToBeDeleted(itemsKey)
|
||||
expect(Uuids(this.application.itemManager.getDisplayableItemsKeys()).includes(itemsKey.uuid)).to.equal(false)
|
||||
expect(Uuids(this.application.items.getDisplayableItemsKeys()).includes(itemsKey.uuid)).to.equal(false)
|
||||
|
||||
Factory.createMappedNote(this.application)
|
||||
|
||||
@@ -186,10 +186,10 @@ describe('upgrading', () => {
|
||||
version: ProtocolVersion.V003,
|
||||
})
|
||||
|
||||
expect(this.application.itemManager.getDisplayableItemsKeys().length).to.equal(1)
|
||||
expect(this.application.items.getDisplayableItemsKeys().length).to.equal(1)
|
||||
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(ProtocolVersion.V003)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(ProtocolVersion.V003)
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(ProtocolVersion.V003)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(ProtocolVersion.V003)
|
||||
|
||||
/** Ensure note is encrypted with 003 */
|
||||
const notePayloads = await Factory.getStoragePayloadsOfType(this.application, ContentType.TYPES.Note)
|
||||
@@ -199,16 +199,16 @@ describe('upgrading', () => {
|
||||
const { error } = await this.application.changePassword(this.password, 'foobarfoo')
|
||||
expect(error).to.not.exist
|
||||
|
||||
const latestVersion = this.application.encryptionService.getLatestVersion()
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(latestVersion)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(latestVersion)
|
||||
const latestVersion = this.application.encryption.getLatestVersion()
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(latestVersion)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(latestVersion)
|
||||
|
||||
const defaultItemsKey = await this.application.encryptionService.getSureDefaultItemsKey()
|
||||
const defaultItemsKey = await this.application.encryption.getSureDefaultItemsKey()
|
||||
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
||||
|
||||
/** After change, note should now be encrypted with latest protocol version */
|
||||
|
||||
const note = this.application.itemManager.getDisplayableNotes()[0]
|
||||
const note = this.application.items.getDisplayableNotes()[0]
|
||||
await Factory.markDirtyAndSyncItem(this.application, note)
|
||||
|
||||
const refreshedNotePayloads = await Factory.getStoragePayloadsOfType(this.application, ContentType.TYPES.Note)
|
||||
@@ -243,44 +243,44 @@ describe('upgrading', () => {
|
||||
})
|
||||
|
||||
it('rolls back the local protocol upgrade if syncing fails', async function () {
|
||||
sinon.replace(this.application.syncService, 'sync', sinon.fake())
|
||||
sinon.replace(this.application.sync, 'sync', sinon.fake())
|
||||
this.application.setLaunchCallback({
|
||||
receiveChallenge: this.receiveChallenge,
|
||||
})
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
oldVersion,
|
||||
)
|
||||
const errors = await this.application.upgradeProtocolVersion()
|
||||
expect(errors).to.not.be.empty
|
||||
|
||||
/** Ensure we're still on 003 */
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
oldVersion,
|
||||
)
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryptionService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||
})
|
||||
|
||||
it('rolls back the local protocol upgrade if the server responds with an error', async function () {
|
||||
sinon.replace(this.application.sessionManager, 'changeCredentials', () => [Error()])
|
||||
sinon.replace(this.application.sessions, 'changeCredentials', () => [Error()])
|
||||
|
||||
this.application.setLaunchCallback({
|
||||
receiveChallenge: this.receiveChallenge,
|
||||
})
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
oldVersion,
|
||||
)
|
||||
const errors = await this.application.upgradeProtocolVersion()
|
||||
expect(errors).to.not.be.empty
|
||||
|
||||
/** Ensure we're still on 003 */
|
||||
expect((await this.application.encryptionService.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
expect((await this.application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(
|
||||
oldVersion,
|
||||
)
|
||||
expect((await this.application.encryptionService.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryptionService.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryptionService.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
||||
expect((await this.application.encryption.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,10 +34,14 @@ describe('asymmetric messages', function () {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
const eventData = {
|
||||
oldKeyPair: context.encryption.getKeyPair(),
|
||||
oldSigningKeyPair: context.encryption.getSigningKeyPair(),
|
||||
newKeyPair: context.encryption.getKeyPair(),
|
||||
newSigningKeyPair: context.encryption.getSigningKeyPair(),
|
||||
current: {
|
||||
encryption: context.encryption.getKeyPair(),
|
||||
signing: context.encryption.getSigningKeyPair(),
|
||||
},
|
||||
previous: {
|
||||
encryption: context.encryption.getKeyPair(),
|
||||
signing: context.encryption.getSigningKeyPair(),
|
||||
},
|
||||
}
|
||||
|
||||
await service.sendOwnContactChangeEventToAllContacts(eventData)
|
||||
@@ -92,6 +96,38 @@ describe('asymmetric messages', function () {
|
||||
await deinitThirdPartyContext()
|
||||
})
|
||||
|
||||
it('should send contact share message when a member is added to a vault', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
const handleInitialContactShareMessage = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
|
||||
const { thirdPartyContext, deinitThirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdPartyContext)
|
||||
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleTrustedContactShareMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleTrustedContactShareMessage')
|
||||
const thirdPartySpy = sinon.spy(thirdPartyContext.asymmetric, 'handleTrustedContactShareMessage')
|
||||
|
||||
await contactContext.sync()
|
||||
await handleInitialContactShareMessage
|
||||
|
||||
await context.sync()
|
||||
await contactContext.sync()
|
||||
await thirdPartyContext.sync()
|
||||
|
||||
expect(firstPartySpy.callCount).to.equal(0)
|
||||
expect(secondPartySpy.callCount).to.equal(1)
|
||||
expect(thirdPartySpy.callCount).to.equal(0)
|
||||
|
||||
await deinitThirdPartyContext()
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should not send contact share message to self or to contact who is changed', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
@@ -100,12 +136,10 @@ describe('asymmetric messages', function () {
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
const handleInitialContactShareMessage = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdPartyContext)
|
||||
|
||||
await contactContext.sync()
|
||||
await handleInitialContactShareMessage
|
||||
|
||||
const sendContactSharePromise = context.resolveWhenSharedVaultServiceSendsContactShareMessage()
|
||||
|
||||
@@ -161,8 +195,8 @@ describe('asymmetric messages', function () {
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleVaultMetadataChangedMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleVaultMetadataChangedMessage')
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleTrustedVaultMetadataChangedMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleTrustedVaultMetadataChangedMessage')
|
||||
|
||||
await context.sync()
|
||||
await contactContext.sync()
|
||||
@@ -201,6 +235,61 @@ describe('asymmetric messages', function () {
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should trust and process messages sent after sender keypair changed', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
await context.changePassword('new password')
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const completedProcessingMessagesPromise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
await contactContext.sync()
|
||||
await completedProcessingMessagesPromise
|
||||
|
||||
const updatedVault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(updatedVault.name).to.equal('New Name')
|
||||
expect(updatedVault.description).to.equal('New Description')
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should not send back a vault change message after receiving a vault change message', async () => {
|
||||
/**
|
||||
* If userA receives a vault change message and mutates their vault locally, this should not create a
|
||||
* chain of vault change messages that then ping-pongs back and forth between the two users.
|
||||
*/
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
await context.changePassword('new password')
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
context.lockSyncing()
|
||||
|
||||
const completedProcessingMessagesPromise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
await contactContext.sync()
|
||||
await completedProcessingMessagesPromise
|
||||
|
||||
/**
|
||||
* There's really no good way to await the exact call since
|
||||
* the relevant part fires in the SharedVaultSerivce item observer
|
||||
*/
|
||||
await context.sleep(0.25)
|
||||
|
||||
const messages = await context.asymmetric.getInboundMessages()
|
||||
expect(messages.length).to.equal(0)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should process sender keypair changed message', async () => {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
||||
await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
||||
@@ -272,6 +361,28 @@ describe('asymmetric messages', function () {
|
||||
|
||||
it('should delete all inbound messages after changing user password', async () => {
|
||||
/** Messages to user are encrypted with old keypair and are no longer decryptable */
|
||||
console.error('TODO: implement test')
|
||||
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
contactContext.lockSyncing()
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const promise = contactContext.resolveWhenAllInboundAsymmetricMessagesAreDeleted()
|
||||
await contactContext.changePassword('new-password')
|
||||
await promise
|
||||
|
||||
const messages = await contactContext.asymmetric.getInboundMessages()
|
||||
expect(messages.length).to.equal(0)
|
||||
|
||||
const updatedVault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(updatedVault.name).to.not.equal('New Name')
|
||||
expect(updatedVault.description).to.not.equal('New Description')
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -71,6 +71,18 @@ describe('contacts', function () {
|
||||
expect(updatedSelfContact.publicKeySet.signing).to.equal(context.signingPublicKey)
|
||||
})
|
||||
|
||||
it('should update self contact reference when changed', async () => {
|
||||
const selfContact = context.contacts.getSelfContact()
|
||||
|
||||
await context.mutator.changeItem(selfContact, (mutator) => {
|
||||
mutator.name = 'New Name'
|
||||
})
|
||||
|
||||
const updatedSelfContact = context.contacts.getSelfContact()
|
||||
|
||||
expect(updatedSelfContact.name).to.equal('New Name')
|
||||
})
|
||||
|
||||
it('should not be able to delete self contact', async () => {
|
||||
const selfContact = context.contacts.getSelfContact()
|
||||
|
||||
@@ -80,4 +92,8 @@ describe('contacts', function () {
|
||||
it('should not be able to delete a trusted contact if it belongs to a vault I administer', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should be able to refresh a contact using a collaborationID that includes full chain of previouos public keys', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -50,9 +50,10 @@ describe('shared vault crypto', function () {
|
||||
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
||||
|
||||
await contactContext.changeNoteTitleAndSync(note, 'new title')
|
||||
|
||||
await context.sync()
|
||||
|
||||
const rawPayloads = await context.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await context.application.storage.getAllRawPayloads()
|
||||
const noteRawPayload = rawPayloads.find((payload) => payload.uuid === note.uuid)
|
||||
|
||||
expect(noteRawPayload.signatureData).to.not.be.undefined
|
||||
@@ -166,11 +167,13 @@ describe('shared vault crypto', function () {
|
||||
const { note, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
||||
|
||||
expect(context.contacts.isItemAuthenticallySigned(note)).to.equal('not-applicable')
|
||||
expect(context.contacts.isItemAuthenticallySigned(note)).to.equal(ItemSignatureValidationResult.NotApplicable)
|
||||
|
||||
const contactNote = contactContext.items.findItem(note.uuid)
|
||||
|
||||
expect(contactContext.contacts.isItemAuthenticallySigned(contactNote)).to.equal('yes')
|
||||
expect(contactContext.contacts.isItemAuthenticallySigned(contactNote)).to.equal(
|
||||
ItemSignatureValidationResult.Trusted,
|
||||
)
|
||||
|
||||
await contactContext.changeNoteTitleAndSync(contactNote, 'new title')
|
||||
|
||||
@@ -178,27 +181,9 @@ describe('shared vault crypto', function () {
|
||||
|
||||
let updatedNote = context.items.findItem(note.uuid)
|
||||
|
||||
expect(context.contacts.isItemAuthenticallySigned(updatedNote)).to.equal('yes')
|
||||
expect(context.contacts.isItemAuthenticallySigned(updatedNote)).to.equal(ItemSignatureValidationResult.Trusted)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
})
|
||||
|
||||
describe('keypair revocation', () => {
|
||||
it('should be able to revoke non-current keypair', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('revoking a keypair should send a keypair revocation event to trusted contacts', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('should not be able to revoke current key pair', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('should distrust revoked keypair as contact', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,9 @@ describe('shared vault invites', function () {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
||||
const contact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
||||
|
||||
const vaultInvite = await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
||||
const vaultInvite = (
|
||||
await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
||||
).getValue()
|
||||
|
||||
expect(vaultInvite).to.not.be.undefined
|
||||
expect(vaultInvite.shared_vault_uuid).to.equal(sharedVault.sharing.sharedVaultUuid)
|
||||
@@ -78,8 +80,10 @@ describe('shared vault invites', function () {
|
||||
|
||||
const message = invites[0].message
|
||||
const delegatedContacts = message.data.trustedContacts
|
||||
expect(delegatedContacts.length).to.equal(1)
|
||||
expect(delegatedContacts[0].contactUuid).to.equal(contactContext.userUuid)
|
||||
expect(delegatedContacts.length).to.equal(2)
|
||||
|
||||
expect(delegatedContacts.some((contact) => contact.contactUuid === context.userUuid)).to.be.true
|
||||
expect(delegatedContacts.some((contact) => contact.contactUuid === contactContext.userUuid)).to.be.true
|
||||
|
||||
await deinitThirdPartyContext()
|
||||
await deinitContactContext()
|
||||
@@ -197,7 +201,17 @@ describe('shared vault invites', function () {
|
||||
|
||||
it('should delete all inbound invites after changing user password', async () => {
|
||||
/** Invites to user are encrypted with old keypair and are no longer decryptable */
|
||||
console.error('TODO: implement test')
|
||||
const { contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithUnacceptedButTrustedInvite(context)
|
||||
|
||||
const promise = contactContext.resolveWhenAllInboundSharedVaultInvitesAreDeleted()
|
||||
await contactContext.changePassword('new-password')
|
||||
await promise
|
||||
|
||||
const invites = await contactContext.sharedVaults.downloadInboundInvites()
|
||||
expect(invites.length).to.equal(0)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('sharing a vault with user inputted and ephemeral password should share the key as synced for the recipient', async () => {
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('shared vault key rotation', function () {
|
||||
|
||||
contactContext.lockSyncing()
|
||||
|
||||
const spy = sinon.spy(context.encryption, 'reencryptKeySystemItemsKeysForVault')
|
||||
const spy = sinon.spy(context.keys, 'reencryptKeySystemItemsKeysForVault')
|
||||
|
||||
const promise = context.resolveWhenSharedVaultKeyRotationInvitesGetSent(sharedVault)
|
||||
await vaults.rotateVaultRootKey(sharedVault)
|
||||
|
||||
41
packages/snjs/mocha/vaults/keypair-change.test.js
Normal file
41
packages/snjs/mocha/vaults/keypair-change.test.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('keypair change', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let context
|
||||
|
||||
afterEach(async function () {
|
||||
await context.deinit()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createAppContextWithRealCrypto()
|
||||
|
||||
await context.launch()
|
||||
await context.register()
|
||||
})
|
||||
|
||||
it('contacts should be able to handle receiving multiple keypair changed messages and trust them in order', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should not trust messages sent with previous key pair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should reupload invites after rotating keypair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should reupload asymmetric messages after rotating keypair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
@@ -43,7 +43,7 @@ describe('shared vault permissions', function () {
|
||||
SharedVaultPermission.Write,
|
||||
)
|
||||
|
||||
expect(isClientDisplayableError(result)).to.be.true
|
||||
expect(result.isFailed()).to.be.true
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
@@ -63,15 +63,15 @@ describe('shared vaults', function () {
|
||||
await promise
|
||||
|
||||
expect(contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(contactContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
const recreatedContext = await Factory.createAppContextWithRealCrypto(contactContext.identifier)
|
||||
await recreatedContext.launch()
|
||||
|
||||
expect(recreatedContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(recreatedContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
await deinitContactContext()
|
||||
await recreatedContext.deinit()
|
||||
@@ -90,15 +90,15 @@ describe('shared vaults', function () {
|
||||
await promise
|
||||
|
||||
expect(contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(contactContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
const recreatedContext = await Factory.createAppContextWithRealCrypto(contactContext.identifier)
|
||||
await recreatedContext.launch()
|
||||
|
||||
expect(recreatedContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(recreatedContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
await deinitContactContext()
|
||||
await recreatedContext.deinit()
|
||||
|
||||
33
packages/snjs/mocha/vaults/signatures.test.js
Normal file
33
packages/snjs/mocha/vaults/signatures.test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('signatures', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let context
|
||||
|
||||
afterEach(async function () {
|
||||
await context.deinit()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createAppContextWithRealCrypto()
|
||||
|
||||
await context.launch()
|
||||
await context.register()
|
||||
})
|
||||
|
||||
it('signatures should be marked as of questionable integrity when signed with non root contact public key', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('items marked with questionable integrity should have option to trust the item which would resync it', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user