Skip to content

Commit 99f7097

Browse files
authored
Merge pull request #378 from internxt/upgrade_mail
[_] update internxt-crypto to 1.0.2
2 parents eaba2be + 4d590bd commit 99f7097

5 files changed

Lines changed: 222 additions & 206 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
},
4545
"dependencies": {
4646
"axios": "1.13.6",
47-
"internxt-crypto": "0.0.14"
47+
"internxt-crypto": "1.0.2"
4848
},
4949
"lint-staged": {
5050
"*.{js,jsx,tsx,ts}": [

src/mail/create.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import {
2+
EncryptedKeystore,
3+
HybridEncryptedEmail,
4+
PwdProtectedEmail,
5+
HybridKeyPair,
6+
Email,
7+
EmailBody,
8+
createEncryptionAndRecoveryKeystores,
9+
openEncryptionKeystore,
10+
RecipientWithPublicKey,
11+
encryptEmailHybridForMultipleRecipients,
12+
decryptEmailHybrid,
13+
createPwdProtectedEmail,
14+
decryptPwdProtectedEmail,
15+
openRecoveryKeystore,
16+
UTF8ToUint8,
17+
} from 'internxt-crypto';
18+
19+
/**
20+
* Creates recovery and encryption keystores for a user
21+
*
22+
* @param userEmail - The email of the user
23+
* @param baseKey - The secret key of the user
24+
* @returns The created keystores, keys and recovery codes for opening recovery keystore
25+
*/
26+
export async function createKeystores(
27+
userEmail: string,
28+
baseKey: Uint8Array,
29+
): Promise<{
30+
encryptionKeystore: EncryptedKeystore;
31+
recoveryKeystore: EncryptedKeystore;
32+
recoveryCodes: string;
33+
keys: HybridKeyPair;
34+
}> {
35+
return createEncryptionAndRecoveryKeystores(userEmail, baseKey);
36+
}
37+
38+
/**
39+
* Opens user's keystore and returns the keys
40+
*
41+
* @param keystore - The encrypted keystore
42+
* @param baseKey - The secret key of the user
43+
* @returns The keys of the user
44+
*/
45+
export async function openKeystore(keystore: EncryptedKeystore, baseKey: Uint8Array): Promise<HybridKeyPair> {
46+
return openEncryptionKeystore(keystore, baseKey);
47+
}
48+
49+
/**
50+
* Recovery of user's keys using recovery keystore
51+
*
52+
* @param keystore - The recovery keystore
53+
* @param recoveryCodes - The recovery codes of the user
54+
* @returns The keys of the user
55+
*/
56+
export async function recoverKeys(keystore: EncryptedKeystore, recoveryCodes: string): Promise<HybridKeyPair> {
57+
return openRecoveryKeystore(recoveryCodes, keystore);
58+
}
59+
60+
/**
61+
* Encrypts the email
62+
*
63+
* @param email - The email to encrypt
64+
* @param recipients - The recipients of the email
65+
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
66+
* @returns The encrypted emails for each recipient
67+
*/
68+
export async function encryptEmail(
69+
email: Email,
70+
recipients: RecipientWithPublicKey[],
71+
aux?: string,
72+
): Promise<HybridEncryptedEmail[]> {
73+
const auxArray = aux ? UTF8ToUint8(aux) : new Uint8Array();
74+
return encryptEmailHybridForMultipleRecipients(email.body, recipients, auxArray);
75+
}
76+
77+
/**
78+
* Password-protects the email
79+
*
80+
* @param email - The email to password-protect
81+
* @param pwd - The password to protect the email with
82+
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
83+
* @returns The password-protected email
84+
*/
85+
export async function passwordProtectAndSendEmail(email: Email, pwd: string, aux?: string): Promise<PwdProtectedEmail> {
86+
const auxArray = aux ? UTF8ToUint8(aux) : new Uint8Array();
87+
return createPwdProtectedEmail(email.body, pwd, auxArray);
88+
}
89+
90+
/**
91+
* Opens the password-protected email
92+
*
93+
* @param email - The password-protected email
94+
* @param pwd - The shared password
95+
* @param aux - The optional auxilary data that was encrypted together with the email (e.g. email sender)
96+
* @returns The decrypted email body
97+
*/
98+
export async function openPasswordProtectedEmail(
99+
email: PwdProtectedEmail,
100+
pwd: string,
101+
aux?: string,
102+
): Promise<EmailBody> {
103+
const auxArray = aux ? UTF8ToUint8(aux) : new Uint8Array();
104+
return decryptPwdProtectedEmail(email, pwd, auxArray);
105+
}
106+
107+
/**
108+
* Decrypt the email
109+
*
110+
* @param email - The encrypted email
111+
* @param recipientPrivateKeys - The private keys of the email recipient
112+
* @param aux - The optional auxilary data that was encrypted together with the email (e.g. email sender)
113+
* @returns The decrypted email body
114+
*/
115+
export async function decryptEmail(
116+
email: HybridEncryptedEmail,
117+
recipientPrivateKeys: Uint8Array,
118+
aux?: string,
119+
): Promise<EmailBody> {
120+
const auxArray = aux ? UTF8ToUint8(aux) : new Uint8Array();
121+
return decryptEmailHybrid(email, recipientPrivateKeys, auxArray);
122+
}

src/mail/index.ts

Lines changed: 44 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,17 @@ import { HttpClient } from '../shared/http/client';
44
import {
55
EncryptedKeystore,
66
KeystoreType,
7-
PublicKeysBase64,
8-
PrivateKeys,
97
HybridEncryptedEmail,
108
PwdProtectedEmail,
11-
base64ToPublicKey,
12-
EmailKeys,
9+
HybridKeyPair,
1310
Email,
14-
createEncryptionAndRecoveryKeystores,
15-
encryptEmailHybrid,
16-
User,
17-
openEncryptionKeystore,
18-
UserWithPublicKeys,
19-
encryptEmailHybridForMultipleRecipients,
20-
decryptEmailHybrid,
21-
createPwdProtectedEmail,
22-
decryptPwdProtectedEmail,
23-
openRecoveryKeystore,
11+
RecipientWithPublicKey,
12+
base64ToUint8Array,
13+
EmailPublicParameters,
2414
} from 'internxt-crypto';
2515

16+
import { createKeystores, encryptEmail, passwordProtectAndSendEmail, openKeystore, recoverKeys } from './create';
17+
2618
export class Mail {
2719
private readonly client: HttpClient;
2820
private readonly appDetails: AppDetails;
@@ -55,15 +47,15 @@ export class Mail {
5547
*
5648
* @param userEmail - The email of the user
5749
* @param baseKey - The secret key of the user
58-
* @returns The recovery codes for opening recovery keystore
50+
* @returns The recovery codes and keys of the user
5951
*/
60-
async createAndUploadKeystores(userEmail: string, baseKey: Uint8Array): Promise<string> {
61-
const { encryptionKeystore, recoveryKeystore, recoveryCodes } = await createEncryptionAndRecoveryKeystores(
62-
userEmail,
63-
baseKey,
64-
);
52+
async createAndUploadKeystores(
53+
userEmail: string,
54+
baseKey: Uint8Array,
55+
): Promise<{ recoveryCodes: string; keys: HybridKeyPair }> {
56+
const { encryptionKeystore, recoveryKeystore, recoveryCodes, keys } = await createKeystores(userEmail, baseKey);
6557
await Promise.all([this.uploadKeystoreToServer(encryptionKeystore), this.uploadKeystoreToServer(recoveryKeystore)]);
66-
return recoveryCodes;
58+
return { recoveryCodes, keys };
6759
}
6860

6961
/**
@@ -82,23 +74,23 @@ export class Mail {
8274
*
8375
* @param userEmail - The email of the user
8476
* @param baseKey - The secret key of the user
85-
* @returns The email keys of the user
77+
* @returns The hybrid keys of the user
8678
*/
87-
async getUserEmailKeys(userEmail: string, baseKey: Uint8Array): Promise<EmailKeys> {
79+
async getUserEmailKeys(userEmail: string, baseKey: Uint8Array): Promise<HybridKeyPair> {
8880
const keystore = await this.downloadKeystoreFromServer(userEmail, KeystoreType.ENCRYPTION);
89-
return openEncryptionKeystore(keystore, baseKey);
81+
return openKeystore(keystore, baseKey);
9082
}
9183

9284
/**
9385
* Requests recovery keystore from the server and opens it
9486
*
9587
* @param userEmail - The email of the user
9688
* @param recoveryCodes - The recovery codes of the user
97-
* @returns The email keys of the user
89+
* @returns The hybrid keys of the user
9890
*/
99-
async recoverUserEmailKeys(userEmail: string, recoveryCodes: string): Promise<EmailKeys> {
91+
async recoverUserEmailKeys(userEmail: string, recoveryCodes: string): Promise<HybridKeyPair> {
10092
const keystore = await this.downloadKeystoreFromServer(userEmail, KeystoreType.RECOVERY);
101-
return openRecoveryKeystore(recoveryCodes, keystore);
93+
return recoverKeys(keystore, recoveryCodes);
10294
}
10395

10496
/**
@@ -107,16 +99,16 @@ export class Mail {
10799
* @param userEmail - The email of the user
108100
* @returns User with corresponding public keys
109101
*/
110-
async getUserWithPublicKeys(userEmail: string): Promise<UserWithPublicKeys> {
111-
const response = await this.client.post<{ publicKeys: PublicKeysBase64; user: User }[]>(
102+
async getUserWithPublicKeys(userEmail: string): Promise<RecipientWithPublicKey> {
103+
const response = await this.client.post<{ publicKey: string; email: string }[]>(
112104
`${this.apiUrl}/users/public-keys`,
113105
{ emails: [userEmail] },
114106
this.headers(),
115107
);
116108
if (!response[0]) throw new Error(`No public keys found for ${userEmail}`);
117109
const singleResponse = response[0];
118-
const publicKeys = await base64ToPublicKey(singleResponse.publicKeys);
119-
const result = { ...singleResponse.user, publicKeys };
110+
const publicHybridKey = base64ToUint8Array(singleResponse.publicKey);
111+
const result = { email: singleResponse.email, publicHybridKey };
120112
return result;
121113
}
122114

@@ -126,86 +118,47 @@ export class Mail {
126118
* @param emails - The emails of the users
127119
* @returns Users with corresponding public keys
128120
*/
129-
async getSeveralUsersWithPublicKeys(emails: string[]): Promise<UserWithPublicKeys[]> {
130-
const response = await this.client.post<{ publicKeys: PublicKeysBase64; user: User }[]>(
121+
async getSeveralUsersWithPublicKeys(emails: string[]): Promise<RecipientWithPublicKey[]> {
122+
const response = await this.client.post<{ publicKey: string; email: string }[]>(
131123
`${this.apiUrl}/users/public-keys`,
132124
{ emails },
133125
this.headers(),
134126
);
135127

136128
const result = await Promise.all(
137129
response.map(async (item) => {
138-
const publicKeys = await base64ToPublicKey(item.publicKeys);
139-
return { ...item.user, publicKeys };
130+
const publicHybridKey = base64ToUint8Array(item.publicKey);
131+
return { email: item.email, publicHybridKey };
140132
}),
141133
);
142134

143135
return result;
144136
}
145137

146138
/**
147-
* Sends the encrypted email to the server
148-
*
149-
* @param email - The encrypted email
150-
* @returns Server response
151-
*/
152-
async sendEncryptedEmail(email: HybridEncryptedEmail): Promise<void> {
153-
return this.client.post(`${this.apiUrl}/emails`, { emails: [email] }, this.headers());
154-
}
155-
156-
/**
157-
* Encrypts email and sends it to the server
158-
*
159-
* @param email - The message to encrypt
160-
* @param senderPrivateKeys - The private keys of the sender
161-
* @param isSubjectEncrypted - Indicates if the subject field should be encrypted
162-
* @returns Server response
163-
*/
164-
async encryptAndSendEmail(
165-
email: Email,
166-
senderPrivateKeys: PrivateKeys,
167-
isSubjectEncrypted: boolean = false,
168-
): Promise<void> {
169-
const recipient = await this.getUserWithPublicKeys(email.params.recipient.email);
170-
const encEmail = await encryptEmailHybrid(email, recipient, senderPrivateKeys, isSubjectEncrypted);
171-
return this.sendEncryptedEmail(encEmail);
172-
}
173-
174-
/**
175-
* Sends the encrypted emails for multiple recipients to the server
139+
* Sends the encrypted emails to the server
176140
*
177141
* @param emails - The encrypted emails
142+
* @param params - The public parameters of the email (sender, recipients, CCs, BCCs, etc.)
178143
* @returns Server response
179144
*/
180-
async sendEncryptedEmailToMultipleRecipients(emails: HybridEncryptedEmail[]): Promise<void> {
181-
return this.client.post(`${this.apiUrl}/emails`, { emails }, this.headers());
145+
async sendEncryptedEmail(emails: HybridEncryptedEmail[], params: EmailPublicParameters): Promise<void> {
146+
return this.client.post(`${this.apiUrl}/emails`, { emails, params }, this.headers());
182147
}
183148

184149
/**
185-
* Encrypts emails for multiple recipients and sends emails to the server
150+
* Encrypts and sends email(s) to the server
186151
*
187152
* @param email - The message to encrypt
188-
* @param senderPrivateKeys - The private keys of the sender
189-
* @param isSubjectEncrypted - Indicates if the subject field should be encrypted
153+
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
190154
* @returns Server response
191155
*/
192-
async encryptAndSendEmailToMultipleRecipients(
193-
email: Email,
194-
senderPrivateKeys: PrivateKeys,
195-
isSubjectEncrypted: boolean = false,
196-
): Promise<void> {
197-
const recipientEmails = email.params.recipients
198-
? email.params.recipients.map((user) => user.email)
199-
: [email.params.recipient.email];
200-
156+
async encryptAndSendEmail(email: Email, aux?: string): Promise<void> {
157+
const recipientEmails = email.params.recipients.map((user) => user.email);
201158
const recipients = await this.getSeveralUsersWithPublicKeys(recipientEmails);
202-
const encEmails = await encryptEmailHybridForMultipleRecipients(
203-
email,
204-
recipients,
205-
senderPrivateKeys,
206-
isSubjectEncrypted,
207-
);
208-
return this.sendEncryptedEmailToMultipleRecipients(encEmails);
159+
160+
const encEmails = await encryptEmail(email, recipients, aux);
161+
return this.sendEncryptedEmail(encEmails, email.params);
209162
}
210163

211164
/**
@@ -214,45 +167,21 @@ export class Mail {
214167
* @param email - The password-protected email
215168
* @returns Server response
216169
*/
217-
async sendPasswordProtectedEmail(email: PwdProtectedEmail): Promise<void> {
218-
return this.client.post(`${this.apiUrl}/emails`, { email }, this.headers());
170+
async sendPasswordProtectedEmail(email: PwdProtectedEmail, params: EmailPublicParameters): Promise<void> {
171+
return this.client.post(`${this.apiUrl}/emails`, { email, params }, this.headers());
219172
}
220173

221174
/**
222175
* Creates the password-protected email and sends it to the server
223176
*
224177
* @param email - The email
225178
* @param pwd - The password
226-
* @param isSubjectEncrypted - Indicates if the subject field should be encrypted
179+
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
227180
* @returns Server response
228181
*/
229-
async passwordProtectAndSendEmail(email: Email, pwd: string, isSubjectEncrypted: boolean = false): Promise<void> {
230-
const encEmail = await createPwdProtectedEmail(email, pwd, isSubjectEncrypted);
231-
return this.sendPasswordProtectedEmail(encEmail);
232-
}
233-
234-
/**
235-
* Opens the password-protected email
236-
*
237-
* @param email - The password-protected email
238-
* @param pwd - The shared password
239-
* @returns The decrypted email
240-
*/
241-
async openPasswordProtectedEmail(email: PwdProtectedEmail, pwd: string): Promise<Email> {
242-
return decryptPwdProtectedEmail(email, pwd);
243-
}
244-
245-
/**
246-
* Decrypt the email
247-
*
248-
* @param email - The encrypted email
249-
* @param recipientPrivateKeys - The private keys of the email recipient
250-
* @returns The decrypted email
251-
*/
252-
async decryptEmail(email: HybridEncryptedEmail, recipientPrivateKeys: PrivateKeys): Promise<Email> {
253-
const senderEmail = email.params.sender.email;
254-
const sender = await this.getUserWithPublicKeys(senderEmail);
255-
return decryptEmailHybrid(email, sender.publicKeys, recipientPrivateKeys);
182+
async passwordProtectAndSendEmail(email: Email, pwd: string, aux?: string): Promise<void> {
183+
const encEmail = await passwordProtectAndSendEmail(email, pwd, aux);
184+
return this.sendPasswordProtectedEmail(encEmail, email.params);
256185
}
257186

258187
/**

0 commit comments

Comments
 (0)