Use same lock values as mobile clients
[ProtonMail-WebClient.git] / packages / docs-core / lib / UseCase / DecryptComment.ts
blobe4700cdf4d9cc2b2fe019ee0d8a4d3ce81527307
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
20     if (!emailToUse) {
21       return Result.fail('No author email or author address found in comment')
22     }
24     const decrypted = await this.encryption.decryptData(
25       base64StringToUint8Array(dto.Content),
26       GetAssociatedEncryptionDataForComment({ authorAddress: emailToUse, markId }),
27       keys.documentContentKey,
28     )
30     if (decrypted.isFailed()) {
31       metrics.docs_comments_download_error_total.increment({
32         reason: 'decryption_error',
33       })
35       return Result.fail(decrypted.getError())
36     }
38     const verificationKey = await this.encryption.getVerificationKey(emailToUse)
40     if (verificationKey.isFailed()) {
41       return Result.fail(verificationKey.getError())
42     }
44     const verifyResult = await this.encryption.verifyData(
45       decrypted.getValue().content,
46       decrypted.getValue().signature,
47       GetAssociatedEncryptionDataForComment({ authorAddress: emailToUse, markId }),
48       verificationKey.getValue(),
49     )
51     if (verifyResult.isFailed()) {
52       return Result.fail(verifyResult.getError())
53     }
55     const verifyValue = verifyResult.getValue()
57     if (verifyValue !== VERIFICATION_STATUS.SIGNED_AND_VALID) {
58       return Result.fail(`Comment content verification failed: ${verifyValue}`)
59     }
61     return Result.ok(
62       new Comment(
63         dto.CommentID,
64         new ServerTime(dto.CreateTime),
65         new ServerTime(dto.ModifyTime),
66         utf8ArrayToString(decrypted.getValue().content),
67         dto.ParentCommentID,
68         emailToUse,
69         [],
70         false,
71       ),
72     )
73   }