1 import { utf8ArrayToString } from '@proton/crypto/lib/utils'
2 import { VERIFICATION_STATUS } from '@proton/crypto'
3 import type { UseCaseInterface } from '../Domain/UseCase/UseCaseInterface'
4 import { Result } from '../Domain/Result/Result'
5 import type { EncryptionService } from '../Services/Encryption/EncryptionService'
6 import type { DocumentKeys } from '@proton/drive-store'
7 import { GetAssociatedEncryptionDataForComment } from './GetAdditionalEncryptionData'
8 import type { EncryptionContext } from '../Services/Encryption/EncryptionContext'
9 import { Comment } from '../Models'
10 import { ServerTime } from '@proton/docs-shared'
11 import { base64StringToUint8Array } from '@proton/shared/lib/helpers/encoding'
12 import metrics from '@proton/metrics'
13 import type { CommentResponseDto } from '../Api/Types/CommentResponseDto'
15 export class DecryptComment implements UseCaseInterface<Comment> {
16 constructor(private encryption: EncryptionService<EncryptionContext.PersistentComment>) {}
18 async execute(dto: CommentResponseDto, markId: string, keys: DocumentKeys): Promise<Result<Comment>> {
19 const emailToUse = dto.AuthorEmail || dto.Author
21 return Result.fail('No author email or author address found in comment')
24 const decrypted = await this.encryption.decryptData(
25 base64StringToUint8Array(dto.Content),
26 GetAssociatedEncryptionDataForComment({ authorAddress: emailToUse, markId }),
27 keys.documentContentKey,
30 if (decrypted.isFailed()) {
31 metrics.docs_comments_download_error_total.increment({
32 reason: 'decryption_error',
35 return Result.fail(decrypted.getError())
38 const verificationKey = await this.encryption.getVerificationKey(emailToUse)
40 if (verificationKey.isFailed()) {
41 return Result.fail(verificationKey.getError())
44 const verifyResult = await this.encryption.verifyData(
45 decrypted.getValue().content,
46 decrypted.getValue().signature,
47 GetAssociatedEncryptionDataForComment({ authorAddress: emailToUse, markId }),
48 verificationKey.getValue(),
51 if (verifyResult.isFailed()) {
52 return Result.fail(verifyResult.getError())
55 const verifyValue = verifyResult.getValue()
57 if (verifyValue !== VERIFICATION_STATUS.SIGNED_AND_VALID) {
58 return Result.fail(`Comment content verification failed: ${verifyValue}`)
64 new ServerTime(dto.CreateTime),
65 new ServerTime(dto.ModifyTime),
66 utf8ArrayToString(decrypted.getValue().content),