Skip to content

Commit b2bd737

Browse files
authored
Merge pull request #380 from internxt/feature/mail
[_]: feature/mail EPs
2 parents 99f7097 + 8fe2583 commit b2bd737

10 files changed

Lines changed: 859 additions & 207 deletions

File tree

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@internxt/sdk",
33
"author": "Internxt <hello@internxt.com>",
4-
"version": "1.15.6",
4+
"version": "1.15.7",
55
"description": "An sdk for interacting with Internxt's services",
66
"repository": {
77
"type": "git",
@@ -25,7 +25,8 @@
2525
"build": "yarn clean && tsc",
2626
"lint": "eslint ./src",
2727
"format": "prettier --write **/*.{js,jsx,tsx,ts}",
28-
"swagger": "openapi-typescript https://gateway.internxt.com/drive/api-json -o ./src/schema.ts && yarn format"
28+
"swagger": "openapi-typescript https://gateway.internxt.com/drive/api-json -o ./src/schema.ts && yarn format",
29+
"swagger:mail": "openapi-typescript http://localhost:3100/api-json -o ./src/mail/schema.ts && yarn format"
2930
},
3031
"devDependencies": {
3132
"@internxt/eslint-config-internxt": "2.1.0",
@@ -51,4 +52,4 @@
5152
"prettier --write"
5253
]
5354
}
54-
}
55+
}

src/mail/api.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { ApiSecurity, ApiUrl, AppDetails } from '../shared';
2+
import { headersWithToken } from '../shared/headers';
3+
import { HttpClient } from '../shared/http/client';
4+
import {
5+
EncryptedKeystore,
6+
KeystoreType,
7+
HybridEncryptedEmail,
8+
PwdProtectedEmail,
9+
RecipientWithPublicKey,
10+
base64ToUint8Array,
11+
EmailPublicParameters,
12+
} from 'internxt-crypto';
13+
import {
14+
MailboxResponse,
15+
EmailListResponse,
16+
EmailResponse,
17+
EmailCreatedResponse,
18+
SendEmailRequest,
19+
DraftEmailRequest,
20+
UpdateEmailRequest,
21+
ListEmailsQuery,
22+
} from './types';
23+
24+
export class MailApi {
25+
private readonly client: HttpClient;
26+
private readonly appDetails: AppDetails;
27+
private readonly apiSecurity: ApiSecurity;
28+
private readonly apiUrl: ApiUrl;
29+
30+
public static client(apiUrl: ApiUrl, appDetails: AppDetails, apiSecurity: ApiSecurity) {
31+
return new MailApi(apiUrl, appDetails, apiSecurity);
32+
}
33+
34+
private constructor(apiUrl: ApiUrl, appDetails: AppDetails, apiSecurity: ApiSecurity) {
35+
this.client = HttpClient.create(apiUrl, apiSecurity.unauthorizedCallback);
36+
this.appDetails = appDetails;
37+
this.apiSecurity = apiSecurity;
38+
this.apiUrl = apiUrl;
39+
}
40+
41+
/**
42+
* Uploads encrypted keystore to the server
43+
*
44+
* @param keystore - The encrypted keystore
45+
* @returns Server response
46+
*/
47+
async uploadKeystore(keystore: EncryptedKeystore): Promise<void> {
48+
return this.client.post(`${this.apiUrl}/keystore`, { encryptedKeystore: keystore }, this.headers());
49+
}
50+
51+
/**
52+
* Requests encrypted keystore from the server
53+
*
54+
* @param userEmail - The email of the user
55+
* @param keystoreType - The type of the keystore
56+
* @returns The encrypted keystore
57+
*/
58+
async downloadKeystore(userEmail: string, keystoreType: KeystoreType): Promise<EncryptedKeystore> {
59+
return this.client.getWithParams(`${this.apiUrl}/user/keystore`, { userEmail, keystoreType }, this.headers());
60+
}
61+
62+
/**
63+
* Requests users with corresponding public keys from the server
64+
*
65+
* @param emails - The emails of the users
66+
* @returns Users with corresponding public keys
67+
*/
68+
async getUsersWithPublicKeys(emails: string[]): Promise<RecipientWithPublicKey[]> {
69+
const response = await this.client.post<{ publicKey: string; email: string }[]>(
70+
`${this.apiUrl}/users/public-keys`,
71+
{ emails },
72+
this.headers(),
73+
);
74+
75+
const result = await Promise.all(
76+
response.map(async (item) => {
77+
const publicHybridKey = base64ToUint8Array(item.publicKey);
78+
return { email: item.email, publicHybridKey };
79+
}),
80+
);
81+
82+
return result;
83+
}
84+
85+
/**
86+
* Sends the encrypted emails to the server
87+
*
88+
* @param emails - The encrypted emails
89+
* @param params - The public parameters of the email
90+
* @returns Server response
91+
*/
92+
async sendE2EEmails(emails: HybridEncryptedEmail[], params: EmailPublicParameters): Promise<void> {
93+
return this.client.post(`${this.apiUrl}/emails`, { emails, params }, this.headers());
94+
}
95+
96+
/**
97+
* Sends the password-protected email to the server
98+
*
99+
* @param email - The password-protected email
100+
* @param params - The public parameters of the email
101+
* @returns Server response
102+
*/
103+
async sendE2EPasswordProtectedEmail(email: PwdProtectedEmail, params: EmailPublicParameters): Promise<void> {
104+
return this.client.post(`${this.apiUrl}/emails`, { email, params }, this.headers());
105+
}
106+
107+
async getMailboxes(): Promise<MailboxResponse[]> {
108+
return this.client.get(`${this.apiUrl}/email/mailboxes`, this.headers());
109+
}
110+
111+
async listEmails(query?: ListEmailsQuery): Promise<EmailListResponse> {
112+
return this.client.getWithParams(`${this.apiUrl}/email`, query ?? {}, this.headers());
113+
}
114+
115+
async getEmail(id: string): Promise<EmailResponse> {
116+
return this.client.get(`${this.apiUrl}/email/${id}`, this.headers());
117+
}
118+
119+
async deleteEmail(id: string): Promise<void> {
120+
return this.client.delete(`${this.apiUrl}/email/${id}`, this.headers());
121+
}
122+
123+
async updateEmail(id: string, body: UpdateEmailRequest): Promise<void> {
124+
return this.client.patch(`${this.apiUrl}/email/${id}`, body, this.headers());
125+
}
126+
127+
async sendEmail(body: SendEmailRequest): Promise<EmailCreatedResponse> {
128+
return this.client.post(`${this.apiUrl}/email/send`, body, this.headers());
129+
}
130+
131+
async saveDraft(body: DraftEmailRequest): Promise<EmailCreatedResponse> {
132+
return this.client.post(`${this.apiUrl}/email/drafts`, body, this.headers());
133+
}
134+
135+
/**
136+
* Returns the needed headers for the module requests
137+
* @private
138+
*/
139+
private headers() {
140+
return headersWithToken({
141+
clientName: this.appDetails.clientName,
142+
clientVersion: this.appDetails.clientVersion,
143+
token: this.apiSecurity.token,
144+
desktopToken: this.appDetails.desktopHeader,
145+
customHeaders: this.appDetails.customHeaders,
146+
});
147+
}
148+
}
File renamed without changes.

src/mail/index.ts

Lines changed: 2 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,200 +1,2 @@
1-
import { ApiSecurity, ApiUrl, AppDetails } from '../shared';
2-
import { headersWithToken } from '../shared/headers';
3-
import { HttpClient } from '../shared/http/client';
4-
import {
5-
EncryptedKeystore,
6-
KeystoreType,
7-
HybridEncryptedEmail,
8-
PwdProtectedEmail,
9-
HybridKeyPair,
10-
Email,
11-
RecipientWithPublicKey,
12-
base64ToUint8Array,
13-
EmailPublicParameters,
14-
} from 'internxt-crypto';
15-
16-
import { createKeystores, encryptEmail, passwordProtectAndSendEmail, openKeystore, recoverKeys } from './create';
17-
18-
export class Mail {
19-
private readonly client: HttpClient;
20-
private readonly appDetails: AppDetails;
21-
private readonly apiSecurity: ApiSecurity;
22-
private readonly apiUrl: ApiUrl;
23-
24-
public static client(apiUrl: ApiUrl, appDetails: AppDetails, apiSecurity: ApiSecurity) {
25-
return new Mail(apiUrl, appDetails, apiSecurity);
26-
}
27-
28-
private constructor(apiUrl: ApiUrl, appDetails: AppDetails, apiSecurity: ApiSecurity) {
29-
this.client = HttpClient.create(apiUrl, apiSecurity.unauthorizedCallback);
30-
this.appDetails = appDetails;
31-
this.apiSecurity = apiSecurity;
32-
this.apiUrl = apiUrl;
33-
}
34-
35-
/**
36-
* Uploads encrypted keystore to the server
37-
*
38-
* @param encryptedKeystore - The encrypted keystore
39-
* @returns Server response
40-
*/
41-
async uploadKeystoreToServer(encryptedKeystore: EncryptedKeystore): Promise<void> {
42-
return this.client.post(`${this.apiUrl}/keystore`, { encryptedKeystore }, this.headers());
43-
}
44-
45-
/**
46-
* Creates recovery and encryption keystores and uploads them to the server
47-
*
48-
* @param userEmail - The email of the user
49-
* @param baseKey - The secret key of the user
50-
* @returns The recovery codes and keys of the user
51-
*/
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);
57-
await Promise.all([this.uploadKeystoreToServer(encryptionKeystore), this.uploadKeystoreToServer(recoveryKeystore)]);
58-
return { recoveryCodes, keys };
59-
}
60-
61-
/**
62-
* Requests encrypted keystore from the server
63-
*
64-
* @param userEmail - The email of the user
65-
* @param keystoreType - The type of the keystore
66-
* @returns The encrypted keystore
67-
*/
68-
async downloadKeystoreFromServer(userEmail: string, keystoreType: KeystoreType): Promise<EncryptedKeystore> {
69-
return this.client.getWithParams(`${this.apiUrl}/user/keystore`, { userEmail, keystoreType }, this.headers());
70-
}
71-
72-
/**
73-
* Requests encrypted keystore from the server and opens it
74-
*
75-
* @param userEmail - The email of the user
76-
* @param baseKey - The secret key of the user
77-
* @returns The hybrid keys of the user
78-
*/
79-
async getUserEmailKeys(userEmail: string, baseKey: Uint8Array): Promise<HybridKeyPair> {
80-
const keystore = await this.downloadKeystoreFromServer(userEmail, KeystoreType.ENCRYPTION);
81-
return openKeystore(keystore, baseKey);
82-
}
83-
84-
/**
85-
* Requests recovery keystore from the server and opens it
86-
*
87-
* @param userEmail - The email of the user
88-
* @param recoveryCodes - The recovery codes of the user
89-
* @returns The hybrid keys of the user
90-
*/
91-
async recoverUserEmailKeys(userEmail: string, recoveryCodes: string): Promise<HybridKeyPair> {
92-
const keystore = await this.downloadKeystoreFromServer(userEmail, KeystoreType.RECOVERY);
93-
return recoverKeys(keystore, recoveryCodes);
94-
}
95-
96-
/**
97-
* Request user with corresponding public keys from the server
98-
*
99-
* @param userEmail - The email of the user
100-
* @returns User with corresponding public keys
101-
*/
102-
async getUserWithPublicKeys(userEmail: string): Promise<RecipientWithPublicKey> {
103-
const response = await this.client.post<{ publicKey: string; email: string }[]>(
104-
`${this.apiUrl}/users/public-keys`,
105-
{ emails: [userEmail] },
106-
this.headers(),
107-
);
108-
if (!response[0]) throw new Error(`No public keys found for ${userEmail}`);
109-
const singleResponse = response[0];
110-
const publicHybridKey = base64ToUint8Array(singleResponse.publicKey);
111-
const result = { email: singleResponse.email, publicHybridKey };
112-
return result;
113-
}
114-
115-
/**
116-
* Request users with corresponding public keys from the server
117-
*
118-
* @param emails - The emails of the users
119-
* @returns Users with corresponding public keys
120-
*/
121-
async getSeveralUsersWithPublicKeys(emails: string[]): Promise<RecipientWithPublicKey[]> {
122-
const response = await this.client.post<{ publicKey: string; email: string }[]>(
123-
`${this.apiUrl}/users/public-keys`,
124-
{ emails },
125-
this.headers(),
126-
);
127-
128-
const result = await Promise.all(
129-
response.map(async (item) => {
130-
const publicHybridKey = base64ToUint8Array(item.publicKey);
131-
return { email: item.email, publicHybridKey };
132-
}),
133-
);
134-
135-
return result;
136-
}
137-
138-
/**
139-
* Sends the encrypted emails to the server
140-
*
141-
* @param emails - The encrypted emails
142-
* @param params - The public parameters of the email (sender, recipients, CCs, BCCs, etc.)
143-
* @returns Server response
144-
*/
145-
async sendEncryptedEmail(emails: HybridEncryptedEmail[], params: EmailPublicParameters): Promise<void> {
146-
return this.client.post(`${this.apiUrl}/emails`, { emails, params }, this.headers());
147-
}
148-
149-
/**
150-
* Encrypts and sends email(s) to the server
151-
*
152-
* @param email - The message to encrypt
153-
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
154-
* @returns Server response
155-
*/
156-
async encryptAndSendEmail(email: Email, aux?: string): Promise<void> {
157-
const recipientEmails = email.params.recipients.map((user) => user.email);
158-
const recipients = await this.getSeveralUsersWithPublicKeys(recipientEmails);
159-
160-
const encEmails = await encryptEmail(email, recipients, aux);
161-
return this.sendEncryptedEmail(encEmails, email.params);
162-
}
163-
164-
/**
165-
* Sends the password-protected email to the server
166-
*
167-
* @param email - The password-protected email
168-
* @returns Server response
169-
*/
170-
async sendPasswordProtectedEmail(email: PwdProtectedEmail, params: EmailPublicParameters): Promise<void> {
171-
return this.client.post(`${this.apiUrl}/emails`, { email, params }, this.headers());
172-
}
173-
174-
/**
175-
* Creates the password-protected email and sends it to the server
176-
*
177-
* @param email - The email
178-
* @param pwd - The password
179-
* @param aux - The optional auxilary data to encrypt together with the email (e.g. email sender)
180-
* @returns Server response
181-
*/
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);
185-
}
186-
187-
/**
188-
* Returns the needed headers for the module requests
189-
* @private
190-
*/
191-
private headers() {
192-
return headersWithToken({
193-
clientName: this.appDetails.clientName,
194-
clientVersion: this.appDetails.clientVersion,
195-
token: this.apiSecurity.token,
196-
desktopToken: this.appDetails.desktopHeader,
197-
customHeaders: this.appDetails.customHeaders,
198-
});
199-
}
200-
}
1+
export * from './types';
2+
export * from './mail';

0 commit comments

Comments
 (0)