tests: vaults (#2365)

* tests: signature tests

* tests: asymmetric

* feat: delete contact use case

* chore: lint

* chore: lint
This commit is contained in:
Mo
2023-07-24 14:28:28 -05:00
committed by GitHub
parent d6bcc808d5
commit 98c0228139
40 changed files with 649 additions and 145 deletions

View File

@@ -1,3 +1,4 @@
import { DeleteContact } from './UseCase/DeleteContact'
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
import { UserKeyPairChangedEventData } from './../Session/UserKeyPairChangedEventData'
import { SessionEvent } from './../Session/SessionEvent'
@@ -21,6 +22,7 @@ import { CreateOrEditContact } from './UseCase/CreateOrEditContact'
import { EditContact } from './UseCase/EditContact'
import { GetAllContacts } from './UseCase/GetAllContacts'
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
import { Result } from '@standardnotes/domain-core'
export class ContactService
extends AbstractService<ContactServiceEvent>
@@ -34,6 +36,7 @@ export class ContactService
private user: UserClientInterface,
private selfContactManager: SelfContactManager,
private encryption: EncryptionProviderInterface,
private _deleteContact: DeleteContact,
private _findContact: FindContact,
private _getAllContacts: GetAllContacts,
private _createOrEditContact: CreateOrEditContact,
@@ -167,20 +170,15 @@ export class ContactService
return contact
}
async deleteContact(contact: TrustedContactInterface): Promise<void> {
if (contact.isMe) {
throw new Error('Cannot delete self')
}
await this.mutator.setItemToBeDeleted(contact)
await this.sync.sync()
async deleteContact(contact: TrustedContactInterface): Promise<Result<void>> {
return this._deleteContact.execute({ contact, ownUserUuid: this.session.userUuid })
}
getAllContacts(): TrustedContactInterface[] {
return this._getAllContacts.execute().getValue()
}
findTrustedContact(userUuid: string): TrustedContactInterface | undefined {
findContact(userUuid: string): TrustedContactInterface | undefined {
const result = this._findContact.execute({ userUuid })
if (result.isFailed()) {
return undefined
@@ -188,12 +186,12 @@ export class ContactService
return result.getValue()
}
findTrustedContactForServerUser(user: SharedVaultUserServerHash): TrustedContactInterface | undefined {
return this.findTrustedContact(user.user_uuid)
findContactForServerUser(user: SharedVaultUserServerHash): TrustedContactInterface | undefined {
return this.findContact(user.user_uuid)
}
findTrustedContactForInvite(invite: SharedVaultInviteServerHash): TrustedContactInterface | undefined {
return this.findTrustedContact(invite.sender_uuid)
findContactForInvite(invite: SharedVaultInviteServerHash): TrustedContactInterface | undefined {
return this.findContact(invite.sender_uuid)
}
getCollaborationIDForTrustedContact(contact: TrustedContactInterface): string {
@@ -205,7 +203,7 @@ export class ContactService
})
}
isItemAuthenticallySigned(item: DecryptedItemInterface): ItemSignatureValidationResult {
getItemSignatureStatus(item: DecryptedItemInterface): ItemSignatureValidationResult {
return this._validateItemSigner.execute(item)
}

View File

@@ -2,6 +2,7 @@ import { DecryptedItemInterface, TrustedContactInterface } from '@standardnotes/
import { AbstractService } from '../Service/AbstractService'
import { SharedVaultInviteServerHash, SharedVaultUserServerHash } from '@standardnotes/responses'
import { ItemSignatureValidationResult } from './UseCase/Types/ItemSignatureValidationResult'
import { Result } from '@standardnotes/domain-core'
export enum ContactServiceEvent {}
@@ -26,13 +27,13 @@ export interface ContactServiceInterface extends AbstractService<ContactServiceE
contact: TrustedContactInterface,
params: { name: string; collaborationID: string },
): Promise<TrustedContactInterface>
deleteContact(contact: TrustedContactInterface): Promise<void>
deleteContact(contact: TrustedContactInterface): Promise<Result<void>>
getAllContacts(): TrustedContactInterface[]
getSelfContact(): TrustedContactInterface | undefined
findTrustedContact(userUuid: string): TrustedContactInterface | undefined
findTrustedContactForServerUser(user: SharedVaultUserServerHash): TrustedContactInterface | undefined
findTrustedContactForInvite(invite: SharedVaultInviteServerHash): TrustedContactInterface | undefined
findContact(userUuid: string): TrustedContactInterface | undefined
findContactForServerUser(user: SharedVaultUserServerHash): TrustedContactInterface | undefined
findContactForInvite(invite: SharedVaultInviteServerHash): TrustedContactInterface | undefined
isItemAuthenticallySigned(item: DecryptedItemInterface): ItemSignatureValidationResult
getItemSignatureStatus(item: DecryptedItemInterface): ItemSignatureValidationResult
}

View File

@@ -0,0 +1,87 @@
import { ContactBelongsToVault } from './../../SharedVaults/UseCase/ContactBelongsToVault'
import { GetOwnedSharedVaults } from './../../SharedVaults/UseCase/GetOwnedSharedVaults'
import { SyncServiceInterface } from './../../Sync/SyncServiceInterface'
import { MutatorClientInterface } from './../../Mutator/MutatorClientInterface'
import { Result } from '@standardnotes/domain-core'
import { TrustedContactInterface } from '@standardnotes/models'
import { DeleteContact } from './DeleteContact'
describe('DeleteContact', () => {
let mutator: jest.Mocked<MutatorClientInterface>
let sync: jest.Mocked<SyncServiceInterface>
let getOwnedVaults: jest.Mocked<GetOwnedSharedVaults>
let contactBelongsToVault: jest.Mocked<ContactBelongsToVault>
let deleteContact: DeleteContact
let mockDto: {
contact: TrustedContactInterface
ownUserUuid: string
}
let mockVaults: { id: string }[]
beforeEach(() => {
mutator = {} as jest.Mocked<MutatorClientInterface>
sync = {} as jest.Mocked<SyncServiceInterface>
getOwnedVaults = {} as jest.Mocked<GetOwnedSharedVaults>
getOwnedVaults.execute = jest.fn()
contactBelongsToVault = {} as jest.Mocked<ContactBelongsToVault>
contactBelongsToVault.execute = jest.fn()
deleteContact = new DeleteContact(mutator, sync, getOwnedVaults, contactBelongsToVault)
mockDto = {
contact: { isMe: false } as TrustedContactInterface,
ownUserUuid: 'test-user-uuid',
}
mockVaults = [{ id: 'vault1' }, { id: 'vault2' }]
})
describe('execute', () => {
it('should throw error when deleting self', async () => {
mockDto.contact.isMe = true
await expect(deleteContact.execute(mockDto)).rejects.toThrow('Cannot delete self')
})
it('should return failure when getting owned vaults fails', async () => {
getOwnedVaults.execute = jest.fn().mockReturnValue(Result.fail('Failed to get owned vaults'))
const result = await deleteContact.execute(mockDto)
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Failed to get owned vaults')
})
it('should return failure when checking contact membership fails', async () => {
getOwnedVaults.execute = jest.fn().mockReturnValue(Result.ok(mockVaults))
contactBelongsToVault.execute = jest.fn().mockResolvedValue(Result.fail('Failed to check contact membership'))
const result = await deleteContact.execute(mockDto)
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Failed to check contact membership')
})
it('should return failure when contact belongs to an owned vault', async () => {
getOwnedVaults.execute = jest.fn().mockReturnValue(Result.ok(mockVaults))
contactBelongsToVault.execute = jest.fn().mockResolvedValue(Result.ok(true))
const result = await deleteContact.execute(mockDto)
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Cannot delete contact that belongs to an owned vault')
})
it('should return success when contact is successfully deleted', async () => {
getOwnedVaults.execute = jest.fn().mockReturnValue(Result.ok(mockVaults))
contactBelongsToVault.execute = jest.fn().mockResolvedValue(Result.ok(false))
mutator.setItemToBeDeleted = jest.fn().mockResolvedValue(undefined)
sync.sync = jest.fn().mockResolvedValue(undefined)
const result = await deleteContact.execute(mockDto)
expect(result.isFailed()).toBe(false)
})
})
})

View File

@@ -0,0 +1,45 @@
import { ContactBelongsToVault } from './../../SharedVaults/UseCase/ContactBelongsToVault'
import { GetOwnedSharedVaults } from './../../SharedVaults/UseCase/GetOwnedSharedVaults'
import { SyncServiceInterface } from './../../Sync/SyncServiceInterface'
import { MutatorClientInterface } from './../../Mutator/MutatorClientInterface'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { TrustedContactInterface } from '@standardnotes/models'
export class DeleteContact implements UseCaseInterface<void> {
constructor(
private mutator: MutatorClientInterface,
private sync: SyncServiceInterface,
private getOwnedVaults: GetOwnedSharedVaults,
private contactBelongsToVault: ContactBelongsToVault,
) {}
async execute(dto: { contact: TrustedContactInterface; ownUserUuid: string }): Promise<Result<void>> {
if (dto.contact.isMe) {
throw new Error('Cannot delete self')
}
const vaults = this.getOwnedVaults.execute({ userUuid: dto.ownUserUuid })
if (vaults.isFailed()) {
return Result.fail('Failed to get owned vaults')
}
for (const vault of vaults.getValue()) {
const contactBelongsToVault = await this.contactBelongsToVault.execute({
contact: dto.contact,
vault: vault,
})
if (contactBelongsToVault.isFailed()) {
return Result.fail('Failed to check contact membership')
}
if (contactBelongsToVault.getValue()) {
return Result.fail('Cannot delete contact that belongs to an owned vault')
}
}
await this.mutator.setItemToBeDeleted(dto.contact)
await this.sync.sync()
return Result.ok()
}
}