@secrecy/lib 1.7.0 → 1.8.0
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.
- package/LICENSE +1 -1
- package/dist/lib/base-client.js +91 -0
- package/dist/lib/cache.js +4 -0
- package/dist/lib/client/SecrecryCareClient.js +19 -0
- package/dist/lib/client/SecrecyAppClient.js +87 -0
- package/dist/lib/client/SecrecyCloudClient.js +475 -0
- package/dist/lib/client/SecrecyDbClient.js +10 -0
- package/dist/lib/client/SecrecyMailClient.js +283 -0
- package/dist/lib/client/SecrecyPayClient.js +34 -0
- package/dist/lib/client/SecrecyUserClient.js +27 -0
- package/dist/lib/client/SecrecyWalletClient.js +50 -0
- package/dist/lib/client/convert/file.js +29 -0
- package/dist/lib/client/convert/mail.js +42 -0
- package/dist/lib/client/convert/node.js +100 -0
- package/dist/lib/client/helpers.js +103 -0
- package/dist/lib/client/index.js +49 -0
- package/dist/lib/client/storage.js +7 -0
- package/dist/lib/client/types/app.js +1 -0
- package/dist/lib/client/types/file.js +1 -0
- package/dist/lib/client/types/index.js +15 -0
- package/dist/lib/client/types/mail.js +1 -0
- package/dist/lib/client/types/node.js +1 -0
- package/dist/lib/client/types/user.js +1 -0
- package/dist/lib/client.js +47 -0
- package/dist/lib/crypto/file.js +184 -0
- package/dist/lib/crypto/index.js +41 -0
- package/dist/lib/error/client.js +10 -0
- package/dist/lib/error/index.js +10 -0
- package/dist/lib/error/server.js +27 -0
- package/dist/lib/index.js +10 -0
- package/dist/lib/minify/index.js +23 -0
- package/dist/lib/minify/lz4.js +517 -0
- package/dist/lib/sodium.js +5 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils/array.js +25 -0
- package/dist/lib/utils/base64.js +2 -0
- package/dist/lib/utils/popup-tools.js +180 -0
- package/dist/lib/utils/promise.js +20 -0
- package/dist/lib/utils/store-buddy.js +60 -0
- package/dist/lib/utils/time.js +13 -0
- package/dist/lib/worker/md5.js +18 -0
- package/dist/lib/worker/sodium.js +95 -0
- package/dist/lib/worker/workerCodes.js +254 -0
- package/dist/types/base-client.d.ts +28 -0
- package/dist/types/cache.d.ts +11 -0
- package/dist/types/client/SecrecryCareClient.d.ts +9 -0
- package/dist/types/client/SecrecyAppClient.d.ts +20 -0
- package/dist/types/client/SecrecyCloudClient.d.ts +88 -0
- package/dist/types/client/SecrecyDbClient.d.ts +7 -0
- package/dist/types/client/SecrecyMailClient.d.ts +42 -0
- package/dist/types/client/SecrecyPayClient.d.ts +27 -0
- package/dist/types/client/SecrecyUserClient.d.ts +14 -0
- package/dist/{client → types/client}/SecrecyWalletClient.d.ts +9 -12
- package/dist/types/client/convert/file.d.ts +4 -0
- package/dist/types/client/convert/mail.d.ts +8 -0
- package/dist/types/client/convert/node.d.ts +7 -0
- package/dist/types/client/helpers.d.ts +26 -0
- package/dist/types/client/index.d.ts +29 -0
- package/dist/{client → types/client}/storage.d.ts +2 -2
- package/dist/types/client/types/app.d.ts +2 -0
- package/dist/types/client/types/file.d.ts +6 -0
- package/dist/types/client/types/index.d.ts +46 -0
- package/dist/types/client/types/mail.d.ts +87 -0
- package/dist/{client/types/Node.d.ts → types/client/types/node.d.ts} +20 -25
- package/dist/types/client/types/user.d.ts +3 -0
- package/dist/types/client.d.ts +12138 -0
- package/dist/{crypto → types/crypto}/file.d.ts +4 -4
- package/dist/{crypto → types/crypto}/index.d.ts +1 -4
- package/dist/types/error/client.d.ts +22 -0
- package/dist/types/error/index.d.ts +40 -0
- package/dist/types/error/server.d.ts +26 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/{minify → types/minify}/index.d.ts +1 -1
- package/dist/types/minify/lz4.d.ts +35 -0
- package/dist/{sodium.d.ts → types/sodium.d.ts} +1 -1
- package/dist/types/types.d.ts +10 -0
- package/dist/{utils/utils.d.ts → types/utils/array.d.ts} +0 -1
- package/dist/types/utils/base64.d.ts +1 -0
- package/dist/types/utils/popup-tools.d.ts +52 -0
- package/dist/types/utils/promise.d.ts +1 -0
- package/dist/types/utils/store-buddy.d.ts +130 -0
- package/dist/{worker → types/worker}/sodium.d.ts +1 -1
- package/package.json +48 -73
- package/dist/BaseClient.d.ts +0 -111
- package/dist/BaseClient.js +0 -506
- package/dist/PopupTools.d.ts +0 -17
- package/dist/PopupTools.js +0 -195
- package/dist/ZeusThunder.d.ts +0 -2
- package/dist/ZeusThunder.js +0 -65
- package/dist/cache.d.ts +0 -6
- package/dist/cache.js +0 -4
- package/dist/client/SecrecyAppClient.d.ts +0 -17
- package/dist/client/SecrecyAppClient.js +0 -226
- package/dist/client/SecrecyCloudClient.d.ts +0 -89
- package/dist/client/SecrecyCloudClient.js +0 -1405
- package/dist/client/SecrecyDbClient.d.ts +0 -48
- package/dist/client/SecrecyDbClient.js +0 -419
- package/dist/client/SecrecyMailClient.d.ts +0 -42
- package/dist/client/SecrecyMailClient.js +0 -1022
- package/dist/client/SecrecyPayClient.d.ts +0 -28
- package/dist/client/SecrecyPayClient.js +0 -68
- package/dist/client/SecrecyWalletClient.js +0 -73
- package/dist/client/convert/file.d.ts +0 -5
- package/dist/client/convert/file.js +0 -33
- package/dist/client/convert/mail.d.ts +0 -3
- package/dist/client/convert/mail.js +0 -42
- package/dist/client/convert/node.d.ts +0 -9
- package/dist/client/convert/node.js +0 -87
- package/dist/client/helpers.d.ts +0 -28
- package/dist/client/helpers.js +0 -119
- package/dist/client/index.d.ts +0 -34
- package/dist/client/index.js +0 -46
- package/dist/client/storage.js +0 -12
- package/dist/client/types/File.d.ts +0 -14
- package/dist/client/types/File.js +0 -3
- package/dist/client/types/Inputs.d.ts +0 -16
- package/dist/client/types/Inputs.js +0 -3
- package/dist/client/types/Node.js +0 -3
- package/dist/client/types/UserAppNotifications.d.ts +0 -6
- package/dist/client/types/UserAppNotifications.js +0 -3
- package/dist/client/types/UserAppSettings.d.ts +0 -5
- package/dist/client/types/UserAppSettings.js +0 -3
- package/dist/client/types/index.d.ts +0 -120
- package/dist/client/types/index.js +0 -8
- package/dist/client/types/selectors.d.ts +0 -400
- package/dist/client/types/selectors.js +0 -135
- package/dist/crypto/file.js +0 -195
- package/dist/crypto/index.js +0 -45
- package/dist/error.d.ts +0 -33
- package/dist/error.js +0 -3
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -10
- package/dist/minify/index.js +0 -23
- package/dist/minify/lz4.d.ts +0 -5
- package/dist/minify/lz4.js +0 -539
- package/dist/sodium.js +0 -6
- package/dist/utils/encoders.d.ts +0 -26
- package/dist/utils/encoders.js +0 -18
- package/dist/utils/store-buddy.d.ts +0 -14
- package/dist/utils/store-buddy.js +0 -58
- package/dist/utils/time.js +0 -12
- package/dist/utils/utils.js +0 -47
- package/dist/worker/md5.js +0 -24
- package/dist/worker/sodium.js +0 -118
- package/dist/worker/workerCodes.js +0 -255
- package/dist/zeus/const.d.ts +0 -7
- package/dist/zeus/const.js +0 -1846
- package/dist/zeus/index.d.ts +0 -8721
- package/dist/zeus/index.js +0 -642
- /package/dist/{utils → types/utils}/time.d.ts +0 -0
- /package/dist/{worker → types/worker}/md5.d.ts +0 -0
- /package/dist/{worker → types/worker}/workerCodes.d.ts +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { filesCache } from '../cache.js';
|
|
2
|
+
import { encryptCryptoBox, sodium } from '../index.js';
|
|
3
|
+
import { convertInternalMailToExternal } from './convert/mail.js';
|
|
4
|
+
export class SecrecyMailClient {
|
|
5
|
+
#client;
|
|
6
|
+
#keys;
|
|
7
|
+
#apiClient;
|
|
8
|
+
constructor(client, keys, apiClient) {
|
|
9
|
+
this.#client = client;
|
|
10
|
+
this.#keys = keys;
|
|
11
|
+
this.#apiClient = apiClient;
|
|
12
|
+
}
|
|
13
|
+
async get({ id }) {
|
|
14
|
+
const mail = await this.#apiClient.mail.byId.query({ id });
|
|
15
|
+
return await convertInternalMailToExternal({
|
|
16
|
+
mail,
|
|
17
|
+
client: this.#client,
|
|
18
|
+
keyPair: this.#keys,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async recover({ mailId }) {
|
|
22
|
+
const { isRecovered } = await this.#apiClient.mail.recover.mutate({
|
|
23
|
+
id: mailId,
|
|
24
|
+
});
|
|
25
|
+
return isRecovered;
|
|
26
|
+
}
|
|
27
|
+
async deletedMails({ mailType, }) {
|
|
28
|
+
const deletedMails = await this.#apiClient.mail.deleted.query({
|
|
29
|
+
type: mailType,
|
|
30
|
+
});
|
|
31
|
+
return await Promise.all(deletedMails.map(async (mail) => await convertInternalMailToExternal({
|
|
32
|
+
mail,
|
|
33
|
+
client: this.#client,
|
|
34
|
+
keyPair: this.#keys,
|
|
35
|
+
})));
|
|
36
|
+
}
|
|
37
|
+
async create(data, customMessage) {
|
|
38
|
+
const mail = await this.createDraft(data);
|
|
39
|
+
return await this.sendDraft(mail.mailIntegrityId, customMessage);
|
|
40
|
+
}
|
|
41
|
+
async waitingReceivedMails() {
|
|
42
|
+
// TODO
|
|
43
|
+
// const waitingReceivedMails =
|
|
44
|
+
// await this.#apiClient.mail.waitingReceived.query({})
|
|
45
|
+
// const result = waitingReceivedMails.map((m) => ({
|
|
46
|
+
// id: Math.random().toString(36).substr(2, 9),
|
|
47
|
+
// ...m,
|
|
48
|
+
// }))
|
|
49
|
+
// return result
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
async updateDraft(draftId, { body, subject, senderFiles, recipients, replyToId }) {
|
|
53
|
+
const drafts = await this.draftMails();
|
|
54
|
+
const draft = drafts.find((d) => d.mailIntegrityId === draftId);
|
|
55
|
+
if (draft === undefined) {
|
|
56
|
+
throw new Error(`Invalid draft ${draftId}`);
|
|
57
|
+
}
|
|
58
|
+
let hashKey = null;
|
|
59
|
+
let hash = null;
|
|
60
|
+
if (body !== undefined || subject !== undefined) {
|
|
61
|
+
hashKey = sodium.randombytes_buf(sodium.crypto_generichash_KEYBYTES, 'hex');
|
|
62
|
+
hash = sodium.crypto_generichash(sodium.crypto_generichash_BYTES, JSON.stringify({ body, subject }), hashKey, 'hex');
|
|
63
|
+
}
|
|
64
|
+
if (senderFiles !== undefined) {
|
|
65
|
+
for (const f of senderFiles) {
|
|
66
|
+
let file = filesCache.get(f.id);
|
|
67
|
+
if (file === undefined) {
|
|
68
|
+
await this.#client.cloud.fileMetadata({ id: f.id });
|
|
69
|
+
file = filesCache.get(f.id);
|
|
70
|
+
if (file === undefined) {
|
|
71
|
+
throw new Error(`File ${f.name} (${f.id}) does not exists`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
f.name = sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#keys.publicKey, this.#keys.privateKey));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const updateDraftMail = await this.#apiClient.mail.updateDraft.mutate({
|
|
78
|
+
id: draftId,
|
|
79
|
+
recipients: recipients ?? null,
|
|
80
|
+
replyToId: replyToId ?? null,
|
|
81
|
+
body: body !== undefined
|
|
82
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#keys.publicKey, this.#keys.privateKey))
|
|
83
|
+
: null,
|
|
84
|
+
subject: subject !== undefined
|
|
85
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#keys.publicKey, this.#keys.privateKey))
|
|
86
|
+
: null,
|
|
87
|
+
senderFiles: senderFiles ?? null,
|
|
88
|
+
hash,
|
|
89
|
+
hashKey,
|
|
90
|
+
});
|
|
91
|
+
return (await convertInternalMailToExternal({
|
|
92
|
+
mail: updateDraftMail,
|
|
93
|
+
client: this.#client,
|
|
94
|
+
keyPair: this.#keys,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
async deleteDraft(draftId) {
|
|
98
|
+
const { isDeleted } = await this.#apiClient.mail.deleteDraft.mutate({
|
|
99
|
+
id: draftId,
|
|
100
|
+
});
|
|
101
|
+
return isDeleted;
|
|
102
|
+
}
|
|
103
|
+
async deleteTrash({ ids }) {
|
|
104
|
+
const { isDeleted } = await this.#apiClient.mail.deleteTrash.mutate({
|
|
105
|
+
ids,
|
|
106
|
+
});
|
|
107
|
+
return isDeleted;
|
|
108
|
+
}
|
|
109
|
+
async emptyTrash() {
|
|
110
|
+
const { isDeleted } = await this.#apiClient.mail.emptyTrash.mutate({});
|
|
111
|
+
return isDeleted;
|
|
112
|
+
}
|
|
113
|
+
async delete({ mailId }) {
|
|
114
|
+
const { isDeleted } = await this.#apiClient.mail.delete.mutate({
|
|
115
|
+
id: mailId,
|
|
116
|
+
});
|
|
117
|
+
return isDeleted;
|
|
118
|
+
}
|
|
119
|
+
async sendDraft(draftId, customMessage) {
|
|
120
|
+
const drafts = await this.draftMails();
|
|
121
|
+
const draft = drafts.find((d) => d.mailIntegrityId === draftId);
|
|
122
|
+
if (draft === undefined) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const temporaryRecipients = new Array();
|
|
126
|
+
const recipients = new Array(); // TODO
|
|
127
|
+
for (const { email } of draft.temporaryRecipients) {
|
|
128
|
+
if (email === undefined) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const input = await this._eachUser(draft.files, draft.subject, draft.body, email);
|
|
132
|
+
if (input === null) {
|
|
133
|
+
temporaryRecipients.push(email);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
recipients.push(input);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (const { id } of draft.recipients) {
|
|
140
|
+
const input = await this._eachUser(draft.files, draft.subject, draft.body, id);
|
|
141
|
+
if (input === null) {
|
|
142
|
+
temporaryRecipients.push(id);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
recipients.push(input);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const { isSent } = await this.#apiClient.mail.sendDraft.mutate({
|
|
149
|
+
temporaryRecipients,
|
|
150
|
+
recipients,
|
|
151
|
+
id: draft.mailIntegrityId,
|
|
152
|
+
customMessage: customMessage ?? null,
|
|
153
|
+
});
|
|
154
|
+
return isSent;
|
|
155
|
+
}
|
|
156
|
+
async sendWaitingEmails() {
|
|
157
|
+
// TODO opti this
|
|
158
|
+
const mails = await this.sentMails();
|
|
159
|
+
const filtered = mails.filter((m) => m.temporaryRecipients.length > 0);
|
|
160
|
+
for (const mail of filtered) {
|
|
161
|
+
for (const { email } of mail.temporaryRecipients) {
|
|
162
|
+
if (email === undefined) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const input = await this._eachUser(mail.files, mail.subject, mail.body, email);
|
|
167
|
+
if (input === null) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
await this.#apiClient.mail.sendOne.mutate({
|
|
171
|
+
id: mail.mailIntegrityId,
|
|
172
|
+
recipient: input,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async createDraft({ body, subject, senderFiles, recipients, replyToId, }) {
|
|
182
|
+
const hashKey = sodium.randombytes_buf(sodium.crypto_generichash_KEYBYTES, 'hex');
|
|
183
|
+
const hash = sodium.crypto_generichash(sodium.crypto_generichash_BYTES, JSON.stringify({ body, subject }), hashKey, 'hex');
|
|
184
|
+
for (const f of senderFiles) {
|
|
185
|
+
let file = filesCache.get(f.id);
|
|
186
|
+
if (file === undefined) {
|
|
187
|
+
await this.#client.cloud.fileMetadata({ id: f.id });
|
|
188
|
+
file = filesCache.get(f.id);
|
|
189
|
+
if (file === undefined) {
|
|
190
|
+
throw new Error(`File ${f.name} (${f.id}) does not exists`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
senderFiles.push({
|
|
194
|
+
id: file.id,
|
|
195
|
+
name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), this.#keys.publicKey, this.#keys.privateKey)),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const createDraftMail = await this.#apiClient.mail.createDraft.mutate({
|
|
199
|
+
// recipients: recipientsIds,
|
|
200
|
+
recipients, // TODO
|
|
201
|
+
replyToId,
|
|
202
|
+
body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#keys.publicKey, this.#keys.privateKey)),
|
|
203
|
+
subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#keys.publicKey, this.#keys.privateKey)),
|
|
204
|
+
senderFiles,
|
|
205
|
+
hash,
|
|
206
|
+
hashKey,
|
|
207
|
+
});
|
|
208
|
+
return (await convertInternalMailToExternal({
|
|
209
|
+
mail: createDraftMail,
|
|
210
|
+
client: this.#client,
|
|
211
|
+
keyPair: this.#keys,
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
async read({ mailId }) {
|
|
215
|
+
const { isRead } = await this.#apiClient.mail.read.mutate({
|
|
216
|
+
id: mailId,
|
|
217
|
+
});
|
|
218
|
+
return isRead;
|
|
219
|
+
}
|
|
220
|
+
async unread({ mailId }) {
|
|
221
|
+
const { isUnread } = await this.#apiClient.mail.unread.mutate({
|
|
222
|
+
id: mailId,
|
|
223
|
+
});
|
|
224
|
+
return isUnread;
|
|
225
|
+
}
|
|
226
|
+
async receivedMails() {
|
|
227
|
+
const receivedMails = await this.#apiClient.mail.received.query({});
|
|
228
|
+
return await Promise.all(receivedMails.map(async (mail) => (await convertInternalMailToExternal({
|
|
229
|
+
mail,
|
|
230
|
+
client: this.#client,
|
|
231
|
+
keyPair: this.#keys,
|
|
232
|
+
}))));
|
|
233
|
+
}
|
|
234
|
+
async sentMails() {
|
|
235
|
+
const sentMails = await this.#apiClient.mail.sent.query({});
|
|
236
|
+
return await Promise.all(sentMails.map(async (mail) => (await convertInternalMailToExternal({
|
|
237
|
+
mail,
|
|
238
|
+
client: this.#client,
|
|
239
|
+
keyPair: this.#keys,
|
|
240
|
+
}))));
|
|
241
|
+
}
|
|
242
|
+
async draftMails() {
|
|
243
|
+
const draftMails = await this.#apiClient.mail.draft.query({});
|
|
244
|
+
return await Promise.all(draftMails.map(async (mail) => (await convertInternalMailToExternal({
|
|
245
|
+
mail,
|
|
246
|
+
client: this.#client,
|
|
247
|
+
keyPair: this.#keys,
|
|
248
|
+
}))));
|
|
249
|
+
}
|
|
250
|
+
async unreadReceivedMailsCount() {
|
|
251
|
+
const unreadReceivedMailsCount = await this.#apiClient.mail.unreadReceivedCount.query({});
|
|
252
|
+
return unreadReceivedMailsCount;
|
|
253
|
+
}
|
|
254
|
+
_eachUser = async (files, subject, body, idOrMail) => {
|
|
255
|
+
// const pubKey = await this.#client.app.userPublicKey(userId)
|
|
256
|
+
const pubKey = await this.#client.app.userPublicKey(idOrMail);
|
|
257
|
+
// const recipientsFiles = new Array<MailFileInput>()
|
|
258
|
+
const recipientsFiles = new Array();
|
|
259
|
+
for (const f of files) {
|
|
260
|
+
let fileInHistory = filesCache.get(f.id);
|
|
261
|
+
if (fileInHistory === undefined) {
|
|
262
|
+
await this.#client.cloud.fileMetadata({ id: f.id });
|
|
263
|
+
fileInHistory = filesCache.get(f.id);
|
|
264
|
+
if (fileInHistory === undefined) {
|
|
265
|
+
throw new Error(`File ${f.name} (${f.id}) does not exists`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const key = fileInHistory.key;
|
|
269
|
+
recipientsFiles.push({
|
|
270
|
+
id: f.id,
|
|
271
|
+
name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), pubKey, this.#keys.privateKey)),
|
|
272
|
+
fileKey: sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), pubKey, this.#keys.privateKey)),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
// recipientId: userId,
|
|
277
|
+
recipientId: idOrMail,
|
|
278
|
+
body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), pubKey, this.#keys.privateKey)),
|
|
279
|
+
subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), pubKey, this.#keys.privateKey)),
|
|
280
|
+
files: recipientsFiles,
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getUrl } from '../index.js';
|
|
2
|
+
import { popup } from '../utils/popup-tools.js';
|
|
3
|
+
export class SecrecyPayClient {
|
|
4
|
+
#client;
|
|
5
|
+
// #keys: KeyPair
|
|
6
|
+
// #apiClient: ApiClient
|
|
7
|
+
constructor(client, _keys, _apiClient) {
|
|
8
|
+
this.#client = client;
|
|
9
|
+
// this.#keys = keys
|
|
10
|
+
// this.#apiClient = apiClient
|
|
11
|
+
}
|
|
12
|
+
async confirmPaymentIntent({ paymentIntentId, secrecyIdWhoCreatedPaymentIntent, secrecyIdWhoNeedToConfirmPaymentIntent, amount, currency, }) {
|
|
13
|
+
const url = getUrl({
|
|
14
|
+
hash: Buffer.from(JSON.stringify({
|
|
15
|
+
appSession: this.#client.sessionId,
|
|
16
|
+
paymentIntentId,
|
|
17
|
+
secrecyIdWhoCreatedPaymentIntent,
|
|
18
|
+
secrecyIdWhoNeedToConfirmPaymentIntent,
|
|
19
|
+
amount,
|
|
20
|
+
currency,
|
|
21
|
+
})).toString('base64'),
|
|
22
|
+
path: '/account/iframe/pay-confirm',
|
|
23
|
+
});
|
|
24
|
+
return await new Promise((resolve, reject) => popup(url, 'Secrecy Pay - Confirm Payment Intent', {
|
|
25
|
+
width: 500,
|
|
26
|
+
}, (err, data) => {
|
|
27
|
+
if (err !== undefined) {
|
|
28
|
+
reject(err);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
resolve(data);
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class SecrecyUserClient {
|
|
2
|
+
#apiClient;
|
|
3
|
+
constructor(_client, _keys, apiClient) {
|
|
4
|
+
this.#apiClient = apiClient;
|
|
5
|
+
}
|
|
6
|
+
async answerInvitation(input) {
|
|
7
|
+
return await this.#apiClient.contacts.answerInvitation.mutate(input);
|
|
8
|
+
}
|
|
9
|
+
async cancelInvitation(input) {
|
|
10
|
+
return await this.#apiClient.contacts.cancelInvitation.mutate(input);
|
|
11
|
+
}
|
|
12
|
+
async createInvitation(input) {
|
|
13
|
+
return await this.#apiClient.contacts.createInvitation.mutate(input);
|
|
14
|
+
}
|
|
15
|
+
async getContacts(input) {
|
|
16
|
+
return await this.#apiClient.contacts.getContacts.query(input);
|
|
17
|
+
}
|
|
18
|
+
async getReceivedInvitations(input) {
|
|
19
|
+
return await this.#apiClient.contacts.getReceivedInvitations.query(input);
|
|
20
|
+
}
|
|
21
|
+
async getSentInvitations(input) {
|
|
22
|
+
return await this.#apiClient.contacts.getSentInvitations.query(input);
|
|
23
|
+
}
|
|
24
|
+
async removeContact(input) {
|
|
25
|
+
return await this.#apiClient.contacts.removeContact.mutate(input);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getUrl } from '../index.js';
|
|
2
|
+
import { popup } from '../utils/popup-tools.js';
|
|
3
|
+
export class SecrecyWalletClient {
|
|
4
|
+
#client;
|
|
5
|
+
// #keys: KeyPair;
|
|
6
|
+
// #thunder: ReturnType<typeof Thunder>;
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.#client = client;
|
|
9
|
+
// this.#keys = keys;
|
|
10
|
+
// this.#thunder = thunder;
|
|
11
|
+
}
|
|
12
|
+
async createTransaction({ network = 'mainnet', tx, }) {
|
|
13
|
+
const url = getUrl({
|
|
14
|
+
hash: Buffer.from(JSON.stringify({
|
|
15
|
+
appSession: this.#client.sessionId,
|
|
16
|
+
network,
|
|
17
|
+
tx,
|
|
18
|
+
})).toString('base64'),
|
|
19
|
+
path: '/account/iframe/wallet-transaction',
|
|
20
|
+
});
|
|
21
|
+
return await new Promise((resolve, reject) => popup(url, 'Secrecy Wallet - Transaction', {
|
|
22
|
+
width: 500,
|
|
23
|
+
}, (err, data) => {
|
|
24
|
+
if (err !== undefined) {
|
|
25
|
+
reject(err);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
resolve(data);
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
async createSignature({ network = 'mainnet', message, }) {
|
|
32
|
+
const url = getUrl({
|
|
33
|
+
hash: Buffer.from(JSON.stringify({
|
|
34
|
+
appSession: this.#client.sessionId,
|
|
35
|
+
network,
|
|
36
|
+
message,
|
|
37
|
+
})).toString('base64'),
|
|
38
|
+
path: '/account/iframe/wallet-signature',
|
|
39
|
+
});
|
|
40
|
+
return await new Promise((resolve, reject) => popup(url, 'Secrecy Wallet - Signature', {
|
|
41
|
+
width: 500,
|
|
42
|
+
}, (err, data) => {
|
|
43
|
+
if (err !== undefined) {
|
|
44
|
+
reject(err);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
resolve(data);
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { filesCache } from '../../cache.js';
|
|
2
|
+
import { decryptCryptoBox } from '../../crypto/index.js';
|
|
3
|
+
import { sodium } from '../../sodium.js';
|
|
4
|
+
export function apiFileToInternal(apiFile, keyPair) {
|
|
5
|
+
const file = {
|
|
6
|
+
id: apiFile.id,
|
|
7
|
+
md5: apiFile.md5,
|
|
8
|
+
md5Encrypted: apiFile.md5Encrypted,
|
|
9
|
+
createdAt: apiFile.createdAt,
|
|
10
|
+
size: apiFile.size,
|
|
11
|
+
sizeBefore: apiFile.sizeBefore,
|
|
12
|
+
key: sodium.to_hex(decryptCryptoBox(sodium.from_hex(apiFile.access.key), apiFile.access.sharedByPubKey, keyPair.privateKey)),
|
|
13
|
+
};
|
|
14
|
+
filesCache.set(file.id, file);
|
|
15
|
+
return file;
|
|
16
|
+
}
|
|
17
|
+
export function internalFileToFile(internal) {
|
|
18
|
+
return {
|
|
19
|
+
id: internal.id,
|
|
20
|
+
md5: internal.md5,
|
|
21
|
+
md5Encrypted: internal.md5Encrypted,
|
|
22
|
+
createdAt: internal.createdAt,
|
|
23
|
+
size: internal.size,
|
|
24
|
+
sizeBefore: internal.sizeBefore,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function apiFileToExternal(apiFile, keyPair) {
|
|
28
|
+
return internalFileToFile(apiFileToInternal(apiFile, keyPair));
|
|
29
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { sodium, decryptCryptoBox, } from '../../index.js';
|
|
2
|
+
export async function convertInternalMailToExternal({ client, mail, keyPair, }) {
|
|
3
|
+
let type = mail.type;
|
|
4
|
+
if (mail.mailIntegrityDraft !== null) {
|
|
5
|
+
type = 'draft';
|
|
6
|
+
}
|
|
7
|
+
const mI = type === 'draft' ? mail.mailIntegrityDraft : mail.mailIntegrity;
|
|
8
|
+
if (mI === null) {
|
|
9
|
+
throw new Error('Mail integrity is null');
|
|
10
|
+
}
|
|
11
|
+
const pubKey = mail.type === 'received'
|
|
12
|
+
? await client.app.userPublicKey(mail.sender.id)
|
|
13
|
+
: keyPair.publicKey;
|
|
14
|
+
const privateKey = keyPair.privateKey;
|
|
15
|
+
const body = sodium.to_string(decryptCryptoBox(sodium.from_hex(mail.body), pubKey, privateKey));
|
|
16
|
+
const subject = sodium.to_string(decryptCryptoBox(sodium.from_hex(mail.subject), pubKey, privateKey));
|
|
17
|
+
const hash = sodium.crypto_generichash(sodium.crypto_generichash_BYTES, JSON.stringify({ body, subject }), mI.hashKey, 'hex');
|
|
18
|
+
return {
|
|
19
|
+
type,
|
|
20
|
+
id: mail.id,
|
|
21
|
+
mailIntegrityId: mI.id,
|
|
22
|
+
replyTo: mI.replyTo?.id,
|
|
23
|
+
body,
|
|
24
|
+
subject,
|
|
25
|
+
createdAt: mail.createdAt,
|
|
26
|
+
deletedAt: mail.deletedAt,
|
|
27
|
+
openedAt: mail.openedAt,
|
|
28
|
+
isAltered: hash !== mI.hash,
|
|
29
|
+
// temporaryRecipients: mI.temporaryRecipients,
|
|
30
|
+
temporaryRecipients: [], // TODO
|
|
31
|
+
recipients: mI.recipients,
|
|
32
|
+
sender: mail.sender,
|
|
33
|
+
files: mail.files.map((f) => {
|
|
34
|
+
const name = sodium.to_string(decryptCryptoBox(sodium.from_hex(f.filename), pubKey, privateKey));
|
|
35
|
+
return {
|
|
36
|
+
id: f.fileId,
|
|
37
|
+
name,
|
|
38
|
+
key: f.fileKey,
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { sodium } from '../../sodium.js';
|
|
2
|
+
import { decryptCryptoBox } from '../../crypto/index.js';
|
|
3
|
+
import { nodesCache } from '../../cache.js';
|
|
4
|
+
import { decryptSecretstream } from '../../crypto/file.js';
|
|
5
|
+
import { apiFileToInternal, internalFileToFile } from './file.js';
|
|
6
|
+
export async function apiNodeToInternal(apiNode, keyPair) {
|
|
7
|
+
const internal = {
|
|
8
|
+
id: apiNode.id,
|
|
9
|
+
type: apiNode.type,
|
|
10
|
+
access: apiNode.access,
|
|
11
|
+
name: apiNode.name,
|
|
12
|
+
isFavorite: apiNode.isFavorite,
|
|
13
|
+
// TODO
|
|
14
|
+
// breadcrumb: apiNode.breadcrumb,
|
|
15
|
+
// createdBy: apiNode.createdBy.user,
|
|
16
|
+
breadcrumb: [],
|
|
17
|
+
createdBy: {
|
|
18
|
+
firstname: apiNode.createdBy.userId,
|
|
19
|
+
lastname: apiNode.createdBy.userId,
|
|
20
|
+
avatar: apiNode.createdBy.userId,
|
|
21
|
+
id: apiNode.createdBy.userId,
|
|
22
|
+
isSearchable: true,
|
|
23
|
+
},
|
|
24
|
+
currentFileId: null,
|
|
25
|
+
// currentFileId: apiNode.currentFileId ?? null,
|
|
26
|
+
sizes: {
|
|
27
|
+
// size: apiNode.sizes.size,
|
|
28
|
+
// sizeBefore: apiNode.sizes.sizeBefore,
|
|
29
|
+
size: 0n,
|
|
30
|
+
sizeBefore: 0n,
|
|
31
|
+
},
|
|
32
|
+
createdAt: apiNode.createdAt,
|
|
33
|
+
updatedAt: apiNode.updatedAt,
|
|
34
|
+
deletedAt: apiNode.deletedAt,
|
|
35
|
+
users: apiNode.users,
|
|
36
|
+
parentId: apiNode.parentId ?? null,
|
|
37
|
+
};
|
|
38
|
+
internal.access = { ...apiNode.access };
|
|
39
|
+
if (apiNode.access.nameKey !== null) {
|
|
40
|
+
const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPubKey, keyPair.privateKey);
|
|
41
|
+
internal.name = sodium.to_string(await decryptSecretstream(key, sodium.from_hex(internal.name)));
|
|
42
|
+
internal.access.nameKey = sodium.to_hex(key);
|
|
43
|
+
}
|
|
44
|
+
for (const b of internal.breadcrumb) {
|
|
45
|
+
if (b.nameKey === null) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const key = decryptCryptoBox(sodium.from_hex(b.nameKey), b.pubKey, keyPair.privateKey);
|
|
49
|
+
b.nameKey = sodium.to_hex(key);
|
|
50
|
+
b.name = sodium.to_string(await decryptSecretstream(key, sodium.from_hex(b.name)));
|
|
51
|
+
}
|
|
52
|
+
nodesCache.set(internal.id, internal);
|
|
53
|
+
return internal;
|
|
54
|
+
}
|
|
55
|
+
export async function apiNodeFullToInternalFull(apiNodeFull, keyPair) {
|
|
56
|
+
const f = await apiNodeToInternal(apiNodeFull, keyPair);
|
|
57
|
+
return {
|
|
58
|
+
...f,
|
|
59
|
+
current: apiNodeFull.current !== null
|
|
60
|
+
? apiFileToInternal(apiNodeFull.current, keyPair)
|
|
61
|
+
: undefined,
|
|
62
|
+
parent: apiNodeFull.parent !== null
|
|
63
|
+
? await apiNodeToInternal(apiNodeFull.parent, keyPair)
|
|
64
|
+
: null,
|
|
65
|
+
children: await Promise.all(apiNodeFull.children.map(async (s) => await apiNodeToInternal(s, keyPair))),
|
|
66
|
+
history: apiNodeFull.history.map((f) => apiFileToInternal(f, keyPair)),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function internalNodeToNode(internal) {
|
|
70
|
+
const node = {
|
|
71
|
+
...internal,
|
|
72
|
+
breadcrumb: internal.breadcrumb.map((b) => ({
|
|
73
|
+
id: b.id,
|
|
74
|
+
name: b.name,
|
|
75
|
+
})),
|
|
76
|
+
access: {
|
|
77
|
+
isRoot: internal.access.isRoot,
|
|
78
|
+
rights: internal.access.rights,
|
|
79
|
+
sharedByPubKey: internal.access.sharedByPubKey,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
export function internalNodeFullToNodeFull(internal) {
|
|
85
|
+
return {
|
|
86
|
+
...internalNodeToNode(internal),
|
|
87
|
+
parent: internal.parent !== null ? internalNodeToNode(internal.parent) : null,
|
|
88
|
+
children: internal.children.map(internalNodeToNode),
|
|
89
|
+
history: internal.history.map((f) => internalFileToFile(f)),
|
|
90
|
+
current: internal.current !== null && internal.current !== undefined
|
|
91
|
+
? internalFileToFile(internal.current)
|
|
92
|
+
: undefined,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function apiNodeToExternalNodeFull(apiNodeFull, keyPair) {
|
|
96
|
+
return internalNodeFullToNodeFull(await apiNodeFullToInternalFull(apiNodeFull, keyPair));
|
|
97
|
+
}
|
|
98
|
+
export async function apiNodeToExternal(apiNode, keyPair) {
|
|
99
|
+
return internalNodeToNode(await apiNodeToInternal(apiNode, keyPair));
|
|
100
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { SecrecyClient } from './index.js';
|
|
2
|
+
import { popup } from '../utils/popup-tools.js';
|
|
3
|
+
import { secrecyUserApp } from './types/index.js';
|
|
4
|
+
import { getStorage } from './storage.js';
|
|
5
|
+
export function parseInfos() {
|
|
6
|
+
if (window.location.hash === '') {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const hash = window.location.hash.substr(1);
|
|
10
|
+
try {
|
|
11
|
+
const res = JSON.parse(atob(hash));
|
|
12
|
+
window.location.hash = '';
|
|
13
|
+
const data = secrecyUserApp.safeParse(res);
|
|
14
|
+
return data.success ? data.data : null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export const getUrl = ({ hash, path, }) => {
|
|
21
|
+
const lang = document.documentElement.lang;
|
|
22
|
+
const rawAuthUrl = process.env.NEXT_PUBLIC_SECRECY_AUTH_URL ?? 'https://auth.secrecy.me/';
|
|
23
|
+
const authUrl = rawAuthUrl.endsWith('/') ? rawAuthUrl : `${rawAuthUrl}/`;
|
|
24
|
+
path = path.startsWith('/') ? path : `/${path}`;
|
|
25
|
+
return `${authUrl}${lang}${path}#${hash}`;
|
|
26
|
+
};
|
|
27
|
+
export function getSecrecyClient(session) {
|
|
28
|
+
const storage = getStorage(session);
|
|
29
|
+
const uaSession = storage.userAppSession.load();
|
|
30
|
+
const uaKeys = storage.userAppKeys.load();
|
|
31
|
+
const uaJwt = storage.jwt.load();
|
|
32
|
+
if (uaSession === null || uaKeys === null || uaJwt === null) {
|
|
33
|
+
const infos = parseInfos();
|
|
34
|
+
if (infos !== null) {
|
|
35
|
+
storage.userAppKeys.save(infos.keys);
|
|
36
|
+
storage.userAppSession.save(infos.uaSession);
|
|
37
|
+
storage.jwt.save(infos.jwt);
|
|
38
|
+
return new SecrecyClient(infos.uaSession, infos.keys, infos.jwt);
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return new SecrecyClient(uaSession, uaKeys, uaJwt);
|
|
43
|
+
}
|
|
44
|
+
export async function login({ appId, path, redirect, scopes, backPath, session, }) {
|
|
45
|
+
return await new Promise((resolve, reject) => {
|
|
46
|
+
const appUrl = window.location.origin;
|
|
47
|
+
const client = getSecrecyClient();
|
|
48
|
+
if (client === null) {
|
|
49
|
+
const infos = {
|
|
50
|
+
appUrl,
|
|
51
|
+
appId,
|
|
52
|
+
redirect,
|
|
53
|
+
path,
|
|
54
|
+
scopes,
|
|
55
|
+
backPath,
|
|
56
|
+
};
|
|
57
|
+
const data = btoa(JSON.stringify(infos)).replaceAll('=', '');
|
|
58
|
+
const url = getUrl({
|
|
59
|
+
hash: data,
|
|
60
|
+
path: 'login',
|
|
61
|
+
});
|
|
62
|
+
const validate = (infos) => {
|
|
63
|
+
const storage = getStorage(session);
|
|
64
|
+
storage.userAppSession.save(infos.uaSession);
|
|
65
|
+
storage.userAppKeys.save(infos.keys);
|
|
66
|
+
storage.jwt.save(infos.jwt);
|
|
67
|
+
resolve(new SecrecyClient(infos.uaSession, infos.keys, infos.jwt));
|
|
68
|
+
};
|
|
69
|
+
if (redirect === true) {
|
|
70
|
+
const infos = parseInfos();
|
|
71
|
+
if (infos !== null) {
|
|
72
|
+
validate(infos);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
window.location.href = url;
|
|
76
|
+
resolve(null);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
popup(url, 'Secrecy Login', {
|
|
81
|
+
width: 500,
|
|
82
|
+
height: 750,
|
|
83
|
+
resizable: 'no',
|
|
84
|
+
menubar: 'no',
|
|
85
|
+
location: 'no',
|
|
86
|
+
centered: true,
|
|
87
|
+
scrollbars: 'no',
|
|
88
|
+
}, (err, data) => {
|
|
89
|
+
if (err !== undefined) {
|
|
90
|
+
reject(err);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const res = secrecyUserApp.safeParse(data);
|
|
94
|
+
res.success ? validate(res.data) : reject(res.error.message);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
resolve(client);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|