@secrecy/lib 1.10.1 → 1.11.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.
@@ -58,7 +58,7 @@ export class BaseClient {
58
58
  }
59
59
  async updateProfile(data) {
60
60
  const updateProfile = await this.client.user.updateProfile.mutate(data);
61
- return updateProfile; // TODO
61
+ return updateProfile;
62
62
  }
63
63
  static async isCryptoTransactionDone({ idOrHash, network = 'mainnet', }) {
64
64
  const { isDone } = await this.getBaseClient().crypto.isTransactionDone.query({
package/dist/lib/cache.js CHANGED
@@ -1,4 +1,13 @@
1
+ import { LRUCache } from 'lru-cache';
2
+ import { gigaToBytes } from './utils.js';
1
3
  export const filesCache = new Map();
2
4
  export const nodesCache = new Map();
3
5
  export const usersCache = new Map();
4
6
  export const publicKeysCache = new Map();
7
+ export const dataCache = new LRUCache({
8
+ max: 500,
9
+ maxSize: gigaToBytes(0.5),
10
+ sizeCalculation: (value) => {
11
+ return value.byteLength;
12
+ },
13
+ });
@@ -1,8 +1,8 @@
1
1
  import axios from 'axios';
2
2
  import ky from 'ky';
3
3
  import { encryptName } from '../index.js';
4
- import { nodesCache, filesCache } from '../cache.js';
5
- import { secretstreamKeygen } from '../crypto/file.js';
4
+ import { nodesCache, filesCache, dataCache } from '../cache.js';
5
+ import { secretStreamKeygen } from '../crypto/file.js';
6
6
  import { decryptCryptoBox, encryptCryptoBox } from '../crypto/index.js';
7
7
  import { compress, decompress } from '../minify/index.js';
8
8
  import { sodium } from '../sodium.js';
@@ -35,16 +35,19 @@ export class SecrecyCloudClient {
35
35
  await this.#apiClient.cloud.shareFileInHistory.mutate({
36
36
  fileId: file.id,
37
37
  nodeId,
38
- users: users.map(([u]) => ({
39
- id: u.id,
40
- key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(file.key), this.#keys.publicKey, this.#keys.privateKey)),
38
+ users: await Promise.all(users.map(async ([u]) => {
39
+ const userPubKey = await this.#client.app.userPublicKey(u.id);
40
+ return {
41
+ id: u.id,
42
+ key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(file.key), userPubKey, this.#keys.privateKey)),
43
+ };
41
44
  })),
42
45
  });
43
46
  }
44
47
  return internalNodeFullToNodeFull(node);
45
48
  }
46
49
  async uploadFile({ file, encryptProgress, uploadProgress, signal, }) {
47
- const fileKey = secretstreamKeygen();
50
+ const fileKey = secretStreamKeygen();
48
51
  const fileBuffer = file instanceof File ? new Uint8Array(await file.arrayBuffer()) : file;
49
52
  const compressed = compress(fileBuffer);
50
53
  const { data: encryptedFile, md5: md5File, md5Encrypted, } = await encrypt(fileKey, compressed, encryptProgress, signal);
@@ -118,16 +121,12 @@ export class SecrecyCloudClient {
118
121
  signal,
119
122
  });
120
123
  await uploadPartEnded(chunk.md5, chunk.order);
121
- // if ((e as any).response.status === 0) {
122
- // // TODO https://github.com/sindresorhus/ky/issues/305
123
- // } else {
124
- // throw e;
125
- // }
126
124
  };
127
125
  await promiseAllLimit(3, uploadFile.parts.map((p) => async () => {
128
126
  await byPart(p);
129
127
  }));
130
128
  await uploadEnded();
129
+ dataCache.set(uploadFile.fileId, fileBuffer);
131
130
  return uploadFile.fileId;
132
131
  }
133
132
  async uploadFileInCloud({ file, name, nodeId, encryptProgress, uploadProgress, signal, }) {
@@ -194,7 +193,7 @@ export class SecrecyCloudClient {
194
193
  return isDeleted;
195
194
  }
196
195
  async createFolder({ name, parentFolderId, }) {
197
- const key = secretstreamKeygen();
196
+ const key = secretStreamKeygen();
198
197
  const encryptedName = await encryptName(name, sodium.to_hex(key));
199
198
  const encryptedKey = encryptCryptoBox(key, this.#keys.publicKey, this.#keys.privateKey);
200
199
  const createFolder = await this.#apiClient.cloud.createFolder.mutate({
@@ -272,6 +271,10 @@ export class SecrecyCloudClient {
272
271
  return await apiNodeToExternalNodeFull(updateNode, this.#keys);
273
272
  }
274
273
  async fileContent({ fileId, onDownloadProgress, progressDecrypt, signal, }) {
274
+ const cached = dataCache.get(fileId);
275
+ if (cached !== undefined) {
276
+ return cached;
277
+ }
275
278
  const fileContent = await this.#apiClient.cloud.fileContentById.query({
276
279
  id: fileId,
277
280
  });
@@ -344,7 +347,9 @@ export class SecrecyCloudClient {
344
347
  if (encryptedContent === null) {
345
348
  throw `Can't find content for file ${fileId}`;
346
349
  }
347
- return await finalize(encryptedContent);
350
+ const data = await finalize(encryptedContent);
351
+ dataCache.set(fileId, data);
352
+ return data;
348
353
  }
349
354
  async deleteFile({ fileId, nodeId, }) {
350
355
  const { isDeleted } = await this.#apiClient.cloud.deleteFile.mutate({
@@ -425,7 +430,7 @@ export class SecrecyCloudClient {
425
430
  key = file.key;
426
431
  }
427
432
  key = sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#keys.publicKey, this.#keys.privateKey));
428
- const nameKey = secretstreamKeygen();
433
+ const nameKey = secretStreamKeygen();
429
434
  const encryptedName = await encryptName(name, sodium.to_hex(nameKey));
430
435
  const encryptedNameKey = sodium.to_hex(encryptCryptoBox(nameKey, this.#keys.publicKey, this.#keys.privateKey));
431
436
  const saveInCloud = await this.#apiClient.cloud.saveInCloud.mutate({
@@ -123,7 +123,7 @@ export class SecrecyMailClient {
123
123
  return false;
124
124
  }
125
125
  const temporaryRecipients = new Array();
126
- const recipients = new Array(); // TODO
126
+ const recipients = new Array();
127
127
  for (const { email } of draft.temporaryRecipients) {
128
128
  if (email === undefined) {
129
129
  continue;
@@ -154,7 +154,7 @@ export class SecrecyMailClient {
154
154
  return isSent;
155
155
  }
156
156
  async sendWaitingEmails() {
157
- // TODO opti this
157
+ // TODO optimize this
158
158
  const mails = await this.sentMails();
159
159
  const filtered = mails.filter((m) => m.temporaryRecipients.length > 0);
160
160
  for (const mail of filtered) {
@@ -196,8 +196,7 @@ export class SecrecyMailClient {
196
196
  });
197
197
  }
198
198
  const createDraftMail = await this.#apiClient.mail.createDraft.mutate({
199
- // recipients: recipientsIds,
200
- recipients, // TODO
199
+ recipients,
201
200
  replyToId,
202
201
  body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), this.#keys.publicKey, this.#keys.privateKey)),
203
202
  subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), this.#keys.publicKey, this.#keys.privateKey)),
@@ -1,7 +1,7 @@
1
1
  import { sodium } from '../../sodium.js';
2
2
  import { decryptCryptoBox } from '../../crypto/index.js';
3
3
  import { nodesCache } from '../../cache.js';
4
- import { decryptSecretstream } from '../../crypto/file.js';
4
+ import { decryptSecretStream } from '../../crypto/file.js';
5
5
  import { apiFileToInternal, internalFileToFile } from './file.js';
6
6
  export async function apiNodeToInternal(apiNode, keyPair) {
7
7
  const internal = {
@@ -28,7 +28,7 @@ export async function apiNodeToInternal(apiNode, keyPair) {
28
28
  internal.access = { ...apiNode.access };
29
29
  if (apiNode.access.nameKey !== null) {
30
30
  const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPubKey, keyPair.privateKey);
31
- internal.name = sodium.to_string(await decryptSecretstream(key, sodium.from_hex(internal.name)));
31
+ internal.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(internal.name)));
32
32
  internal.access.nameKey = sodium.to_hex(key);
33
33
  }
34
34
  for (const b of internal.breadcrumb) {
@@ -37,7 +37,7 @@ export async function apiNodeToInternal(apiNode, keyPair) {
37
37
  }
38
38
  const key = decryptCryptoBox(sodium.from_hex(b.nameKey), b.pubKey, keyPair.privateKey);
39
39
  b.nameKey = sodium.to_hex(key);
40
- b.name = sodium.to_string(await decryptSecretstream(key, sodium.from_hex(b.name)));
40
+ b.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(b.name)));
41
41
  }
42
42
  nodesCache.set(internal.id, internal);
43
43
  return internal;
@@ -1,5 +1,5 @@
1
1
  import { BaseClient } from '../base-client.js';
2
- import { encryptSecretstream } from '../crypto/file.js';
2
+ import { encryptSecretStream } from '../crypto/file.js';
3
3
  import { sodium } from '../sodium.js';
4
4
  import { SecrecyCloudClient } from './SecrecyCloudClient.js';
5
5
  import { SecrecyMailClient } from './SecrecyMailClient.js';
@@ -11,7 +11,7 @@ import { SecrecyPayClient } from './SecrecyPayClient.js';
11
11
  import { SecrecyUserClient } from './SecrecyUserClient.js';
12
12
  import { SecrecyCareClient } from './SecrecryCareClient.js';
13
13
  export const encryptName = async (name, nameKey) => {
14
- const { data } = await encryptSecretstream(sodium.from_hex(nameKey), sodium.from_string(name));
14
+ const { data } = await encryptSecretStream(sodium.from_hex(nameKey), sodium.from_string(name));
15
15
  const nameEncrypted = sodium.to_hex(data);
16
16
  return nameEncrypted;
17
17
  };
@@ -6,7 +6,7 @@ function assert(c, message) {
6
6
  throw new Error(message);
7
7
  }
8
8
  }
9
- export function secretstreamKeygen() {
9
+ export function secretStreamKeygen() {
10
10
  return sodium.crypto_secretstream_xchacha20poly1305_keygen();
11
11
  }
12
12
  function encrypt(key) {
@@ -46,7 +46,7 @@ function decrypt(header, key) {
46
46
  };
47
47
  }
48
48
  export const CHUNK_SIZE = 8192;
49
- export async function encryptSecretstream(key, data, progress, abort) {
49
+ export async function encryptSecretStream(key, data, progress, abort) {
50
50
  await setup();
51
51
  const { encrypt: crypt, destroy, header } = encrypt(key);
52
52
  const encryptedChunk = CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
@@ -102,11 +102,11 @@ export async function encryptSecretstream(key, data, progress, abort) {
102
102
  md5: spark.end(),
103
103
  };
104
104
  }
105
- export async function decryptSecretstream(key, data, progress, abort) {
105
+ export async function decryptSecretStream(key, data, progress, abort) {
106
106
  await setup();
107
107
  const header = data.slice(0, sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES);
108
108
  data = data.slice(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES);
109
- const { decrypt: decryptt, destroy } = decrypt(header, key);
109
+ const { decrypt: decryptFn, destroy } = decrypt(header, key);
110
110
  const chunkSize = CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
111
111
  const max = Math.ceil(data.byteLength / chunkSize) * CHUNK_SIZE;
112
112
  void progress?.({
@@ -121,9 +121,9 @@ export async function decryptSecretstream(key, data, progress, abort) {
121
121
  if (abort?.signal.aborted === true) {
122
122
  throw new Error(`Decrypt aborted`);
123
123
  }
124
- const tmp = decryptt(chunk);
125
- final.set(tmp.message, total);
126
- total += tmp.message.byteLength;
124
+ const messageTag = decryptFn(chunk);
125
+ final.set(messageTag.message, total);
126
+ total += messageTag.message.byteLength;
127
127
  const percent = total / max;
128
128
  if (percent > lastPercent + 0.01) {
129
129
  void progress?.({
@@ -142,13 +142,13 @@ export async function decryptSecretstream(key, data, progress, abort) {
142
142
  });
143
143
  return final.slice(0, total);
144
144
  }
145
- // async function mainSecretstream(random: Uint8Array): Promise<vo id> {
145
+ // async function mainSecretStream(random: Uint8Array): Promise<vo id> {
146
146
  // const key = secretstreamKeygen();
147
147
  // console.time("secretstream_encrypt");
148
- // const crypted = en cryptSecretstream(key, random);
148
+ // const crypted = en cryptSecretStream(key, random);
149
149
  // consol e.timeEnd("secretstream_encrypt");
150
150
  // console.time("secretstream_decrypt");
151
- // const decrypted = decryptSecretstream(key, crypted);
151
+ // const decrypted = decryptSecretStream(key, crypted);
152
152
  // con sole.timeEnd("secretstream_decrypt");
153
153
  // const first = t o_hex(random).slice(0, 32);
154
154
  // const final = to_hex(decrypted).slice(0, 32);
@@ -158,7 +158,7 @@ export async function decryptSecretstream(key, data, progress, abort) {
158
158
  // equals: firs t === final
159
159
  // }) ;
160
160
  // }
161
- // async function mai nSecretbox(random: Uint8Array): Promise< void> {
161
+ // async function mainSecretBox(random: Uint8Array): Promise< void> {
162
162
  // const key = generateSecretBox();
163
163
  // console.time("secretbox _encrypt");
164
164
  // const crypted = encryptFile(random, key);
@@ -179,6 +179,6 @@ export async function decryptSecretstream(key, data, progress, abort) {
179
179
  // console.time("randombytes_buf");
180
180
  // const random = randombytes_buf(1_000_000 * 1024);
181
181
  // consol e.timeEnd("randombytes_buf");
182
- // await Promise.all([m ainSecretstream(random), mainSecretbox(random)]);
182
+ // await Promise.all([mainSecretStream(random), mainSecretBox(random)]);
183
183
  // }
184
184
  // main();
package/dist/lib/index.js CHANGED
@@ -1,6 +1,3 @@
1
- /* eslint-disable @typescript-eslint/triple-slash-reference */
2
- /// <reference lib="dom" />
3
- /// <reference lib="dom.iterable" />
4
1
  export * from './client/index.js';
5
2
  export * from './crypto/index.js';
6
3
  export { BaseClient } from './base-client.js';
@@ -0,0 +1,2 @@
1
+ export const kiloToBytes = (kb) => kb * 1024;
2
+ export const gigaToBytes = (gb) => gb * 2 ** 30;
@@ -12,7 +12,7 @@ export declare class BaseClient {
12
12
  static getUser(userId: string, sessionId?: string | null | undefined): Promise<PublicUser>;
13
13
  getUser(userId: string): Promise<PublicUser>;
14
14
  searchUsers(search: string): Promise<PublicUser[]>;
15
- updateProfile(data: RouterInputs['user']['updateProfile']): Promise<SelfUser>;
15
+ updateProfile(data: RouterInputs['user']['updateProfile']): Promise<Omit<SelfUser, 'account'>>;
16
16
  static isCryptoTransactionDone({ idOrHash, network, }: {
17
17
  idOrHash: string;
18
18
  network?: InfuraNetwork;
@@ -1,4 +1,5 @@
1
1
  import type { InternalNode, InternalFile, InternalNodeFull } from './client/types/index.js';
2
+ import { LRUCache } from 'lru-cache';
2
3
  export declare const filesCache: Map<string, InternalFile>;
3
4
  export declare const nodesCache: Map<string, InternalNode | InternalNodeFull>;
4
5
  export declare const usersCache: Map<string, {
@@ -9,3 +10,4 @@ export declare const usersCache: Map<string, {
9
10
  isSearchable: boolean;
10
11
  }>;
11
12
  export declare const publicKeysCache: Map<string, string>;
13
+ export declare const dataCache: LRUCache<string, Uint8Array, unknown>;
@@ -5186,6 +5186,52 @@ export declare const createTRPCClient: (session?: string | null | undefined, onA
5186
5186
  };
5187
5187
  }, unknown>>;
5188
5188
  };
5189
+ updateWallet: {
5190
+ mutate: import("@trpc/client").Resolver<import("@trpc/server").BuildProcedure<"mutation", {
5191
+ _config: import("@trpc/server").RootConfig<{
5192
+ ctx: {};
5193
+ meta: object;
5194
+ errorShape: {
5195
+ message: string;
5196
+ code: import("@trpc/server/rpc").TRPC_ERROR_CODE_NUMBER;
5197
+ data: _trpc_server_dist_error_formatter.DefaultErrorData;
5198
+ } | {
5199
+ data: {
5200
+ zodError: import("zod").typeToFlattenedError<any, string> | null;
5201
+ code: "UNAUTHORIZED" | "NOT_FOUND" | "PARSE_ERROR" | "BAD_REQUEST" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "FORBIDDEN" | "METHOD_NOT_SUPPORTED" | "TIMEOUT" | "CONFLICT" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "UNPROCESSABLE_CONTENT" | "TOO_MANY_REQUESTS" | "CLIENT_CLOSED_REQUEST";
5202
+ httpStatus: number;
5203
+ path?: string | undefined;
5204
+ stack?: string | undefined;
5205
+ };
5206
+ message: string;
5207
+ code: import("@trpc/server/rpc").TRPC_ERROR_CODE_NUMBER;
5208
+ };
5209
+ transformer: typeof superjson;
5210
+ }>;
5211
+ _meta: object;
5212
+ _ctx_out: {};
5213
+ _input_in: {
5214
+ address: string;
5215
+ encryptedKeystore: string;
5216
+ };
5217
+ _input_out: {
5218
+ address: string;
5219
+ encryptedKeystore: string;
5220
+ };
5221
+ _output_in: {
5222
+ userId: string;
5223
+ createdAt: Date;
5224
+ address: string;
5225
+ encryptedKeystore: string;
5226
+ };
5227
+ _output_out: {
5228
+ userId: string;
5229
+ createdAt: Date;
5230
+ address: string;
5231
+ encryptedKeystore: string;
5232
+ };
5233
+ }, unknown>>;
5234
+ };
5189
5235
  isTransactionDone: {
5190
5236
  query: import("@trpc/client").Resolver<import("@trpc/server").BuildProcedure<"query", {
5191
5237
  _config: import("@trpc/server").RootConfig<{
@@ -3,12 +3,12 @@ export interface EncryptedFile {
3
3
  md5: string;
4
4
  md5Encrypted: string;
5
5
  }
6
- export declare function secretstreamKeygen(): Uint8Array;
6
+ export declare function secretStreamKeygen(): Uint8Array;
7
7
  export declare const CHUNK_SIZE = 8192;
8
8
  export interface Progress {
9
9
  percent: number;
10
10
  total: number;
11
11
  current: number;
12
12
  }
13
- export declare function encryptSecretstream(key: Uint8Array, data: Uint8Array, progress?: (progress: Progress) => Promise<void>, abort?: AbortController): Promise<EncryptedFile>;
14
- export declare function decryptSecretstream(key: Uint8Array, data: Uint8Array, progress?: (progress: Progress) => Promise<void>, abort?: AbortController): Promise<Uint8Array>;
13
+ export declare function encryptSecretStream(key: Uint8Array, data: Uint8Array, progress?: (progress: Progress) => Promise<void>, abort?: AbortController): Promise<EncryptedFile>;
14
+ export declare function decryptSecretStream(key: Uint8Array, data: Uint8Array, progress?: (progress: Progress) => Promise<void>, abort?: AbortController): Promise<Uint8Array>;
@@ -1,5 +1,3 @@
1
- /// <reference lib="dom" />
2
- /// <reference lib="dom.iterable" />
3
1
  export * from './client/index.js';
4
2
  export * from './crypto/index.js';
5
3
  export type { Progress } from './crypto/file.js';
@@ -0,0 +1,2 @@
1
+ export declare const kiloToBytes: (kb: number) => number;
2
+ export declare const gigaToBytes: (gb: number) => number;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@secrecy/lib",
3
3
  "author": "Anonymize <anonymize@gmail.com>",
4
4
  "description": "Anonymize Secrecy Library",
5
- "version": "1.10.1",
5
+ "version": "1.11.1",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/anonymize-org/lib.git"
@@ -74,7 +74,7 @@
74
74
  },
75
75
  "dependencies": {
76
76
  "@secrecy/lib-utils": "^1.0.18",
77
- "@secrecy/trpc-api-types": "1.18.0-dev.8",
77
+ "@secrecy/trpc-api-types": "1.18.0-fix-crypto-wallet.1",
78
78
  "@trpc/client": "10.45.2",
79
79
  "@trpc/server": "10.45.2",
80
80
  "@types/libsodium-wrappers-sumo": "^0.7.8",
@@ -84,6 +84,7 @@
84
84
  "jsonwebtoken": "^9.0.2",
85
85
  "ky": "^1.2.3",
86
86
  "libsodium-wrappers-sumo": "^0.7.13",
87
+ "lru-cache": "^10.2.0",
87
88
  "spark-md5": "^3.0.2",
88
89
  "superjson": "2.2.1",
89
90
  "zod": "3.22.4"