chore: vault tests refactors and lint (#2374)
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
KeySystemRootKeyContentSpecialized,
|
||||
TrustedContactInterface,
|
||||
} from '@standardnotes/models'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
describe('AsymmetricMessageService', () => {
|
||||
let sync: jest.Mocked<SyncServiceInterface>
|
||||
@@ -61,6 +62,7 @@ describe('AsymmetricMessageService', () => {
|
||||
encryption,
|
||||
mutator,
|
||||
sessions,
|
||||
sync,
|
||||
messageServer,
|
||||
createOrEditContact,
|
||||
findContact,
|
||||
@@ -115,6 +117,45 @@ describe('AsymmetricMessageService', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('handleTrustedMessageResult', () => {
|
||||
it('should not double handle the same message', async () => {
|
||||
/**
|
||||
* Because message retrieval is based on a syncToken, and the server aligns syncTokens to items sent back
|
||||
* rather than messages, we may receive the same message twice. We want to keep track of processed messages
|
||||
* and avoid double processing.
|
||||
*/
|
||||
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
updated_at_timestamp: 2,
|
||||
}
|
||||
|
||||
const decryptedMessagePayload: AsymmetricMessageTrustedContactShare = {
|
||||
type: AsymmetricMessagePayloadType.ContactShare,
|
||||
data: {
|
||||
recipientUuid: '1',
|
||||
trustedContact: {} as TrustedContactInterface,
|
||||
},
|
||||
}
|
||||
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
service.handleTrustedContactShareMessage = jest.fn()
|
||||
await service.handleTrustedMessageResult(message, decryptedMessagePayload)
|
||||
expect(service.handleTrustedContactShareMessage).toHaveBeenCalledTimes(1)
|
||||
|
||||
service.handleTrustedContactShareMessage = jest.fn()
|
||||
await service.handleTrustedMessageResult(message, decryptedMessagePayload)
|
||||
expect(service.handleTrustedContactShareMessage).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('should process incoming messages oldest first', async () => {
|
||||
const messages: AsymmetricMessageServerHash[] = [
|
||||
{
|
||||
@@ -139,7 +180,7 @@ describe('AsymmetricMessageService', () => {
|
||||
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(trustedPayloadMock)
|
||||
.mockReturnValue(Result.ok(trustedPayloadMock))
|
||||
|
||||
const handleTrustedContactShareMessageMock = jest.fn()
|
||||
service.handleTrustedContactShareMessage = handleTrustedContactShareMessageMock
|
||||
@@ -171,7 +212,7 @@ describe('AsymmetricMessageService', () => {
|
||||
service.handleTrustedContactShareMessage = jest.fn()
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await service.handleRemoteReceivedAsymmetricMessages([message])
|
||||
|
||||
@@ -200,7 +241,7 @@ describe('AsymmetricMessageService', () => {
|
||||
service.handleTrustedSenderKeypairChangedMessage = jest.fn()
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await service.handleRemoteReceivedAsymmetricMessages([message])
|
||||
|
||||
@@ -228,7 +269,7 @@ describe('AsymmetricMessageService', () => {
|
||||
service.handleTrustedSharedVaultRootKeyChangedMessage = jest.fn()
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await service.handleRemoteReceivedAsymmetricMessages([message])
|
||||
|
||||
@@ -258,7 +299,7 @@ describe('AsymmetricMessageService', () => {
|
||||
service.handleTrustedVaultMetadataChangedMessage = jest.fn()
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await service.handleRemoteReceivedAsymmetricMessages([message])
|
||||
|
||||
@@ -284,7 +325,7 @@ describe('AsymmetricMessageService', () => {
|
||||
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await expect(service.handleRemoteReceivedAsymmetricMessages([message])).rejects.toThrow(
|
||||
'Shared vault invites payloads are not handled as part of asymmetric messages',
|
||||
@@ -313,7 +354,7 @@ describe('AsymmetricMessageService', () => {
|
||||
service.handleTrustedContactShareMessage = jest.fn()
|
||||
service.getTrustedMessagePayload = service.getUntrustedMessagePayload = jest
|
||||
.fn()
|
||||
.mockReturnValue(decryptedMessagePayload)
|
||||
.mockReturnValue(Result.ok(decryptedMessagePayload))
|
||||
|
||||
await service.handleRemoteReceivedAsymmetricMessages([message])
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SyncServiceInterface } from './../Sync/SyncServiceInterface'
|
||||
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
||||
import { AsymmetricMessageServerHash, ClientDisplayableError, isClientDisplayableError } from '@standardnotes/responses'
|
||||
import { AsymmetricMessageServerHash } from '@standardnotes/responses'
|
||||
import { SyncEvent, SyncEventReceivedAsymmetricMessagesData } from '../Event/SyncEvent'
|
||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||
import { InternalEventHandlerInterface } from '../Internal/InternalEventHandlerInterface'
|
||||
@@ -20,7 +21,6 @@ import {
|
||||
VaultListingInterface,
|
||||
} from '@standardnotes/models'
|
||||
import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage'
|
||||
import { SessionEvent } from '../Session/SessionEvent'
|
||||
import { AsymmetricMessageServer } from '@standardnotes/api'
|
||||
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
||||
import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
||||
@@ -31,15 +31,19 @@ import { FindContact } from '../Contacts/UseCase/FindContact'
|
||||
import { CreateOrEditContact } from '../Contacts/UseCase/CreateOrEditContact'
|
||||
import { ReplaceContactData } from '../Contacts/UseCase/ReplaceContactData'
|
||||
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
export class AsymmetricMessageService
|
||||
extends AbstractService
|
||||
implements AsymmetricMessageServiceInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private handledMessages = new Set<string>()
|
||||
|
||||
constructor(
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sessions: SessionsClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
private messageServer: AsymmetricMessageServer,
|
||||
private _createOrEditContact: CreateOrEditContact,
|
||||
private _findContact: FindContact,
|
||||
@@ -73,30 +77,27 @@ export class AsymmetricMessageService
|
||||
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
switch (event.type) {
|
||||
case SessionEvent.UserKeyPairChanged:
|
||||
void this.messageServer.deleteAllInboundMessages()
|
||||
break
|
||||
case SyncEvent.ReceivedAsymmetricMessages:
|
||||
void this.handleRemoteReceivedAsymmetricMessages(event.payload as SyncEventReceivedAsymmetricMessagesData)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public async getOutboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError> {
|
||||
public async getOutboundMessages(): Promise<Result<AsymmetricMessageServerHash[]>> {
|
||||
return this._getOutboundMessagesUseCase.execute()
|
||||
}
|
||||
|
||||
public async getInboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError> {
|
||||
public async getInboundMessages(): Promise<Result<AsymmetricMessageServerHash[]>> {
|
||||
return this._getInboundMessagesUseCase.execute()
|
||||
}
|
||||
|
||||
public async downloadAndProcessInboundMessages(): Promise<void> {
|
||||
const messages = await this.getInboundMessages()
|
||||
if (isClientDisplayableError(messages)) {
|
||||
if (messages.isFailed()) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.handleRemoteReceivedAsymmetricMessages(messages)
|
||||
await this.handleRemoteReceivedAsymmetricMessages(messages.getValue())
|
||||
}
|
||||
|
||||
sortServerMessages(messages: AsymmetricMessageServerHash[]): AsymmetricMessageServerHash[] {
|
||||
@@ -143,11 +144,11 @@ export class AsymmetricMessageService
|
||||
getServerMessageType(message: AsymmetricMessageServerHash): AsymmetricMessagePayloadType | undefined {
|
||||
const result = this.getUntrustedMessagePayload(message)
|
||||
|
||||
if (!result) {
|
||||
if (result.isFailed()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return result.type
|
||||
return result.getValue().type
|
||||
}
|
||||
|
||||
async handleRemoteReceivedAsymmetricMessages(messages: AsymmetricMessageServerHash[]): Promise<void> {
|
||||
@@ -159,18 +160,26 @@ export class AsymmetricMessageService
|
||||
|
||||
for (const message of sortedMessages) {
|
||||
const trustedPayload = this.getTrustedMessagePayload(message)
|
||||
if (!trustedPayload) {
|
||||
if (trustedPayload.isFailed()) {
|
||||
continue
|
||||
}
|
||||
|
||||
await this.handleTrustedMessageResult(message, trustedPayload)
|
||||
await this.handleTrustedMessageResult(message, trustedPayload.getValue())
|
||||
}
|
||||
|
||||
void this.sync.sync()
|
||||
}
|
||||
|
||||
private async handleTrustedMessageResult(
|
||||
async handleTrustedMessageResult(
|
||||
message: AsymmetricMessageServerHash,
|
||||
payload: AsymmetricMessagePayload,
|
||||
): Promise<void> {
|
||||
if (this.handledMessages.has(message.uuid)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.handledMessages.add(message.uuid)
|
||||
|
||||
if (payload.type === AsymmetricMessagePayloadType.ContactShare) {
|
||||
await this.handleTrustedContactShareMessage(message, payload)
|
||||
} else if (payload.type === AsymmetricMessagePayloadType.SenderKeypairChanged) {
|
||||
@@ -186,23 +195,23 @@ export class AsymmetricMessageService
|
||||
await this.deleteMessageAfterProcessing(message)
|
||||
}
|
||||
|
||||
getUntrustedMessagePayload(message: AsymmetricMessageServerHash): AsymmetricMessagePayload | undefined {
|
||||
getUntrustedMessagePayload(message: AsymmetricMessageServerHash): Result<AsymmetricMessagePayload> {
|
||||
const result = this._getUntrustedPayload.execute({
|
||||
privateKey: this.encryption.getKeyPair().privateKey,
|
||||
message,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
return undefined
|
||||
return Result.fail(result.getError())
|
||||
}
|
||||
|
||||
return result.getValue()
|
||||
return result
|
||||
}
|
||||
|
||||
getTrustedMessagePayload(message: AsymmetricMessageServerHash): AsymmetricMessagePayload | undefined {
|
||||
getTrustedMessagePayload(message: AsymmetricMessageServerHash): Result<AsymmetricMessagePayload> {
|
||||
const contact = this._findContact.execute({ userUuid: message.sender_uuid })
|
||||
if (contact.isFailed()) {
|
||||
return undefined
|
||||
return Result.fail(contact.getError())
|
||||
}
|
||||
|
||||
const result = this._getTrustedPayload.execute({
|
||||
@@ -213,10 +222,10 @@ export class AsymmetricMessageService
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
return undefined
|
||||
return Result.fail(result.getError())
|
||||
}
|
||||
|
||||
return result.getValue()
|
||||
return result
|
||||
}
|
||||
|
||||
async deleteMessageAfterProcessing(message: AsymmetricMessageServerHash): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { AsymmetricMessageServerHash, ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { AsymmetricMessageServerHash } from '@standardnotes/responses'
|
||||
|
||||
export interface AsymmetricMessageServiceInterface {
|
||||
getOutboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError>
|
||||
getInboundMessages(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError>
|
||||
getOutboundMessages(): Promise<Result<AsymmetricMessageServerHash[]>>
|
||||
getInboundMessages(): Promise<Result<AsymmetricMessageServerHash[]>>
|
||||
downloadAndProcessInboundMessages(): Promise<void>
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { ClientDisplayableError, isErrorResponse, AsymmetricMessageServerHash } from '@standardnotes/responses'
|
||||
import { isErrorResponse, AsymmetricMessageServerHash, getErrorFromErrorResponse } from '@standardnotes/responses'
|
||||
import { AsymmetricMessageServerInterface } from '@standardnotes/api'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetInboundMessages {
|
||||
export class GetInboundMessages implements UseCaseInterface<AsymmetricMessageServerHash[]> {
|
||||
constructor(private messageServer: AsymmetricMessageServerInterface) {}
|
||||
|
||||
async execute(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError> {
|
||||
async execute(): Promise<Result<AsymmetricMessageServerHash[]>> {
|
||||
const response = await this.messageServer.getMessages()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromNetworkError(response)
|
||||
return Result.fail(getErrorFromErrorResponse(response).message)
|
||||
}
|
||||
|
||||
return response.data.messages
|
||||
return Result.ok(response.data.messages)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { ClientDisplayableError, isErrorResponse, AsymmetricMessageServerHash } from '@standardnotes/responses'
|
||||
import { isErrorResponse, AsymmetricMessageServerHash, getErrorFromErrorResponse } from '@standardnotes/responses'
|
||||
import { AsymmetricMessageServerInterface } from '@standardnotes/api'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetOutboundMessages {
|
||||
export class GetOutboundMessages implements UseCaseInterface<AsymmetricMessageServerHash[]> {
|
||||
constructor(private messageServer: AsymmetricMessageServerInterface) {}
|
||||
|
||||
async execute(): Promise<AsymmetricMessageServerHash[] | ClientDisplayableError> {
|
||||
async execute(): Promise<Result<AsymmetricMessageServerHash[]>> {
|
||||
const response = await this.messageServer.getOutboundUserMessages()
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
return ClientDisplayableError.FromNetworkError(response)
|
||||
return Result.fail(getErrorFromErrorResponse(response).message)
|
||||
}
|
||||
|
||||
return response.data.messages
|
||||
return Result.ok(response.data.messages)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import { ResendAllMessages } from './ResendAllMessages'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||
import { AsymmetricMessagePayloadType } from '@standardnotes/models'
|
||||
|
||||
describe('ResendAllMessages', () => {
|
||||
let mockDecryptOwnMessage: any
|
||||
let mockMessageServer: any
|
||||
let mockResendMessage: any
|
||||
let mockFindContact: any
|
||||
|
||||
let useCase: ResendAllMessages
|
||||
let params: {
|
||||
keys: { encryption: PkcKeyPair; signing: PkcKeyPair }
|
||||
previousKeys?: { encryption: PkcKeyPair; signing: PkcKeyPair }
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
mockDecryptOwnMessage = {
|
||||
execute: jest.fn(),
|
||||
}
|
||||
|
||||
mockMessageServer = {
|
||||
getOutboundUserMessages: jest.fn(),
|
||||
deleteMessage: jest.fn(),
|
||||
}
|
||||
|
||||
mockResendMessage = {
|
||||
execute: jest.fn(),
|
||||
}
|
||||
|
||||
mockFindContact = {
|
||||
execute: jest.fn(),
|
||||
}
|
||||
|
||||
useCase = new ResendAllMessages(mockResendMessage, mockDecryptOwnMessage, mockMessageServer, mockFindContact)
|
||||
params = {
|
||||
keys: {
|
||||
encryption: { publicKey: 'new_public_key', privateKey: 'new_private_key' },
|
||||
signing: { publicKey: 'new_public_key', privateKey: 'new_private_key' },
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
it('should successfully resend all messages', async () => {
|
||||
const messages = {
|
||||
data: { messages: [{ recipient_uuid: 'uuid', uuid: 'uuid', encrypted_message: 'encrypted_message' }] },
|
||||
}
|
||||
const recipient = { publicKeySet: { encryption: 'public_key' } }
|
||||
const decryptedMessage = { type: AsymmetricMessagePayloadType.ContactShare }
|
||||
|
||||
mockMessageServer.getOutboundUserMessages.mockReturnValue(messages)
|
||||
mockFindContact.execute.mockReturnValue(Result.ok(recipient))
|
||||
mockDecryptOwnMessage.execute.mockReturnValue(Result.ok(decryptedMessage))
|
||||
|
||||
const result = await useCase.execute(params)
|
||||
|
||||
expect(result).toEqual(Result.ok())
|
||||
expect(mockMessageServer.getOutboundUserMessages).toHaveBeenCalled()
|
||||
expect(mockFindContact.execute).toHaveBeenCalled()
|
||||
expect(mockDecryptOwnMessage.execute).toHaveBeenCalled()
|
||||
expect(mockResendMessage.execute).toHaveBeenCalled()
|
||||
expect(mockMessageServer.deleteMessage).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle errors while getting outbound user messages', async () => {
|
||||
mockMessageServer.getOutboundUserMessages.mockReturnValue({ data: { error: 'Error' } })
|
||||
|
||||
const result = await useCase.execute(params)
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toBe('Failed to get outbound user messages')
|
||||
})
|
||||
|
||||
it('should handle errors while finding contact', async () => {
|
||||
const messages = {
|
||||
data: { messages: [{ recipient_uuid: 'uuid', uuid: 'uuid', encrypted_message: 'encrypted_message' }] },
|
||||
}
|
||||
|
||||
mockMessageServer.getOutboundUserMessages.mockReturnValue(messages)
|
||||
mockFindContact.execute.mockReturnValue(Result.fail('Contact not found'))
|
||||
|
||||
const result = await useCase.execute(params)
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toContain('Contact not found')
|
||||
})
|
||||
|
||||
it('should skip messages of excluded types', async () => {
|
||||
const messages = {
|
||||
data: {
|
||||
messages: [
|
||||
{ recipient_uuid: 'uuid', uuid: 'uuid', encrypted_message: 'encrypted_message' },
|
||||
{ recipient_uuid: 'uuid2', uuid: 'uuid2', encrypted_message: 'encrypted_message2' },
|
||||
],
|
||||
},
|
||||
}
|
||||
const recipient = { publicKeySet: { encryption: 'public_key' } }
|
||||
const decryptedMessage1 = { type: AsymmetricMessagePayloadType.SenderKeypairChanged }
|
||||
const decryptedMessage2 = { type: AsymmetricMessagePayloadType.ContactShare }
|
||||
|
||||
mockMessageServer.getOutboundUserMessages.mockReturnValue(messages)
|
||||
mockFindContact.execute.mockReturnValue(Result.ok(recipient))
|
||||
|
||||
mockDecryptOwnMessage.execute
|
||||
.mockReturnValueOnce(Result.ok(decryptedMessage1))
|
||||
.mockReturnValueOnce(Result.ok(decryptedMessage2))
|
||||
|
||||
const result = await useCase.execute(params)
|
||||
|
||||
expect(result).toEqual(Result.ok())
|
||||
expect(mockMessageServer.getOutboundUserMessages).toHaveBeenCalled()
|
||||
expect(mockFindContact.execute).toHaveBeenCalledTimes(2)
|
||||
expect(mockDecryptOwnMessage.execute).toHaveBeenCalledTimes(2)
|
||||
expect(mockResendMessage.execute).toHaveBeenCalledTimes(1)
|
||||
expect(mockMessageServer.deleteMessage).toHaveBeenCalledTimes(1)
|
||||
expect(mockResendMessage.execute).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ rawMessage: messages.data.messages[1] }),
|
||||
)
|
||||
expect(mockMessageServer.deleteMessage).toHaveBeenCalledWith({ messageUuid: messages.data.messages[1].uuid })
|
||||
})
|
||||
})
|
||||
@@ -1,17 +1,28 @@
|
||||
import { DecryptOwnMessage } from './../../Encryption/UseCase/Asymmetric/DecryptOwnMessage'
|
||||
import { AsymmetricMessageServerHash, isErrorResponse } from '@standardnotes/responses'
|
||||
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { AsymmetricMessageServerInterface } from '@standardnotes/api'
|
||||
import { ResendMessage } from './ResendMessage'
|
||||
import { FindContact } from '../../Contacts/UseCase/FindContact'
|
||||
import { AsymmetricMessagePayload, AsymmetricMessagePayloadType } from '@standardnotes/models'
|
||||
|
||||
export class ResendAllMessages implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private resendMessage: ResendMessage,
|
||||
private decryptOwnMessage: DecryptOwnMessage<AsymmetricMessagePayload>,
|
||||
private messageServer: AsymmetricMessageServerInterface,
|
||||
private findContact: FindContact,
|
||||
) {}
|
||||
|
||||
messagesToExcludeFromResending(): AsymmetricMessagePayloadType[] {
|
||||
/**
|
||||
* Sender key pair changed messages should never be re-encrypted with new keys as they must use the
|
||||
* previous keys used by the sender before their keypair changed.
|
||||
*/
|
||||
return [AsymmetricMessagePayloadType.SenderKeypairChanged]
|
||||
}
|
||||
|
||||
async execute(params: {
|
||||
keys: {
|
||||
encryption: PkcKeyPair
|
||||
@@ -37,10 +48,27 @@ export class ResendAllMessages implements UseCaseInterface<void> {
|
||||
continue
|
||||
}
|
||||
|
||||
const decryptionResult = this.decryptOwnMessage.execute({
|
||||
message: message.encrypted_message,
|
||||
privateKey: params.previousKeys?.encryption.privateKey ?? params.keys.encryption.privateKey,
|
||||
recipientPublicKey: recipient.getValue().publicKeySet.encryption,
|
||||
})
|
||||
|
||||
if (decryptionResult.isFailed()) {
|
||||
errors.push(`Failed to decrypt message ${message.uuid}`)
|
||||
continue
|
||||
}
|
||||
|
||||
const decryptedMessage = decryptionResult.getValue()
|
||||
if (this.messagesToExcludeFromResending().includes(decryptedMessage.type)) {
|
||||
continue
|
||||
}
|
||||
|
||||
await this.resendMessage.execute({
|
||||
keys: params.keys,
|
||||
previousKeys: params.previousKeys,
|
||||
message: message,
|
||||
decryptedMessage: decryptedMessage,
|
||||
rawMessage: message,
|
||||
recipient: recipient.getValue(),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DecryptOwnMessage } from '../../Encryption/UseCase/Asymmetric/DecryptOwnMessage'
|
||||
import { AsymmetricMessagePayload, TrustedContactInterface } from '@standardnotes/models'
|
||||
import { AsymmetricMessageServerHash } from '@standardnotes/responses'
|
||||
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||
@@ -8,7 +7,6 @@ import { SendMessage } from './SendMessage'
|
||||
|
||||
export class ResendMessage implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private decryptOwnMessage: DecryptOwnMessage<AsymmetricMessagePayload>,
|
||||
private sendMessage: SendMessage,
|
||||
private encryptMessage: EncryptMessage,
|
||||
) {}
|
||||
@@ -23,22 +21,11 @@ export class ResendMessage implements UseCaseInterface<void> {
|
||||
signing: PkcKeyPair
|
||||
}
|
||||
recipient: TrustedContactInterface
|
||||
message: AsymmetricMessageServerHash
|
||||
rawMessage: AsymmetricMessageServerHash
|
||||
decryptedMessage: AsymmetricMessagePayload
|
||||
}): Promise<Result<AsymmetricMessageServerHash>> {
|
||||
const decryptionResult = this.decryptOwnMessage.execute({
|
||||
message: params.message.encrypted_message,
|
||||
privateKey: params.previousKeys?.encryption.privateKey ?? params.keys.encryption.privateKey,
|
||||
recipientPublicKey: params.recipient.publicKeySet.encryption,
|
||||
})
|
||||
|
||||
if (decryptionResult.isFailed()) {
|
||||
return Result.fail(decryptionResult.getError())
|
||||
}
|
||||
|
||||
const decryptedMessage = decryptionResult.getValue()
|
||||
|
||||
const encryptedMessage = this.encryptMessage.execute({
|
||||
message: decryptedMessage,
|
||||
message: params.decryptedMessage,
|
||||
keys: params.keys,
|
||||
recipientPublicKey: params.recipient.publicKeySet.encryption,
|
||||
})
|
||||
@@ -50,7 +37,7 @@ export class ResendMessage implements UseCaseInterface<void> {
|
||||
const sendMessageResult = await this.sendMessage.execute({
|
||||
recipientUuid: params.recipient.contactUuid,
|
||||
encryptedMessage: encryptedMessage.getValue(),
|
||||
replaceabilityIdentifier: params.message.replaceabilityIdentifier,
|
||||
replaceabilityIdentifier: params.rawMessage.replaceabilityIdentifier,
|
||||
})
|
||||
|
||||
return sendMessageResult
|
||||
|
||||
Reference in New Issue
Block a user