@secrecy/lib 1.61.3 → 1.62.0-feat-storage-providers.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.
|
@@ -50,7 +50,7 @@ export class SecrecyCloudClient {
|
|
|
50
50
|
}
|
|
51
51
|
return internalNodeFullToNodeFull(node);
|
|
52
52
|
}
|
|
53
|
-
async uploadData({
|
|
53
|
+
async uploadData({ storage, data, encrypted = true, encryptProgress, uploadProgress, signal, meta, }) {
|
|
54
54
|
const dataBuffer = data instanceof File ? new Uint8Array(await data.arrayBuffer()) : data;
|
|
55
55
|
let filetype;
|
|
56
56
|
if (meta === true) {
|
|
@@ -62,7 +62,8 @@ export class SecrecyCloudClient {
|
|
|
62
62
|
else if (!encrypted) {
|
|
63
63
|
filetype = await fileTypeFromBuffer(dataBuffer);
|
|
64
64
|
}
|
|
65
|
-
if (
|
|
65
|
+
if (storage.protocol === 'mongo' &&
|
|
66
|
+
dataBuffer.byteLength > kiloToBytes(1024)) {
|
|
66
67
|
throw new Error('The data is too big for lite upload!');
|
|
67
68
|
}
|
|
68
69
|
const compressed = encrypted ? compress(dataBuffer) : dataBuffer;
|
|
@@ -81,11 +82,11 @@ export class SecrecyCloudClient {
|
|
|
81
82
|
current: 0,
|
|
82
83
|
percent: 0,
|
|
83
84
|
});
|
|
84
|
-
if (
|
|
85
|
+
if (storage.protocol === 'mongo') {
|
|
85
86
|
const uploadDataArgs = encryptedDataKey && md5Encrypted
|
|
86
87
|
? {
|
|
87
88
|
type: 'encrypted',
|
|
88
|
-
|
|
89
|
+
bytes: Buffer.from(encryptedData),
|
|
89
90
|
sizeEncrypted: BigInt(encryptedData.byteLength),
|
|
90
91
|
size: BigInt(dataBuffer.byteLength),
|
|
91
92
|
key: sodium.to_hex(encryptedDataKey),
|
|
@@ -95,13 +96,13 @@ export class SecrecyCloudClient {
|
|
|
95
96
|
}
|
|
96
97
|
: {
|
|
97
98
|
type: 'unencrypted',
|
|
98
|
-
|
|
99
|
+
bytes: Buffer.from(encryptedData),
|
|
99
100
|
md5: md5Data,
|
|
100
101
|
sizeEncrypted: undefined,
|
|
101
102
|
size: BigInt(dataBuffer.byteLength),
|
|
102
103
|
...filetype,
|
|
103
104
|
};
|
|
104
|
-
const uploadData = await this.#apiClient.cloud.
|
|
105
|
+
const uploadData = await this.#apiClient.cloud.uploadMongoData.mutate(uploadDataArgs, { signal });
|
|
105
106
|
await uploadProgress?.({
|
|
106
107
|
total: encryptedData.byteLength,
|
|
107
108
|
current: encryptedData.byteLength,
|
|
@@ -109,7 +110,7 @@ export class SecrecyCloudClient {
|
|
|
109
110
|
});
|
|
110
111
|
const localData = {
|
|
111
112
|
id: uploadData.id,
|
|
112
|
-
|
|
113
|
+
storage: storage,
|
|
113
114
|
size: uploadDataArgs.size,
|
|
114
115
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
115
116
|
data: dataBuffer,
|
|
@@ -118,7 +119,7 @@ export class SecrecyCloudClient {
|
|
|
118
119
|
dataContentCache.set(uploadData.id, localData);
|
|
119
120
|
return localData;
|
|
120
121
|
}
|
|
121
|
-
if (
|
|
122
|
+
if (storage.protocol === 's3') {
|
|
122
123
|
const uploadDataArgs = encryptedDataKey && md5Encrypted
|
|
123
124
|
? {
|
|
124
125
|
type: 'encrypted',
|
|
@@ -136,7 +137,7 @@ export class SecrecyCloudClient {
|
|
|
136
137
|
sizeEncrypted: undefined,
|
|
137
138
|
...filetype,
|
|
138
139
|
};
|
|
139
|
-
const uploadDataCaller =
|
|
140
|
+
const uploadDataCaller = storage.protocol === 's3'
|
|
140
141
|
? this.#apiClient.cloud.uploadData
|
|
141
142
|
: this.#apiClient.cloud.uploadColdData;
|
|
142
143
|
const uploadData = await uploadDataCaller.mutate(uploadDataArgs, {
|
|
@@ -153,7 +154,7 @@ export class SecrecyCloudClient {
|
|
|
153
154
|
});
|
|
154
155
|
const localData = {
|
|
155
156
|
id: uploadData.id,
|
|
156
|
-
|
|
157
|
+
storage: storage,
|
|
157
158
|
size: uploadDataArgs.size,
|
|
158
159
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
159
160
|
data: dataBuffer,
|
|
@@ -210,7 +211,7 @@ export class SecrecyCloudClient {
|
|
|
210
211
|
}));
|
|
211
212
|
const localData = {
|
|
212
213
|
id: uploadData.id,
|
|
213
|
-
|
|
214
|
+
storage: storage,
|
|
214
215
|
size: uploadDataArgs.size,
|
|
215
216
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
216
217
|
data: dataBuffer,
|
|
@@ -219,11 +220,11 @@ export class SecrecyCloudClient {
|
|
|
219
220
|
dataContentCache.set(uploadData.id, localData);
|
|
220
221
|
return localData;
|
|
221
222
|
}
|
|
222
|
-
throw new Error(`
|
|
223
|
+
throw new Error(`Not implemented yet!`);
|
|
223
224
|
}
|
|
224
|
-
async uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress,
|
|
225
|
+
async uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress, storage, signal, }) {
|
|
225
226
|
const uploadedData = await this.uploadData({
|
|
226
|
-
|
|
227
|
+
storage,
|
|
227
228
|
data,
|
|
228
229
|
encryptProgress,
|
|
229
230
|
uploadProgress,
|
|
@@ -397,13 +398,13 @@ export class SecrecyCloudClient {
|
|
|
397
398
|
id: data.id,
|
|
398
399
|
size: data.size,
|
|
399
400
|
sizeEncrypted: data.sizeEncrypted,
|
|
400
|
-
|
|
401
|
+
storage: data.storage,
|
|
401
402
|
})),
|
|
402
403
|
...cachedData.map((data) => ({
|
|
403
404
|
id: data.id,
|
|
404
405
|
size: data.size,
|
|
405
406
|
sizeEncrypted: data.sizeEncrypted,
|
|
406
|
-
|
|
407
|
+
storage: data.storage,
|
|
407
408
|
})),
|
|
408
409
|
];
|
|
409
410
|
const allDataContentsBytes = Number(allDataContents.reduce((curr, next) => curr + (next.sizeEncrypted ?? next.size), 0n));
|
|
@@ -573,13 +574,18 @@ export class SecrecyCloudClient {
|
|
|
573
574
|
: null,
|
|
574
575
|
});
|
|
575
576
|
}
|
|
576
|
-
async
|
|
577
|
+
async updateDataStorage(input) {
|
|
577
578
|
const data = dataContentCache.get(input.dataId);
|
|
578
579
|
if (data) {
|
|
579
|
-
if (data.
|
|
580
|
-
|
|
580
|
+
if (data.storage.protocol === input.protocol &&
|
|
581
|
+
data.storage.provider === input.provider &&
|
|
582
|
+
data.storage.mode === input.mode &&
|
|
583
|
+
data.storage.region === input.region) {
|
|
584
|
+
throw new Error(`The data is already on "${data.storage}`);
|
|
581
585
|
}
|
|
582
|
-
if (data.
|
|
586
|
+
if (data.storage.protocol === 's3' &&
|
|
587
|
+
data.storage.mode === 'glacier' &&
|
|
588
|
+
input.protocol === 'mongo') {
|
|
583
589
|
throw new Error("It's not possible to transfer a cold stored data to a lite storage!");
|
|
584
590
|
}
|
|
585
591
|
}
|
|
@@ -641,19 +647,25 @@ export class SecrecyCloudClient {
|
|
|
641
647
|
.sort((a, b) => a.order - b.order)
|
|
642
648
|
.map((p) => p.data));
|
|
643
649
|
};
|
|
644
|
-
const encryptedContent = dataContent.type === '
|
|
645
|
-
? new Uint8Array(dataContent.
|
|
646
|
-
: dataContent.type === '
|
|
650
|
+
const encryptedContent = dataContent.type === 'mongo'
|
|
651
|
+
? new Uint8Array(dataContent.bytes)
|
|
652
|
+
: dataContent.type === 's3'
|
|
647
653
|
? await encryptedContentFromParts({
|
|
648
654
|
dataId: dataContent.id,
|
|
649
|
-
dataParts: dataContent.parts,
|
|
655
|
+
dataParts: dataContent.parts.map(({ url, ...part }) => ({
|
|
656
|
+
...part,
|
|
657
|
+
contentUrl: url,
|
|
658
|
+
})),
|
|
650
659
|
})
|
|
651
|
-
: dataContent.
|
|
652
|
-
? new Uint8Array(dataContent.
|
|
660
|
+
: dataContent.maybeBytes !== null
|
|
661
|
+
? new Uint8Array(dataContent.maybeBytes)
|
|
653
662
|
: dataContent.maybeParts !== null
|
|
654
663
|
? await encryptedContentFromParts({
|
|
655
664
|
dataId: dataContent.id,
|
|
656
|
-
dataParts: dataContent.maybeParts,
|
|
665
|
+
dataParts: dataContent.maybeParts.map(({ url, ...part }) => ({
|
|
666
|
+
...part,
|
|
667
|
+
contentUrl: url,
|
|
668
|
+
})),
|
|
657
669
|
})
|
|
658
670
|
: null;
|
|
659
671
|
if (encryptedContent === null) {
|
|
@@ -666,7 +678,7 @@ export class SecrecyCloudClient {
|
|
|
666
678
|
const key = dataContent.key
|
|
667
679
|
? decryptCryptoBox(sodium.from_hex(dataContent.key), dataContent.type === 'received_mail'
|
|
668
680
|
? dataContent.senderPublicKey
|
|
669
|
-
: dataContent.type === '
|
|
681
|
+
: dataContent.type === 's3'
|
|
670
682
|
? dataContent.publicKey
|
|
671
683
|
: this.#keys.publicKey, this.#keys.privateKey)
|
|
672
684
|
: null;
|
|
@@ -678,11 +690,20 @@ export class SecrecyCloudClient {
|
|
|
678
690
|
throw new Error(`Content does not match`);
|
|
679
691
|
}
|
|
680
692
|
const decompressed = decompress(src);
|
|
693
|
+
const storageOptions = dataContent.storage.protocol === 'mongo'
|
|
694
|
+
? dataContent.storage.mongoStorageOptions
|
|
695
|
+
: dataContent.storage.s3StorageOptions;
|
|
696
|
+
const storage = {
|
|
697
|
+
protocol: dataContent.storage.protocol,
|
|
698
|
+
provider: dataContent.storage.provider,
|
|
699
|
+
mode: storageOptions.mode,
|
|
700
|
+
region: storageOptions.region,
|
|
701
|
+
};
|
|
681
702
|
dataContentCache.set(dataContent.id, {
|
|
682
703
|
id: dataContent.id,
|
|
683
704
|
size: dataContent.size,
|
|
684
705
|
sizeEncrypted: dataContent.sizeEncrypted,
|
|
685
|
-
|
|
706
|
+
storage: storage,
|
|
686
707
|
data: decompressed,
|
|
687
708
|
mime: dataContent.mime ?? undefined,
|
|
688
709
|
ext: dataContent.ext ?? undefined,
|
|
@@ -691,7 +712,7 @@ export class SecrecyCloudClient {
|
|
|
691
712
|
id: dataContent.id,
|
|
692
713
|
size: dataContent.size,
|
|
693
714
|
sizeEncrypted: dataContent.sizeEncrypted,
|
|
694
|
-
|
|
715
|
+
storage: storage,
|
|
695
716
|
data: decompressed,
|
|
696
717
|
mime: dataContent.mime ?? undefined,
|
|
697
718
|
ext: dataContent.ext ?? undefined,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProgressCallback, SecrecyClient } from '../index.js';
|
|
2
|
-
import type { DataMetadata,
|
|
2
|
+
import type { DataMetadata, DataStorageInput, KeyPair, LocalData, Node, NodeFull, NodeType, Rights } from './types/index.js';
|
|
3
3
|
import { type RouterInputs, type ApiClient, type RouterOutputs } from '../client.js';
|
|
4
4
|
import { type DownloadProgress } from '../types.js';
|
|
5
5
|
import { FileTypeResult } from 'file-type';
|
|
@@ -10,8 +10,8 @@ export declare class SecrecyCloudClient {
|
|
|
10
10
|
dataId: string;
|
|
11
11
|
nodeId: string;
|
|
12
12
|
}): Promise<NodeFull>;
|
|
13
|
-
uploadData({
|
|
14
|
-
|
|
13
|
+
uploadData({ storage, data, encrypted, encryptProgress, uploadProgress, signal, meta, }: {
|
|
14
|
+
storage: DataStorageInput;
|
|
15
15
|
data: globalThis.File | Uint8Array;
|
|
16
16
|
encrypted?: boolean;
|
|
17
17
|
encryptProgress?: ProgressCallback;
|
|
@@ -19,14 +19,14 @@ export declare class SecrecyCloudClient {
|
|
|
19
19
|
signal?: AbortSignal;
|
|
20
20
|
meta?: FileTypeResult | true;
|
|
21
21
|
}): Promise<LocalData>;
|
|
22
|
-
uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress,
|
|
22
|
+
uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress, storage, signal, }: {
|
|
23
23
|
data: globalThis.File | Uint8Array;
|
|
24
24
|
name: string;
|
|
25
25
|
nodeId?: string;
|
|
26
26
|
encryptProgress?: ProgressCallback;
|
|
27
27
|
uploadProgress?: ProgressCallback;
|
|
28
28
|
signal?: AbortSignal;
|
|
29
|
-
|
|
29
|
+
storage: DataStorageInput;
|
|
30
30
|
}): Promise<NodeFull>;
|
|
31
31
|
deletedNodes(): Promise<Node[]>;
|
|
32
32
|
sharedNodes(): Promise<Node[]>;
|
|
@@ -102,10 +102,14 @@ export declare class SecrecyCloudClient {
|
|
|
102
102
|
}): Promise<NodeFull>;
|
|
103
103
|
private readonly perNode;
|
|
104
104
|
reportData({ id, reasons, }: Omit<RouterInputs['cloud']['reportData'], 'encryptedDataKey'>): Promise<RouterOutputs['cloud']['reportData']>;
|
|
105
|
-
|
|
105
|
+
updateDataStorage(input: RouterInputs['cloud']['moveToStorageType']): Promise<{
|
|
106
106
|
isMoved: boolean;
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
fromProtocol?: "s3" | "mongo" | undefined;
|
|
108
|
+
fromMode?: "standard" | "glacier" | undefined;
|
|
109
|
+
fromRegion?: string | undefined;
|
|
110
|
+
toProtocol?: "s3" | "mongo" | undefined;
|
|
111
|
+
toMode?: "standard" | "glacier" | undefined;
|
|
112
|
+
toRegion?: string | undefined;
|
|
109
113
|
}>;
|
|
110
114
|
getPublicDataLink(input: RouterInputs['cloud']['dataLink']): Promise<{
|
|
111
115
|
name: string;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { type RouterOutputs } from '../../client.js';
|
|
2
2
|
export type ApiData = NonNullable<RouterOutputs['cloud']['dataById']>;
|
|
3
|
-
export type ApiExtendedData = NonNullable<RouterOutputs['cloud']['
|
|
4
|
-
export type
|
|
3
|
+
export type ApiExtendedData = NonNullable<RouterOutputs['cloud']['dataContentById']>;
|
|
4
|
+
export type DataStorageInput = {
|
|
5
|
+
protocol: 's3';
|
|
6
|
+
provider: 'scaleway' | 'ovh';
|
|
7
|
+
mode: 'standard' | 'glacier';
|
|
8
|
+
region: string;
|
|
9
|
+
} | {
|
|
10
|
+
protocol: 'mongo';
|
|
11
|
+
provider: 'secrecy';
|
|
12
|
+
mode: 'standard';
|
|
13
|
+
region: string;
|
|
14
|
+
};
|
|
15
|
+
export type DataStorage = ApiData['storage'];
|
|
16
|
+
export type DataStorageProtocol = ApiData['storage']['protocol'];
|
|
17
|
+
export type DataStorageProvider = ApiData['storage']['provider'];
|
|
5
18
|
export type LocalData = {
|
|
6
19
|
id: string;
|
|
7
|
-
|
|
20
|
+
storage: DataStorageInput;
|
|
8
21
|
size: bigint;
|
|
9
22
|
sizeEncrypted: bigint | null;
|
|
10
23
|
data: Uint8Array;
|