Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / applications / drive / src / app / components / SignatureAlert.tsx
blob03857970eb685e95efa1db8a5ca4697ccd7879e2
1 import { c } from 'ttag';
3 import { Alert, TextLoader } from '@proton/components';
4 import { VERIFICATION_STATUS } from '@proton/crypto';
5 import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url';
7 import type { SignatureIssueLocation, SignatureIssues } from '../store';
8 import { hasValidAnonymousSignature } from './hasValidAnonymousSignature';
10 type Props = {
11     loading: boolean;
12     signatureIssues: SignatureIssues | undefined;
13     signatureNetworkError?: boolean;
14     signatureAddress: string | undefined;
15     isFile: boolean;
16     name: string;
17     corruptedLink?: boolean;
18     className?: string;
21 export default function SignatureAlert({
22     loading,
23     signatureIssues,
24     signatureAddress,
25     signatureNetworkError,
26     corruptedLink,
27     className,
28     ...props
29 }: Props) {
30     if (loading) {
31         return (
32             <Alert type="info" className={className}>
33                 <TextLoader className="m-0">{c('Info').t`Checking signatures`}</TextLoader>
34             </Alert>
35         );
36     }
38     if (corruptedLink) {
39         return (
40             <Alert type="warning" className={className}>
41                 <span>{c('Info')
42                     .t`Unfortunately, it appears that the file or some of its data cannot be decrypted.`}</span>
43             </Alert>
44         );
45     }
47     if (signatureNetworkError) {
48         return (
49             <Alert type="warning" className={className}>
50                 <span>{c('Info').t`Signature cannot be validated due to network error, please try again later.`}</span>
51             </Alert>
52         );
53     }
55     const validAnonymousSignature =
56         !!signatureIssues && !signatureAddress && hasValidAnonymousSignature(signatureIssues);
58     return (
59         <Alert type={signatureIssues && !validAnonymousSignature ? 'error' : 'success'} className={className}>
60             <SignatureAlertBody
61                 signatureIssues={signatureIssues}
62                 signatureAddress={signatureAddress}
63                 validAnonymousSignature={validAnonymousSignature}
64                 {...props}
65             />
66         </Alert>
67     );
70 type PropsBody = {
71     signatureIssues: SignatureIssues | undefined;
72     signatureAddress: string | undefined;
73     isFile: boolean;
74     name: string;
75     validAnonymousSignature?: boolean;
78 export function SignatureAlertBody({
79     signatureIssues,
80     signatureAddress,
81     validAnonymousSignature,
82     isFile,
83     name,
84 }: PropsBody) {
85     const fileName = (
86         <strong className="text-break" key="fileName">
87             {name}
88         </strong>
89     );
91     const emailAddress = (
92         <strong className="text-break" key="signatureAddress" data-testid="signature-address">
93             {signatureAddress || c('Info').t`an anonymous user`}
94         </strong>
95     );
97     if (!signatureIssues) {
98         return (
99             <>
100                 {isFile
101                     ? c('Info').jt`Digital signature verified. This file was securely uploaded by ${emailAddress}.`
102                     : c('Info').jt`Digital signature verified. This folder was securely uploaded by ${emailAddress}.`}
103             </>
104         );
105     }
107     if (
108         !signatureAddress &&
109         (validAnonymousSignature === undefined ? hasValidAnonymousSignature(signatureIssues) : validAnonymousSignature)
110     ) {
111         return (
112             <>
113                 {isFile
114                     ? c('Info')
115                           .jt`The digital signature has been partially verified. The file was uploaded from a public page that does not specify a specific user origin.`
116                     : c('Info')
117                           .jt`The digital signature has been partially verified. The folder was uploaded from a public page that does not specify a specific user origin.`}
118             </>
119         );
120     }
122     const locationTranslations: { [key in SignatureIssueLocation]: string } = {
123         passphrase: c('Item').t`keys`,
124         hash: c('Item').t`hash key`,
125         name: c('Item').t`name`,
126         xattrs: c('Item').t`file attributes`,
127         contentKeyPacket: c('Item').t`file data key`,
128         blocks: c('Item').t`file data`,
129         thumbnail: c('Item').t`thumbnail`,
130         manifest: c('Item').t`file data order`,
131     };
132     const items = Object.keys(signatureIssues)
133         .map((location) => locationTranslations[location as SignatureIssueLocation])
134         .join(', ');
136     const statuses = Object.values(signatureIssues);
137     const hasNoSignatureIssue = statuses.some((status) => status === VERIFICATION_STATUS.NOT_SIGNED);
138     const hasBadSignatureIssue = statuses.some((status) => status === VERIFICATION_STATUS.SIGNED_AND_INVALID);
140     let textReason;
141     let textWarning;
142     if (hasNoSignatureIssue && !hasBadSignatureIssue) {
143         if (signatureAddress) {
144             textReason = isFile
145                 ? c('Info').jt`File is missing signature. We couldn’t verify that ${emailAddress} uploaded ${fileName}.`
146                 : c('Info')
147                       .jt`Folder is missing signature. We couldn’t verify that ${emailAddress} uploaded ${fileName}.`;
148         } else {
149             textReason = isFile
150                 ? c('Info').jt`File is missing signature. We couldn’t verify who uploaded ${fileName}.`
151                 : c('Info').jt`Folder is missing signature. We couldn’t verify who uploaded ${fileName}.`;
152         }
153         textWarning = c('Info').jt`The following may have been tampered with: ${items}. Only open if you trust it.`;
154     } else {
155         if (signatureAddress) {
156             textReason = c('Info').jt`We couldn’t verify that ${emailAddress} uploaded ${fileName}.`;
157             textWarning = c('Info')
158                 .jt`The account may have a new key, or the following may have been tampered with: ${items}. Only open if you trust it.`;
159         } else {
160             textReason = c('Info').jt`We couldn’t verify who uploaded ${fileName}.`;
161             textWarning = c('Info').jt`The following may have been tampered with: ${items}. Only open if you trust it.`;
162         }
163     }
165     return (
166         <>
167             {textReason}
168             &nbsp;
169             {textWarning}
170             &nbsp;
171             <a href={getKnowledgeBaseUrl('/drive-signature-management')} target="_blank">
172                 {c('Action').t`Learn more`}
173             </a>
174         </>
175     );