@secrecy/lib 1.74.0-feat-groups-identity.4 → 1.74.0-feat-transfer-adaptations.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/lib/base-client.js +4 -27
  2. package/dist/lib/client/SecrecyAppClient.js +17 -13
  3. package/dist/lib/client/SecrecyCloudClient.js +156 -368
  4. package/dist/lib/client/SecrecyDbClient.js +7 -3
  5. package/dist/lib/client/SecrecyMailClient.js +48 -38
  6. package/dist/lib/client/SecrecyOrganizationClient.js +12 -10
  7. package/dist/lib/client/SecrecyPayClient.js +5 -1
  8. package/dist/lib/client/SecrecyPseudonymClient.js +8 -4
  9. package/dist/lib/client/SecrecyUserClient.js +11 -11
  10. package/dist/lib/client/SecrecyWalletClient.js +2 -0
  11. package/dist/lib/client/convert/data.js +4 -4
  12. package/dist/lib/client/convert/mail.js +6 -5
  13. package/dist/lib/client/convert/node.js +34 -46
  14. package/dist/lib/client/data-link.js +77 -0
  15. package/dist/lib/client/download.js +84 -0
  16. package/dist/lib/client/helpers.js +11 -18
  17. package/dist/lib/client/index.js +12 -48
  18. package/dist/lib/client/storage.js +2 -3
  19. package/dist/lib/client/types/index.js +7 -3
  20. package/dist/lib/client/upload.js +252 -0
  21. package/dist/lib/client.js +7 -0
  22. package/dist/lib/crypto/data.js +3 -0
  23. package/dist/lib/crypto/domain.js +123 -12
  24. package/dist/lib/crypto/helpers.js +23 -0
  25. package/dist/lib/index.js +0 -1
  26. package/dist/types/base-client.d.ts +1 -2
  27. package/dist/types/client/SecrecyAppClient.d.ts +3 -2
  28. package/dist/types/client/SecrecyCloudClient.d.ts +28 -20
  29. package/dist/types/client/SecrecyDbClient.d.ts +3 -1
  30. package/dist/types/client/SecrecyMailClient.d.ts +3 -2
  31. package/dist/types/client/SecrecyOrganizationClient.d.ts +3 -2
  32. package/dist/types/client/SecrecyPayClient.d.ts +3 -1
  33. package/dist/types/client/SecrecyPseudonymClient.d.ts +3 -2
  34. package/dist/types/client/SecrecyUserClient.d.ts +3 -2
  35. package/dist/types/client/convert/data.d.ts +3 -3
  36. package/dist/types/client/convert/mail.d.ts +5 -3
  37. package/dist/types/client/convert/node.d.ts +5 -5
  38. package/dist/types/client/data-link.d.ts +37 -0
  39. package/dist/types/client/download.d.ts +2 -0
  40. package/dist/types/client/index.d.ts +3 -11
  41. package/dist/types/client/storage.d.ts +2 -3
  42. package/dist/types/client/types/index.d.ts +9 -13
  43. package/dist/types/client/types/mail.d.ts +1 -2
  44. package/dist/types/client/types/node.d.ts +9 -12
  45. package/dist/types/client/types/user.d.ts +0 -15
  46. package/dist/types/client/upload.d.ts +38 -0
  47. package/dist/types/client.d.ts +6174 -681
  48. package/dist/types/crypto/domain.d.ts +36 -8
  49. package/dist/types/crypto/helpers.d.ts +12 -0
  50. package/dist/types/crypto/index.d.ts +3 -3
  51. package/dist/types/index.d.ts +1 -2
  52. package/package.json +4 -2
  53. package/dist/lib/client/types/identity.js +0 -18
  54. package/dist/types/client/types/identity.d.ts +0 -29
@@ -1,6 +1,10 @@
1
1
  export class SecrecyDbClient {
2
- #client;
3
- constructor(client) {
4
- this.#client = client;
2
+ // #client: SecrecyClient;
3
+ // #keys: KeyPair;
4
+ #apiClient;
5
+ constructor(_client, _keys, apiClient) {
6
+ // this.#client = client;
7
+ // this.#keys = keys;
8
+ this.#apiClient = apiClient;
5
9
  }
6
10
  }
@@ -3,29 +3,35 @@ import { encryptCryptoBox, sodium } from '../index.js';
3
3
  import { convertInternalMailToExternal } from './convert/mail.js';
4
4
  export class SecrecyMailClient {
5
5
  #client;
6
- constructor(client) {
6
+ #keys;
7
+ #apiClient;
8
+ constructor(client, keys, apiClient) {
7
9
  this.#client = client;
10
+ this.#keys = keys;
11
+ this.#apiClient = apiClient;
8
12
  }
9
13
  async get({ id }) {
10
- const mail = await this.#client.apiClient.mail.byId.query({ id });
14
+ const mail = await this.#apiClient.mail.byId.query({ id });
11
15
  return await convertInternalMailToExternal({
12
16
  mail,
13
- keyPairs: this.#client.keyPairs,
17
+ client: this.#client,
18
+ keyPair: this.#keys,
14
19
  });
15
20
  }
16
21
  async recover({ mailId }) {
17
- const { isRecovered } = await this.#client.apiClient.mail.recover.mutate({
22
+ const { isRecovered } = await this.#apiClient.mail.recover.mutate({
18
23
  id: mailId,
19
24
  });
20
25
  return isRecovered;
21
26
  }
22
27
  async deletedMails({ mailType, }) {
23
- const deletedMails = await this.#client.apiClient.mail.deleted.query({
28
+ const deletedMails = await this.#apiClient.mail.deleted.query({
24
29
  type: mailType,
25
30
  });
26
31
  return await Promise.all(deletedMails.map(async (mail) => await convertInternalMailToExternal({
27
32
  mail,
28
- keyPairs: this.#client.keyPairs,
33
+ client: this.#client,
34
+ keyPair: this.#keys,
29
35
  })));
30
36
  }
31
37
  async create(data, customMessage) {
@@ -37,7 +43,7 @@ export class SecrecyMailClient {
37
43
  return { ...mail, type: 'sent' };
38
44
  }
39
45
  async waitingReceivedMails() {
40
- const waitingReceivedMails = await this.#client.apiClient.mail.waitingReceived.query({});
46
+ const waitingReceivedMails = await this.#apiClient.mail.waitingReceived.query({});
41
47
  const waitingReceivedMailsWithIds = waitingReceivedMails.map((mail) => ({
42
48
  id: Math.random().toString(36).substring(2, 9),
43
49
  sender: mail.sender,
@@ -73,18 +79,18 @@ export class SecrecyMailClient {
73
79
  throw new Error(`File ${f.name} (${f.id}) does not exists`);
74
80
  }
75
81
  }
76
- f.name = sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey));
82
+ f.name = sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#keys.publicKey, this.#keys.privateKey));
77
83
  }
78
84
  }
79
- const updateDraftMail = await this.#client.apiClient.mail.updateDraft.mutate({
85
+ const updateDraftMail = await this.#apiClient.mail.updateDraft.mutate({
80
86
  id: draftId,
81
87
  recipients: recipients ?? null,
82
88
  replyToId: replyToId ?? null,
83
89
  body: body !== undefined
84
- ? sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey))
90
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#keys.publicKey, this.#keys.privateKey))
85
91
  : null,
86
92
  subject: subject !== undefined
87
- ? sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey))
93
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#keys.publicKey, this.#keys.privateKey))
88
94
  : null,
89
95
  senderFiles: senderFiles ?? null,
90
96
  hash,
@@ -92,27 +98,28 @@ export class SecrecyMailClient {
92
98
  });
93
99
  return (await convertInternalMailToExternal({
94
100
  mail: updateDraftMail,
95
- keyPairs: this.#client.keyPairs,
101
+ client: this.#client,
102
+ keyPair: this.#keys,
96
103
  }));
97
104
  }
98
105
  async deleteDraft(draftId) {
99
- const { isDeleted } = await this.#client.apiClient.mail.deleteDraft.mutate({
106
+ const { isDeleted } = await this.#apiClient.mail.deleteDraft.mutate({
100
107
  id: draftId,
101
108
  });
102
109
  return isDeleted;
103
110
  }
104
111
  async deleteTrash({ ids }) {
105
- const { isDeleted } = await this.#client.apiClient.mail.deleteTrash.mutate({
112
+ const { isDeleted } = await this.#apiClient.mail.deleteTrash.mutate({
106
113
  ids,
107
114
  });
108
115
  return isDeleted;
109
116
  }
110
117
  async emptyTrash() {
111
- const { isDeleted } = await this.#client.apiClient.mail.emptyTrash.mutate({});
118
+ const { isDeleted } = await this.#apiClient.mail.emptyTrash.mutate({});
112
119
  return isDeleted;
113
120
  }
114
121
  async delete({ mailId }) {
115
- const { isDeleted } = await this.#client.apiClient.mail.delete.mutate({
122
+ const { isDeleted } = await this.#apiClient.mail.delete.mutate({
116
123
  id: mailId,
117
124
  });
118
125
  return isDeleted;
@@ -146,7 +153,7 @@ export class SecrecyMailClient {
146
153
  recipients.push(input);
147
154
  }
148
155
  }
149
- const { isSent } = await this.#client.apiClient.mail.sendDraft.mutate({
156
+ const { isSent } = await this.#apiClient.mail.sendDraft.mutate({
150
157
  temporaryRecipients,
151
158
  recipients,
152
159
  id: draft.mailIntegrityId,
@@ -168,11 +175,10 @@ export class SecrecyMailClient {
168
175
  if (input === null) {
169
176
  continue;
170
177
  }
171
- await this.#client.apiClient.mail.sendOne.mutate({
178
+ await this.#apiClient.mail.sendOne.mutate({
172
179
  id: mail.mailIntegrityId,
173
180
  recipient: {
174
181
  ...input,
175
- recipientPublicKey: input.recipientPubKey,
176
182
  attachments: input.attachments.map((attachment) => ({
177
183
  id: attachment.dataId,
178
184
  key: attachment.key,
@@ -201,58 +207,62 @@ export class SecrecyMailClient {
201
207
  }
202
208
  senderFiles.push({
203
209
  id: data.id,
204
- name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)),
210
+ name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#keys.publicKey, this.#keys.privateKey)),
205
211
  });
206
212
  }
207
- const createDraftMail = await this.#client.apiClient.mail.createDraft.mutate({
213
+ const createDraftMail = await this.#apiClient.mail.createDraft.mutate({
208
214
  recipients,
209
215
  replyToId,
210
- body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)),
211
- subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)),
216
+ body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#keys.publicKey, this.#keys.privateKey)),
217
+ subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#keys.publicKey, this.#keys.privateKey)),
212
218
  senderFiles,
213
219
  hash,
214
220
  hashKey,
215
221
  });
216
222
  return (await convertInternalMailToExternal({
217
223
  mail: createDraftMail,
218
- keyPairs: this.#client.keyPairs,
224
+ client: this.#client,
225
+ keyPair: this.#keys,
219
226
  }));
220
227
  }
221
228
  async read({ mailId }) {
222
- const { isRead } = await this.#client.apiClient.mail.read.mutate({
229
+ const { isRead } = await this.#apiClient.mail.read.mutate({
223
230
  id: mailId,
224
231
  });
225
232
  return isRead;
226
233
  }
227
234
  async unread({ mailId }) {
228
- const { isUnread } = await this.#client.apiClient.mail.unread.mutate({
235
+ const { isUnread } = await this.#apiClient.mail.unread.mutate({
229
236
  id: mailId,
230
237
  });
231
238
  return isUnread;
232
239
  }
233
240
  async receivedMails(input) {
234
- const receivedMails = await this.#client.apiClient.mail.received.query(input);
241
+ const receivedMails = await this.#apiClient.mail.received.query(input);
235
242
  return await Promise.all(receivedMails.map(async (mail) => (await convertInternalMailToExternal({
236
243
  mail,
237
- keyPairs: this.#client.keyPairs,
244
+ client: this.#client,
245
+ keyPair: this.#keys,
238
246
  }))));
239
247
  }
240
248
  async sentMails(input) {
241
- const sentMails = await this.#client.apiClient.mail.sent.query(input);
249
+ const sentMails = await this.#apiClient.mail.sent.query(input);
242
250
  return await Promise.all(sentMails.map(async (mail) => (await convertInternalMailToExternal({
243
251
  mail,
244
- keyPairs: this.#client.keyPairs,
252
+ client: this.#client,
253
+ keyPair: this.#keys,
245
254
  }))));
246
255
  }
247
256
  async draftMails(input) {
248
- const draftMails = await this.#client.apiClient.mail.draft.query(input);
257
+ const draftMails = await this.#apiClient.mail.draft.query(input);
249
258
  return await Promise.all(draftMails.map(async (mail) => (await convertInternalMailToExternal({
250
259
  mail,
251
- keyPairs: this.#client.keyPairs,
260
+ client: this.#client,
261
+ keyPair: this.#keys,
252
262
  }))));
253
263
  }
254
264
  async unreadReceivedMailsCount() {
255
- const unreadReceivedMailsCount = await this.#client.apiClient.mail.unreadReceivedCount.query({});
265
+ const unreadReceivedMailsCount = await this.#apiClient.mail.unreadReceivedCount.query({});
256
266
  return unreadReceivedMailsCount;
257
267
  }
258
268
  _eachUser = async (data, subject, body, idOrMail) => {
@@ -272,17 +282,17 @@ export class SecrecyMailClient {
272
282
  const key = dataInHistory.key;
273
283
  attachments.push({
274
284
  dataId: f.id,
275
- name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), pubKey, this.#client.uaPrivateKey)),
285
+ name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), pubKey, this.#keys.privateKey)),
276
286
  key: key
277
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), pubKey, this.#client.uaPrivateKey))
287
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), pubKey, this.#keys.privateKey))
278
288
  : null,
279
289
  });
280
290
  }
281
291
  return {
282
292
  // recipientId: userId,
283
- recipientPubKey: pubKey,
284
- body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), pubKey, this.#client.uaPrivateKey)),
285
- subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), pubKey, this.#client.uaPrivateKey)),
293
+ recipientId: idOrMail,
294
+ body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), pubKey, this.#keys.privateKey)),
295
+ subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), pubKey, this.#keys.privateKey)),
286
296
  attachments,
287
297
  };
288
298
  };
@@ -1,27 +1,29 @@
1
1
  export class SecrecyOrganizationClient {
2
- #client;
3
- constructor(client) {
4
- this.#client = client;
2
+ // readonly #client: SecrecyClient
3
+ #apiClient;
4
+ constructor(_client, _keys, apiClient) {
5
+ // this.#client = client
6
+ this.#apiClient = apiClient;
5
7
  }
6
8
  async create(input) {
7
- return this.#client.apiClient.org.create.mutate(input);
9
+ return this.#apiClient.org.create.mutate(input);
8
10
  }
9
11
  async update(input) {
10
- return this.#client.apiClient.org.update.mutate(input);
12
+ return this.#apiClient.org.update.mutate(input);
11
13
  }
12
14
  async addMember(input) {
13
- return this.#client.apiClient.org.addMember.mutate(input);
15
+ return this.#apiClient.org.addMember.mutate(input);
14
16
  }
15
17
  async removeMember(input) {
16
- return this.#client.apiClient.org.removeMember.mutate(input);
18
+ return this.#apiClient.org.removeMember.mutate(input);
17
19
  }
18
20
  async updateRole(input) {
19
- return this.#client.apiClient.org.updateRole.mutate(input);
21
+ return this.#apiClient.org.updateRole.mutate(input);
20
22
  }
21
23
  async list(input) {
22
- return this.#client.apiClient.org.list.query(input);
24
+ return this.#apiClient.org.list.query(input);
23
25
  }
24
26
  async plans(input) {
25
- return this.#client.apiClient.org.plans.query(input);
27
+ return this.#apiClient.org.plans.query(input);
26
28
  }
27
29
  }
@@ -1,8 +1,12 @@
1
1
  import { popup } from '../utils/popup-tools.js';
2
2
  export class SecrecyPayClient {
3
3
  #client;
4
- constructor(client) {
4
+ // #keys: KeyPair
5
+ // #apiClient: ApiClient
6
+ constructor(client, _keys, _apiClient) {
5
7
  this.#client = client;
8
+ // this.#keys = keys
9
+ // this.#apiClient = apiClient
6
10
  }
7
11
  async confirmPaymentIntent({ paymentIntentId, secrecyIdWhoCreatedPaymentIntent, secrecyIdWhoNeedToConfirmPaymentIntent, amount, currency, }) {
8
12
  const hash = Buffer.from(JSON.stringify({
@@ -1,15 +1,19 @@
1
1
  export class SecrecyPseudonymClient {
2
2
  #client;
3
- constructor(client) {
3
+ #keys;
4
+ #apiClient;
5
+ constructor(client, keys, apiClient) {
4
6
  this.#client = client;
7
+ this.#keys = keys;
8
+ this.#apiClient = apiClient;
5
9
  }
6
10
  async askForLabel(input) {
7
- return await this.#client.apiClient.pseudonym.askForLabel.query(input);
11
+ return await this.#apiClient.pseudonym.askForLabel.query(input);
8
12
  }
9
13
  async askForUser(input) {
10
- return await this.#client.apiClient.pseudonym.askForUser.query(input);
14
+ return await this.#apiClient.pseudonym.askForUser.query(input);
11
15
  }
12
16
  async cross(input) {
13
- return await this.#client.apiClient.pseudonym.cross.query(input);
17
+ return await this.#apiClient.pseudonym.cross.query(input);
14
18
  }
15
19
  }
@@ -1,30 +1,30 @@
1
1
  export class SecrecyUserClient {
2
- #client;
3
- constructor(client) {
4
- this.#client = client;
2
+ #apiClient;
3
+ constructor(_client, _keys, apiClient) {
4
+ this.#apiClient = apiClient;
5
5
  }
6
6
  async answerInvitation(input) {
7
- return await this.#client.apiClient.contacts.answerInvitation.mutate(input);
7
+ return await this.#apiClient.contacts.answerInvitation.mutate(input);
8
8
  }
9
9
  async cancelInvitation(input) {
10
- return await this.#client.apiClient.contacts.cancelInvitation.mutate(input);
10
+ return await this.#apiClient.contacts.cancelInvitation.mutate(input);
11
11
  }
12
12
  async createInvitation(input) {
13
- return await this.#client.apiClient.contacts.createInvitation.mutate(input);
13
+ return await this.#apiClient.contacts.createInvitation.mutate(input);
14
14
  }
15
15
  async getContacts(input) {
16
- return await this.#client.apiClient.contacts.getContacts.query(input);
16
+ return await this.#apiClient.contacts.getContacts.query(input);
17
17
  }
18
18
  async getReceivedInvitations(input) {
19
- return await this.#client.apiClient.contacts.getReceivedInvitations.query(input);
19
+ return await this.#apiClient.contacts.getReceivedInvitations.query(input);
20
20
  }
21
21
  async getSentInvitations(input) {
22
- return await this.#client.apiClient.contacts.getSentInvitations.query(input);
22
+ return await this.#apiClient.contacts.getSentInvitations.query(input);
23
23
  }
24
24
  async removeContact(input) {
25
- return await this.#client.apiClient.contacts.removeContact.mutate(input);
25
+ return await this.#apiClient.contacts.removeContact.mutate(input);
26
26
  }
27
27
  async getUsers(input) {
28
- return await this.#client.apiClient.account.getUsers.query(input);
28
+ return await this.#apiClient.account.getUsers.query(input);
29
29
  }
30
30
  }
@@ -1,9 +1,11 @@
1
1
  import { popup } from '../utils/popup-tools.js';
2
2
  export class SecrecyWalletClient {
3
3
  #client;
4
+ // #keys: KeyPair;
4
5
  // #thunder: ReturnType<typeof Thunder>;
5
6
  constructor(client) {
6
7
  this.#client = client;
8
+ // this.#keys = keys;
7
9
  // this.#thunder = thunder;
8
10
  }
9
11
  async createTransaction({ network = 'mainnet', tx, }) {
@@ -1,7 +1,7 @@
1
1
  import { dataCache } from '../../cache.js';
2
2
  import { decryptCryptoBox } from '../../crypto/index.js';
3
3
  import { sodium } from '../../sodium.js';
4
- export function apiDataToInternal(apiData, keyPairs) {
4
+ export function apiDataToInternal(apiData, keyPair) {
5
5
  const data = {
6
6
  id: apiData.id,
7
7
  md5: apiData.md5,
@@ -10,7 +10,7 @@ export function apiDataToInternal(apiData, keyPairs) {
10
10
  size: apiData.size,
11
11
  sizeEncrypted: apiData.sizeEncrypted,
12
12
  key: apiData.access.key
13
- ? sodium.to_hex(decryptCryptoBox(sodium.from_hex(apiData.access.key), apiData.access.sharedByPubKey, keyPairs[apiData.access.identityPubKey]))
13
+ ? sodium.to_hex(decryptCryptoBox(sodium.from_hex(apiData.access.key), apiData.access.sharedByPubKey, keyPair.privateKey))
14
14
  : null,
15
15
  mime: apiData.mime ?? undefined,
16
16
  ext: apiData.ext ?? undefined,
@@ -30,6 +30,6 @@ export function internalDataToExternalData(internal) {
30
30
  ext: internal.ext ?? undefined,
31
31
  };
32
32
  }
33
- export function apiDataToExternal(apiData, keyPairs) {
34
- return internalDataToExternalData(apiDataToInternal(apiData, keyPairs));
33
+ export function apiDataToExternal(apiData, keyPair) {
34
+ return internalDataToExternalData(apiDataToInternal(apiData, keyPair));
35
35
  }
@@ -1,5 +1,5 @@
1
- import { sodium, decryptCryptoBox } from '../../index.js';
2
- export async function convertInternalMailToExternal({ mail, keyPairs, }) {
1
+ import { sodium, decryptCryptoBox, } from '../../index.js';
2
+ export async function convertInternalMailToExternal({ client, mail, keyPair, }) {
3
3
  let type = mail.type;
4
4
  if (mail.mailIntegrityDraft !== null) {
5
5
  type = 'draft';
@@ -8,8 +8,10 @@ export async function convertInternalMailToExternal({ mail, keyPairs, }) {
8
8
  if (mI === null) {
9
9
  throw new Error('Mail integrity is null');
10
10
  }
11
- const pubKey = mail.senderPubKey;
12
- const privateKey = keyPairs[mail.recipientPubKey];
11
+ const pubKey = mail.type === 'received'
12
+ ? await client.app.userPublicKey(mail.sender.id)
13
+ : keyPair.publicKey;
14
+ const privateKey = keyPair.privateKey;
13
15
  const body = sodium.to_string(decryptCryptoBox(sodium.from_hex(mail.body), pubKey, privateKey));
14
16
  const subject = sodium.to_string(decryptCryptoBox(sodium.from_hex(mail.subject), pubKey, privateKey));
15
17
  const hash = sodium.crypto_generichash(sodium.crypto_generichash_BYTES, JSON.stringify({ body, subject }), mI.hashKey, 'hex');
@@ -28,7 +30,6 @@ export async function convertInternalMailToExternal({ mail, keyPairs, }) {
28
30
  temporaryRecipients: [], // TODO
29
31
  recipients: mI.recipients,
30
32
  sender: mail.sender,
31
- senderPublicKey: mail.senderPubKey,
32
33
  attachments: mail.attachments.map((f) => {
33
34
  const name = sodium.to_string(decryptCryptoBox(sodium.from_hex(f.name), pubKey, privateKey));
34
35
  return {
@@ -3,11 +3,11 @@ import { decryptCryptoBox } from '../../crypto/index.js';
3
3
  import { nodesCache, nodesEncryptionCache } from '../../cache.js';
4
4
  import { decryptSecretStream } from '../../crypto/data.js';
5
5
  import { apiDataToInternal, internalDataToExternalData } from './data.js';
6
- async function apiNodeToInternal(apiNode, keyPairs) {
6
+ async function apiNodeToInternal(apiNode, keyPair) {
7
7
  const internal = {
8
8
  id: apiNode.id,
9
9
  type: apiNode.type,
10
- accesses: apiNode.accesses,
10
+ access: apiNode.access,
11
11
  name: apiNode.name,
12
12
  isFavorite: apiNode.isFavorite,
13
13
  breadcrumb: 'breadcrumb' in apiNode ? apiNode.breadcrumb : [],
@@ -21,48 +21,38 @@ async function apiNodeToInternal(apiNode, keyPairs) {
21
21
  createdAt: apiNode.createdAt,
22
22
  updatedAt: apiNode.updatedAt,
23
23
  deletedAt: apiNode.deletedAt,
24
- identities: apiNode.identities,
25
- permissions: apiNode.permissions,
24
+ users: apiNode.users,
26
25
  parentId: apiNode.parentId ?? null,
27
26
  currentDataId: apiNode.currentDataId ?? null,
28
27
  };
29
- for (const access of internal.accesses) {
30
- if (access.nameKey === null) {
31
- continue;
32
- }
33
- const pk = keyPairs[access.identityPubKey];
34
- const key = decryptCryptoBox(sodium.from_hex(access.nameKey), access.sharedByPubKey, pk);
35
- access.nameKey = sodium.to_hex(key);
36
- }
37
- const firstAccess = internal.accesses[0];
38
- if (!firstAccess || firstAccess.nameKey === null) {
39
- throw new Error('No access found for node ' + internal.id);
28
+ if (apiNode.access.nameKey !== null) {
29
+ const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPubKey, keyPair.privateKey);
30
+ internal.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(internal.name)));
31
+ internal.access.nameKey = sodium.to_hex(key);
40
32
  }
41
- internal.name = sodium.to_string(await decryptSecretStream(sodium.from_hex(firstAccess.nameKey), sodium.from_hex(internal.name)));
42
33
  for (const b of internal.breadcrumb) {
43
34
  if (b.nameKey === null) {
44
35
  continue;
45
36
  }
46
- const pk = keyPairs[b.identityPubKey];
47
- const key = decryptCryptoBox(sodium.from_hex(b.nameKey), b.sharedByPubKey, pk);
37
+ const key = decryptCryptoBox(sodium.from_hex(b.nameKey), b.pubKey, keyPair.privateKey);
48
38
  b.nameKey = sodium.to_hex(key);
49
39
  b.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(b.name)));
50
40
  }
51
41
  nodesCache.set(internal.id, internal);
52
42
  return internal;
53
43
  }
54
- export async function apiNodeFullToInternalFull(apiNodeFull, keyPairs) {
55
- const f = await apiNodeToInternal(apiNodeFull, keyPairs);
44
+ export async function apiNodeFullToInternalFull(apiNodeFull, keyPair) {
45
+ const f = await apiNodeToInternal(apiNodeFull, keyPair);
56
46
  const nodeFull = {
57
47
  ...f,
58
48
  current: !!apiNodeFull.current
59
- ? apiDataToInternal(apiNodeFull.current, keyPairs)
49
+ ? apiDataToInternal(apiNodeFull.current, keyPair)
60
50
  : undefined,
61
51
  parent: apiNodeFull.parent !== null
62
- ? await apiNodeToInternal(apiNodeFull.parent, keyPairs)
52
+ ? await apiNodeToInternal(apiNodeFull.parent, keyPair)
63
53
  : null,
64
- children: await Promise.all(apiNodeFull.children.map(async (s) => await apiNodeToInternal(s, keyPairs))),
65
- history: apiNodeFull.history.map((f) => apiDataToInternal(f, keyPairs)),
54
+ children: await Promise.all(apiNodeFull.children.map(async (s) => await apiNodeToInternal(s, keyPair))),
55
+ history: apiNodeFull.history.map((f) => apiDataToInternal(f, keyPair)),
66
56
  };
67
57
  nodesCache.set(f.id, nodeFull);
68
58
  return nodeFull;
@@ -70,19 +60,19 @@ export async function apiNodeFullToInternalFull(apiNodeFull, keyPairs) {
70
60
  function internalNodeToNode(internal) {
71
61
  const node = {
72
62
  ...internal,
73
- // breadcrumb: internal.breadcrumb.map((b) => ({
74
- // id: b.id,
75
- // name: b.name,
76
- // })),
77
- // access: {
78
- // isRoot: internal.access.isRoot,
79
- // sharedByPubKey: internal.access.sharedByPubKey,
80
- // rights: internal.access.rights,
81
- // addAccess: internal.access.addAccess,
82
- // delAccess: internal.access.delAccess,
83
- // sharingAddAccess: internal.access.sharingAddAccess,
84
- // sharingDelAccess: internal.access.sharingDelAccess,
85
- // },
63
+ breadcrumb: internal.breadcrumb.map((b) => ({
64
+ id: b.id,
65
+ name: b.name,
66
+ })),
67
+ access: {
68
+ isRoot: internal.access.isRoot,
69
+ sharedByPubKey: internal.access.sharedByPubKey,
70
+ rights: internal.access.rights,
71
+ addAccess: internal.access.addAccess,
72
+ delAccess: internal.access.delAccess,
73
+ sharingAddAccess: internal.access.sharingAddAccess,
74
+ sharingDelAccess: internal.access.sharingDelAccess,
75
+ },
86
76
  };
87
77
  return node;
88
78
  }
@@ -97,18 +87,17 @@ export function internalNodeFullToNodeFull(internal) {
97
87
  : undefined,
98
88
  };
99
89
  }
100
- export async function apiNodeToExternalNodeFull(apiNodeFull, keyPairs) {
101
- const apiNode = await apiNodeFullToInternalFull(apiNodeFull, keyPairs);
90
+ export async function apiNodeToExternalNodeFull(apiNodeFull, keyPair) {
91
+ const apiNode = await apiNodeFullToInternalFull(apiNodeFull, keyPair);
102
92
  return internalNodeFullToNodeFull(apiNode);
103
93
  }
104
- export async function apiNodeToExternal(apiNode, keyPairs) {
105
- const internal = await apiNodeToInternal(apiNode, keyPairs);
94
+ export async function apiNodeToExternal(apiNode, keyPair) {
95
+ const internal = await apiNodeToInternal(apiNode, keyPair);
106
96
  return internalNodeToNode(internal);
107
97
  }
108
- export async function apiNodeForEncryptionToInternal(apiNode, keyPairs) {
98
+ export async function apiNodeForEncryptionToInternal(apiNode, keyPair) {
109
99
  const history = apiNode.history.map((history) => {
110
- const pk = keyPairs[history.access.identityPubKey];
111
- const key = decryptCryptoBox(sodium.from_hex(history.access.key), history.access.sharedByPublicKey, pk);
100
+ const key = decryptCryptoBox(sodium.from_hex(history.access.key), history.access.sharedByPublicKey, keyPair.privateKey);
112
101
  return {
113
102
  id: history.id,
114
103
  key: sodium.to_hex(key),
@@ -123,8 +112,7 @@ export async function apiNodeForEncryptionToInternal(apiNode, keyPairs) {
123
112
  };
124
113
  internal.access = { ...apiNode.access };
125
114
  if (apiNode.access.nameKey !== null) {
126
- const pk = keyPairs[apiNode.access.identityPubKey];
127
- const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPublicKey, pk);
115
+ const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPublicKey, keyPair.privateKey);
128
116
  internal.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(internal.name)));
129
117
  internal.access.nameKey = sodium.to_hex(key);
130
118
  }
@@ -0,0 +1,77 @@
1
+ import z from 'zod';
2
+ import { buildBytesFromDataLink } from '../crypto/domain';
3
+ import { sodium } from '../sodium';
4
+ import { derivePassword } from '../crypto/helpers';
5
+ import { decryptSecretBox } from '../crypto';
6
+ import { decrypt } from '../worker/sodium';
7
+ import { md5 } from '../worker/md5';
8
+ import { decompress } from '../minify';
9
+ const downloadDataLinkS3Schema = z.object({
10
+ name: z.string(),
11
+ md5: z.string(),
12
+ md5Encrypted: z.string().nullable(),
13
+ size: z.coerce.bigint().gte(0n),
14
+ parts: z.array(z.object({ order: z.number(), md5: z.string(), contentUrl: z.string() })),
15
+ mime: z.string(),
16
+ isEncrypted: z.boolean(),
17
+ });
18
+ const downloadDataLinkLiteSchema = z.object({
19
+ name: z.string(),
20
+ md5: z.string(),
21
+ md5Encrypted: z.string().nullable(),
22
+ size: z.coerce.bigint().gte(0n),
23
+ bytes: z.string(),
24
+ mime: z.string(),
25
+ isEncrypted: z.boolean(),
26
+ });
27
+ export const downloadDataLinkSchema = z.union([
28
+ downloadDataLinkS3Schema,
29
+ downloadDataLinkLiteSchema,
30
+ ]);
31
+ // TODO: Add an opt header for authed users!
32
+ export async function downloadDataFromLink(opts) {
33
+ let dataUrl = opts.dataUrl ?? 'https://data.secrecy.tech/';
34
+ dataUrl = dataUrl.endsWith('/') ? dataUrl : `${dataUrl}/`;
35
+ const rawDataLink = await fetch(`${dataUrl}${opts.dataLinkSlug}/json`)
36
+ .then((res) => res.json())
37
+ .catch((err) => {
38
+ throw new Error(`Unable to fetch "${`${dataUrl}${opts.dataLinkSlug}/json"`}`, { cause: err });
39
+ });
40
+ const dataLink = downloadDataLinkSchema.safeParse(rawDataLink);
41
+ if (dataLink.error) {
42
+ throw new Error(`Should not happen!`, { cause: dataLink.error });
43
+ }
44
+ if (dataLink.data.isEncrypted && !opts.crypto) {
45
+ throw new Error('Unable to read encrypted data without password!');
46
+ }
47
+ const bytes = await buildBytesFromDataLink({
48
+ dataLink: dataLink.data,
49
+ totalBytes: Number(dataLink.data.size),
50
+ signal: opts.signal,
51
+ onDownloadProgress: opts.downloadProgress,
52
+ });
53
+ if (!dataLink.data.isEncrypted) {
54
+ return bytes;
55
+ }
56
+ if (!opts.crypto) {
57
+ throw new Error('Unable to read encrypted data without password!');
58
+ }
59
+ try {
60
+ const salt = sodium.crypto_generichash(sodium.crypto_pwhash_SALTBYTES, opts.crypto.password + dataLink.data.md5);
61
+ const derivedPassword = derivePassword(opts.crypto.password, salt);
62
+ const decryptedSharingDataKey = decryptSecretBox(sodium.from_hex(opts.crypto.key), derivedPassword);
63
+ const decryptedBytes = await decrypt(decryptedSharingDataKey, bytes, opts.decryptProgress, opts.signal);
64
+ const md5Content = await md5(decryptedBytes);
65
+ if (md5Content !== dataLink.data.md5) {
66
+ throw new Error(`Content does not match`);
67
+ }
68
+ return decompress(decryptedBytes);
69
+ }
70
+ catch (err) {
71
+ console.error(err);
72
+ if (opts.crypto.password) {
73
+ throw new Error('Unable to decrypt the data! The password is not valid!');
74
+ }
75
+ throw new Error('Unable to decrypt the data!');
76
+ }
77
+ }