@protontech/drive-sdk 0.3.0 → 0.3.2
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/dist/crypto/driveCrypto.d.ts +1 -1
- package/dist/crypto/driveCrypto.js.map +1 -1
- package/dist/crypto/interface.d.ts +6 -1
- package/dist/crypto/openPGPCrypto.d.ts +1 -1
- package/dist/crypto/openPGPCrypto.js +4 -1
- package/dist/crypto/openPGPCrypto.js.map +1 -1
- package/dist/diagnostic/httpClient.d.ts +3 -3
- package/dist/interface/httpClient.d.ts +5 -5
- package/dist/interface/index.d.ts +15 -5
- package/dist/internal/apiService/apiService.js +1 -1
- package/dist/internal/apiService/apiService.js.map +1 -1
- package/dist/internal/apiService/errorCodes.d.ts +1 -0
- package/dist/internal/apiService/errorCodes.js.map +1 -1
- package/dist/internal/apiService/errors.d.ts +4 -3
- package/dist/internal/apiService/errors.js +7 -4
- package/dist/internal/apiService/errors.js.map +1 -1
- package/dist/internal/apiService/errors.test.js +2 -1
- package/dist/internal/apiService/errors.test.js.map +1 -1
- package/dist/internal/download/cryptoService.js +2 -2
- package/dist/internal/download/cryptoService.js.map +1 -1
- package/dist/internal/download/fileDownloader.js +2 -2
- package/dist/internal/download/fileDownloader.js.map +1 -1
- package/dist/internal/download/fileDownloader.test.js +3 -1
- package/dist/internal/download/fileDownloader.test.js.map +1 -1
- package/dist/internal/events/index.d.ts +1 -1
- package/dist/internal/nodes/cache.js +3 -1
- package/dist/internal/nodes/cache.js.map +1 -1
- package/dist/internal/nodes/cryptoCache.js +6 -7
- package/dist/internal/nodes/cryptoCache.js.map +1 -1
- package/dist/internal/nodes/cryptoCache.test.js +4 -7
- package/dist/internal/nodes/cryptoCache.test.js.map +1 -1
- package/dist/internal/nodes/cryptoReporter.d.ts +20 -0
- package/dist/internal/nodes/cryptoReporter.js +96 -0
- package/dist/internal/nodes/cryptoReporter.js.map +1 -0
- package/dist/internal/nodes/cryptoService.d.ts +17 -12
- package/dist/internal/nodes/cryptoService.js +17 -97
- package/dist/internal/nodes/cryptoService.js.map +1 -1
- package/dist/internal/nodes/cryptoService.test.js +3 -1
- package/dist/internal/nodes/cryptoService.test.js.map +1 -1
- package/dist/internal/nodes/index.js +3 -1
- package/dist/internal/nodes/index.js.map +1 -1
- package/dist/internal/nodes/interface.d.ts +1 -1
- package/dist/internal/nodes/nodesAccess.d.ts +2 -2
- package/dist/internal/nodes/nodesAccess.js +52 -54
- package/dist/internal/nodes/nodesAccess.js.map +1 -1
- package/dist/internal/shares/cryptoCache.d.ts +4 -3
- package/dist/internal/shares/cryptoCache.js +23 -6
- package/dist/internal/shares/cryptoCache.js.map +1 -1
- package/dist/internal/shares/cryptoCache.test.js +3 -2
- package/dist/internal/shares/cryptoCache.test.js.map +1 -1
- package/dist/internal/shares/index.js +1 -1
- package/dist/internal/shares/index.js.map +1 -1
- package/dist/internal/sharing/cache.d.ts +3 -0
- package/dist/internal/sharing/cache.js +17 -2
- package/dist/internal/sharing/cache.js.map +1 -1
- package/dist/internal/sharing/cryptoService.js +8 -6
- package/dist/internal/sharing/cryptoService.js.map +1 -1
- package/dist/internal/sharing/cryptoService.test.js +13 -0
- package/dist/internal/sharing/cryptoService.test.js.map +1 -1
- package/dist/internal/sharing/index.js +1 -1
- package/dist/internal/sharing/index.js.map +1 -1
- package/dist/internal/sharing/interface.d.ts +1 -1
- package/dist/internal/sharing/interface.js +1 -1
- package/dist/internal/sharing/sharingAccess.js +6 -0
- package/dist/internal/sharing/sharingAccess.js.map +1 -1
- package/dist/internal/sharing/sharingAccess.test.js +242 -33
- package/dist/internal/sharing/sharingAccess.test.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.d.ts +3 -1
- package/dist/internal/sharing/sharingManagement.js +10 -1
- package/dist/internal/sharing/sharingManagement.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.test.js +32 -1
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
- package/dist/internal/sharingPublic/apiService.d.ts +19 -0
- package/dist/internal/sharingPublic/apiService.js +141 -0
- package/dist/internal/sharingPublic/apiService.js.map +1 -0
- package/dist/internal/sharingPublic/cryptoCache.d.ts +19 -0
- package/dist/internal/sharingPublic/cryptoCache.js +72 -0
- package/dist/internal/sharingPublic/cryptoCache.js.map +1 -0
- package/dist/internal/sharingPublic/cryptoService.d.ts +9 -0
- package/dist/internal/sharingPublic/cryptoService.js +57 -0
- package/dist/internal/sharingPublic/cryptoService.js.map +1 -0
- package/dist/internal/sharingPublic/index.d.ts +15 -0
- package/dist/internal/sharingPublic/index.js +27 -0
- package/dist/internal/sharingPublic/index.js.map +1 -0
- package/dist/internal/sharingPublic/interface.d.ts +6 -0
- package/dist/internal/sharingPublic/interface.js +3 -0
- package/dist/internal/sharingPublic/interface.js.map +1 -0
- package/dist/internal/sharingPublic/manager.d.ts +19 -0
- package/dist/internal/sharingPublic/manager.js +81 -0
- package/dist/internal/sharingPublic/manager.js.map +1 -0
- package/dist/internal/sharingPublic/session/apiService.d.ts +28 -0
- package/dist/internal/sharingPublic/session/apiService.js +55 -0
- package/dist/internal/sharingPublic/session/apiService.js.map +1 -0
- package/dist/internal/sharingPublic/session/httpClient.d.ts +16 -0
- package/dist/internal/sharingPublic/session/httpClient.js +41 -0
- package/dist/internal/sharingPublic/session/httpClient.js.map +1 -0
- package/dist/internal/sharingPublic/session/index.d.ts +1 -0
- package/dist/internal/sharingPublic/session/index.js +6 -0
- package/dist/internal/sharingPublic/session/index.js.map +1 -0
- package/dist/internal/sharingPublic/session/interface.d.ts +18 -0
- package/dist/internal/sharingPublic/session/interface.js +3 -0
- package/dist/internal/sharingPublic/session/interface.js.map +1 -0
- package/dist/internal/sharingPublic/session/manager.d.ts +49 -0
- package/dist/internal/sharingPublic/session/manager.js +75 -0
- package/dist/internal/sharingPublic/session/manager.js.map +1 -0
- package/dist/internal/sharingPublic/session/session.d.ts +34 -0
- package/dist/internal/sharingPublic/session/session.js +67 -0
- package/dist/internal/sharingPublic/session/session.js.map +1 -0
- package/dist/internal/sharingPublic/session/url.d.ts +12 -0
- package/dist/internal/sharingPublic/session/url.js +23 -0
- package/dist/internal/sharingPublic/session/url.js.map +1 -0
- package/dist/internal/sharingPublic/session/url.test.d.ts +1 -0
- package/dist/internal/sharingPublic/session/url.test.js +59 -0
- package/dist/internal/sharingPublic/session/url.test.js.map +1 -0
- package/dist/internal/upload/streamUploader.js +1 -1
- package/dist/internal/upload/streamUploader.js.map +1 -1
- package/dist/internal/upload/streamUploader.test.js +3 -1
- package/dist/internal/upload/streamUploader.test.js.map +1 -1
- package/dist/protonDriveClient.d.ts +18 -3
- package/dist/protonDriveClient.js +31 -8
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePublicLinkClient.d.ts +57 -0
- package/dist/protonDrivePublicLinkClient.js +73 -0
- package/dist/protonDrivePublicLinkClient.js.map +1 -0
- package/package.json +1 -1
- package/src/crypto/driveCrypto.ts +1 -1
- package/src/crypto/interface.ts +12 -1
- package/src/crypto/openPGPCrypto.ts +5 -2
- package/src/diagnostic/httpClient.ts +4 -4
- package/src/interface/httpClient.ts +5 -5
- package/src/interface/index.ts +18 -6
- package/src/internal/apiService/apiService.ts +1 -1
- package/src/internal/apiService/errorCodes.ts +1 -0
- package/src/internal/apiService/errors.test.ts +2 -1
- package/src/internal/apiService/errors.ts +15 -4
- package/src/internal/download/cryptoService.ts +2 -2
- package/src/internal/download/fileDownloader.test.ts +3 -1
- package/src/internal/download/fileDownloader.ts +2 -2
- package/src/internal/events/index.ts +1 -1
- package/src/internal/nodes/cache.ts +3 -1
- package/src/internal/nodes/cryptoCache.test.ts +4 -7
- package/src/internal/nodes/cryptoCache.ts +6 -7
- package/src/internal/nodes/cryptoReporter.ts +145 -0
- package/src/internal/nodes/cryptoService.test.ts +3 -1
- package/src/internal/nodes/cryptoService.ts +44 -137
- package/src/internal/nodes/index.ts +3 -1
- package/src/internal/nodes/interface.ts +3 -1
- package/src/internal/nodes/nodesAccess.ts +59 -61
- package/src/internal/shares/cryptoCache.test.ts +3 -2
- package/src/internal/shares/cryptoCache.ts +26 -7
- package/src/internal/shares/index.ts +1 -1
- package/src/internal/sharing/cache.ts +19 -2
- package/src/internal/sharing/cryptoService.test.ts +22 -1
- package/src/internal/sharing/cryptoService.ts +8 -6
- package/src/internal/sharing/index.ts +1 -0
- package/src/internal/sharing/interface.ts +1 -1
- package/src/internal/sharing/sharingAccess.test.ts +282 -34
- package/src/internal/sharing/sharingAccess.ts +6 -0
- package/src/internal/sharing/sharingManagement.test.ts +33 -0
- package/src/internal/sharing/sharingManagement.ts +9 -0
- package/src/internal/sharingPublic/apiService.ts +173 -0
- package/src/internal/sharingPublic/cryptoCache.ts +79 -0
- package/src/internal/sharingPublic/cryptoService.ts +98 -0
- package/src/internal/sharingPublic/index.ts +41 -0
- package/src/internal/sharingPublic/interface.ts +14 -0
- package/src/internal/sharingPublic/manager.ts +86 -0
- package/src/internal/sharingPublic/session/apiService.ts +74 -0
- package/src/internal/sharingPublic/session/httpClient.ts +48 -0
- package/src/internal/sharingPublic/session/index.ts +1 -0
- package/src/internal/sharingPublic/session/interface.ts +20 -0
- package/src/internal/sharingPublic/session/manager.ts +97 -0
- package/src/internal/sharingPublic/session/session.ts +78 -0
- package/src/internal/sharingPublic/session/url.test.ts +72 -0
- package/src/internal/sharingPublic/session/url.ts +23 -0
- package/src/internal/upload/streamUploader.test.ts +3 -1
- package/src/internal/upload/streamUploader.ts +1 -1
- package/src/protonDriveClient.ts +48 -11
- package/src/protonDrivePublicLinkClient.ts +135 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProtonDrivePublicLinkClient = void 0;
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const crypto_1 = require("./crypto");
|
|
6
|
+
const telemetry_1 = require("./telemetry");
|
|
7
|
+
const transformers_1 = require("./transformers");
|
|
8
|
+
const apiService_1 = require("./internal/apiService");
|
|
9
|
+
const sdkEvents_1 = require("./internal/sdkEvents");
|
|
10
|
+
const sharingPublic_1 = require("./internal/sharingPublic");
|
|
11
|
+
/**
|
|
12
|
+
* ProtonDrivePublicLinkClient is the interface for the public link client.
|
|
13
|
+
*
|
|
14
|
+
* The client provides high-level operations for managing nodes, and
|
|
15
|
+
* downloading/uploading files.
|
|
16
|
+
*
|
|
17
|
+
* Do not use this client direclty, use ProtonDriveClient instead.
|
|
18
|
+
* The main client handles public link sessions and provides access to
|
|
19
|
+
* public links.
|
|
20
|
+
*
|
|
21
|
+
* See `experimental.getPublicLinkInfo` and `experimental.authPublicLink`
|
|
22
|
+
* for more information.
|
|
23
|
+
*/
|
|
24
|
+
class ProtonDrivePublicLinkClient {
|
|
25
|
+
logger;
|
|
26
|
+
sdkEvents;
|
|
27
|
+
sharingPublic;
|
|
28
|
+
experimental;
|
|
29
|
+
constructor({ httpClient, cryptoCache, account, openPGPCryptoModule, srpModule, config, telemetry, token, password, }) {
|
|
30
|
+
if (!telemetry) {
|
|
31
|
+
telemetry = new telemetry_1.Telemetry();
|
|
32
|
+
}
|
|
33
|
+
this.logger = telemetry.getLogger('interface');
|
|
34
|
+
const fullConfig = (0, config_1.getConfig)(config);
|
|
35
|
+
this.sdkEvents = new sdkEvents_1.SDKEvents(telemetry);
|
|
36
|
+
const apiService = new apiService_1.DriveAPIService(telemetry, this.sdkEvents, httpClient, fullConfig.baseUrl, fullConfig.language);
|
|
37
|
+
const driveCrypto = new crypto_1.DriveCrypto(openPGPCryptoModule, srpModule);
|
|
38
|
+
this.sharingPublic = (0, sharingPublic_1.initSharingPublicModule)(telemetry, apiService, cryptoCache, driveCrypto, account, token, password);
|
|
39
|
+
this.experimental = {
|
|
40
|
+
getNodeUrl: async (nodeUid) => {
|
|
41
|
+
this.logger.debug(`Getting node URL for ${(0, transformers_1.getUid)(nodeUid)}`);
|
|
42
|
+
// TODO: public node has different URL
|
|
43
|
+
return '';
|
|
44
|
+
},
|
|
45
|
+
getDocsKey: async (nodeUid) => {
|
|
46
|
+
this.logger.debug(`Getting docs keys for ${(0, transformers_1.getUid)(nodeUid)}`);
|
|
47
|
+
const keys = await this.sharingPublic.getNodeKeys((0, transformers_1.getUid)(nodeUid));
|
|
48
|
+
if (!keys.contentKeyPacketSessionKey) {
|
|
49
|
+
throw new Error('Node does not have a content key packet session key');
|
|
50
|
+
}
|
|
51
|
+
return keys.contentKeyPacketSessionKey;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @returns The root folder to the public link.
|
|
57
|
+
*/
|
|
58
|
+
async getRootNode() {
|
|
59
|
+
this.logger.info(`Getting root node`);
|
|
60
|
+
return (0, transformers_1.convertInternalNodePromise)(this.sharingPublic.getRootNode());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Iterates the children of the given parent node.
|
|
64
|
+
*
|
|
65
|
+
* See `ProtonDriveClient.iterateFolderChildren` for more information.
|
|
66
|
+
*/
|
|
67
|
+
async *iterateFolderChildren(parentUid, signal) {
|
|
68
|
+
this.logger.info(`Iterating children of ${(0, transformers_1.getUid)(parentUid)}`);
|
|
69
|
+
yield* (0, transformers_1.convertInternalNodeIterator)(this.sharingPublic.iterateFolderChildren((0, transformers_1.getUid)(parentUid), signal));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.ProtonDrivePublicLinkClient = ProtonDrivePublicLinkClient;
|
|
73
|
+
//# sourceMappingURL=protonDrivePublicLinkClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protonDrivePublicLinkClient.js","sourceRoot":"","sources":["../src/protonDrivePublicLinkClient.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACrC,qCAA6E;AAW7E,2CAAwC;AACxC,iDAAiG;AACjG,sDAAwD;AACxD,oDAAiD;AACjD,4DAAmE;AAEnE;;;;;;;;;;;;GAYG;AACH,MAAa,2BAA2B;IAC5B,MAAM,CAAS;IACf,SAAS,CAAY;IACrB,aAAa,CAA6C;IAE3D,YAAY,CAejB;IAEF,YAAY,EACR,UAAU,EACV,WAAW,EACX,OAAO,EACP,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,SAAS,EACT,KAAK,EACL,QAAQ,GAWX;QACG,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,SAAS,GAAG,IAAI,qBAAS,EAAE,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAE/C,MAAM,UAAU,GAAG,IAAA,kBAAS,EAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,IAAI,qBAAS,CAAC,SAAS,CAAC,CAAC;QAE1C,MAAM,UAAU,GAAG,IAAI,4BAAe,CAClC,SAAS,EACT,IAAI,CAAC,SAAS,EACd,UAAU,EACV,UAAU,CAAC,OAAO,EAClB,UAAU,CAAC,QAAQ,CACtB,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,oBAAW,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,aAAa,GAAG,IAAA,uCAAuB,EACxC,SAAS,EACT,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,KAAK,EACL,QAAQ,CACX,CAAC;QAEF,IAAI,CAAC,YAAY,GAAG;YAChB,UAAU,EAAE,KAAK,EAAE,OAAkB,EAAE,EAAE;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,IAAA,qBAAM,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC7D,sCAAsC;gBACtC,OAAO,EAAE,CAAC;YACd,CAAC;YACD,UAAU,EAAE,KAAK,EAAE,OAAkB,EAAE,EAAE;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,IAAA,qBAAM,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC9D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,IAAA,qBAAM,EAAC,OAAO,CAAC,CAAC,CAAC;gBACnE,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC;oBACnC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBAC3E,CAAC;gBACD,OAAO,IAAI,CAAC,0BAA0B,CAAC;YAC3C,CAAC;SACJ,CAAC;IACN,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACtC,OAAO,IAAA,yCAA0B,EAAC,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,CAAC,qBAAqB,CAAC,SAAoB,EAAE,MAAoB;QACnE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAA,qBAAM,EAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/D,KAAM,CAAC,CAAC,IAAA,0CAA2B,EAAC,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAA,qBAAM,EAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7G,CAAC;CACJ;AAvGD,kEAuGC"}
|
package/package.json
CHANGED
|
@@ -170,7 +170,7 @@ export class DriveCrypto {
|
|
|
170
170
|
async decryptKey(
|
|
171
171
|
armoredKey: string,
|
|
172
172
|
armoredPassphrase: string,
|
|
173
|
-
armoredPassphraseSignature: string,
|
|
173
|
+
armoredPassphraseSignature: string | undefined,
|
|
174
174
|
decryptionKeys: PrivateKey[],
|
|
175
175
|
verificationKeys: PublicKey[],
|
|
176
176
|
): Promise<{
|
package/src/crypto/interface.ts
CHANGED
|
@@ -52,6 +52,17 @@ export enum VERIFICATION_STATUS {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export interface SRPModule {
|
|
55
|
+
getSrp: (
|
|
56
|
+
version: number,
|
|
57
|
+
modulus: string,
|
|
58
|
+
serverEphemeral: string,
|
|
59
|
+
salt: string,
|
|
60
|
+
password: string,
|
|
61
|
+
) => Promise<{
|
|
62
|
+
expectedServerProof: string;
|
|
63
|
+
clientProof: string;
|
|
64
|
+
clientEphemeral: string;
|
|
65
|
+
}>;
|
|
55
66
|
getSrpVerifier: (password: string) => Promise<SRPVerifier>;
|
|
56
67
|
computeKeyPassword: (password: string, salt: string) => Promise<string>;
|
|
57
68
|
}
|
|
@@ -229,7 +240,7 @@ export interface OpenPGPCrypto {
|
|
|
229
240
|
|
|
230
241
|
decryptArmoredAndVerifyDetached: (
|
|
231
242
|
armoredData: string,
|
|
232
|
-
armoredSignature: string,
|
|
243
|
+
armoredSignature: string | undefined,
|
|
233
244
|
sessionKey: SessionKey,
|
|
234
245
|
verificationKeys: PublicKey | PublicKey[],
|
|
235
246
|
) => Promise<{
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { c } from 'ttag';
|
|
1
2
|
import { OpenPGPCrypto, PrivateKey, PublicKey, SessionKey, VERIFICATION_STATUS } from './interface';
|
|
2
3
|
import { uint8ArrayToBase64String } from './utils';
|
|
3
4
|
|
|
@@ -393,7 +394,7 @@ export class OpenPGPCryptoWithCryptoProxy implements OpenPGPCrypto {
|
|
|
393
394
|
|
|
394
395
|
async decryptArmoredAndVerifyDetached(
|
|
395
396
|
armoredData: string,
|
|
396
|
-
armoredSignature: string,
|
|
397
|
+
armoredSignature: string | undefined,
|
|
397
398
|
sessionKey: SessionKey,
|
|
398
399
|
verificationKeys: PublicKey | PublicKey[],
|
|
399
400
|
) {
|
|
@@ -410,7 +411,9 @@ export class OpenPGPCryptoWithCryptoProxy implements OpenPGPCrypto {
|
|
|
410
411
|
// pmcrypto 8.3.0 changes `verified` to `verificationStatus`.
|
|
411
412
|
// Proper typing is too complex, it will be removed to support only newer pmcrypto.
|
|
412
413
|
verified: verified || verificationStatus!,
|
|
413
|
-
verificationErrors
|
|
414
|
+
verificationErrors: !armoredSignature
|
|
415
|
+
? [new Error(c('Error').t`Signature is missing`)]
|
|
416
|
+
: verificationErrors,
|
|
414
417
|
};
|
|
415
418
|
}
|
|
416
419
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProtonDriveHTTPClient,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
ProtonDriveHTTPClientBlobRequest,
|
|
4
|
+
ProtonDriveHTTPClientJsonRequest,
|
|
5
5
|
} from '../interface';
|
|
6
6
|
import { EventsGenerator } from './eventsGenerator';
|
|
7
7
|
|
|
@@ -19,7 +19,7 @@ export class DiagnosticHTTPClient extends EventsGenerator implements ProtonDrive
|
|
|
19
19
|
this.httpClient = httpClient;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
async fetchJson(options:
|
|
22
|
+
async fetchJson(options: ProtonDriveHTTPClientJsonRequest): Promise<Response> {
|
|
23
23
|
try {
|
|
24
24
|
const response = await this.httpClient.fetchJson(options);
|
|
25
25
|
|
|
@@ -78,7 +78,7 @@ export class DiagnosticHTTPClient extends EventsGenerator implements ProtonDrive
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
fetchBlob(options:
|
|
81
|
+
fetchBlob(options: ProtonDriveHTTPClientBlobRequest): Promise<Response> {
|
|
82
82
|
return this.httpClient.fetchBlob(options);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export interface ProtonDriveHTTPClient {
|
|
2
|
-
fetchJson(
|
|
3
|
-
fetchBlob(
|
|
2
|
+
fetchJson(request: ProtonDriveHTTPClientJsonRequest): Promise<Response>;
|
|
3
|
+
fetchBlob(request: ProtonDriveHTTPClientBlobRequest): Promise<Response>;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type ProtonDriveHTTPClientJsonRequest = ProtonDriveHTTPClientBaseRequest & {
|
|
7
7
|
json?: object;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export type
|
|
10
|
+
export type ProtonDriveHTTPClientBlobRequest = ProtonDriveHTTPClientBaseRequest & {
|
|
11
11
|
body?: XMLHttpRequestBodyInit;
|
|
12
12
|
onProgress?: (progress: number) => void;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
type
|
|
15
|
+
type ProtonDriveHTTPClientBaseRequest = {
|
|
16
16
|
url: string;
|
|
17
17
|
method: string;
|
|
18
18
|
headers: Headers;
|
package/src/interface/index.ts
CHANGED
|
@@ -27,8 +27,8 @@ export type {
|
|
|
27
27
|
export { DriveEventType, SDKEvent } from './events';
|
|
28
28
|
export type {
|
|
29
29
|
ProtonDriveHTTPClient,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
ProtonDriveHTTPClientJsonRequest,
|
|
31
|
+
ProtonDriveHTTPClientBlobRequest,
|
|
32
32
|
} from './httpClient';
|
|
33
33
|
export type {
|
|
34
34
|
MaybeNode,
|
|
@@ -89,10 +89,22 @@ export type ProtonDriveTelemetry = Telemetry<MetricEvent>;
|
|
|
89
89
|
export type ProtonDriveEntitiesCache = ProtonDriveCache<string>;
|
|
90
90
|
export type ProtonDriveCryptoCache = ProtonDriveCache<CachedCryptoMaterial>;
|
|
91
91
|
export type CachedCryptoMaterial = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
nodeKeys?: {
|
|
93
|
+
// Passphrase should not be needed to keep, sessionKey should be enough.
|
|
94
|
+
// We will improve this in the future.
|
|
95
|
+
passphrase: string;
|
|
96
|
+
key: PrivateKey;
|
|
97
|
+
passphraseSessionKey: SessionKey;
|
|
98
|
+
contentKeyPacketSessionKey?: SessionKey;
|
|
99
|
+
hashKey?: Uint8Array;
|
|
100
|
+
};
|
|
101
|
+
shareKey?: {
|
|
102
|
+
key: PrivateKey;
|
|
103
|
+
passphraseSessionKey: SessionKey;
|
|
104
|
+
};
|
|
105
|
+
publicShareKey?: {
|
|
106
|
+
key: PrivateKey;
|
|
107
|
+
};
|
|
96
108
|
};
|
|
97
109
|
|
|
98
110
|
export interface ProtonDriveClientContructorParameters {
|
|
@@ -62,7 +62,8 @@ describe('apiErrorFactory should return', () => {
|
|
|
62
62
|
it('NotFoundAPIError when code is ErrorCode.NOT_EXISTS', () => {
|
|
63
63
|
const error = apiErrorFactory(mockAPIResponseAndResult({ code: ErrorCode.NOT_EXISTS, message: 'Not found' }));
|
|
64
64
|
expect(error).toBeInstanceOf(errors.NotFoundAPIError);
|
|
65
|
-
|
|
65
|
+
expect(error.message).toBe('Not found');
|
|
66
|
+
expect((error as errors.NotFoundAPIError).code).toBe(ErrorCode.NOT_EXISTS);
|
|
66
67
|
});
|
|
67
68
|
});
|
|
68
69
|
|
|
@@ -3,12 +3,23 @@ import { c } from 'ttag';
|
|
|
3
3
|
import { ServerError, ValidationError } from '../../errors';
|
|
4
4
|
import { ErrorCode, HTTPErrorCode } from './errorCodes';
|
|
5
5
|
|
|
6
|
-
export function apiErrorFactory({
|
|
6
|
+
export function apiErrorFactory({
|
|
7
|
+
response,
|
|
8
|
+
result,
|
|
9
|
+
error,
|
|
10
|
+
}: {
|
|
11
|
+
response: Response;
|
|
12
|
+
result?: unknown;
|
|
13
|
+
error?: unknown;
|
|
14
|
+
}): ServerError {
|
|
7
15
|
// Backend responses with 404 both in the response and body code.
|
|
8
16
|
// In such a case we want to stick to APIHTTPError to be very clear
|
|
9
17
|
// it is not NotFoundAPIError.
|
|
10
18
|
if (response.status === HTTPErrorCode.NOT_FOUND || !result) {
|
|
11
|
-
|
|
19
|
+
const fallbackMessage = error instanceof Error ? error.message : c('Error').t`Unknown error`;
|
|
20
|
+
const apiHttpError = new APIHTTPError(response.statusText || fallbackMessage, response.status);
|
|
21
|
+
apiHttpError.cause = error;
|
|
22
|
+
return apiHttpError;
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
const typedResult = result as {
|
|
@@ -40,7 +51,7 @@ export function apiErrorFactory({ response, result }: { response: Response; resu
|
|
|
40
51
|
|
|
41
52
|
switch (code) {
|
|
42
53
|
case ErrorCode.NOT_EXISTS:
|
|
43
|
-
return new NotFoundAPIError(message, code);
|
|
54
|
+
return new NotFoundAPIError(message, code, details);
|
|
44
55
|
// ValidationError should be only when it is clearly user input error,
|
|
45
56
|
// otherwise it should be ServerError.
|
|
46
57
|
// Here we convert only general enough codes. Specific cases that are
|
|
@@ -94,6 +105,6 @@ export class APICodeError extends ServerError {
|
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
|
|
97
|
-
export class NotFoundAPIError extends
|
|
108
|
+
export class NotFoundAPIError extends ValidationError {
|
|
98
109
|
name = 'NotFoundAPIError';
|
|
99
110
|
}
|
|
@@ -49,7 +49,7 @@ export class DownloadCryptoService {
|
|
|
49
49
|
);
|
|
50
50
|
} catch (error: unknown) {
|
|
51
51
|
const message = getErrorMessage(error);
|
|
52
|
-
throw new DecryptionError(c('Error').t`Failed to decrypt block: ${message}
|
|
52
|
+
throw new DecryptionError(c('Error').t`Failed to decrypt block: ${message}`, { cause: error });
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
return decryptedBlock;
|
|
@@ -66,7 +66,7 @@ export class DownloadCryptoService {
|
|
|
66
66
|
decryptedBlock = result.decryptedThumbnail;
|
|
67
67
|
} catch (error: unknown) {
|
|
68
68
|
const message = getErrorMessage(error);
|
|
69
|
-
throw new DecryptionError(c('Error').t`Failed to decrypt thumbnail: ${message}
|
|
69
|
+
throw new DecryptionError(c('Error').t`Failed to decrypt thumbnail: ${message}`, { cause: error });
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
return decryptedBlock;
|
|
@@ -123,8 +123,10 @@ describe('FileDownloader', () => {
|
|
|
123
123
|
|
|
124
124
|
const verifyOnProgress = async (downloadedBytes: number[]) => {
|
|
125
125
|
expect(onProgress).toHaveBeenCalledTimes(downloadedBytes.length);
|
|
126
|
+
let fileProgress = 0;
|
|
126
127
|
for (let i = 0; i < downloadedBytes.length; i++) {
|
|
127
|
-
|
|
128
|
+
fileProgress += downloadedBytes[i];
|
|
129
|
+
expect(onProgress).toHaveBeenNthCalledWith(i + 1, fileProgress);
|
|
128
130
|
}
|
|
129
131
|
};
|
|
130
132
|
|
|
@@ -134,7 +134,7 @@ export class FileDownloader {
|
|
|
134
134
|
const blockData = await this.downloadBlockData(blockMetadata, true, cryptoKeys);
|
|
135
135
|
return blockData.slice(blockOffset);
|
|
136
136
|
} catch (error: unknown) {
|
|
137
|
-
return error instanceof Error ? error : new Error(`Unknown error: ${error}
|
|
137
|
+
return error instanceof Error ? error : new Error(`Unknown error: ${error}`, { cause: error });
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -193,7 +193,7 @@ export class FileDownloader {
|
|
|
193
193
|
cryptoKeys,
|
|
194
194
|
(downloadedBytes) => {
|
|
195
195
|
fileProgress += downloadedBytes;
|
|
196
|
-
onProgress?.(
|
|
196
|
+
onProgress?.(fileProgress);
|
|
197
197
|
},
|
|
198
198
|
);
|
|
199
199
|
this.ongoingDownloads.set(blockMetadata.index, { downloadPromise });
|
|
@@ -7,7 +7,7 @@ import { VolumeEventManager } from './volumeEventManager';
|
|
|
7
7
|
import { EventManager } from './eventManager';
|
|
8
8
|
import { SharesManager } from '../shares/manager';
|
|
9
9
|
|
|
10
|
-
export type { DriveEvent, DriveListener } from './interface';
|
|
10
|
+
export type { DriveEvent, DriveListener, EventSubscription } from './interface';
|
|
11
11
|
export { DriveEventType } from './interface';
|
|
12
12
|
|
|
13
13
|
const OWN_VOLUME_POLLING_INTERVAL = 30;
|
|
@@ -53,7 +53,9 @@ export class NodesCache {
|
|
|
53
53
|
return deserialiseNode(nodeData);
|
|
54
54
|
} catch (error: unknown) {
|
|
55
55
|
await this.removeCorruptedNode({ nodeUid }, error);
|
|
56
|
-
throw new Error(`Failed to deserialise node: ${error instanceof Error ? error.message : error}
|
|
56
|
+
throw new Error(`Failed to deserialise node: ${error instanceof Error ? error.message : error}`, {
|
|
57
|
+
cause: error,
|
|
58
|
+
});
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -18,10 +18,7 @@ describe('nodesCryptoCache', () => {
|
|
|
18
18
|
|
|
19
19
|
beforeEach(async () => {
|
|
20
20
|
memoryCache = new MemoryCache();
|
|
21
|
-
await memoryCache.setEntity('nodeKeys-
|
|
22
|
-
key: 'privateKey',
|
|
23
|
-
sessionKey: 'sessionKey',
|
|
24
|
-
} as any);
|
|
21
|
+
await memoryCache.setEntity('nodeKeys-missingProperties', {} as any);
|
|
25
22
|
|
|
26
23
|
cache = new NodesCryptoCache(getMockLogger(), memoryCache);
|
|
27
24
|
});
|
|
@@ -96,14 +93,14 @@ describe('nodesCryptoCache', () => {
|
|
|
96
93
|
|
|
97
94
|
it('should throw an error when retrieving a bad keys and remove the key', async () => {
|
|
98
95
|
try {
|
|
99
|
-
await cache.getNodeKeys('
|
|
96
|
+
await cache.getNodeKeys('missingProperties');
|
|
100
97
|
throw new Error('Should have thrown an error');
|
|
101
98
|
} catch (error) {
|
|
102
|
-
expect(`${error}`).toBe('Error: Failed to deserialize node keys
|
|
99
|
+
expect(`${error}`).toBe('Error: Failed to deserialize node keys');
|
|
103
100
|
}
|
|
104
101
|
|
|
105
102
|
try {
|
|
106
|
-
await memoryCache.getEntity('nodeKeys-
|
|
103
|
+
await memoryCache.getEntity('nodeKeys-missingProperties');
|
|
107
104
|
throw new Error('Should have thrown an error');
|
|
108
105
|
} catch (error) {
|
|
109
106
|
expect(`${error}`).toBe('Error: Entity not found');
|
|
@@ -18,12 +18,14 @@ export class NodesCryptoCache {
|
|
|
18
18
|
|
|
19
19
|
async setNodeKeys(nodeUid: string, keys: DecryptedNodeKeys): Promise<void> {
|
|
20
20
|
const cacheUid = getCacheKey(nodeUid);
|
|
21
|
-
await this.driveCache.setEntity(cacheUid,
|
|
21
|
+
await this.driveCache.setEntity(cacheUid, {
|
|
22
|
+
nodeKeys: keys,
|
|
23
|
+
});
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
async getNodeKeys(nodeUid: string): Promise<DecryptedNodeKeys> {
|
|
25
27
|
const nodeKeysData = await this.driveCache.getEntity(getCacheKey(nodeUid));
|
|
26
|
-
if (!nodeKeysData.
|
|
28
|
+
if (!nodeKeysData.nodeKeys) {
|
|
27
29
|
try {
|
|
28
30
|
await this.removeNodeKeys([nodeUid]);
|
|
29
31
|
} catch (removingError: unknown) {
|
|
@@ -33,12 +35,9 @@ export class NodesCryptoCache {
|
|
|
33
35
|
`Failed to remove corrupted node keys from the cache: ${removingError instanceof Error ? removingError.message : removingError}`,
|
|
34
36
|
);
|
|
35
37
|
}
|
|
36
|
-
throw new Error(`Failed to deserialize node keys
|
|
38
|
+
throw new Error(`Failed to deserialize node keys`);
|
|
37
39
|
}
|
|
38
|
-
return
|
|
39
|
-
...nodeKeysData,
|
|
40
|
-
passphrase: nodeKeysData.passphrase,
|
|
41
|
-
};
|
|
40
|
+
return nodeKeysData.nodeKeys;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
async removeNodeKeys(nodeUids: string[]): Promise<void> {
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { VERIFICATION_STATUS } from '../../crypto';
|
|
2
|
+
import {
|
|
3
|
+
resultOk,
|
|
4
|
+
resultError,
|
|
5
|
+
Author,
|
|
6
|
+
AnonymousUser,
|
|
7
|
+
ProtonDriveTelemetry,
|
|
8
|
+
Logger,
|
|
9
|
+
MetricsDecryptionErrorField,
|
|
10
|
+
MetricVerificationErrorField,
|
|
11
|
+
} from '../../interface';
|
|
12
|
+
import { getVerificationMessage } from '../errors';
|
|
13
|
+
import { splitNodeUid } from '../uids';
|
|
14
|
+
import {
|
|
15
|
+
EncryptedNode,
|
|
16
|
+
SharesService,
|
|
17
|
+
} from './interface';
|
|
18
|
+
|
|
19
|
+
export class NodesCryptoReporter {
|
|
20
|
+
private logger: Logger;
|
|
21
|
+
|
|
22
|
+
private reportedDecryptionErrors = new Set<string>();
|
|
23
|
+
private reportedVerificationErrors = new Set<string>();
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
private telemetry: ProtonDriveTelemetry,
|
|
27
|
+
private shareService: SharesService,
|
|
28
|
+
) {
|
|
29
|
+
this.telemetry = telemetry;
|
|
30
|
+
this.logger = telemetry.getLogger('nodes-crypto');
|
|
31
|
+
this.shareService = shareService;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async handleClaimedAuthor(
|
|
35
|
+
node: { uid: string; creationTime: Date },
|
|
36
|
+
field: MetricVerificationErrorField,
|
|
37
|
+
signatureType: string,
|
|
38
|
+
verified: VERIFICATION_STATUS,
|
|
39
|
+
verificationErrors?: Error[],
|
|
40
|
+
claimedAuthor?: string,
|
|
41
|
+
notAvailableVerificationKeys = false,
|
|
42
|
+
): Promise<Author> {
|
|
43
|
+
const author = handleClaimedAuthor(
|
|
44
|
+
signatureType,
|
|
45
|
+
verified,
|
|
46
|
+
verificationErrors,
|
|
47
|
+
claimedAuthor,
|
|
48
|
+
notAvailableVerificationKeys,
|
|
49
|
+
);
|
|
50
|
+
if (!author.ok) {
|
|
51
|
+
void this.reportVerificationError(node, field, verificationErrors, claimedAuthor);
|
|
52
|
+
}
|
|
53
|
+
return author;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async reportVerificationError(
|
|
57
|
+
node: { uid: string; creationTime: Date },
|
|
58
|
+
field: MetricVerificationErrorField,
|
|
59
|
+
verificationErrors?: Error[],
|
|
60
|
+
claimedAuthor?: string,
|
|
61
|
+
) {
|
|
62
|
+
if (this.reportedVerificationErrors.has(node.uid)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.reportedVerificationErrors.add(node.uid);
|
|
66
|
+
|
|
67
|
+
const fromBefore2024 = node.creationTime < new Date('2024-01-01');
|
|
68
|
+
|
|
69
|
+
let addressMatchingDefaultShare, volumeType;
|
|
70
|
+
try {
|
|
71
|
+
const { volumeId } = splitNodeUid(node.uid);
|
|
72
|
+
const { email } = await this.shareService.getMyFilesShareMemberEmailKey();
|
|
73
|
+
addressMatchingDefaultShare = claimedAuthor ? claimedAuthor === email : undefined;
|
|
74
|
+
volumeType = await this.shareService.getVolumeMetricContext(volumeId);
|
|
75
|
+
} catch (error: unknown) {
|
|
76
|
+
this.logger.error('Failed to check if claimed author matches default share', error);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.logger.warn(
|
|
80
|
+
`Failed to verify ${field} for node ${node.uid} (from before 2024: ${fromBefore2024}, matching address: ${addressMatchingDefaultShare})`,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
this.telemetry.recordMetric({
|
|
84
|
+
eventName: 'verificationError',
|
|
85
|
+
volumeType,
|
|
86
|
+
field,
|
|
87
|
+
addressMatchingDefaultShare,
|
|
88
|
+
fromBefore2024,
|
|
89
|
+
error: verificationErrors?.map((e) => e.message).join(', '),
|
|
90
|
+
uid: node.uid,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async reportDecryptionError(node: EncryptedNode, field: MetricsDecryptionErrorField, error: unknown) {
|
|
95
|
+
if (this.reportedDecryptionErrors.has(node.uid)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fromBefore2024 = node.creationTime < new Date('2024-01-01');
|
|
100
|
+
|
|
101
|
+
let volumeType;
|
|
102
|
+
try {
|
|
103
|
+
const { volumeId } = splitNodeUid(node.uid);
|
|
104
|
+
volumeType = await this.shareService.getVolumeMetricContext(volumeId);
|
|
105
|
+
} catch (error: unknown) {
|
|
106
|
+
this.logger.error('Failed to get metric context', error);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.logger.error(`Failed to decrypt node ${node.uid} (from before 2024: ${fromBefore2024})`, error);
|
|
110
|
+
|
|
111
|
+
this.telemetry.recordMetric({
|
|
112
|
+
eventName: 'decryptionError',
|
|
113
|
+
volumeType,
|
|
114
|
+
field,
|
|
115
|
+
fromBefore2024,
|
|
116
|
+
error,
|
|
117
|
+
uid: node.uid,
|
|
118
|
+
});
|
|
119
|
+
this.reportedDecryptionErrors.add(node.uid);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param signatureType - Must be translated before calling this function.
|
|
125
|
+
*/
|
|
126
|
+
function handleClaimedAuthor(
|
|
127
|
+
signatureType: string,
|
|
128
|
+
verified: VERIFICATION_STATUS,
|
|
129
|
+
verificationErrors?: Error[],
|
|
130
|
+
claimedAuthor?: string,
|
|
131
|
+
notAvailableVerificationKeys = false,
|
|
132
|
+
): Author {
|
|
133
|
+
if (!claimedAuthor && notAvailableVerificationKeys) {
|
|
134
|
+
return resultOk(null as AnonymousUser);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (verified === VERIFICATION_STATUS.SIGNED_AND_VALID) {
|
|
138
|
+
return resultOk(claimedAuthor || (null as AnonymousUser));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return resultError({
|
|
142
|
+
claimedAuthor,
|
|
143
|
+
error: getVerificationMessage(verified, verificationErrors, signatureType, notAvailableVerificationKeys),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -3,6 +3,7 @@ import { MemberRole, ProtonDriveAccount, ProtonDriveTelemetry, RevisionState } f
|
|
|
3
3
|
import { getMockTelemetry } from '../../tests/telemetry';
|
|
4
4
|
import { DecryptedNode, DecryptedNodeKeys, DecryptedUnparsedNode, EncryptedNode, SharesService } from './interface';
|
|
5
5
|
import { NodesCryptoService } from './cryptoService';
|
|
6
|
+
import { NodesCryptoReporter } from './cryptoReporter';
|
|
6
7
|
|
|
7
8
|
describe('nodesCryptoService', () => {
|
|
8
9
|
let telemetry: ProtonDriveTelemetry;
|
|
@@ -74,7 +75,8 @@ describe('nodesCryptoService', () => {
|
|
|
74
75
|
getVolumeMetricContext: jest.fn().mockResolvedValue('own_volume'),
|
|
75
76
|
};
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
const nodesCryptoReporter = new NodesCryptoReporter(telemetry, sharesService);
|
|
79
|
+
cryptoService = new NodesCryptoService(telemetry, driveCrypto, account, nodesCryptoReporter);
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
const parentKey = 'parentKey' as unknown as PrivateKey;
|