internal: change password preprocessing step (#2347)

This commit is contained in:
Mo
2023-07-06 08:51:06 -05:00
committed by GitHub
parent 5c6ccaf4e1
commit c8e52b667c
39 changed files with 647 additions and 332 deletions

View File

@@ -1,3 +1,4 @@
import { AsymmetricMessageServiceInterface } from './../AsymmetricMessage/AsymmetricMessageServiceInterface'
import { SyncOptions } from './../Sync/SyncOptions'
import { ImportDataReturnType } from './../Mutator/ImportDataUseCase'
import { ChallengeServiceInterface } from './../Challenge/ChallengeServiceInterface'
@@ -102,6 +103,8 @@ export interface ApplicationInterface {
get vaults(): VaultServiceInterface
get challenges(): ChallengeServiceInterface
get alerts(): AlertService
get asymmetric(): AsymmetricMessageServiceInterface
readonly identifier: ApplicationIdentifier
readonly platform: Platform
deviceInterface: DeviceInterface

View File

@@ -1,6 +1,6 @@
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
import { ContactServiceInterface } from './../Contacts/ContactServiceInterface'
import { AsymmetricMessageServerHash, ClientDisplayableError } from '@standardnotes/responses'
import { AsymmetricMessageServerHash, ClientDisplayableError, isClientDisplayableError } from '@standardnotes/responses'
import { SyncEvent, SyncEventReceivedAsymmetricMessagesData } from '../Event/SyncEvent'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { InternalEventHandlerInterface } from '../Internal/InternalEventHandlerInterface'
@@ -27,8 +27,12 @@ import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessa
import { GetOutboundAsymmetricMessages } from './UseCase/GetOutboundAsymmetricMessages'
import { GetInboundAsymmetricMessages } from './UseCase/GetInboundAsymmetricMessages'
import { GetVaultUseCase } from '../Vaults/UseCase/GetVault'
import { AsymmetricMessageServiceInterface } from './AsymmetricMessageServiceInterface'
export class AsymmetricMessageService extends AbstractService implements InternalEventHandlerInterface {
export class AsymmetricMessageService
extends AbstractService
implements AsymmetricMessageServiceInterface, InternalEventHandlerInterface
{
private messageServer: AsymmetricMessageServer
constructor(
@@ -69,7 +73,16 @@ export class AsymmetricMessageService extends AbstractService implements Interna
return usecase.execute()
}
async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise<void> {
public async downloadAndProcessInboundMessages(): Promise<void> {
const messages = await this.getInboundMessages()
if (isClientDisplayableError(messages)) {
return
}
await this.handleRemoteReceivedAsymmetricMessages(messages)
}
private async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise<void> {
if (!data.oldKeyPair || !data.oldSigningKeyPair) {
return
}

View File

@@ -0,0 +1,7 @@
import { AsymmetricMessageServerHash, ClientDisplayableError } from '@standardnotes/responses'
export interface AsymmetricMessageServiceInterface {
getOutboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError>
getInboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError>
downloadAndProcessInboundMessages(): Promise<void>
}

View File

@@ -237,7 +237,7 @@ export class ContactService
}
findTrustedContactForInvite(invite: SharedVaultInviteServerHash): TrustedContactInterface | undefined {
return this.findTrustedContact(invite.user_uuid)
return this.findTrustedContact(invite.sender_uuid)
}
getCollaborationIDForTrustedContact(contact: TrustedContactInterface): string {

View File

@@ -21,7 +21,7 @@ import { PublicKeySet } from '@standardnotes/encryption'
export class SelfContactManager {
public selfContact?: TrustedContactInterface
private shouldReloadSelfContact = true
private isReloadingSelfContact = false
private eventDisposers: (() => void)[] = []
@@ -32,16 +32,14 @@ export class SelfContactManager {
private session: SessionsClientInterface,
private singletons: SingletonManagerInterface,
) {
this.eventDisposers.push(
items.addObserver(ContentType.TrustedContact, () => {
this.shouldReloadSelfContact = true
}),
)
this.eventDisposers.push(
sync.addEventObserver((event) => {
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded || event === SyncEvent.LocalDataIncrementalLoad) {
void this.reloadSelfContact()
if (event === SyncEvent.LocalDataIncrementalLoad) {
this.loadSelfContactFromDatabase()
}
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded) {
void this.reloadSelfContactAndCreateIfNecessary()
}
}),
)
@@ -49,13 +47,21 @@ export class SelfContactManager {
public async handleApplicationStage(stage: ApplicationStage): Promise<void> {
if (stage === ApplicationStage.LoadedDatabase_12) {
this.selfContact = this.singletons.findSingleton<TrustedContactInterface>(
ContentType.UserPrefs,
TrustedContact.singletonPredicate,
)
this.loadSelfContactFromDatabase()
}
}
private loadSelfContactFromDatabase(): void {
if (this.selfContact) {
return
}
this.selfContact = this.singletons.findSingleton<TrustedContactInterface>(
ContentType.TrustedContact,
TrustedContact.singletonPredicate,
)
}
public async updateWithNewPublicKeySet(publicKeySet: PublicKeySet) {
if (!InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)) {
return
@@ -74,12 +80,16 @@ export class SelfContactManager {
})
}
private async reloadSelfContact() {
private async reloadSelfContactAndCreateIfNecessary() {
if (!InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)) {
return
}
if (!this.shouldReloadSelfContact || this.isReloadingSelfContact) {
if (this.selfContact) {
return
}
if (this.isReloadingSelfContact) {
return
}
@@ -105,17 +115,13 @@ export class SelfContactManager {
}),
}
try {
this.selfContact = await this.singletons.findOrCreateSingleton<TrustedContactContent, TrustedContact>(
TrustedContact.singletonPredicate,
ContentType.TrustedContact,
FillItemContent<TrustedContactContent>(content),
)
this.selfContact = await this.singletons.findOrCreateSingleton<TrustedContactContent, TrustedContact>(
TrustedContact.singletonPredicate,
ContentType.TrustedContact,
FillItemContent<TrustedContactContent>(content),
)
this.shouldReloadSelfContact = false
} finally {
this.isReloadingSelfContact = false
}
this.isReloadingSelfContact = false
}
deinit() {

View File

@@ -283,6 +283,7 @@ export class EncryptionService
const usecase = new CreateNewItemsKeyWithRollbackUseCase(
this.mutator,
this.items,
this.storage,
this.operators,
this.rootKeyManager,
)

View File

@@ -1,8 +1,10 @@
import { StorageServiceInterface } from './../../../Storage/StorageServiceInterface'
import { ItemsKeyMutator, OperatorManager, findDefaultItemsKey } from '@standardnotes/encryption'
import { MutatorClientInterface } from '../../../Mutator/MutatorClientInterface'
import { ItemManagerInterface } from '../../../Item/ItemManagerInterface'
import { RootKeyManager } from '../../RootKey/RootKeyManager'
import { CreateNewDefaultItemsKeyUseCase } from './CreateNewDefaultItemsKey'
import { RemoveItemsLocallyUseCase } from '../../../UseCase/RemoveItemsLocally'
export class CreateNewItemsKeyWithRollbackUseCase {
private createDefaultItemsKeyUseCase = new CreateNewDefaultItemsKeyUseCase(
@@ -12,9 +14,12 @@ export class CreateNewItemsKeyWithRollbackUseCase {
this.rootKeyManager,
)
private removeItemsLocallyUsecase = new RemoveItemsLocallyUseCase(this.items, this.storage)
constructor(
private mutator: MutatorClientInterface,
private items: ItemManagerInterface,
private storage: StorageServiceInterface,
private operatorManager: OperatorManager,
private rootKeyManager: RootKeyManager,
) {}
@@ -24,7 +29,7 @@ export class CreateNewItemsKeyWithRollbackUseCase {
const newDefaultItemsKey = await this.createDefaultItemsKeyUseCase.execute()
const rollback = async () => {
await this.mutator.setItemToBeDeleted(newDefaultItemsKey)
await this.removeItemsLocallyUsecase.execute([newDefaultItemsKey])
if (currentDefaultItemsKey) {
await this.mutator.changeItem<ItemsKeyMutator>(currentDefaultItemsKey, (mutator) => {

View File

@@ -111,7 +111,9 @@ export class SharedVaultService
)
this.eventDisposers.push(
items.addObserver<TrustedContactInterface>(ContentType.TrustedContact, ({ changed, inserted, source }) => {
items.addObserver<TrustedContactInterface>(ContentType.TrustedContact, async ({ changed, inserted, source }) => {
await this.reprocessCachedInvitesTrustStatusAfterTrustedContactsChange()
if (source === PayloadEmitSource.LocalChanged && inserted.length > 0) {
void this.handleCreationOfNewTrustedContacts(inserted)
}
@@ -250,8 +252,6 @@ export class SharedVaultService
}
private async handleTrustedContactsChange(contacts: TrustedContactInterface[]): Promise<void> {
await this.reprocessCachedInvitesTrustStatusAfterTrustedContactsChange()
for (const contact of contacts) {
await this.shareContactWithUserAdministeredSharedVaults(contact)
}
@@ -328,28 +328,9 @@ export class SharedVaultService
}
private async reprocessCachedInvitesTrustStatusAfterTrustedContactsChange(): Promise<void> {
const cachedInvites = this.getCachedPendingInviteRecords()
const cachedInvites = this.getCachedPendingInviteRecords().map((record) => record.invite)
for (const record of cachedInvites) {
if (record.trusted) {
continue
}
const trustedMessageUseCase = new GetAsymmetricMessageTrustedPayload<AsymmetricMessageSharedVaultInvite>(
this.encryption,
this.contacts,
)
const trustedMessage = trustedMessageUseCase.execute({
message: record.invite,
privateKey: this.encryption.getKeyPair().privateKey,
})
if (trustedMessage) {
record.message = trustedMessage
record.trusted = true
}
}
await this.processInboundInvites(cachedInvites)
}
private async processInboundInvites(invites: SharedVaultInviteServerHash[]): Promise<void> {

View File

@@ -3,10 +3,12 @@ import { StorageServiceInterface } from '../../Storage/StorageServiceInterface'
import { EncryptionProviderInterface } from '@standardnotes/encryption'
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { AnyItemInterface, VaultListingInterface } from '@standardnotes/models'
import { Uuids } from '@standardnotes/utils'
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
import { RemoveItemsLocallyUseCase } from '../../UseCase/RemoveItemsLocally'
export class DeleteExternalSharedVaultUseCase {
private removeItemsLocallyUsecase = new RemoveItemsLocallyUseCase(this.items, this.storage)
constructor(
private items: ItemManagerInterface,
private mutator: MutatorClientInterface,
@@ -28,15 +30,13 @@ export class DeleteExternalSharedVaultUseCase {
* The data will be removed locally without syncing the items
*/
private async deleteDataSharedByVaultUsers(vault: VaultListingInterface): Promise<void> {
const vaultItems = this.items
.allTrackedItems()
.filter((item) => item.key_system_identifier === vault.systemIdentifier)
this.items.removeItemsLocally(vaultItems as AnyItemInterface[])
const vaultItems = <AnyItemInterface[]>(
this.items.allTrackedItems().filter((item) => item.key_system_identifier === vault.systemIdentifier)
)
const itemsKeys = this.encryption.keys.getKeySystemItemsKeys(vault.systemIdentifier)
this.items.removeItemsLocally(itemsKeys)
await this.storage.deletePayloadsWithUuids([...Uuids(vaultItems), ...Uuids(itemsKeys)])
await this.removeItemsLocallyUsecase.execute([...vaultItems, ...itemsKeys])
}
private async deleteDataOwnedByThisUser(vault: VaultListingInterface): Promise<void> {

View File

@@ -0,0 +1,14 @@
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { AnyItemInterface } from '@standardnotes/models'
import { Uuids } from '@standardnotes/utils'
export class RemoveItemsLocallyUseCase {
constructor(private readonly items: ItemManagerInterface, private readonly storage: StorageServiceInterface) {}
async execute(items: AnyItemInterface[]): Promise<void> {
this.items.removeItemsLocally(items)
await this.storage.deletePayloadsWithUuids(Uuids(items))
}
}

View File

@@ -589,7 +589,6 @@ export class UserService
this.lockSyncing()
/** Now, change the credentials on the server. Roll back on failure */
const { response } = await this.sessionManager.changeCredentials({
currentServerPassword: currentRootKey.serverPassword as string,
newRootKey: newRootKey,

View File

@@ -9,6 +9,7 @@ export * from './Application/DeinitMode'
export * from './Application/DeinitSource'
export * from './AsymmetricMessage/AsymmetricMessageService'
export * from './AsymmetricMessage/AsymmetricMessageServiceInterface'
export * from './Auth/AuthClientInterface'
export * from './Auth/AuthManager'