@protontech/drive-sdk 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/diagnostic/{sdkDiagnosticFull.d.ts → diagnostic.d.ts} +5 -4
  2. package/dist/diagnostic/{sdkDiagnosticFull.js → diagnostic.js} +13 -10
  3. package/dist/diagnostic/diagnostic.js.map +1 -0
  4. package/dist/diagnostic/index.js +2 -4
  5. package/dist/diagnostic/index.js.map +1 -1
  6. package/dist/diagnostic/interface.d.ts +22 -1
  7. package/dist/diagnostic/sdkDiagnostic.d.ts +3 -2
  8. package/dist/diagnostic/sdkDiagnostic.js +79 -7
  9. package/dist/diagnostic/sdkDiagnostic.js.map +1 -1
  10. package/dist/interface/index.d.ts +1 -1
  11. package/dist/interface/index.js.map +1 -1
  12. package/dist/interface/nodes.d.ts +9 -0
  13. package/dist/interface/telemetry.d.ts +4 -1
  14. package/dist/interface/telemetry.js.map +1 -1
  15. package/dist/internal/apiService/driveTypes.d.ts +2571 -2356
  16. package/dist/internal/download/controller.d.ts +2 -0
  17. package/dist/internal/download/controller.js +15 -1
  18. package/dist/internal/download/controller.js.map +1 -1
  19. package/dist/internal/download/fileDownloader.js +6 -1
  20. package/dist/internal/download/fileDownloader.js.map +1 -1
  21. package/dist/internal/nodes/apiService.js +27 -12
  22. package/dist/internal/nodes/apiService.js.map +1 -1
  23. package/dist/internal/nodes/apiService.test.js +60 -2
  24. package/dist/internal/nodes/apiService.test.js.map +1 -1
  25. package/dist/internal/nodes/debouncer.d.ts +3 -2
  26. package/dist/internal/nodes/debouncer.js +16 -4
  27. package/dist/internal/nodes/debouncer.js.map +1 -1
  28. package/dist/internal/nodes/debouncer.test.js +20 -12
  29. package/dist/internal/nodes/debouncer.test.js.map +1 -1
  30. package/dist/internal/nodes/extendedAttributes.js +2 -2
  31. package/dist/internal/nodes/extendedAttributes.js.map +1 -1
  32. package/dist/internal/nodes/index.js +1 -1
  33. package/dist/internal/nodes/index.js.map +1 -1
  34. package/dist/internal/nodes/nodesAccess.d.ts +5 -4
  35. package/dist/internal/nodes/nodesAccess.js +6 -5
  36. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  37. package/dist/internal/nodes/nodesAccess.test.js +17 -5
  38. package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
  39. package/dist/internal/nodes/nodesManagement.d.ts +2 -2
  40. package/dist/internal/nodes/nodesManagement.js +5 -3
  41. package/dist/internal/nodes/nodesManagement.js.map +1 -1
  42. package/dist/internal/nodes/nodesManagement.test.js +3 -1
  43. package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
  44. package/dist/internal/photos/apiService.js +9 -20
  45. package/dist/internal/photos/apiService.js.map +1 -1
  46. package/dist/internal/photos/upload.js +7 -1
  47. package/dist/internal/photos/upload.js.map +1 -1
  48. package/dist/internal/sharing/apiService.d.ts +1 -1
  49. package/dist/internal/sharing/apiService.js +2 -2
  50. package/dist/internal/sharing/apiService.js.map +1 -1
  51. package/dist/internal/sharing/sharingManagement.d.ts +4 -1
  52. package/dist/internal/sharing/sharingManagement.js +7 -4
  53. package/dist/internal/sharing/sharingManagement.js.map +1 -1
  54. package/dist/internal/sharingPublic/apiService.d.ts +8 -10
  55. package/dist/internal/sharingPublic/apiService.js +9 -63
  56. package/dist/internal/sharingPublic/apiService.js.map +1 -1
  57. package/dist/internal/sharingPublic/index.d.ts +3 -3
  58. package/dist/internal/sharingPublic/index.js +5 -11
  59. package/dist/internal/sharingPublic/index.js.map +1 -1
  60. package/dist/internal/sharingPublic/nodes.d.ts +13 -8
  61. package/dist/internal/sharingPublic/nodes.js +20 -2
  62. package/dist/internal/sharingPublic/nodes.js.map +1 -1
  63. package/dist/internal/sharingPublic/session/apiService.d.ts +7 -5
  64. package/dist/internal/sharingPublic/session/apiService.js +25 -4
  65. package/dist/internal/sharingPublic/session/apiService.js.map +1 -1
  66. package/dist/internal/sharingPublic/session/interface.d.ts +17 -0
  67. package/dist/internal/sharingPublic/session/manager.d.ts +12 -4
  68. package/dist/internal/sharingPublic/session/manager.js +14 -4
  69. package/dist/internal/sharingPublic/session/manager.js.map +1 -1
  70. package/dist/internal/sharingPublic/session/session.d.ts +5 -2
  71. package/dist/internal/sharingPublic/session/session.js +7 -3
  72. package/dist/internal/sharingPublic/session/session.js.map +1 -1
  73. package/dist/internal/sharingPublic/shares.d.ts +3 -10
  74. package/dist/internal/sharingPublic/shares.js +10 -33
  75. package/dist/internal/sharingPublic/shares.js.map +1 -1
  76. package/dist/internal/upload/controller.d.ts +3 -1
  77. package/dist/internal/upload/controller.js +16 -2
  78. package/dist/internal/upload/controller.js.map +1 -1
  79. package/dist/internal/upload/fileUploader.js +2 -2
  80. package/dist/internal/upload/fileUploader.js.map +1 -1
  81. package/dist/internal/upload/streamUploader.d.ts +4 -3
  82. package/dist/internal/upload/streamUploader.js +61 -18
  83. package/dist/internal/upload/streamUploader.js.map +1 -1
  84. package/dist/internal/upload/streamUploader.test.js +38 -12
  85. package/dist/internal/upload/streamUploader.test.js.map +1 -1
  86. package/dist/protonDriveClient.d.ts +8 -3
  87. package/dist/protonDriveClient.js +7 -6
  88. package/dist/protonDriveClient.js.map +1 -1
  89. package/dist/protonDrivePublicLinkClient.d.ts +4 -3
  90. package/dist/protonDrivePublicLinkClient.js +2 -2
  91. package/dist/protonDrivePublicLinkClient.js.map +1 -1
  92. package/dist/tests/telemetry.d.ts +4 -2
  93. package/dist/tests/telemetry.js +3 -1
  94. package/dist/tests/telemetry.js.map +1 -1
  95. package/dist/transformers.d.ts +3 -2
  96. package/dist/transformers.js +6 -0
  97. package/dist/transformers.js.map +1 -1
  98. package/package.json +1 -1
  99. package/src/diagnostic/{sdkDiagnosticFull.ts → diagnostic.ts} +10 -6
  100. package/src/diagnostic/index.ts +3 -5
  101. package/src/diagnostic/interface.ts +39 -0
  102. package/src/diagnostic/sdkDiagnostic.ts +110 -9
  103. package/src/interface/index.ts +1 -0
  104. package/src/interface/nodes.ts +3 -0
  105. package/src/interface/telemetry.ts +5 -0
  106. package/src/internal/apiService/driveTypes.ts +2698 -2529
  107. package/src/internal/download/controller.ts +13 -1
  108. package/src/internal/download/fileDownloader.ts +8 -1
  109. package/src/internal/nodes/apiService.test.ts +64 -0
  110. package/src/internal/nodes/apiService.ts +38 -17
  111. package/src/internal/nodes/debouncer.test.ts +25 -13
  112. package/src/internal/nodes/debouncer.ts +20 -4
  113. package/src/internal/nodes/extendedAttributes.ts +2 -2
  114. package/src/internal/nodes/index.ts +1 -8
  115. package/src/internal/nodes/nodesAccess.test.ts +17 -5
  116. package/src/internal/nodes/nodesAccess.ts +15 -5
  117. package/src/internal/nodes/nodesManagement.test.ts +3 -1
  118. package/src/internal/nodes/nodesManagement.ts +11 -5
  119. package/src/internal/photos/apiService.ts +12 -29
  120. package/src/internal/photos/upload.ts +19 -1
  121. package/src/internal/sharing/apiService.ts +2 -2
  122. package/src/internal/sharing/sharingManagement.ts +7 -4
  123. package/src/internal/sharingPublic/apiService.ts +23 -77
  124. package/src/internal/sharingPublic/index.ts +11 -10
  125. package/src/internal/sharingPublic/nodes.ts +33 -11
  126. package/src/internal/sharingPublic/session/apiService.ts +31 -9
  127. package/src/internal/sharingPublic/session/interface.ts +20 -0
  128. package/src/internal/sharingPublic/session/manager.ts +31 -8
  129. package/src/internal/sharingPublic/session/session.ts +10 -5
  130. package/src/internal/sharingPublic/shares.ts +7 -43
  131. package/src/internal/upload/controller.ts +16 -4
  132. package/src/internal/upload/fileUploader.ts +2 -2
  133. package/src/internal/upload/streamUploader.test.ts +46 -14
  134. package/src/internal/upload/streamUploader.ts +74 -21
  135. package/src/protonDriveClient.ts +25 -7
  136. package/src/protonDrivePublicLinkClient.ts +7 -4
  137. package/src/tests/telemetry.ts +6 -3
  138. package/src/transformers.ts +8 -0
  139. package/dist/diagnostic/sdkDiagnosticFull.js.map +0 -1
  140. package/dist/internal/sharingPublic/cryptoCache.d.ts +0 -15
  141. package/dist/internal/sharingPublic/cryptoCache.js +0 -44
  142. package/dist/internal/sharingPublic/cryptoCache.js.map +0 -1
  143. package/dist/internal/sharingPublic/cryptoService.d.ts +0 -8
  144. package/dist/internal/sharingPublic/cryptoService.js +0 -19
  145. package/dist/internal/sharingPublic/cryptoService.js.map +0 -1
  146. package/dist/internal/sharingPublic/interface.d.ts +0 -5
  147. package/dist/internal/sharingPublic/interface.js +0 -3
  148. package/dist/internal/sharingPublic/interface.js.map +0 -1
  149. package/src/internal/sharingPublic/cryptoCache.ts +0 -45
  150. package/src/internal/sharingPublic/cryptoService.ts +0 -22
  151. package/src/internal/sharingPublic/interface.ts +0 -5
@@ -133,7 +133,7 @@ describe('StreamUploader', () => {
133
133
  metadata,
134
134
  onFinish,
135
135
  controller,
136
- abortController.signal,
136
+ abortController,
137
137
  );
138
138
  });
139
139
 
@@ -146,10 +146,10 @@ describe('StreamUploader', () => {
146
146
 
147
147
  const verifySuccess = async () => {
148
148
  const result = await uploader.start(stream, thumbnails, onProgress);
149
-
149
+
150
150
  expect(result).toEqual({
151
151
  nodeRevisionUid: 'revisionUid',
152
- nodeUid: 'nodeUid'
152
+ nodeUid: 'nodeUid',
153
153
  });
154
154
 
155
155
  const numberOfExpectedBlocks = Math.ceil(metadata.expectedSize / FILE_CHUNK_SIZE);
@@ -259,7 +259,7 @@ describe('StreamUploader', () => {
259
259
  metadata,
260
260
  onFinish,
261
261
  controller,
262
- abortController.signal,
262
+ abortController,
263
263
  );
264
264
 
265
265
  await verifySuccess();
@@ -288,7 +288,7 @@ describe('StreamUploader', () => {
288
288
  metadata,
289
289
  onFinish,
290
290
  controller,
291
- abortController.signal,
291
+ abortController,
292
292
  );
293
293
 
294
294
  await verifySuccess();
@@ -433,14 +433,6 @@ describe('StreamUploader', () => {
433
433
  await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
434
434
  });
435
435
 
436
- it('should handle abortion', async () => {
437
- const error = new Error('Aborted');
438
- const promise = uploader.start(stream, thumbnails, onProgress);
439
- abortController.abort(error);
440
- await promise;
441
- expect(apiService.uploadBlock.mock.calls[0][4]?.aborted).toBe(true);
442
- });
443
-
444
436
  describe('verifyIntegrity', () => {
445
437
  it('should report block verification error', async () => {
446
438
  blockVerifier.verifyBlock = jest.fn().mockRejectedValue(new IntegrityError('Block verification error'));
@@ -473,7 +465,7 @@ describe('StreamUploader', () => {
473
465
  } as UploadMetadata,
474
466
  onFinish,
475
467
  controller,
476
- abortController.signal,
468
+ abortController,
477
469
  );
478
470
 
479
471
  await verifyFailure(
@@ -498,4 +490,44 @@ describe('StreamUploader', () => {
498
490
  });
499
491
  });
500
492
  });
493
+
494
+ describe('abort', () => {
495
+ const thumbnails: Thumbnail[] = [];
496
+ let stream: ReadableStream<Uint8Array>;
497
+ let streamController: ReadableStreamDefaultController<Uint8Array>;
498
+
499
+ beforeEach(() => {
500
+ stream = new ReadableStream({
501
+ start(controller) {
502
+ streamController = controller;
503
+ },
504
+ });
505
+ });
506
+
507
+ it('should abort at the start', async () => {
508
+ const promise = uploader.start(stream, thumbnails);
509
+ abortController.abort();
510
+ await expect(promise).rejects.toThrow('Operation aborted');
511
+ });
512
+
513
+ it('should abort when encrypting blocks', async () => {
514
+ const promise = uploader.start(stream, thumbnails);
515
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
516
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
517
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
518
+ abortController.abort();
519
+ await expect(promise).rejects.toThrow('Operation aborted');
520
+ });
521
+
522
+ it('should abort when uploading block', async () => {
523
+ apiService.uploadBlock = jest.fn().mockImplementation(async function () {
524
+ abortController.abort();
525
+ });
526
+
527
+ const promise = uploader.start(stream, thumbnails);
528
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
529
+
530
+ await expect(promise).rejects.toThrow('Operation aborted');
531
+ });
532
+ });
501
533
  });
@@ -1,7 +1,7 @@
1
1
  import { c } from 'ttag';
2
2
 
3
3
  import { Thumbnail, Logger, ThumbnailType, UploadMetadata } from '../../interface';
4
- import { IntegrityError } from '../../errors';
4
+ import { AbortError, IntegrityError } from '../../errors';
5
5
  import { LoggerWithPrefix } from '../../telemetry';
6
6
  import { APIHTTPError, HTTPErrorCode, NotFoundAPIError } from '../apiService';
7
7
  import { getErrorMessage } from '../errors';
@@ -59,7 +59,6 @@ export class StreamUploader {
59
59
 
60
60
  protected digests: UploadDigests;
61
61
  protected controller: UploadController;
62
- protected abortController: AbortController;
63
62
 
64
63
  protected encryptedThumbnails = new Map<ThumbnailType, EncryptedThumbnail>();
65
64
  protected encryptedBlocks = new Map<number, EncryptedBlock>();
@@ -75,6 +74,9 @@ export class StreamUploader {
75
74
  protected uploadedThumbnails: ({ type: ThumbnailType } & EncryptedBlockMetadata)[] = [];
76
75
  protected uploadedBlocks: ({ index: number } & EncryptedBlockMetadata)[] = [];
77
76
 
77
+ // Error of the whole upload - either encryption or upload error.
78
+ protected error: unknown | undefined;
79
+
78
80
  constructor(
79
81
  protected telemetry: UploadTelemetry,
80
82
  protected apiService: UploadAPIService,
@@ -85,7 +87,7 @@ export class StreamUploader {
85
87
  protected metadata: UploadMetadata,
86
88
  protected onFinish: (failure: boolean) => Promise<void>,
87
89
  protected uploadController: UploadController,
88
- protected signal?: AbortSignal,
90
+ protected abortController: AbortController,
89
91
  ) {
90
92
  this.telemetry = telemetry;
91
93
  this.logger = telemetry.getLoggerForRevision(revisionDraft.nodeRevisionUid);
@@ -96,23 +98,16 @@ export class StreamUploader {
96
98
  this.metadata = metadata;
97
99
  this.onFinish = onFinish;
98
100
 
99
- this.signal = signal;
100
- this.abortController = new AbortController();
101
- if (signal) {
102
- signal.addEventListener('abort', () => {
103
- this.abortController.abort();
104
- });
105
- }
106
-
107
101
  this.digests = new UploadDigests();
108
102
  this.controller = uploadController;
103
+ this.abortController = abortController;
109
104
  }
110
105
 
111
106
  async start(
112
107
  stream: ReadableStream,
113
108
  thumbnails: Thumbnail[],
114
109
  onProgress?: (uploadedBytes: number) => void,
115
- ): Promise<{ nodeRevisionUid: string, nodeUid: string }> {
110
+ ): Promise<{ nodeRevisionUid: string; nodeUid: string }> {
116
111
  let failure = false;
117
112
 
118
113
  // File progress is tracked for telemetry - to track at what
@@ -157,9 +152,8 @@ export class StreamUploader {
157
152
 
158
153
  return {
159
154
  nodeRevisionUid: this.revisionDraft.nodeRevisionUid,
160
- nodeUid: this.revisionDraft.nodeUid
161
- }
162
-
155
+ nodeUid: this.revisionDraft.nodeUid,
156
+ };
163
157
  }
164
158
 
165
159
  private async encryptAndUploadBlocks(
@@ -183,8 +177,8 @@ export class StreamUploader {
183
177
  void this.abortUpload(error);
184
178
  });
185
179
 
186
- while (!encryptionError) {
187
- await this.controller.waitIfPaused();
180
+ while (!this.isUploadAborted) {
181
+ await this.controller.waitWhilePaused();
188
182
  await this.waitForUploadCapacityAndBufferedBlocks();
189
183
 
190
184
  if (this.isEncryptionFullyFinished) {
@@ -198,6 +192,17 @@ export class StreamUploader {
198
192
  }
199
193
  }
200
194
 
195
+ // If the upload was aborted due to encryption or upload error, throw
196
+ // the original error (it is failing upload).
197
+ // If the upload was aborted due to abort signal, throw AbortError
198
+ // (it is aborted by the user).
199
+ if (this.error) {
200
+ throw this.error;
201
+ }
202
+ if (this.abortController.signal.aborted) {
203
+ throw new AbortError();
204
+ }
205
+
201
206
  this.logger.debug(`All blocks uploading, waiting for them to finish`);
202
207
  // Technically this is finished as while-block above will break
203
208
  // when encryption is finished. But in case of error there could
@@ -233,6 +238,10 @@ export class StreamUploader {
233
238
  }
234
239
 
235
240
  for (const thumbnail of thumbnails) {
241
+ if (this.isUploadAborted) {
242
+ break;
243
+ }
244
+
236
245
  this.logger.debug(`Encrypting thumbnail ${thumbnail.type}`);
237
246
  const encryptedThumbnail = await this.cryptoService.encryptThumbnail(
238
247
  this.revisionDraft.nodeKeys,
@@ -251,9 +260,13 @@ export class StreamUploader {
251
260
 
252
261
  this.digests.update(block);
253
262
 
254
- await this.controller.waitIfPaused();
263
+ await this.controller.waitWhilePaused();
255
264
  await this.waitForBufferCapacity();
256
265
 
266
+ if (this.isUploadAborted) {
267
+ break;
268
+ }
269
+
257
270
  this.logger.debug(`Encrypting block ${index}`);
258
271
  let attempt = 0;
259
272
  let integrityError = false;
@@ -272,6 +285,11 @@ export class StreamUploader {
272
285
  void this.telemetry.logBlockVerificationError(true);
273
286
  }
274
287
  } catch (error: unknown) {
288
+ // Do not retry or report anything if the upload was aborted.
289
+ if (error instanceof AbortError) {
290
+ throw error;
291
+ }
292
+
275
293
  if (error instanceof IntegrityError) {
276
294
  integrityError = true;
277
295
  }
@@ -399,6 +417,11 @@ export class StreamUploader {
399
417
  });
400
418
  break;
401
419
  } catch (error: unknown) {
420
+ // Do not retry or report anything if the upload was aborted.
421
+ if (error instanceof AbortError) {
422
+ throw error;
423
+ }
424
+
402
425
  if (blockProgress !== 0) {
403
426
  onProgress?.(-blockProgress);
404
427
  blockProgress = 0;
@@ -461,6 +484,11 @@ export class StreamUploader {
461
484
  });
462
485
  break;
463
486
  } catch (error: unknown) {
487
+ // Do not retry or report anything if the upload was aborted.
488
+ if (error instanceof AbortError) {
489
+ throw error;
490
+ }
491
+
464
492
  if (blockProgress !== 0) {
465
493
  onProgress?.(-blockProgress);
466
494
  blockProgress = 0;
@@ -510,7 +538,17 @@ export class StreamUploader {
510
538
 
511
539
  private async waitForBufferCapacity() {
512
540
  if (this.encryptedBlocks.size >= MAX_BUFFERED_BLOCKS) {
513
- await waitForCondition(() => this.encryptedBlocks.size < MAX_BUFFERED_BLOCKS);
541
+ try {
542
+ await waitForCondition(
543
+ () => this.encryptedBlocks.size < MAX_BUFFERED_BLOCKS,
544
+ this.abortController.signal,
545
+ );
546
+ } catch (error: unknown) {
547
+ if (error instanceof AbortError) {
548
+ return;
549
+ }
550
+ throw error;
551
+ }
514
552
  }
515
553
  }
516
554
 
@@ -518,7 +556,17 @@ export class StreamUploader {
518
556
  while (this.ongoingUploads.size >= MAX_UPLOADING_BLOCKS) {
519
557
  await Promise.race(this.ongoingUploads.values().map(({ uploadPromise }) => uploadPromise));
520
558
  }
521
- await waitForCondition(() => this.encryptedBlocks.size > 0 || this.encryptionFinished);
559
+ try {
560
+ await waitForCondition(
561
+ () => this.encryptedBlocks.size > 0 || this.encryptionFinished,
562
+ this.abortController.signal,
563
+ );
564
+ } catch (error: unknown) {
565
+ if (error instanceof AbortError) {
566
+ return;
567
+ }
568
+ throw error;
569
+ }
522
570
  }
523
571
 
524
572
  protected verifyIntegrity(thumbnails: Thumbnail[]) {
@@ -573,9 +621,14 @@ export class StreamUploader {
573
621
  }
574
622
 
575
623
  private async abortUpload(error: unknown) {
576
- if (this.abortController.signal.aborted || this.signal?.aborted) {
624
+ if (this.isUploadAborted) {
577
625
  return;
578
626
  }
627
+ this.error = error;
579
628
  this.abortController.abort(error);
580
629
  }
630
+
631
+ private get isUploadAborted(): boolean {
632
+ return !!this.error || this.abortController.signal.aborted;
633
+ }
581
634
  }
@@ -7,6 +7,7 @@ import {
7
7
  MaybeNode,
8
8
  MaybeMissingNode,
9
9
  NodeResult,
10
+ NodeResultWithNewUid,
10
11
  Revision,
11
12
  RevisionOrUid,
12
13
  ShareNodeSettings,
@@ -28,6 +29,7 @@ import {
28
29
  ThumbnailResult,
29
30
  SDKEvent,
30
31
  NodeType,
32
+ MemberRole,
31
33
  } from './interface';
32
34
  import {
33
35
  getUid,
@@ -36,6 +38,7 @@ import {
36
38
  convertInternalNodeIterator,
37
39
  convertInternalMissingNodeIterator,
38
40
  convertInternalNode,
41
+ convertInternalRevisionIterator,
39
42
  } from './transformers';
40
43
  import { Telemetry } from './telemetry';
41
44
  import { DriveAPIService } from './internal/apiService';
@@ -68,7 +71,7 @@ export class ProtonDriveClient {
68
71
  private download: ReturnType<typeof initDownloadModule>;
69
72
  private upload: ReturnType<typeof initUploadModule>;
70
73
  private devices: ReturnType<typeof initDevicesModule>;
71
- private sessionManager: SharingPublicSessionManager;
74
+ private publicSessionManager: SharingPublicSessionManager;
72
75
 
73
76
  public experimental: {
74
77
  /**
@@ -93,6 +96,11 @@ export class ProtonDriveClient {
93
96
  isCustomPasswordProtected: boolean;
94
97
  isLegacy: boolean;
95
98
  vendorType: number;
99
+ directAccess?: {
100
+ nodeUid: string;
101
+ directRole: MemberRole;
102
+ publicRole: MemberRole;
103
+ };
96
104
  }>;
97
105
  /**
98
106
  * Experimental feature to authenticate a public link and
@@ -184,7 +192,13 @@ export class ProtonDriveClient {
184
192
  latestEventIdProvider,
185
193
  );
186
194
 
187
- this.sessionManager = new SharingPublicSessionManager(httpClient, apiService, srpModule);
195
+ this.publicSessionManager = new SharingPublicSessionManager(
196
+ telemetry,
197
+ httpClient,
198
+ cryptoModule,
199
+ srpModule,
200
+ apiService,
201
+ );
188
202
 
189
203
  this.experimental = {
190
204
  getNodeUrl: async (nodeUid: NodeOrUid) => {
@@ -201,11 +215,14 @@ export class ProtonDriveClient {
201
215
  },
202
216
  getPublicLinkInfo: async (url: string) => {
203
217
  this.logger.info(`Getting info for public link ${url}`);
204
- return this.sessionManager.getInfo(url);
218
+ return this.publicSessionManager.getInfo(url);
205
219
  },
206
220
  authPublicLink: async (url: string, customPassword?: string) => {
207
221
  this.logger.info(`Authenticating public link ${url}`);
208
- const { httpClient, token, password } = await this.sessionManager.auth(url, customPassword);
222
+ const { httpClient, token, shareKey, rootUid } = await this.publicSessionManager.auth(
223
+ url,
224
+ customPassword,
225
+ );
209
226
  return new ProtonDrivePublicLinkClient({
210
227
  httpClient,
211
228
  account,
@@ -215,7 +232,8 @@ export class ProtonDriveClient {
215
232
  telemetry,
216
233
  url,
217
234
  token,
218
- password,
235
+ publicShareKey: shareKey,
236
+ publicRootNodeUid: rootUid,
219
237
  });
220
238
  },
221
239
  };
@@ -408,7 +426,7 @@ export class ProtonDriveClient {
408
426
  nodeUids: NodeOrUid[],
409
427
  newParentNodeUid: NodeOrUid,
410
428
  signal?: AbortSignal,
411
- ): AsyncGenerator<NodeResult> {
429
+ ): AsyncGenerator<NodeResultWithNewUid> {
412
430
  this.logger.info(`Copying ${nodeUids.length} nodes to ${getUid(newParentNodeUid)}`);
413
431
  yield* this.nodes.management.copyNodes(getUids(nodeUids), getUid(newParentNodeUid), signal);
414
432
  }
@@ -507,7 +525,7 @@ export class ProtonDriveClient {
507
525
  */
508
526
  async *iterateRevisions(nodeUid: NodeOrUid, signal?: AbortSignal): AsyncGenerator<Revision> {
509
527
  this.logger.info(`Iterating revisions of ${getUid(nodeUid)}`);
510
- yield* this.nodes.revisions.iterateRevisions(getUid(nodeUid), signal);
528
+ yield* convertInternalRevisionIterator(this.nodes.revisions.iterateRevisions(getUid(nodeUid), signal));
511
529
  }
512
530
 
513
531
  /**
@@ -1,6 +1,6 @@
1
1
  import { MemoryCache } from './cache';
2
2
  import { getConfig } from './config';
3
- import { DriveCrypto, OpenPGPCrypto, SRPModule, SessionKey } from './crypto';
3
+ import { DriveCrypto, OpenPGPCrypto, PrivateKey, SRPModule, SessionKey } from './crypto';
4
4
  import {
5
5
  ProtonDriveHTTPClient,
6
6
  ProtonDriveTelemetry,
@@ -74,7 +74,8 @@ export class ProtonDrivePublicLinkClient {
74
74
  telemetry,
75
75
  url,
76
76
  token,
77
- password,
77
+ publicShareKey,
78
+ publicRootNodeUid,
78
79
  }: {
79
80
  httpClient: ProtonDriveHTTPClient;
80
81
  account: ProtonDriveAccount;
@@ -84,7 +85,8 @@ export class ProtonDrivePublicLinkClient {
84
85
  telemetry?: ProtonDriveTelemetry;
85
86
  url: string;
86
87
  token: string;
87
- password: string;
88
+ publicShareKey: PrivateKey;
89
+ publicRootNodeUid: string;
88
90
  }) {
89
91
  if (!telemetry) {
90
92
  telemetry = new Telemetry();
@@ -115,7 +117,8 @@ export class ProtonDrivePublicLinkClient {
115
117
  account,
116
118
  url,
117
119
  token,
118
- password,
120
+ publicShareKey,
121
+ publicRootNodeUid,
119
122
  );
120
123
  this.download = initDownloadModule(
121
124
  telemetry,
@@ -1,9 +1,12 @@
1
- import { ProtonDriveTelemetry } from '../interface';
1
+ import { Logger, ProtonDriveTelemetry } from '../interface';
2
2
  import { getMockLogger } from './logger';
3
3
 
4
- export function getMockTelemetry(): ProtonDriveTelemetry {
4
+ export function getMockTelemetry(): ProtonDriveTelemetry & { mockLogger: Logger } {
5
+ const mockLogger = getMockLogger();
6
+
5
7
  return {
6
- getLogger: getMockLogger,
8
+ mockLogger,
9
+ getLogger: () => mockLogger,
7
10
  recordMetric: jest.fn(),
8
11
  };
9
12
  }
@@ -121,6 +121,14 @@ export function convertInternalNode(node: InternalPartialNode): PublicMaybeNode
121
121
  } as PublicNodeEntity);
122
122
  }
123
123
 
124
+ export async function* convertInternalRevisionIterator(
125
+ revisionIterator: AsyncGenerator<InternalRevision>,
126
+ ): AsyncGenerator<PublicRevision> {
127
+ for await (const revision of revisionIterator) {
128
+ yield convertInternalRevision(revision);
129
+ }
130
+ }
131
+
124
132
  function convertInternalRevision(revision: InternalRevision): PublicRevision {
125
133
  return {
126
134
  uid: revision.uid,
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdkDiagnosticFull.js","sourceRoot":"","sources":["../../src/diagnostic/sdkDiagnosticFull.ts"],"names":[],"mappings":";;;AAIA,mDAAgD;AAEhD;;;GAGG;AACH,MAAa,iBAAiB;IAEd;IACA;IACA;IAHZ,YACY,UAAsB,EACtB,SAA8B,EAC9B,UAAgC;QAFhC,eAAU,GAAV,UAAU,CAAY;QACtB,cAAS,GAAT,SAAS,CAAqB;QAC9B,eAAU,GAAV,UAAU,CAAsB;QAExC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,CAAC,aAAa,CAAC,OAA2B;QAC5C,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,CAAC,cAAc,CAAC,IAAe,EAAE,OAA2B;QAC9D,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3E,CAAC;IAEO,KAAK,CAAC,CAAC,WAAW,CAAC,SAA2C;QAClE,KAAK,CAAC,CAAC,IAAA,6BAAa,EAAC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IACzF,CAAC;IAEO,KAAK,CAAC,CAAC,iBAAiB;QAC5B,KAAK,CAAC,CAAC,IAAA,6BAAa,EAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1F,CAAC;CACJ;AA1BD,8CA0BC"}
@@ -1,15 +0,0 @@
1
- import { PrivateKey } from '../../crypto';
2
- import { ProtonDriveCryptoCache, Logger } from '../../interface';
3
- /**
4
- * Provides caching for public link crypto material.
5
- *
6
- * The cache is responsible for serialising and deserialising public link
7
- * crypto material.
8
- */
9
- export declare class SharingPublicCryptoCache {
10
- private logger;
11
- private driveCache;
12
- constructor(logger: Logger, driveCache: ProtonDriveCryptoCache);
13
- setShareKey(shareKey: PrivateKey): Promise<void>;
14
- getShareKey(): Promise<PrivateKey>;
15
- }
@@ -1,44 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SharingPublicCryptoCache = void 0;
4
- /**
5
- * Provides caching for public link crypto material.
6
- *
7
- * The cache is responsible for serialising and deserialising public link
8
- * crypto material.
9
- */
10
- class SharingPublicCryptoCache {
11
- logger;
12
- driveCache;
13
- constructor(logger, driveCache) {
14
- this.logger = logger;
15
- this.driveCache = driveCache;
16
- this.logger = logger;
17
- this.driveCache = driveCache;
18
- }
19
- async setShareKey(shareKey) {
20
- await this.driveCache.setEntity(getShareKeyCacheKey(), {
21
- publicShareKey: {
22
- key: shareKey,
23
- },
24
- });
25
- }
26
- async getShareKey() {
27
- const shareKeyData = await this.driveCache.getEntity(getShareKeyCacheKey());
28
- if (!shareKeyData.publicShareKey) {
29
- try {
30
- await this.driveCache.removeEntities([getShareKeyCacheKey()]);
31
- }
32
- catch (removingError) {
33
- this.logger.warn(`Failed to remove corrupted public share key from the cache: ${removingError instanceof Error ? removingError.message : removingError}`);
34
- }
35
- throw new Error('Failed to deserialize public share key');
36
- }
37
- return shareKeyData.publicShareKey.key;
38
- }
39
- }
40
- exports.SharingPublicCryptoCache = SharingPublicCryptoCache;
41
- function getShareKeyCacheKey() {
42
- return 'publicShareKey';
43
- }
44
- //# sourceMappingURL=cryptoCache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cryptoCache.js","sourceRoot":"","sources":["../../../src/internal/sharingPublic/cryptoCache.ts"],"names":[],"mappings":";;;AAGA;;;;;GAKG;AACH,MAAa,wBAAwB;IAErB;IACA;IAFZ,YACY,MAAc,EACd,UAAkC;QADlC,WAAM,GAAN,MAAM,CAAQ;QACd,eAAU,GAAV,UAAU,CAAwB;QAE1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,QAAoB;QAClC,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE;YACnD,cAAc,EAAE;gBACZ,GAAG,EAAE,QAAQ;aAChB;SACJ,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,WAAW;QACb,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACD,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC;YAClE,CAAC;YAAC,OAAO,aAAsB,EAAE,CAAC;gBAC9B,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,+DAA+D,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAC1I,CAAC;YACN,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,YAAY,CAAC,cAAc,CAAC,GAAG,CAAC;IAC3C,CAAC;CACJ;AA/BD,4DA+BC;AAED,SAAS,mBAAmB;IACxB,OAAO,gBAAgB,CAAC;AAC5B,CAAC"}
@@ -1,8 +0,0 @@
1
- import { DriveCrypto, PrivateKey } from '../../crypto';
2
- import { EncryptedShareCrypto } from './interface';
3
- export declare class SharingPublicCryptoService {
4
- private driveCrypto;
5
- private password;
6
- constructor(driveCrypto: DriveCrypto, password: string);
7
- decryptPublicLinkShareKey(encryptedShare: EncryptedShareCrypto): Promise<PrivateKey>;
8
- }
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SharingPublicCryptoService = void 0;
4
- class SharingPublicCryptoService {
5
- driveCrypto;
6
- password;
7
- constructor(driveCrypto, password) {
8
- this.driveCrypto = driveCrypto;
9
- this.password = password;
10
- this.driveCrypto = driveCrypto;
11
- this.password = password;
12
- }
13
- async decryptPublicLinkShareKey(encryptedShare) {
14
- const { key: shareKey } = await this.driveCrypto.decryptKeyWithSrpPassword(this.password, encryptedShare.base64UrlPasswordSalt, encryptedShare.armoredKey, encryptedShare.armoredPassphrase);
15
- return shareKey;
16
- }
17
- }
18
- exports.SharingPublicCryptoService = SharingPublicCryptoService;
19
- //# sourceMappingURL=cryptoService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cryptoService.js","sourceRoot":"","sources":["../../../src/internal/sharingPublic/cryptoService.ts"],"names":[],"mappings":";;;AAGA,MAAa,0BAA0B;IAEvB;IACA;IAFZ,YACY,WAAwB,EACxB,QAAgB;QADhB,gBAAW,GAAX,WAAW,CAAa;QACxB,aAAQ,GAAR,QAAQ,CAAQ;QAExB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,yBAAyB,CAAC,cAAoC;QAChE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,yBAAyB,CACtE,IAAI,CAAC,QAAQ,EACb,cAAc,CAAC,qBAAqB,EACpC,cAAc,CAAC,UAAU,EACzB,cAAc,CAAC,iBAAiB,CACnC,CAAC;QACF,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ;AAlBD,gEAkBC"}
@@ -1,5 +0,0 @@
1
- export interface EncryptedShareCrypto {
2
- base64UrlPasswordSalt: string;
3
- armoredKey: string;
4
- armoredPassphrase: string;
5
- }
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=interface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/internal/sharingPublic/interface.ts"],"names":[],"mappings":""}
@@ -1,45 +0,0 @@
1
- import { PrivateKey } from '../../crypto';
2
- import { ProtonDriveCryptoCache, Logger } from '../../interface';
3
-
4
- /**
5
- * Provides caching for public link crypto material.
6
- *
7
- * The cache is responsible for serialising and deserialising public link
8
- * crypto material.
9
- */
10
- export class SharingPublicCryptoCache {
11
- constructor(
12
- private logger: Logger,
13
- private driveCache: ProtonDriveCryptoCache,
14
- ) {
15
- this.logger = logger;
16
- this.driveCache = driveCache;
17
- }
18
-
19
- async setShareKey(shareKey: PrivateKey): Promise<void> {
20
- await this.driveCache.setEntity(getShareKeyCacheKey(), {
21
- publicShareKey: {
22
- key: shareKey,
23
- },
24
- });
25
- }
26
-
27
- async getShareKey(): Promise<PrivateKey> {
28
- const shareKeyData = await this.driveCache.getEntity(getShareKeyCacheKey());
29
- if (!shareKeyData.publicShareKey) {
30
- try {
31
- await this.driveCache.removeEntities([getShareKeyCacheKey()]);
32
- } catch (removingError: unknown) {
33
- this.logger.warn(
34
- `Failed to remove corrupted public share key from the cache: ${removingError instanceof Error ? removingError.message : removingError}`,
35
- );
36
- }
37
- throw new Error('Failed to deserialize public share key');
38
- }
39
- return shareKeyData.publicShareKey.key;
40
- }
41
- }
42
-
43
- function getShareKeyCacheKey() {
44
- return 'publicShareKey';
45
- }