tests: vault tests (#2366)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { VaultUserServiceInterface, VaultInviteServiceInterface } from '@standardnotes/services'
|
||||||
|
import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface'
|
||||||
import { HistoryServiceInterface } from './../History/HistoryServiceInterface'
|
import { HistoryServiceInterface } from './../History/HistoryServiceInterface'
|
||||||
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
||||||
import { PreferenceServiceInterface } from './../Preferences/PreferenceServiceInterface'
|
import { PreferenceServiceInterface } from './../Preferences/PreferenceServiceInterface'
|
||||||
@@ -5,7 +7,7 @@ import { AsymmetricMessageServiceInterface } from './../AsymmetricMessage/Asymme
|
|||||||
import { SyncOptions } from './../Sync/SyncOptions'
|
import { SyncOptions } from './../Sync/SyncOptions'
|
||||||
import { ImportDataReturnType } from './../Mutator/ImportDataUseCase'
|
import { ImportDataReturnType } from './../Mutator/ImportDataUseCase'
|
||||||
import { ChallengeServiceInterface } from './../Challenge/ChallengeServiceInterface'
|
import { ChallengeServiceInterface } from './../Challenge/ChallengeServiceInterface'
|
||||||
import { VaultServiceInterface } from './../Vaults/VaultServiceInterface'
|
import { VaultServiceInterface } from '../Vault/VaultServiceInterface'
|
||||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||||
import {
|
import {
|
||||||
BackupFile,
|
BackupFile,
|
||||||
@@ -95,24 +97,27 @@ export interface ApplicationInterface {
|
|||||||
syncOptions?: SyncOptions,
|
syncOptions?: SyncOptions,
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
|
|
||||||
get features(): FeaturesClientInterface
|
|
||||||
get componentManager(): ComponentManagerInterface
|
|
||||||
get items(): ItemManagerInterface
|
|
||||||
get mutator(): MutatorClientInterface
|
|
||||||
get user(): UserClientInterface
|
|
||||||
get files(): FilesClientInterface
|
|
||||||
get subscriptions(): SubscriptionManagerInterface
|
|
||||||
get fileBackups(): BackupServiceInterface | undefined
|
|
||||||
get sessions(): SessionsClientInterface
|
|
||||||
get homeServer(): HomeServerServiceInterface | undefined
|
|
||||||
get vaults(): VaultServiceInterface
|
|
||||||
get challenges(): ChallengeServiceInterface
|
|
||||||
get alerts(): AlertService
|
get alerts(): AlertService
|
||||||
get asymmetric(): AsymmetricMessageServiceInterface
|
get asymmetric(): AsymmetricMessageServiceInterface
|
||||||
get preferences(): PreferenceServiceInterface
|
get challenges(): ChallengeServiceInterface
|
||||||
get events(): InternalEventBusInterface
|
get componentManager(): ComponentManagerInterface
|
||||||
get history(): HistoryServiceInterface
|
|
||||||
get encryption(): EncryptionProviderInterface
|
get encryption(): EncryptionProviderInterface
|
||||||
|
get events(): InternalEventBusInterface
|
||||||
|
get features(): FeaturesClientInterface
|
||||||
|
get fileBackups(): BackupServiceInterface | undefined
|
||||||
|
get files(): FilesClientInterface
|
||||||
|
get history(): HistoryServiceInterface
|
||||||
|
get homeServer(): HomeServerServiceInterface | undefined
|
||||||
|
get items(): ItemManagerInterface
|
||||||
|
get mutator(): MutatorClientInterface
|
||||||
|
get preferences(): PreferenceServiceInterface
|
||||||
|
get sessions(): SessionsClientInterface
|
||||||
|
get subscriptions(): SubscriptionManagerInterface
|
||||||
|
get user(): UserClientInterface
|
||||||
|
get vaults(): VaultServiceInterface
|
||||||
|
get vaultLocks(): VaultLockServiceInterface
|
||||||
|
get vaultUsers(): VaultUserServiceInterface
|
||||||
|
get vaultInvites(): VaultInviteServiceInterface
|
||||||
|
|
||||||
readonly identifier: ApplicationIdentifier
|
readonly identifier: ApplicationIdentifier
|
||||||
readonly platform: Platform
|
readonly platform: Platform
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { GetVault } from './../Vault/UseCase/GetVault'
|
||||||
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
||||||
import { EncryptionProviderInterface } from './../Encryption/EncryptionProviderInterface'
|
import { EncryptionProviderInterface } from './../Encryption/EncryptionProviderInterface'
|
||||||
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
||||||
@@ -5,7 +6,6 @@ import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
|||||||
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
||||||
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
||||||
import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage'
|
import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage'
|
||||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
|
||||||
import { GetTrustedPayload } from './UseCase/GetTrustedPayload'
|
import { GetTrustedPayload } from './UseCase/GetTrustedPayload'
|
||||||
import { ReplaceContactData } from './../Contacts/UseCase/ReplaceContactData'
|
import { ReplaceContactData } from './../Contacts/UseCase/ReplaceContactData'
|
||||||
import { GetAllContacts } from './../Contacts/UseCase/GetAllContacts'
|
import { GetAllContacts } from './../Contacts/UseCase/GetAllContacts'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { UserKeyPairChangedEventData } from '../Session/UserKeyPairChangedEventD
|
|||||||
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
||||||
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
||||||
import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
||||||
import { GetVault } from '../Vaults/UseCase/GetVault'
|
import { GetVault } from '../Vault/UseCase/GetVault'
|
||||||
import { AsymmetricMessageServiceInterface } from './AsymmetricMessageServiceInterface'
|
import { AsymmetricMessageServiceInterface } from './AsymmetricMessageServiceInterface'
|
||||||
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
||||||
import { FindContact } from '../Contacts/UseCase/FindContact'
|
import { FindContact } from '../Contacts/UseCase/FindContact'
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
|
|
||||||
import { ContentType } from '@standardnotes/domain-core'
|
import { ContentType } from '@standardnotes/domain-core'
|
||||||
import { GetVault } from '../../Vaults/UseCase/GetVault'
|
import { GetVault } from '../../Vault/UseCase/GetVault'
|
||||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||||
|
|
||||||
export class HandleRootKeyChangedMessage {
|
export class HandleRootKeyChangedMessage {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessa
|
|||||||
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
|
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
|
||||||
import { HandleKeyPairChange } from './../Contacts/UseCase/HandleKeyPairChange'
|
import { HandleKeyPairChange } from './../Contacts/UseCase/HandleKeyPairChange'
|
||||||
import { CreateSharedVault } from './UseCase/CreateSharedVault'
|
import { CreateSharedVault } from './UseCase/CreateSharedVault'
|
||||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
import { GetVault } from './../Vault/UseCase/GetVault'
|
||||||
import { SharedVaultService } from './SharedVaultService'
|
import { SharedVaultService } from './SharedVaultService'
|
||||||
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
|
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
|
||||||
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import { InternalEventInterface } from '../Internal/InternalEventInterface'
|
|||||||
import { UserEventServiceEvent, UserEventServiceEventPayload } from '../UserEvent/UserEventServiceEvent'
|
import { UserEventServiceEvent, UserEventServiceEventPayload } from '../UserEvent/UserEventServiceEvent'
|
||||||
import { DeleteThirdPartyVault } from './UseCase/DeleteExternalSharedVault'
|
import { DeleteThirdPartyVault } from './UseCase/DeleteExternalSharedVault'
|
||||||
import { DeleteSharedVault } from './UseCase/DeleteSharedVault'
|
import { DeleteSharedVault } from './UseCase/DeleteSharedVault'
|
||||||
import { VaultServiceEvent, VaultServiceEventPayload } from '../Vaults/VaultServiceEvent'
|
import { VaultServiceEvent, VaultServiceEventPayload } from '../Vault/VaultServiceEvent'
|
||||||
import { ShareContactWithVault } from './UseCase/ShareContactWithVault'
|
import { ShareContactWithVault } from './UseCase/ShareContactWithVault'
|
||||||
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
|
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
|
||||||
import { CreateSharedVault } from './UseCase/CreateSharedVault'
|
import { CreateSharedVault } from './UseCase/CreateSharedVault'
|
||||||
import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessage'
|
import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessage'
|
||||||
import { ConvertToSharedVault } from './UseCase/ConvertToSharedVault'
|
import { ConvertToSharedVault } from './UseCase/ConvertToSharedVault'
|
||||||
import { GetVault } from '../Vaults/UseCase/GetVault'
|
import { GetVault } from '../Vault/UseCase/GetVault'
|
||||||
import { ContentType } from '@standardnotes/domain-core'
|
import { ContentType } from '@standardnotes/domain-core'
|
||||||
import { HandleKeyPairChange } from '../Contacts/UseCase/HandleKeyPairChange'
|
import { HandleKeyPairChange } from '../Contacts/UseCase/HandleKeyPairChange'
|
||||||
import { FindContact } from '../Contacts/UseCase/FindContact'
|
import { FindContact } from '../Contacts/UseCase/FindContact'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { SharedVaultListingInterface, VaultListingInterface, VaultListingMutator
|
|||||||
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
||||||
import { SharedVaultServerInterface } from '@standardnotes/api'
|
import { SharedVaultServerInterface } from '@standardnotes/api'
|
||||||
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||||
import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault'
|
import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault'
|
||||||
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||||
|
|
||||||
export class ConvertToSharedVault {
|
export class ConvertToSharedVault {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import {
|
|||||||
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
|
||||||
import { SharedVaultServerInterface } from '@standardnotes/api'
|
import { SharedVaultServerInterface } from '@standardnotes/api'
|
||||||
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||||
import { CreateVault } from '../../Vaults/UseCase/CreateVault'
|
import { CreateVault } from '../../Vault/UseCase/CreateVault'
|
||||||
import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault'
|
import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault'
|
||||||
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||||
|
|
||||||
export class CreateSharedVault {
|
export class CreateSharedVault {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ClientDisplayableError, isErrorResponse } from '@standardnotes/response
|
|||||||
import { SharedVaultServerInterface } from '@standardnotes/api'
|
import { SharedVaultServerInterface } from '@standardnotes/api'
|
||||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||||
import { SyncServiceInterface } from '../../Sync/SyncServiceInterface'
|
import { SyncServiceInterface } from '../../Sync/SyncServiceInterface'
|
||||||
import { DeleteVault } from '../../Vaults/UseCase/DeleteVault'
|
import { DeleteVault } from '../../Vault/UseCase/DeleteVault'
|
||||||
|
|
||||||
export class DeleteSharedVault {
|
export class DeleteSharedVault {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { GetVaults } from './../../Vaults/UseCase/GetVaults'
|
import { GetVaults } from '../../Vault/UseCase/GetVaults'
|
||||||
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
VaultListingInterface,
|
VaultListingInterface,
|
||||||
VaultListingMutator,
|
VaultListingMutator,
|
||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
import { ChangeVaultOptionsDTO } from '../ChangeVaultOptionsDTO'
|
import { ChangeVaultKeyOptionsDTO } from './ChangeVaultKeyOptionsDTO'
|
||||||
import { GetVault } from './GetVault'
|
import { GetVault } from './GetVault'
|
||||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||||
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
||||||
@@ -19,7 +19,7 @@ export class ChangeVaultKeyOptions {
|
|||||||
private getVault: GetVault,
|
private getVault: GetVault,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(dto: ChangeVaultOptionsDTO): Promise<void> {
|
async execute(dto: ChangeVaultKeyOptionsDTO): Promise<void> {
|
||||||
const useStorageMode = dto.newKeyStorageMode ?? dto.vault.keyStorageMode
|
const useStorageMode = dto.newKeyStorageMode ?? dto.vault.keyStorageMode
|
||||||
|
|
||||||
if (dto.newPasswordType) {
|
if (dto.newPasswordType) {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface } from '@standardnotes/models'
|
import { KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
export type ChangeVaultOptionsDTO = {
|
export type ChangeVaultKeyOptionsDTO = {
|
||||||
vault: VaultListingInterface
|
vault: VaultListingInterface
|
||||||
newPasswordType:
|
newPasswordType:
|
||||||
| { passwordType: KeySystemRootKeyPasswordType.Randomized }
|
| { passwordType: KeySystemRootKeyPasswordType.Randomized }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SyncServiceInterface } from './../../Sync/SyncServiceInterface'
|
import { SyncServiceInterface } from '../../Sync/SyncServiceInterface'
|
||||||
import { UuidGenerator } from '@standardnotes/utils'
|
import { UuidGenerator } from '@standardnotes/utils'
|
||||||
import {
|
import {
|
||||||
KeySystemRootKeyParamsInterface,
|
KeySystemRootKeyParamsInterface,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { VaultListingInterface } from '@standardnotes/models'
|
import { VaultListingInterface } from '@standardnotes/models'
|
||||||
import { ItemManagerInterface } from './../../Item/ItemManagerInterface'
|
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||||
import { ContentType, Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
import { ContentType, Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
export class GetVault implements SyncUseCaseInterface<VaultListingInterface> {
|
export class GetVault implements SyncUseCaseInterface<VaultListingInterface> {
|
||||||
@@ -3,14 +3,13 @@ import {
|
|||||||
DecryptedItemInterface,
|
DecryptedItemInterface,
|
||||||
FileItem,
|
FileItem,
|
||||||
KeySystemIdentifier,
|
KeySystemIdentifier,
|
||||||
KeySystemRootKeyPasswordType,
|
|
||||||
KeySystemRootKeyStorageMode,
|
KeySystemRootKeyStorageMode,
|
||||||
VaultListingInterface,
|
VaultListingInterface,
|
||||||
VaultListingMutator,
|
VaultListingMutator,
|
||||||
isNote,
|
isNote,
|
||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
import { VaultServiceInterface } from './VaultServiceInterface'
|
import { VaultServiceInterface } from './VaultServiceInterface'
|
||||||
import { ChangeVaultOptionsDTO } from './ChangeVaultOptionsDTO'
|
import { ChangeVaultKeyOptionsDTO } from './UseCase/ChangeVaultKeyOptionsDTO'
|
||||||
import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent'
|
import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent'
|
||||||
import { CreateVault } from './UseCase/CreateVault'
|
import { CreateVault } from './UseCase/CreateVault'
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
@@ -25,23 +24,18 @@ import { GetVault } from './UseCase/GetVault'
|
|||||||
import { ChangeVaultKeyOptions } from './UseCase/ChangeVaultKeyOptions'
|
import { ChangeVaultKeyOptions } from './UseCase/ChangeVaultKeyOptions'
|
||||||
import { MutatorClientInterface } from '../Mutator/MutatorClientInterface'
|
import { MutatorClientInterface } from '../Mutator/MutatorClientInterface'
|
||||||
import { AlertService } from '../Alert/AlertService'
|
import { AlertService } from '../Alert/AlertService'
|
||||||
import { ContentType } from '@standardnotes/domain-core'
|
|
||||||
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
|
|
||||||
import { KeySystemKeyManagerInterface } from '../KeySystem/KeySystemKeyManagerInterface'
|
|
||||||
import { GetVaults } from './UseCase/GetVaults'
|
import { GetVaults } from './UseCase/GetVaults'
|
||||||
|
import { VaultLockServiceInterface } from '../VaultLock/VaultLockServiceInterface'
|
||||||
|
|
||||||
export class VaultService
|
export class VaultService
|
||||||
extends AbstractService<VaultServiceEvent, VaultServiceEventPayload[VaultServiceEvent]>
|
extends AbstractService<VaultServiceEvent, VaultServiceEventPayload[VaultServiceEvent]>
|
||||||
implements VaultServiceInterface
|
implements VaultServiceInterface
|
||||||
{
|
{
|
||||||
private lockMap = new Map<VaultListingInterface['uuid'], boolean>()
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private sync: SyncServiceInterface,
|
private sync: SyncServiceInterface,
|
||||||
private items: ItemManagerInterface,
|
private items: ItemManagerInterface,
|
||||||
private mutator: MutatorClientInterface,
|
private mutator: MutatorClientInterface,
|
||||||
private encryption: EncryptionProviderInterface,
|
private vaultLocks: VaultLockServiceInterface,
|
||||||
private keys: KeySystemKeyManagerInterface,
|
|
||||||
private alerts: AlertService,
|
private alerts: AlertService,
|
||||||
private _getVault: GetVault,
|
private _getVault: GetVault,
|
||||||
private _getVaults: GetVaults,
|
private _getVaults: GetVaults,
|
||||||
@@ -49,29 +43,34 @@ export class VaultService
|
|||||||
private _moveItemsToVault: MoveItemsToVault,
|
private _moveItemsToVault: MoveItemsToVault,
|
||||||
private _createVault: CreateVault,
|
private _createVault: CreateVault,
|
||||||
private _removeItemFromVault: RemoveItemFromVault,
|
private _removeItemFromVault: RemoveItemFromVault,
|
||||||
private _deleteVaultUse: DeleteVault,
|
private _deleteVault: DeleteVault,
|
||||||
private _rotateVaultKey: RotateVaultKey,
|
private _rotateVaultKey: RotateVaultKey,
|
||||||
eventBus: InternalEventBusInterface,
|
eventBus: InternalEventBusInterface,
|
||||||
) {
|
) {
|
||||||
super(eventBus)
|
super(eventBus)
|
||||||
|
}
|
||||||
|
|
||||||
items.addObserver(
|
override deinit(): void {
|
||||||
[ContentType.TYPES.KeySystemItemsKey, ContentType.TYPES.KeySystemRootKey, ContentType.TYPES.VaultListing],
|
super.deinit()
|
||||||
() => {
|
;(this.sync as unknown) = undefined
|
||||||
void this.recomputeAllVaultsLockingState()
|
;(this.items as unknown) = undefined
|
||||||
},
|
;(this.mutator as unknown) = undefined
|
||||||
)
|
;(this.vaultLocks as unknown) = undefined
|
||||||
|
;(this.alerts as unknown) = undefined
|
||||||
|
;(this._getVault as unknown) = undefined
|
||||||
|
;(this._getVaults as unknown) = undefined
|
||||||
|
;(this._changeVaultKeyOptions as unknown) = undefined
|
||||||
|
;(this._moveItemsToVault as unknown) = undefined
|
||||||
|
;(this._createVault as unknown) = undefined
|
||||||
|
;(this._removeItemFromVault as unknown) = undefined
|
||||||
|
;(this._deleteVault as unknown) = undefined
|
||||||
|
;(this._rotateVaultKey as unknown) = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
getVaults(): VaultListingInterface[] {
|
getVaults(): VaultListingInterface[] {
|
||||||
return this._getVaults.execute().getValue()
|
return this._getVaults.execute().getValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
getLockedvaults(): VaultListingInterface[] {
|
|
||||||
const vaults = this.getVaults()
|
|
||||||
return vaults.filter((vault) => this.isVaultLocked(vault))
|
|
||||||
}
|
|
||||||
|
|
||||||
public getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined {
|
public getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined {
|
||||||
const result = this._getVault.execute(dto)
|
const result = this._getVault.execute(dto)
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
@@ -90,16 +89,12 @@ export class VaultService
|
|||||||
return vault
|
return vault
|
||||||
}
|
}
|
||||||
|
|
||||||
async createRandomizedVault(dto: {
|
async createRandomizedVault(dto: { name: string; description?: string }): Promise<VaultListingInterface> {
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
storagePreference: KeySystemRootKeyStorageMode
|
|
||||||
}): Promise<VaultListingInterface> {
|
|
||||||
return this.createVaultWithParameters({
|
return this.createVaultWithParameters({
|
||||||
name: dto.name,
|
name: dto.name,
|
||||||
description: dto.description,
|
description: dto.description,
|
||||||
userInputtedPassword: undefined,
|
userInputtedPassword: undefined,
|
||||||
storagePreference: dto.storagePreference,
|
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +127,7 @@ export class VaultService
|
|||||||
vault: VaultListingInterface,
|
vault: VaultListingInterface,
|
||||||
item: DecryptedItemInterface,
|
item: DecryptedItemInterface,
|
||||||
): Promise<DecryptedItemInterface | undefined> {
|
): Promise<DecryptedItemInterface | undefined> {
|
||||||
if (this.isVaultLocked(vault)) {
|
if (this.vaultLocks.isVaultLocked(vault)) {
|
||||||
throw new Error('Attempting to add item to locked vault')
|
throw new Error('Attempting to add item to locked vault')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +157,7 @@ export class VaultService
|
|||||||
throw new Error('Cannot find vault to remove item from')
|
throw new Error('Cannot find vault to remove item from')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isVaultLocked(vault)) {
|
if (this.vaultLocks.isVaultLocked(vault)) {
|
||||||
throw new Error('Attempting to remove item from locked vault')
|
throw new Error('Attempting to remove item from locked vault')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +170,7 @@ export class VaultService
|
|||||||
throw new Error('Shared vault must be deleted through SharedVaultService')
|
throw new Error('Shared vault must be deleted through SharedVaultService')
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = await this._deleteVaultUse.execute(vault)
|
const error = await this._deleteVault.execute(vault)
|
||||||
|
|
||||||
if (isClientDisplayableError(error)) {
|
if (isClientDisplayableError(error)) {
|
||||||
return false
|
return false
|
||||||
@@ -200,7 +195,7 @@ export class VaultService
|
|||||||
}
|
}
|
||||||
|
|
||||||
async rotateVaultRootKey(vault: VaultListingInterface): Promise<void> {
|
async rotateVaultRootKey(vault: VaultListingInterface): Promise<void> {
|
||||||
if (this.computeVaultLockState(vault) === 'locked') {
|
if (this.vaultLocks.isVaultLocked(vault)) {
|
||||||
throw new Error('Cannot rotate root key of locked vault')
|
throw new Error('Cannot rotate root key of locked vault')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,8 +227,8 @@ export class VaultService
|
|||||||
return this.getVault({ keySystemIdentifier: latestItem.key_system_identifier })
|
return this.getVault({ keySystemIdentifier: latestItem.key_system_identifier })
|
||||||
}
|
}
|
||||||
|
|
||||||
async changeVaultOptions(dto: ChangeVaultOptionsDTO): Promise<void> {
|
async changeVaultOptions(dto: ChangeVaultKeyOptionsDTO): Promise<void> {
|
||||||
if (this.isVaultLocked(dto.vault)) {
|
if (this.vaultLocks.isVaultLocked(dto.vault)) {
|
||||||
throw new Error('Attempting to change vault options on a locked vault')
|
throw new Error('Attempting to change vault options on a locked vault')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,99 +238,4 @@ export class VaultService
|
|||||||
await this.notifyEventSync(VaultServiceEvent.VaultRootKeyRotated, { vault: dto.vault })
|
await this.notifyEventSync(VaultServiceEvent.VaultRootKeyRotated, { vault: dto.vault })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public isVaultLocked(vault: VaultListingInterface): boolean {
|
|
||||||
return this.lockMap.get(vault.uuid) === true
|
|
||||||
}
|
|
||||||
|
|
||||||
public async lockNonPersistentVault(vault: VaultListingInterface): Promise<void> {
|
|
||||||
if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) {
|
|
||||||
throw new Error('Vault uses synced root key and cannot be locked')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.keys.clearMemoryOfKeysRelatedToVault(vault)
|
|
||||||
|
|
||||||
this.lockMap.set(vault.uuid, true)
|
|
||||||
void this.notifyEventSync(VaultServiceEvent.VaultLocked, { vault })
|
|
||||||
}
|
|
||||||
|
|
||||||
public async unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise<boolean> {
|
|
||||||
if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) {
|
|
||||||
throw new Error('Vault uses randomized password and cannot be unlocked with user inputted password')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) {
|
|
||||||
throw new Error('Vault uses synced root key and cannot be unlocked with user inputted password')
|
|
||||||
}
|
|
||||||
|
|
||||||
const derivedRootKey = this.encryption.deriveUserInputtedKeySystemRootKey({
|
|
||||||
keyParams: vault.rootKeyParams,
|
|
||||||
userInputtedPassword: password,
|
|
||||||
})
|
|
||||||
|
|
||||||
this.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode)
|
|
||||||
|
|
||||||
await this.encryption.decryptErroredPayloads()
|
|
||||||
|
|
||||||
if (this.computeVaultLockState(vault) === 'locked') {
|
|
||||||
this.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lockMap.set(vault.uuid, false)
|
|
||||||
void this.notifyEventSync(VaultServiceEvent.VaultUnlocked, { vault })
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private recomputeAllVaultsLockingState = async (): Promise<void> => {
|
|
||||||
const vaults = this.getVaults()
|
|
||||||
|
|
||||||
for (const vault of vaults) {
|
|
||||||
const locked = this.computeVaultLockState(vault) === 'locked'
|
|
||||||
|
|
||||||
if (this.lockMap.get(vault.uuid) !== locked) {
|
|
||||||
this.lockMap.set(vault.uuid, locked)
|
|
||||||
|
|
||||||
if (locked) {
|
|
||||||
void this.notifyEvent(VaultServiceEvent.VaultLocked, { vault })
|
|
||||||
} else {
|
|
||||||
void this.notifyEvent(VaultServiceEvent.VaultUnlocked, { vault })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private computeVaultLockState(vault: VaultListingInterface): 'locked' | 'unlocked' {
|
|
||||||
const rootKey = this.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier)
|
|
||||||
if (!rootKey) {
|
|
||||||
return 'locked'
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemsKey = this.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier)
|
|
||||||
if (!itemsKey) {
|
|
||||||
return 'locked'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'unlocked'
|
|
||||||
}
|
|
||||||
|
|
||||||
override deinit(): void {
|
|
||||||
super.deinit()
|
|
||||||
;(this.sync as unknown) = undefined
|
|
||||||
;(this.items as unknown) = undefined
|
|
||||||
;(this.mutator as unknown) = undefined
|
|
||||||
;(this.encryption as unknown) = undefined
|
|
||||||
;(this.alerts as unknown) = undefined
|
|
||||||
;(this._getVault as unknown) = undefined
|
|
||||||
;(this._getVaults as unknown) = undefined
|
|
||||||
;(this._changeVaultKeyOptions as unknown) = undefined
|
|
||||||
;(this._moveItemsToVault as unknown) = undefined
|
|
||||||
;(this._createVault as unknown) = undefined
|
|
||||||
;(this._removeItemFromVault as unknown) = undefined
|
|
||||||
;(this._deleteVaultUse as unknown) = undefined
|
|
||||||
;(this._rotateVaultKey as unknown) = undefined
|
|
||||||
|
|
||||||
this.lockMap.clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,10 @@ import { VaultListingInterface } from '@standardnotes/models'
|
|||||||
|
|
||||||
export enum VaultServiceEvent {
|
export enum VaultServiceEvent {
|
||||||
VaultRootKeyRotated = 'VaultRootKeyRotated',
|
VaultRootKeyRotated = 'VaultRootKeyRotated',
|
||||||
VaultUnlocked = 'VaultUnlocked',
|
|
||||||
VaultLocked = 'VaultLocked',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VaultServiceEventPayload = {
|
export type VaultServiceEventPayload = {
|
||||||
[VaultServiceEvent.VaultRootKeyRotated]: {
|
[VaultServiceEvent.VaultRootKeyRotated]: {
|
||||||
vault: VaultListingInterface
|
vault: VaultListingInterface
|
||||||
}
|
}
|
||||||
[VaultServiceEvent.VaultUnlocked]: {
|
|
||||||
vault: VaultListingInterface
|
|
||||||
}
|
|
||||||
[VaultServiceEvent.VaultLocked]: {
|
|
||||||
vault: VaultListingInterface
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,11 @@ import {
|
|||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent'
|
import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent'
|
||||||
import { ChangeVaultOptionsDTO } from './ChangeVaultOptionsDTO'
|
import { ChangeVaultKeyOptionsDTO } from './UseCase/ChangeVaultKeyOptionsDTO'
|
||||||
|
|
||||||
export interface VaultServiceInterface
|
export interface VaultServiceInterface
|
||||||
extends AbstractService<VaultServiceEvent, VaultServiceEventPayload[VaultServiceEvent]> {
|
extends AbstractService<VaultServiceEvent, VaultServiceEventPayload[VaultServiceEvent]> {
|
||||||
createRandomizedVault(dto: {
|
createRandomizedVault(dto: { name: string; description?: string }): Promise<VaultListingInterface>
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
storagePreference: KeySystemRootKeyStorageMode
|
|
||||||
}): Promise<VaultListingInterface>
|
|
||||||
createUserInputtedPasswordVault(dto: {
|
createUserInputtedPasswordVault(dto: {
|
||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
@@ -24,7 +20,6 @@ export interface VaultServiceInterface
|
|||||||
|
|
||||||
getVaults(): VaultListingInterface[]
|
getVaults(): VaultListingInterface[]
|
||||||
getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined
|
getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined
|
||||||
getLockedvaults(): VaultListingInterface[]
|
|
||||||
deleteVault(vault: VaultListingInterface): Promise<boolean>
|
deleteVault(vault: VaultListingInterface): Promise<boolean>
|
||||||
|
|
||||||
moveItemToVault(
|
moveItemToVault(
|
||||||
@@ -40,8 +35,5 @@ export interface VaultServiceInterface
|
|||||||
params: { name: string; description: string },
|
params: { name: string; description: string },
|
||||||
): Promise<VaultListingInterface>
|
): Promise<VaultListingInterface>
|
||||||
rotateVaultRootKey(vault: VaultListingInterface): Promise<void>
|
rotateVaultRootKey(vault: VaultListingInterface): Promise<void>
|
||||||
changeVaultOptions(dto: ChangeVaultOptionsDTO): Promise<void>
|
changeVaultOptions(dto: ChangeVaultKeyOptionsDTO): Promise<void>
|
||||||
|
|
||||||
isVaultLocked(vault: VaultListingInterface): boolean
|
|
||||||
unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise<boolean>
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import { GetUntrustedPayload } from './../AsymmetricMessage/UseCase/GetUntrusted
|
|||||||
import { GetTrustedPayload } from './../AsymmetricMessage/UseCase/GetTrustedPayload'
|
import { GetTrustedPayload } from './../AsymmetricMessage/UseCase/GetTrustedPayload'
|
||||||
import { InviteRecord } from './InviteRecord'
|
import { InviteRecord } from './InviteRecord'
|
||||||
import { VaultUserServiceInterface } from './../VaultUser/VaultUserServiceInterface'
|
import { VaultUserServiceInterface } from './../VaultUser/VaultUserServiceInterface'
|
||||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
import { GetVault } from '../Vault/UseCase/GetVault'
|
||||||
import { InviteToVault } from './UseCase/InviteToVault'
|
import { InviteToVault } from './UseCase/InviteToVault'
|
||||||
import { GetVaultContacts } from '../VaultUser/UseCase/GetVaultContacts'
|
import { GetVaultContacts } from '../VaultUser/UseCase/GetVaultContacts'
|
||||||
import { SyncServiceInterface } from './../Sync/SyncServiceInterface'
|
import { SyncServiceInterface } from './../Sync/SyncServiceInterface'
|
||||||
|
|||||||
133
packages/services/src/Domain/VaultLock/VaultLockService.ts
Normal file
133
packages/services/src/Domain/VaultLock/VaultLockService.ts
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import { GetVaults } from '../Vault/UseCase/GetVaults'
|
||||||
|
import { KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface } from '@standardnotes/models'
|
||||||
|
import { VaultLockServiceInterface } from './VaultLockServiceInterface'
|
||||||
|
import { VaultLockServiceEvent, VaultLockServiceEventPayload } from './VaultLockServiceEvent'
|
||||||
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
|
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
||||||
|
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||||
|
import { ContentType } from '@standardnotes/domain-core'
|
||||||
|
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
|
||||||
|
import { KeySystemKeyManagerInterface } from '../KeySystem/KeySystemKeyManagerInterface'
|
||||||
|
|
||||||
|
export class VaultLockService
|
||||||
|
extends AbstractService<VaultLockServiceEvent, VaultLockServiceEventPayload[VaultLockServiceEvent]>
|
||||||
|
implements VaultLockServiceInterface
|
||||||
|
{
|
||||||
|
private lockMap = new Map<VaultListingInterface['uuid'], boolean>()
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
items: ItemManagerInterface,
|
||||||
|
private encryption: EncryptionProviderInterface,
|
||||||
|
private keys: KeySystemKeyManagerInterface,
|
||||||
|
private _getVaults: GetVaults,
|
||||||
|
eventBus: InternalEventBusInterface,
|
||||||
|
) {
|
||||||
|
super(eventBus)
|
||||||
|
|
||||||
|
items.addObserver(
|
||||||
|
[ContentType.TYPES.KeySystemItemsKey, ContentType.TYPES.KeySystemRootKey, ContentType.TYPES.VaultListing],
|
||||||
|
() => {
|
||||||
|
void this.recomputeAllVaultsLockingState()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override deinit(): void {
|
||||||
|
super.deinit()
|
||||||
|
;(this.encryption as unknown) = undefined
|
||||||
|
;(this.keys as unknown) = undefined
|
||||||
|
;(this._getVaults as unknown) = undefined
|
||||||
|
|
||||||
|
this.lockMap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLockedvaults(): VaultListingInterface[] {
|
||||||
|
const vaults = this._getVaults.execute().getValue()
|
||||||
|
return vaults.filter((vault) => this.isVaultLocked(vault))
|
||||||
|
}
|
||||||
|
|
||||||
|
public isVaultLocked(vault: VaultListingInterface): boolean {
|
||||||
|
return this.lockMap.get(vault.uuid) === true
|
||||||
|
}
|
||||||
|
|
||||||
|
public isVaultLockable(vault: VaultListingInterface): boolean {
|
||||||
|
return vault.keyPasswordType === KeySystemRootKeyPasswordType.UserInputted
|
||||||
|
}
|
||||||
|
|
||||||
|
public lockNonPersistentVault(vault: VaultListingInterface): void {
|
||||||
|
if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) {
|
||||||
|
throw new Error('Vault uses synced key storage and cannot be locked')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) {
|
||||||
|
throw new Error('Vault uses randomized password and cannot be locked')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keys.clearMemoryOfKeysRelatedToVault(vault)
|
||||||
|
|
||||||
|
this.lockMap.set(vault.uuid, true)
|
||||||
|
|
||||||
|
void this.notifyEventSync(VaultLockServiceEvent.VaultLocked, { vault })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise<boolean> {
|
||||||
|
if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) {
|
||||||
|
throw new Error('Vault uses randomized password and cannot be unlocked with user inputted password')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) {
|
||||||
|
throw new Error('Vault uses synced root key and cannot be unlocked with user inputted password')
|
||||||
|
}
|
||||||
|
|
||||||
|
const derivedRootKey = this.encryption.deriveUserInputtedKeySystemRootKey({
|
||||||
|
keyParams: vault.rootKeyParams,
|
||||||
|
userInputtedPassword: password,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode)
|
||||||
|
|
||||||
|
await this.encryption.decryptErroredPayloads()
|
||||||
|
|
||||||
|
if (this.computeVaultLockState(vault) === 'locked') {
|
||||||
|
this.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lockMap.set(vault.uuid, false)
|
||||||
|
void this.notifyEventSync(VaultLockServiceEvent.VaultUnlocked, { vault })
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private recomputeAllVaultsLockingState = async (): Promise<void> => {
|
||||||
|
const vaults = this._getVaults.execute().getValue()
|
||||||
|
|
||||||
|
for (const vault of vaults) {
|
||||||
|
const locked = this.computeVaultLockState(vault) === 'locked'
|
||||||
|
|
||||||
|
if (this.lockMap.get(vault.uuid) !== locked) {
|
||||||
|
this.lockMap.set(vault.uuid, locked)
|
||||||
|
|
||||||
|
if (locked) {
|
||||||
|
void this.notifyEvent(VaultLockServiceEvent.VaultLocked, { vault })
|
||||||
|
} else {
|
||||||
|
void this.notifyEvent(VaultLockServiceEvent.VaultUnlocked, { vault })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeVaultLockState(vault: VaultListingInterface): 'locked' | 'unlocked' {
|
||||||
|
const rootKey = this.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier)
|
||||||
|
if (!rootKey) {
|
||||||
|
return 'locked'
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemsKey = this.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier)
|
||||||
|
if (!itemsKey) {
|
||||||
|
return 'locked'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unlocked'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { VaultListingInterface } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export enum VaultLockServiceEvent {
|
||||||
|
VaultUnlocked = 'VaultUnlocked',
|
||||||
|
VaultLocked = 'VaultLocked',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VaultLockServiceEventPayload = {
|
||||||
|
[VaultLockServiceEvent.VaultUnlocked]: {
|
||||||
|
vault: VaultListingInterface
|
||||||
|
}
|
||||||
|
[VaultLockServiceEvent.VaultLocked]: {
|
||||||
|
vault: VaultListingInterface
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { VaultListingInterface } from '@standardnotes/models'
|
||||||
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
|
import { VaultLockServiceEvent, VaultLockServiceEventPayload } from './VaultLockServiceEvent'
|
||||||
|
|
||||||
|
export interface VaultLockServiceInterface
|
||||||
|
extends AbstractService<VaultLockServiceEvent, VaultLockServiceEventPayload[VaultLockServiceEvent]> {
|
||||||
|
getLockedvaults(): VaultListingInterface[]
|
||||||
|
isVaultLocked(vault: VaultListingInterface): boolean
|
||||||
|
isVaultLockable(vault: VaultListingInterface): boolean
|
||||||
|
lockNonPersistentVault(vault: VaultListingInterface): void
|
||||||
|
unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise<boolean>
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface'
|
||||||
import { LeaveVault } from './UseCase/LeaveSharedVault'
|
import { LeaveVault } from './UseCase/LeaveSharedVault'
|
||||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
import { GetVault } from '../Vault/UseCase/GetVault'
|
||||||
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
||||||
import { RemoveVaultMember } from './UseCase/RemoveSharedVaultMember'
|
import { RemoveVaultMember } from './UseCase/RemoveSharedVaultMember'
|
||||||
import { VaultServiceInterface } from './../Vaults/VaultServiceInterface'
|
import { VaultServiceInterface } from '../Vault/VaultServiceInterface'
|
||||||
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
||||||
import { GetVaultUsers } from './UseCase/GetVaultUsers'
|
import { GetVaultUsers } from './UseCase/GetVaultUsers'
|
||||||
import { SharedVaultListingInterface } from '@standardnotes/models'
|
import { SharedVaultListingInterface } from '@standardnotes/models'
|
||||||
@@ -17,6 +18,7 @@ export class VaultUserService extends AbstractService<VaultUserServiceEvent> imp
|
|||||||
constructor(
|
constructor(
|
||||||
private session: SessionsClientInterface,
|
private session: SessionsClientInterface,
|
||||||
private vaults: VaultServiceInterface,
|
private vaults: VaultServiceInterface,
|
||||||
|
private vaultLocks: VaultLockServiceInterface,
|
||||||
private _getVaultUsers: GetVaultUsers,
|
private _getVaultUsers: GetVaultUsers,
|
||||||
private _removeVaultMember: RemoveVaultMember,
|
private _removeVaultMember: RemoveVaultMember,
|
||||||
private _isVaultOwner: IsVaultOwner,
|
private _isVaultOwner: IsVaultOwner,
|
||||||
@@ -66,7 +68,7 @@ export class VaultUserService extends AbstractService<VaultUserServiceEvent> imp
|
|||||||
throw new Error('Only vault admins can remove users')
|
throw new Error('Only vault admins can remove users')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.vaults.isVaultLocked(sharedVault)) {
|
if (this.vaultLocks.isVaultLocked(sharedVault)) {
|
||||||
throw new Error('Cannot remove user from locked vault')
|
throw new Error('Cannot remove user from locked vault')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,18 +187,21 @@ export * from './VaultInvite/UseCase/SendVaultInvite'
|
|||||||
export * from './VaultInvite/VaultInviteService'
|
export * from './VaultInvite/VaultInviteService'
|
||||||
export * from './VaultInvite/VaultInviteServiceEvent'
|
export * from './VaultInvite/VaultInviteServiceEvent'
|
||||||
export * from './VaultInvite/VaultInviteServiceInterface'
|
export * from './VaultInvite/VaultInviteServiceInterface'
|
||||||
export * from './Vaults/ChangeVaultOptionsDTO'
|
export * from './Vault/UseCase/ChangeVaultKeyOptionsDTO'
|
||||||
export * from './Vaults/UseCase/ChangeVaultKeyOptions'
|
export * from './Vault/UseCase/ChangeVaultKeyOptions'
|
||||||
export * from './Vaults/UseCase/CreateVault'
|
export * from './Vault/UseCase/CreateVault'
|
||||||
export * from './Vaults/UseCase/DeleteVault'
|
export * from './Vault/UseCase/DeleteVault'
|
||||||
export * from './Vaults/UseCase/GetVault'
|
export * from './Vault/UseCase/GetVault'
|
||||||
export * from './Vaults/UseCase/GetVaults'
|
export * from './Vault/UseCase/GetVaults'
|
||||||
export * from './Vaults/UseCase/MoveItemsToVault'
|
export * from './Vault/UseCase/MoveItemsToVault'
|
||||||
export * from './Vaults/UseCase/RemoveItemFromVault'
|
export * from './Vault/UseCase/RemoveItemFromVault'
|
||||||
export * from './Vaults/UseCase/RotateVaultKey'
|
export * from './Vault/UseCase/RotateVaultKey'
|
||||||
export * from './Vaults/VaultService'
|
export * from './Vault/VaultService'
|
||||||
export * from './Vaults/VaultServiceEvent'
|
export * from './Vault/VaultServiceEvent'
|
||||||
export * from './Vaults/VaultServiceInterface'
|
export * from './Vault/VaultServiceInterface'
|
||||||
|
export * from './VaultLock/VaultLockService'
|
||||||
|
export * from './VaultLock/VaultLockServiceEvent'
|
||||||
|
export * from './VaultLock/VaultLockServiceInterface'
|
||||||
export * from './VaultUser/UseCase/GetVaultContacts'
|
export * from './VaultUser/UseCase/GetVaultContacts'
|
||||||
export * from './VaultUser/UseCase/GetVaultContacts'
|
export * from './VaultUser/UseCase/GetVaultContacts'
|
||||||
export * from './VaultUser/UseCase/GetVaultUsers'
|
export * from './VaultUser/UseCase/GetVaultUsers'
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ import {
|
|||||||
VaultInviteServiceInterface,
|
VaultInviteServiceInterface,
|
||||||
UserEventServiceEvent,
|
UserEventServiceEvent,
|
||||||
VaultServiceEvent,
|
VaultServiceEvent,
|
||||||
|
VaultLockServiceInterface,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import {
|
import {
|
||||||
PayloadEmitSource,
|
PayloadEmitSource,
|
||||||
@@ -1324,18 +1325,6 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return this.dependencies.get<HomeServerServiceInterface | undefined>(TYPES.HomeServerService)
|
return this.dependencies.get<HomeServerServiceInterface | undefined>(TYPES.HomeServerService)
|
||||||
}
|
}
|
||||||
|
|
||||||
public get vaults(): VaultServiceInterface {
|
|
||||||
return this.dependencies.get<VaultServiceInterface>(TYPES.VaultService)
|
|
||||||
}
|
|
||||||
|
|
||||||
public get contacts(): ContactServiceInterface {
|
|
||||||
return this.dependencies.get<ContactServiceInterface>(TYPES.ContactService)
|
|
||||||
}
|
|
||||||
|
|
||||||
public get sharedVaults(): SharedVaultServiceInterface {
|
|
||||||
return this.dependencies.get<SharedVaultServiceInterface>(TYPES.SharedVaultService)
|
|
||||||
}
|
|
||||||
|
|
||||||
public get preferences(): PreferenceServiceInterface {
|
public get preferences(): PreferenceServiceInterface {
|
||||||
return this.dependencies.get<PreferenceServiceInterface>(TYPES.PreferencesService)
|
return this.dependencies.get<PreferenceServiceInterface>(TYPES.PreferencesService)
|
||||||
}
|
}
|
||||||
@@ -1352,6 +1341,14 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return this.dependencies.get<InternalEventBusInterface>(TYPES.InternalEventBus)
|
return this.dependencies.get<InternalEventBusInterface>(TYPES.InternalEventBus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get vaults(): VaultServiceInterface {
|
||||||
|
return this.dependencies.get<VaultServiceInterface>(TYPES.VaultService)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get vaultLocks(): VaultLockServiceInterface {
|
||||||
|
return this.dependencies.get<VaultLockServiceInterface>(TYPES.VaultLockService)
|
||||||
|
}
|
||||||
|
|
||||||
public get vaultUsers(): VaultUserServiceInterface {
|
public get vaultUsers(): VaultUserServiceInterface {
|
||||||
return this.dependencies.get<VaultUserServiceInterface>(TYPES.VaultUserService)
|
return this.dependencies.get<VaultUserServiceInterface>(TYPES.VaultUserService)
|
||||||
}
|
}
|
||||||
@@ -1360,6 +1357,14 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
return this.dependencies.get<VaultInviteServiceInterface>(TYPES.VaultInviteService)
|
return this.dependencies.get<VaultInviteServiceInterface>(TYPES.VaultInviteService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get contacts(): ContactServiceInterface {
|
||||||
|
return this.dependencies.get<ContactServiceInterface>(TYPES.ContactService)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get sharedVaults(): SharedVaultServiceInterface {
|
||||||
|
return this.dependencies.get<SharedVaultServiceInterface>(TYPES.SharedVaultService)
|
||||||
|
}
|
||||||
|
|
||||||
private get migrations(): MigrationService {
|
private get migrations(): MigrationService {
|
||||||
return this.dependencies.get<MigrationService>(TYPES.MigrationService)
|
return this.dependencies.get<MigrationService>(TYPES.MigrationService)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ import {
|
|||||||
GetOwnedSharedVaults,
|
GetOwnedSharedVaults,
|
||||||
ContactBelongsToVault,
|
ContactBelongsToVault,
|
||||||
DeleteContact,
|
DeleteContact,
|
||||||
|
VaultLockService,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { ItemManager } from '../../Services/Items/ItemManager'
|
import { ItemManager } from '../../Services/Items/ItemManager'
|
||||||
import { PayloadManager } from '../../Services/Payloads/PayloadManager'
|
import { PayloadManager } from '../../Services/Payloads/PayloadManager'
|
||||||
@@ -650,6 +651,7 @@ export class Dependencies {
|
|||||||
return new VaultUserService(
|
return new VaultUserService(
|
||||||
this.get(TYPES.SessionManager),
|
this.get(TYPES.SessionManager),
|
||||||
this.get(TYPES.VaultService),
|
this.get(TYPES.VaultService),
|
||||||
|
this.get(TYPES.VaultLockService),
|
||||||
this.get(TYPES.GetVaultUsers),
|
this.get(TYPES.GetVaultUsers),
|
||||||
this.get(TYPES.RemoveVaultMember),
|
this.get(TYPES.RemoveVaultMember),
|
||||||
this.get(TYPES.IsVaultOwner),
|
this.get(TYPES.IsVaultOwner),
|
||||||
@@ -725,13 +727,22 @@ export class Dependencies {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.factory.set(TYPES.VaultLockService, () => {
|
||||||
|
return new VaultLockService(
|
||||||
|
this.get(TYPES.ItemManager),
|
||||||
|
this.get(TYPES.EncryptionService),
|
||||||
|
this.get(TYPES.KeySystemKeyManager),
|
||||||
|
this.get(TYPES.GetVaults),
|
||||||
|
this.get(TYPES.InternalEventBus),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
this.factory.set(TYPES.VaultService, () => {
|
this.factory.set(TYPES.VaultService, () => {
|
||||||
return new VaultService(
|
return new VaultService(
|
||||||
this.get(TYPES.SyncService),
|
this.get(TYPES.SyncService),
|
||||||
this.get(TYPES.ItemManager),
|
this.get(TYPES.ItemManager),
|
||||||
this.get(TYPES.MutatorService),
|
this.get(TYPES.MutatorService),
|
||||||
this.get(TYPES.EncryptionService),
|
this.get(TYPES.VaultLockService),
|
||||||
this.get(TYPES.KeySystemKeyManager),
|
|
||||||
this.get(TYPES.AlertService),
|
this.get(TYPES.AlertService),
|
||||||
this.get(TYPES.GetVault),
|
this.get(TYPES.GetVault),
|
||||||
this.get(TYPES.GetVaults),
|
this.get(TYPES.GetVaults),
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export const TYPES = {
|
|||||||
VaultUserService: Symbol.for('VaultUserService'),
|
VaultUserService: Symbol.for('VaultUserService'),
|
||||||
VaultInviteService: Symbol.for('VaultInviteService'),
|
VaultInviteService: Symbol.for('VaultInviteService'),
|
||||||
VaultUserCache: Symbol.for('VaultUserCache'),
|
VaultUserCache: Symbol.for('VaultUserCache'),
|
||||||
|
VaultLockService: Symbol.for('VaultLockService'),
|
||||||
|
|
||||||
// Servers
|
// Servers
|
||||||
RevisionServer: Symbol.for('RevisionServer'),
|
RevisionServer: Symbol.for('RevisionServer'),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const VaultTests = {
|
|||||||
'vaults/signatures.test.js',
|
'vaults/signatures.test.js',
|
||||||
'vaults/shared_vaults.test.js',
|
'vaults/shared_vaults.test.js',
|
||||||
'vaults/invites.test.js',
|
'vaults/invites.test.js',
|
||||||
|
'vaults/locking.test.js',
|
||||||
'vaults/items.test.js',
|
'vaults/items.test.js',
|
||||||
'vaults/conflicts.test.js',
|
'vaults/conflicts.test.js',
|
||||||
'vaults/deletion.test.js',
|
'vaults/deletion.test.js',
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ export class AppContext {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get vaults() {
|
|
||||||
return this.application.vaults
|
|
||||||
}
|
|
||||||
|
|
||||||
get sessions() {
|
get sessions() {
|
||||||
return this.application.sessions
|
return this.application.sessions
|
||||||
}
|
}
|
||||||
@@ -97,6 +93,14 @@ export class AppContext {
|
|||||||
return this.application.sharedVaults
|
return this.application.sharedVaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get vaults() {
|
||||||
|
return this.application.vaults
|
||||||
|
}
|
||||||
|
|
||||||
|
get vaultLocks() {
|
||||||
|
return this.application.vaultLocks
|
||||||
|
}
|
||||||
|
|
||||||
get vaultUsers() {
|
get vaultUsers() {
|
||||||
return this.application.vaultUsers
|
return this.application.vaultUsers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,27 @@ export const createSharedVaultWithUnacceptedButTrustedInvite = async (
|
|||||||
return { sharedVault, contact, contactContext, deinitContactContext, invite }
|
return { sharedVault, contact, contactContext, deinitContactContext, invite }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const createSharedVaultAndInviteContact = async (
|
||||||
|
createInContext,
|
||||||
|
inviteContext,
|
||||||
|
inviteContact,
|
||||||
|
permissions = SharedVaultPermission.Write,
|
||||||
|
) => {
|
||||||
|
const sharedVault = await createSharedVault(createInContext)
|
||||||
|
|
||||||
|
await createInContext.vaultInvites.inviteContactToSharedVault(sharedVault, inviteContact, permissions)
|
||||||
|
|
||||||
|
const promise = inviteContext.awaitNextSyncSharedVaultFromScratchEvent()
|
||||||
|
|
||||||
|
await inviteContext.sync()
|
||||||
|
|
||||||
|
await acceptAllInvites(inviteContext)
|
||||||
|
|
||||||
|
await promise
|
||||||
|
|
||||||
|
return { sharedVault }
|
||||||
|
}
|
||||||
|
|
||||||
export const createSharedVaultWithUnacceptedAndUntrustedInvite = async (
|
export const createSharedVaultWithUnacceptedAndUntrustedInvite = async (
|
||||||
context,
|
context,
|
||||||
permissions = SharedVaultPermission.Write,
|
permissions = SharedVaultPermission.Write,
|
||||||
@@ -113,7 +134,6 @@ export const inviteNewPartyToSharedVault = async (context, sharedVault, permissi
|
|||||||
export const createPrivateVault = async (context) => {
|
export const createPrivateVault = async (context) => {
|
||||||
const privateVault = await context.vaults.createRandomizedVault({
|
const privateVault = await context.vaults.createRandomizedVault({
|
||||||
name: 'My Private Vault',
|
name: 'My Private Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return privateVault
|
return privateVault
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
await loadTests(MainRegistry.VaultTests.files);
|
await loadTests(MainRegistry.VaultTests.files);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MainRegistry.VaultTests.enabled.exclusive) {
|
if (!MainRegistry.VaultTests.enabled || !MainRegistry.VaultTests.enabled.exclusive) {
|
||||||
await loadTests(MainRegistry.BaseTests);
|
await loadTests(MainRegistry.BaseTests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,16 @@ describe('shared vault deletion', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('being removed from a shared vault should delete respective vault listing', async () => {
|
it('being removed from a shared vault should delete respective vault listing', async () => {
|
||||||
console.error('TODO: implement test')
|
const { sharedVault, contactContext, deinitContactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
|
||||||
|
await context.vaultUsers.removeUserFromSharedVault(sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
await contactContext.sync()
|
||||||
|
|
||||||
|
const vault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(vault).to.be.undefined
|
||||||
|
|
||||||
|
await deinitContactContext()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -200,10 +200,6 @@ describe('shared vault invites', function () {
|
|||||||
await deinitContactContext()
|
await deinitContactContext()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('when inviter keypair changes, recipient should still be able to trust and decrypt previous invite', async () => {
|
|
||||||
console.error('TODO: implement test')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should delete all inbound invites after changing user password', async () => {
|
it('should delete all inbound invites after changing user password', async () => {
|
||||||
/** Invites to user are encrypted with old keypair and are no longer decryptable */
|
/** Invites to user are encrypted with old keypair and are no longer decryptable */
|
||||||
const { contactContext, deinitContactContext } =
|
const { contactContext, deinitContactContext } =
|
||||||
|
|||||||
@@ -117,6 +117,28 @@ describe('shared vault items', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('adding item to vault while belonging to other vault should move the item to new vault', async () => {
|
it('adding item to vault while belonging to other vault should move the item to new vault', async () => {
|
||||||
console.error('TODO: implement test')
|
const { note, sharedVault, contactContext, contact, deinitContactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
||||||
|
|
||||||
|
const { sharedVault: otherSharedVault } = await Collaboration.createSharedVaultAndInviteContact(
|
||||||
|
context,
|
||||||
|
contactContext,
|
||||||
|
contact,
|
||||||
|
)
|
||||||
|
|
||||||
|
const updatedNote = await Collaboration.moveItemToVault(context, otherSharedVault, note)
|
||||||
|
|
||||||
|
expect(updatedNote.key_system_identifier).to.equal(otherSharedVault.systemIdentifier)
|
||||||
|
expect(updatedNote.shared_vault_uuid).to.equal(otherSharedVault.sharing.sharedVaultUuid)
|
||||||
|
|
||||||
|
await contactContext.sync()
|
||||||
|
|
||||||
|
const receivedNote = contactContext.items.findItem(note.uuid)
|
||||||
|
expect(receivedNote).to.not.be.undefined
|
||||||
|
expect(receivedNote.title).to.equal(note.title)
|
||||||
|
expect(receivedNote.key_system_identifier).to.equal(otherSharedVault.systemIdentifier)
|
||||||
|
expect(receivedNote.shared_vault_uuid).to.equal(otherSharedVault.sharing.sharedVaultUuid)
|
||||||
|
|
||||||
|
await deinitContactContext()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -229,36 +229,4 @@ describe('shared vault key rotation', function () {
|
|||||||
|
|
||||||
await deinitContactContext()
|
await deinitContactContext()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw if attempting to change password of locked vault', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respect storage preference when rotating key system root key', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should change storage preference from synced to local', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should change storage preference from local to synced', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should resync key system items key if it is encrypted with noncurrent key system root key', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should change password type from user inputted to randomized', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should change password type from randomized to user inputted', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not be able to change storage mode of third party vault', async () => {
|
|
||||||
console.error('TODO: implement')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
108
packages/snjs/mocha/vaults/locking.test.js
Normal file
108
packages/snjs/mocha/vaults/locking.test.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import * as Factory from '../lib/factory.js'
|
||||||
|
import * as Collaboration from '../lib/Collaboration.js'
|
||||||
|
|
||||||
|
chai.use(chaiAsPromised)
|
||||||
|
const expect = chai.expect
|
||||||
|
|
||||||
|
describe('vault locking', 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('should lock non-persistent vault', async () => {
|
||||||
|
const vault = await context.vaults.createUserInputtedPasswordVault({
|
||||||
|
name: 'test vault',
|
||||||
|
description: 'test vault description',
|
||||||
|
userInputtedPassword: 'test password',
|
||||||
|
storagePreference: KeySystemRootKeyStorageMode.Ephemeral,
|
||||||
|
})
|
||||||
|
|
||||||
|
context.vaultLocks.lockNonPersistentVault(vault)
|
||||||
|
|
||||||
|
expect(context.vaultLocks.isVaultLocked(vault)).to.be.true
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not be able to lock user-inputted vault with synced key', async () => {
|
||||||
|
const vault = await context.vaults.createUserInputtedPasswordVault({
|
||||||
|
name: 'test vault',
|
||||||
|
description: 'test vault description',
|
||||||
|
userInputtedPassword: 'test password',
|
||||||
|
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw(
|
||||||
|
Error,
|
||||||
|
'Vault uses synced key storage and cannot be locked',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not be able to lock randomized vault', async () => {
|
||||||
|
const vault = await context.vaults.createRandomizedVault({
|
||||||
|
name: 'test vault',
|
||||||
|
description: 'test vault description',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw(
|
||||||
|
Error,
|
||||||
|
'Vault uses synced key storage and cannot be locked',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw if attempting to change password of locked vault', async () => {
|
||||||
|
const vault = await context.vaults.createUserInputtedPasswordVault({
|
||||||
|
name: 'test vault',
|
||||||
|
description: 'test vault description',
|
||||||
|
userInputtedPassword: 'test password',
|
||||||
|
storagePreference: KeySystemRootKeyStorageMode.Ephemeral,
|
||||||
|
})
|
||||||
|
|
||||||
|
context.vaultLocks.lockNonPersistentVault(vault)
|
||||||
|
|
||||||
|
await Factory.expectThrowsAsync(
|
||||||
|
() => context.vaults.changeVaultOptions({ vault }),
|
||||||
|
'Attempting to change vault options on a locked vault',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respect storage preference when rotating key system root key', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should change storage preference from synced to local', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should change storage preference from local to synced', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should resync key system items key if it is encrypted with noncurrent key system root key', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should change password type from user inputted to randomized', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should change password type from randomized to user inputted', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not be able to change storage mode of third party vault', async () => {
|
||||||
|
console.error('TODO: implement')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -42,7 +42,6 @@ describe('vaults', function () {
|
|||||||
it('should be able to create an offline vault', async () => {
|
it('should be able to create an offline vault', async () => {
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(vault.systemIdentifier).to.not.be.undefined
|
expect(vault.systemIdentifier).to.not.be.undefined
|
||||||
@@ -59,7 +58,6 @@ describe('vaults', function () {
|
|||||||
await context.application.addPasscode('123')
|
await context.application.addPasscode('123')
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(vault.systemIdentifier).to.not.be.undefined
|
expect(vault.systemIdentifier).to.not.be.undefined
|
||||||
@@ -75,7 +73,6 @@ describe('vaults', function () {
|
|||||||
it('should add item to offline vault', async () => {
|
it('should add item to offline vault', async () => {
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const item = await context.createSyncedNote()
|
const item = await context.createSyncedNote()
|
||||||
|
|
||||||
@@ -89,7 +86,6 @@ describe('vaults', function () {
|
|||||||
const appIdentifier = context.identifier
|
const appIdentifier = context.identifier
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
@@ -110,7 +106,6 @@ describe('vaults', function () {
|
|||||||
const appIdentifier = context.identifier
|
const appIdentifier = context.identifier
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
@@ -138,7 +133,6 @@ describe('vaults', function () {
|
|||||||
const appIdentifier = context.identifier
|
const appIdentifier = context.identifier
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
@@ -168,7 +162,6 @@ describe('vaults', function () {
|
|||||||
it('should create a vault', async () => {
|
it('should create a vault', async () => {
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
expect(vault).to.not.be.undefined
|
expect(vault).to.not.be.undefined
|
||||||
|
|
||||||
@@ -184,7 +177,6 @@ describe('vaults', function () {
|
|||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
@@ -198,7 +190,6 @@ describe('vaults', function () {
|
|||||||
const appIdentifier = context.identifier
|
const appIdentifier = context.identifier
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
@@ -219,7 +210,6 @@ describe('vaults', function () {
|
|||||||
it('rotating a key system root key should create a new vault items key', async () => {
|
it('rotating a key system root key should create a new vault items key', async () => {
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const keySystemItemsKey = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)[0]
|
const keySystemItemsKey = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)[0]
|
||||||
@@ -235,7 +225,6 @@ describe('vaults', function () {
|
|||||||
it('deleting a vault should delete all its items', async () => {
|
it('deleting a vault should delete all its items', async () => {
|
||||||
const vault = await vaults.createRandomizedVault({
|
const vault = await vaults.createRandomizedVault({
|
||||||
name: 'My Vault',
|
name: 'My Vault',
|
||||||
storagePreference: KeySystemRootKeyStorageMode.Synced,
|
|
||||||
})
|
})
|
||||||
const note = await context.createSyncedNote('foo', 'bar')
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
await vaults.moveItemToVault(vault, note)
|
await vaults.moveItemToVault(vault, note)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
InternalEventHandlerInterface,
|
InternalEventHandlerInterface,
|
||||||
InternalEventInterface,
|
InternalEventInterface,
|
||||||
StorageKey,
|
StorageKey,
|
||||||
VaultServiceEvent,
|
VaultLockServiceEvent,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { VaultDisplayOptions, VaultDisplayOptionsPersistable, VaultListingInterface } from '@standardnotes/models'
|
import { VaultDisplayOptions, VaultDisplayOptionsPersistable, VaultListingInterface } from '@standardnotes/models'
|
||||||
import { VaultDisplayServiceEvent } from './VaultDisplayServiceEvent'
|
import { VaultDisplayServiceEvent } from './VaultDisplayServiceEvent'
|
||||||
@@ -33,8 +33,8 @@ export class VaultDisplayService
|
|||||||
|
|
||||||
this.options = new VaultDisplayOptions({ exclude: [], locked: [] })
|
this.options = new VaultDisplayOptions({ exclude: [], locked: [] })
|
||||||
|
|
||||||
internalEventBus.addEventHandler(this, VaultServiceEvent.VaultLocked)
|
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultLocked)
|
||||||
internalEventBus.addEventHandler(this, VaultServiceEvent.VaultUnlocked)
|
internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultUnlocked)
|
||||||
internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged)
|
internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged)
|
||||||
|
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
@@ -51,7 +51,7 @@ export class VaultDisplayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||||
if (event.type === VaultServiceEvent.VaultLocked || event.type === VaultServiceEvent.VaultUnlocked) {
|
if (event.type === VaultLockServiceEvent.VaultLocked || event.type === VaultLockServiceEvent.VaultUnlocked) {
|
||||||
this.handleVaultLockingStatusChanged()
|
this.handleVaultLockingStatusChanged()
|
||||||
} else if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
} else if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||||
@@ -62,7 +62,7 @@ export class VaultDisplayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleVaultLockingStatusChanged(): void {
|
private handleVaultLockingStatusChanged(): void {
|
||||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
const lockedVaults = this.application.vaultLocks.getLockedvaults()
|
||||||
|
|
||||||
const options = this.options.newOptionsByIntakingLockedVaults(lockedVaults)
|
const options = this.options.newOptionsByIntakingLockedVaults(lockedVaults)
|
||||||
this.setVaultSelectionOptions(options)
|
this.setVaultSelectionOptions(options)
|
||||||
@@ -90,7 +90,7 @@ export class VaultDisplayService
|
|||||||
|
|
||||||
changeToMultipleVaultDisplayMode(): void {
|
changeToMultipleVaultDisplayMode(): void {
|
||||||
const vaults = this.application.vaults.getVaults()
|
const vaults = this.application.vaults.getVaults()
|
||||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
const lockedVaults = this.application.vaultLocks.getLockedvaults()
|
||||||
|
|
||||||
const newOptions = new VaultDisplayOptions({
|
const newOptions = new VaultDisplayOptions({
|
||||||
exclude: vaults
|
exclude: vaults
|
||||||
@@ -103,26 +103,26 @@ export class VaultDisplayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
hideVault = (vault: VaultListingInterface) => {
|
hideVault = (vault: VaultListingInterface) => {
|
||||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
const lockedVaults = this.application.vaultLocks.getLockedvaults()
|
||||||
const newOptions = this.options.newOptionsByExcludingVault(vault, lockedVaults)
|
const newOptions = this.options.newOptionsByExcludingVault(vault, lockedVaults)
|
||||||
this.setVaultSelectionOptions(newOptions)
|
this.setVaultSelectionOptions(newOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
unhideVault = async (vault: VaultListingInterface) => {
|
unhideVault = async (vault: VaultListingInterface) => {
|
||||||
if (this.application.vaults.isVaultLocked(vault)) {
|
if (this.application.vaultLocks.isVaultLocked(vault)) {
|
||||||
const unlocked = await this.unlockVault(vault)
|
const unlocked = await this.unlockVault(vault)
|
||||||
if (!unlocked) {
|
if (!unlocked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lockedVaults = this.application.vaults.getLockedvaults()
|
const lockedVaults = this.application.vaultLocks.getLockedvaults()
|
||||||
const newOptions = this.options.newOptionsByUnexcludingVault(vault, lockedVaults)
|
const newOptions = this.options.newOptionsByUnexcludingVault(vault, lockedVaults)
|
||||||
this.setVaultSelectionOptions(newOptions)
|
this.setVaultSelectionOptions(newOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
showOnlyVault = async (vault: VaultListingInterface) => {
|
showOnlyVault = async (vault: VaultListingInterface) => {
|
||||||
if (this.application.vaults.isVaultLocked(vault)) {
|
if (this.application.vaultLocks.isVaultLocked(vault)) {
|
||||||
const unlocked = await this.unlockVault(vault)
|
const unlocked = await this.unlockVault(vault)
|
||||||
if (!unlocked) {
|
if (!unlocked) {
|
||||||
return
|
return
|
||||||
@@ -134,7 +134,7 @@ export class VaultDisplayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
async unlockVault(vault: VaultListingInterface): Promise<boolean> {
|
async unlockVault(vault: VaultListingInterface): Promise<boolean> {
|
||||||
if (!this.application.vaults.isVaultLocked(vault)) {
|
if (!this.application.vaultLocks.isVaultLocked(vault)) {
|
||||||
throw new Error('Attempting to unlock a vault that is not locked.')
|
throw new Error('Attempting to unlock a vault that is not locked.')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ export class VaultDisplayService
|
|||||||
|
|
||||||
const password = value.value as string
|
const password = value.value as string
|
||||||
|
|
||||||
const unlocked = await this.application.vaults.unlockNonPersistentVault(vault, password)
|
const unlocked = await this.application.vaultLocks.unlockNonPersistentVault(vault, password)
|
||||||
if (!unlocked) {
|
if (!unlocked) {
|
||||||
this.application.challenges.setValidationStatusForChallenge(challenge, value, false)
|
this.application.challenges.setValidationStatusForChallenge(challenge, value, false)
|
||||||
resolve(false)
|
resolve(false)
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ const VaultItem = ({ vault }: Props) => {
|
|||||||
}, [application.sharedVaults, vault])
|
}, [application.sharedVaults, vault])
|
||||||
|
|
||||||
const ensureVaultIsUnlocked = useCallback(async () => {
|
const ensureVaultIsUnlocked = useCallback(async () => {
|
||||||
if (!application.vaults.isVaultLocked(vault)) {
|
if (!application.vaultLocks.isVaultLocked(vault)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
||||||
return unlocked
|
return unlocked
|
||||||
}, [application.vaultDisplayService, application.vaults, vault])
|
}, [application, vault])
|
||||||
|
|
||||||
const openEditModal = useCallback(async () => {
|
const openEditModal = useCallback(async () => {
|
||||||
if (!(await ensureVaultIsUnlocked())) {
|
if (!(await ensureVaultIsUnlocked())) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
|||||||
import DecoratedInput from '@/Components/Input/DecoratedInput'
|
import DecoratedInput from '@/Components/Input/DecoratedInput'
|
||||||
import { useApplication } from '@/Components/ApplicationProvider'
|
import { useApplication } from '@/Components/ApplicationProvider'
|
||||||
import {
|
import {
|
||||||
ChangeVaultOptionsDTO,
|
ChangeVaultKeyOptionsDTO,
|
||||||
KeySystemRootKeyPasswordType,
|
KeySystemRootKeyPasswordType,
|
||||||
KeySystemRootKeyStorageMode,
|
KeySystemRootKeyStorageMode,
|
||||||
SharedVaultInviteServerHash,
|
SharedVaultInviteServerHash,
|
||||||
@@ -89,7 +89,7 @@ const EditVaultModal: FunctionComponent<Props> = ({ onCloseDialog, existingVault
|
|||||||
const isChangingPasswordType = vault.keyPasswordType !== passwordType
|
const isChangingPasswordType = vault.keyPasswordType !== passwordType
|
||||||
const isChangingKeyStorageMode = vault.keyStorageMode !== keyStorageMode
|
const isChangingKeyStorageMode = vault.keyStorageMode !== keyStorageMode
|
||||||
|
|
||||||
const getPasswordTypeParams = (): ChangeVaultOptionsDTO['newPasswordType'] => {
|
const getPasswordTypeParams = (): ChangeVaultKeyOptionsDTO['newPasswordType'] => {
|
||||||
if (!isChangingPasswordType) {
|
if (!isChangingPasswordType) {
|
||||||
throw new Error('Password type is not changing')
|
throw new Error('Password type is not changing')
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,6 @@ const EditVaultModal: FunctionComponent<Props> = ({ onCloseDialog, existingVault
|
|||||||
await application.vaults.createRandomizedVault({
|
await application.vaults.createRandomizedVault({
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
storagePreference: keyStorageMode,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +168,7 @@ const EditVaultModal: FunctionComponent<Props> = ({ onCloseDialog, existingVault
|
|||||||
[existingVault, handleDialogClose, handleSubmit],
|
[existingVault, handleDialogClose, handleSubmit],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (existingVault && application.vaults.isVaultLocked(existingVault)) {
|
if (existingVault && application.vaultLocks.isVaultLocked(existingVault)) {
|
||||||
return <div>Vault is locked.</div>
|
return <div>Vault is locked.</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const ManyVaultSelectionMenu: FunctionComponent = () => {
|
|||||||
<Icon type="safe-square" className="mr-2 text-neutral" />
|
<Icon type="safe-square" className="mr-2 text-neutral" />
|
||||||
<div className="flex w-full items-center gap-1">
|
<div className="flex w-full items-center gap-1">
|
||||||
{vault.name}
|
{vault.name}
|
||||||
{application.vaults.isVaultLocked(vault) && <Icon className="ml-1" type="lock" size={'small'} />}
|
{application.vaultLocks.isVaultLocked(vault) && <Icon className="ml-1" type="lock" size={'small'} />}
|
||||||
</div>
|
</div>
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const SingleVaultSelectionMenu: FunctionComponent = () => {
|
|||||||
<MenuRadioButtonItem key={vault.uuid} checked={isVaultVisible(vault)} onClick={() => selectVault(vault)}>
|
<MenuRadioButtonItem key={vault.uuid} checked={isVaultVisible(vault)} onClick={() => selectVault(vault)}>
|
||||||
<div className="flex w-full items-center gap-1">
|
<div className="flex w-full items-center gap-1">
|
||||||
{vault.name}
|
{vault.name}
|
||||||
{application.vaults.isVaultLocked(vault) && <Icon className="ml-1" type="lock" size={'small'} />}
|
{application.vaultLocks.isVaultLocked(vault) && <Icon className="ml-1" type="lock" size={'small'} />}
|
||||||
</div>
|
</div>
|
||||||
</MenuRadioButtonItem>
|
</MenuRadioButtonItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const AddToVaultMenuOption: FunctionComponent<Props> = ({ iconClassName, items }
|
|||||||
|
|
||||||
const addItemsToVault = useCallback(
|
const addItemsToVault = useCallback(
|
||||||
async (vault: VaultListingInterface) => {
|
async (vault: VaultListingInterface) => {
|
||||||
if (application.vaults.isVaultLocked(vault)) {
|
if (application.vaultLocks.isVaultLocked(vault)) {
|
||||||
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
||||||
if (!unlocked) {
|
if (!unlocked) {
|
||||||
return
|
return
|
||||||
@@ -40,7 +40,7 @@ const AddToVaultMenuOption: FunctionComponent<Props> = ({ iconClassName, items }
|
|||||||
await application.vaults.moveItemToVault(vault, item)
|
await application.vaults.moveItemToVault(vault, item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[application.vaultDisplayService, application.vaults, items],
|
[application, items],
|
||||||
)
|
)
|
||||||
|
|
||||||
const removeItemsFromVault = useCallback(async () => {
|
const removeItemsFromVault = useCallback(async () => {
|
||||||
@@ -50,7 +50,7 @@ const AddToVaultMenuOption: FunctionComponent<Props> = ({ iconClassName, items }
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application.vaults.isVaultLocked(vault)) {
|
if (application.vaultLocks.isVaultLocked(vault)) {
|
||||||
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
const unlocked = await application.vaultDisplayService.unlockVault(vault)
|
||||||
if (!unlocked) {
|
if (!unlocked) {
|
||||||
return
|
return
|
||||||
@@ -58,7 +58,7 @@ const AddToVaultMenuOption: FunctionComponent<Props> = ({ iconClassName, items }
|
|||||||
}
|
}
|
||||||
await application.vaults.removeItemFromVault(item)
|
await application.vaults.removeItemFromVault(item)
|
||||||
}
|
}
|
||||||
}, [application.vaultDisplayService, application.vaults, items])
|
}, [application, items])
|
||||||
|
|
||||||
const doesVaultContainItems = (vault: VaultListingInterface) => {
|
const doesVaultContainItems = (vault: VaultListingInterface) => {
|
||||||
return items.every((item) => item.key_system_identifier === vault.systemIdentifier)
|
return items.every((item) => item.key_system_identifier === vault.systemIdentifier)
|
||||||
@@ -140,7 +140,9 @@ const AddToVaultMenuOption: FunctionComponent<Props> = ({ iconClassName, items }
|
|||||||
/>
|
/>
|
||||||
<div className="flex w-full items-center">
|
<div className="flex w-full items-center">
|
||||||
{vault.name}
|
{vault.name}
|
||||||
{application.vaults.isVaultLocked(vault) && <Icon className="ml-1" type="lock" size={'small'} />}
|
{application.vaultLocks.isVaultLocked(vault) && (
|
||||||
|
<Icon className="ml-1" type="lock" size={'small'} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
Reference in New Issue
Block a user