@protontech/drive-sdk 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/crypto/driveCrypto.d.ts +20 -2
  2. package/dist/crypto/driveCrypto.js +72 -14
  3. package/dist/crypto/driveCrypto.js.map +1 -1
  4. package/dist/crypto/driveCrypto.test.js +3 -2
  5. package/dist/crypto/driveCrypto.test.js.map +1 -1
  6. package/dist/crypto/interface.d.ts +22 -8
  7. package/dist/crypto/openPGPCrypto.d.ts +30 -7
  8. package/dist/crypto/openPGPCrypto.js +46 -8
  9. package/dist/crypto/openPGPCrypto.js.map +1 -1
  10. package/dist/diagnostic/telemetry.js +3 -0
  11. package/dist/diagnostic/telemetry.js.map +1 -1
  12. package/dist/interface/featureFlags.d.ts +4 -1
  13. package/dist/interface/featureFlags.js +5 -0
  14. package/dist/interface/featureFlags.js.map +1 -1
  15. package/dist/interface/index.d.ts +2 -0
  16. package/dist/interface/index.js +5 -1
  17. package/dist/interface/index.js.map +1 -1
  18. package/dist/interface/photos.d.ts +13 -1
  19. package/dist/interface/photos.js +14 -0
  20. package/dist/interface/photos.js.map +1 -1
  21. package/dist/interface/telemetry.d.ts +12 -1
  22. package/dist/interface/telemetry.js.map +1 -1
  23. package/dist/internal/apiService/apiService.d.ts +1 -1
  24. package/dist/internal/apiService/apiService.js +2 -2
  25. package/dist/internal/apiService/apiService.js.map +1 -1
  26. package/dist/internal/nodes/apiService.js.map +1 -1
  27. package/dist/internal/nodes/nodesAccess.js +1 -1
  28. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  29. package/dist/internal/photos/addToAlbum.d.ts +1 -5
  30. package/dist/internal/photos/addToAlbum.js +8 -87
  31. package/dist/internal/photos/addToAlbum.js.map +1 -1
  32. package/dist/internal/photos/{albums.d.ts → albumsManager.d.ts} +1 -1
  33. package/dist/internal/photos/{albums.js → albumsManager.js} +4 -4
  34. package/dist/internal/photos/albumsManager.js.map +1 -0
  35. package/dist/internal/photos/{albums.test.js → albumsManager.test.js} +3 -3
  36. package/dist/internal/photos/albumsManager.test.js.map +1 -0
  37. package/dist/internal/photos/apiService.d.ts +8 -4
  38. package/dist/internal/photos/apiService.js +38 -6
  39. package/dist/internal/photos/apiService.js.map +1 -1
  40. package/dist/internal/photos/index.d.ts +7 -5
  41. package/dist/internal/photos/index.js +7 -4
  42. package/dist/internal/photos/index.js.map +1 -1
  43. package/dist/internal/photos/interface.d.ts +3 -26
  44. package/dist/internal/photos/interface.js +0 -14
  45. package/dist/internal/photos/interface.js.map +1 -1
  46. package/dist/internal/photos/nodes.js +1 -1
  47. package/dist/internal/photos/nodes.js.map +1 -1
  48. package/dist/internal/photos/photosManager.d.ts +22 -0
  49. package/dist/internal/photos/photosManager.js +101 -0
  50. package/dist/internal/photos/photosManager.js.map +1 -0
  51. package/dist/internal/photos/photosManager.test.d.ts +1 -0
  52. package/dist/internal/photos/photosManager.test.js +222 -0
  53. package/dist/internal/photos/photosManager.test.js.map +1 -0
  54. package/dist/internal/photos/photosTransferPayloadBuilder.d.ts +57 -0
  55. package/dist/internal/photos/photosTransferPayloadBuilder.js +113 -0
  56. package/dist/internal/photos/photosTransferPayloadBuilder.js.map +1 -0
  57. package/dist/internal/photos/photosTransferPayloadBuilder.test.d.ts +1 -0
  58. package/dist/internal/photos/photosTransferPayloadBuilder.test.js +289 -0
  59. package/dist/internal/photos/photosTransferPayloadBuilder.test.js.map +1 -0
  60. package/dist/internal/photos/upload.d.ts +2 -2
  61. package/dist/internal/photos/upload.js +3 -3
  62. package/dist/internal/photos/upload.js.map +1 -1
  63. package/dist/internal/sharingPublic/nodes.js +11 -4
  64. package/dist/internal/sharingPublic/nodes.js.map +1 -1
  65. package/dist/internal/upload/apiService.d.ts +0 -4
  66. package/dist/internal/upload/apiService.js +0 -4
  67. package/dist/internal/upload/apiService.js.map +1 -1
  68. package/dist/internal/upload/cryptoService.d.ts +4 -2
  69. package/dist/internal/upload/cryptoService.js +18 -6
  70. package/dist/internal/upload/cryptoService.js.map +1 -1
  71. package/dist/internal/upload/index.d.ts +2 -2
  72. package/dist/internal/upload/index.js +2 -2
  73. package/dist/internal/upload/index.js.map +1 -1
  74. package/dist/internal/upload/interface.d.ts +1 -1
  75. package/dist/internal/upload/streamUploader.d.ts +1 -1
  76. package/dist/internal/upload/streamUploader.js +12 -13
  77. package/dist/internal/upload/streamUploader.js.map +1 -1
  78. package/dist/internal/upload/streamUploader.test.js +28 -4
  79. package/dist/internal/upload/streamUploader.test.js.map +1 -1
  80. package/dist/protonDriveClient.js +2 -2
  81. package/dist/protonDriveClient.js.map +1 -1
  82. package/dist/protonDrivePhotosClient.d.ts +20 -3
  83. package/dist/protonDrivePhotosClient.js +27 -3
  84. package/dist/protonDrivePhotosClient.js.map +1 -1
  85. package/dist/protonDrivePublicLinkClient.d.ts +3 -2
  86. package/dist/protonDrivePublicLinkClient.js +7 -3
  87. package/dist/protonDrivePublicLinkClient.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/crypto/driveCrypto.test.ts +3 -1
  90. package/src/crypto/driveCrypto.ts +82 -7
  91. package/src/crypto/interface.ts +21 -8
  92. package/src/crypto/openPGPCrypto.ts +68 -8
  93. package/src/diagnostic/telemetry.ts +3 -0
  94. package/src/interface/featureFlags.ts +5 -1
  95. package/src/interface/index.ts +2 -0
  96. package/src/interface/photos.ts +14 -1
  97. package/src/interface/telemetry.ts +14 -1
  98. package/src/internal/apiService/apiService.ts +6 -2
  99. package/src/internal/nodes/apiService.ts +2 -2
  100. package/src/internal/nodes/nodesAccess.ts +1 -1
  101. package/src/internal/photos/addToAlbum.ts +29 -136
  102. package/src/internal/photos/{albums.test.ts → albumsManager.test.ts} +3 -3
  103. package/src/internal/photos/{albums.ts → albumsManager.ts} +1 -1
  104. package/src/internal/photos/apiService.ts +73 -16
  105. package/src/internal/photos/index.ts +9 -4
  106. package/src/internal/photos/interface.ts +3 -28
  107. package/src/internal/photos/nodes.ts +1 -1
  108. package/src/internal/photos/photosManager.test.ts +266 -0
  109. package/src/internal/photos/photosManager.ts +144 -0
  110. package/src/internal/photos/photosTransferPayloadBuilder.test.ts +380 -0
  111. package/src/internal/photos/photosTransferPayloadBuilder.ts +203 -0
  112. package/src/internal/photos/upload.ts +20 -7
  113. package/src/internal/sharingPublic/nodes.ts +11 -4
  114. package/src/internal/upload/apiService.ts +7 -9
  115. package/src/internal/upload/cryptoService.ts +28 -7
  116. package/src/internal/upload/index.ts +3 -2
  117. package/src/internal/upload/interface.ts +1 -1
  118. package/src/internal/upload/streamUploader.test.ts +33 -4
  119. package/src/internal/upload/streamUploader.ts +13 -13
  120. package/src/protonDriveClient.ts +2 -1
  121. package/src/protonDrivePhotosClient.ts +39 -2
  122. package/src/protonDrivePublicLinkClient.ts +9 -1
  123. package/dist/internal/photos/albums.js.map +0 -1
  124. package/dist/internal/photos/albums.test.js.map +0 -1
  125. /package/dist/internal/photos/{albums.test.d.ts → albumsManager.test.d.ts} +0 -0
@@ -162,22 +162,24 @@ export class UploadAPIService {
162
162
  blocks: {
163
163
  contentBlocks: {
164
164
  index: number;
165
- hash: Uint8Array<ArrayBuffer>;
166
- encryptedSize: number;
167
165
  armoredSignature: string;
168
166
  verificationToken: Uint8Array<ArrayBuffer>;
169
167
  }[];
170
168
  thumbnails?: {
171
169
  type: ThumbnailType;
172
- hash: Uint8Array<ArrayBuffer>;
173
- encryptedSize: number;
174
170
  }[];
175
171
  },
176
172
  ): Promise<UploadTokens> {
177
173
  const { volumeId, nodeId, revisionId } = splitNodeRevisionUid(draftNodeRevisionUid);
178
174
  const result = await this.apiService.post<
179
175
  // TODO: Deprected fields but not properly marked in the types.
180
- Omit<PostRequestBlockUploadRequest, 'ShareID' | 'Thumbnail' | 'ThumbnailHash' | 'ThumbnailSize'>,
176
+ Omit<
177
+ PostRequestBlockUploadRequest,
178
+ 'ShareID' | 'Thumbnail' | 'ThumbnailHash' | 'ThumbnailSize' | 'BlockList' | 'ThumbnailList'
179
+ > & {
180
+ BlockList: Omit<PostRequestBlockUploadRequest['BlockList'][0], 'Hash' | 'Size'>[];
181
+ ThumbnailList: Omit<PostRequestBlockUploadRequest['ThumbnailList'][0], 'Hash' | 'Size'>[];
182
+ },
181
183
  PostRequestBlockUploadResponse
182
184
  >('drive/blocks', {
183
185
  AddressID: addressId,
@@ -186,16 +188,12 @@ export class UploadAPIService {
186
188
  RevisionID: revisionId,
187
189
  BlockList: blocks.contentBlocks.map((block) => ({
188
190
  Index: block.index,
189
- Hash: uint8ArrayToBase64String(block.hash),
190
191
  EncSignature: block.armoredSignature,
191
- Size: block.encryptedSize,
192
192
  Verifier: {
193
193
  Token: uint8ArrayToBase64String(block.verificationToken),
194
194
  },
195
195
  })),
196
196
  ThumbnailList: (blocks.thumbnails || []).map((block) => ({
197
- Hash: uint8ArrayToBase64String(block.hash),
198
- Size: block.encryptedSize,
199
197
  Type: block.type,
200
198
  })),
201
199
  });
@@ -2,7 +2,14 @@ import { c } from 'ttag';
2
2
 
3
3
  import { DriveCrypto, PrivateKey, SessionKey } from '../../crypto';
4
4
  import { IntegrityError } from '../../errors';
5
- import { Thumbnail, AnonymousUser } from '../../interface';
5
+ import {
6
+ Thumbnail,
7
+ AnonymousUser,
8
+ FeatureFlagProvider,
9
+ FeatureFlags,
10
+ ProtonDriveTelemetry,
11
+ Logger,
12
+ } from '../../interface';
6
13
  import {
7
14
  EncryptedBlock,
8
15
  EncryptedThumbnail,
@@ -13,12 +20,18 @@ import {
13
20
  } from './interface';
14
21
 
15
22
  export class UploadCryptoService {
23
+ protected logger: Logger;
24
+
16
25
  constructor(
26
+ telemetry: ProtonDriveTelemetry,
17
27
  protected driveCrypto: DriveCrypto,
18
28
  protected nodesService: NodesService,
29
+ protected featureFlagProvider: FeatureFlagProvider,
19
30
  ) {
31
+ this.logger = telemetry.getLogger('upload');
20
32
  this.driveCrypto = driveCrypto;
21
33
  this.nodesService = nodesService;
34
+ this.featureFlagProvider = featureFlagProvider;
22
35
  }
23
36
 
24
37
  async generateFileCrypto(
@@ -26,6 +39,13 @@ export class UploadCryptoService {
26
39
  parentKeys: { key: PrivateKey; hashKey: Uint8Array<ArrayBuffer> },
27
40
  name: string,
28
41
  ): Promise<NodeCrypto> {
42
+ const useAeadFeatureFlag = await this.featureFlagProvider.isEnabled(
43
+ FeatureFlags.DriveCryptoEncryptBlocksWithPgpAead,
44
+ );
45
+ if (useAeadFeatureFlag) {
46
+ this.logger.info('Generating file crypto with AEAD enabled');
47
+ }
48
+
29
49
  const signingKeys = await this.getSigningKeys({ parentNodeUid: parentUid });
30
50
 
31
51
  if (!signingKeys.nameAndPassphraseSigningKey) {
@@ -33,7 +53,9 @@ export class UploadCryptoService {
33
53
  }
34
54
 
35
55
  const [nodeKeys, { armoredNodeName }, hash] = await Promise.all([
36
- this.driveCrypto.generateKey([parentKeys.key], signingKeys.nameAndPassphraseSigningKey),
56
+ this.driveCrypto.generateKey([parentKeys.key], signingKeys.nameAndPassphraseSigningKey, {
57
+ enableAead: useAeadFeatureFlag,
58
+ }),
37
59
  this.driveCrypto.encryptNodeName(name, undefined, parentKeys.key, signingKeys.nameAndPassphraseSigningKey),
38
60
  this.driveCrypto.generateLookupHash(name, parentKeys.hashKey),
39
61
  ]);
@@ -111,14 +133,14 @@ export class UploadCryptoService {
111
133
  nodeRevisionDraftKeys.signingKeys.contentSigningKey,
112
134
  );
113
135
 
114
- const digest = await crypto.subtle.digest('SHA-256', encryptedData);
136
+ const digestPromise = crypto.subtle.digest('SHA-256', encryptedData);
115
137
 
116
138
  return {
117
139
  type: thumbnail.type,
118
140
  encryptedData: encryptedData,
119
141
  originalSize: thumbnail.thumbnail.length,
120
142
  encryptedSize: encryptedData.length,
121
- hash: new Uint8Array<ArrayBuffer>(digest),
143
+ hashPromise: digestPromise.then((digest) => new Uint8Array<ArrayBuffer>(digest)),
122
144
  };
123
145
  }
124
146
 
@@ -134,8 +156,7 @@ export class UploadCryptoService {
134
156
  nodeRevisionDraftKeys.contentKeyPacketSessionKey,
135
157
  nodeRevisionDraftKeys.signingKeys.contentSigningKey,
136
158
  );
137
-
138
- const digest = await crypto.subtle.digest('SHA-256', encryptedData);
159
+ const digestPromise = crypto.subtle.digest('SHA-256', encryptedData);
139
160
  const { verificationToken } = await verifyBlock(encryptedData);
140
161
 
141
162
  return {
@@ -145,7 +166,7 @@ export class UploadCryptoService {
145
166
  verificationToken,
146
167
  originalSize: block.length,
147
168
  encryptedSize: encryptedData.length,
148
- hash: new Uint8Array<ArrayBuffer>(digest),
169
+ hashPromise: digestPromise.then((digest) => new Uint8Array<ArrayBuffer>(digest)),
149
170
  };
150
171
  }
151
172
 
@@ -1,4 +1,4 @@
1
- import { ProtonDriveTelemetry, UploadMetadata } from '../../interface';
1
+ import { FeatureFlagProvider, ProtonDriveTelemetry, UploadMetadata } from '../../interface';
2
2
  import { DriveAPIService } from '../apiService';
3
3
  import { DriveCrypto } from '../../crypto';
4
4
  import { UploadAPIService } from './apiService';
@@ -22,10 +22,11 @@ export function initUploadModule(
22
22
  driveCrypto: DriveCrypto,
23
23
  sharesService: SharesService,
24
24
  nodesService: NodesService,
25
+ featureFlagProvider: FeatureFlagProvider,
25
26
  clientUid?: string,
26
27
  ) {
27
28
  const api = new UploadAPIService(apiService, clientUid);
28
- const cryptoService = new UploadCryptoService(driveCrypto, nodesService);
29
+ const cryptoService = new UploadCryptoService(telemetry, driveCrypto, nodesService, featureFlagProvider);
29
30
 
30
31
  const uploadTelemetry = new UploadTelemetry(telemetry, sharesService);
31
32
  const manager = new UploadManager(telemetry, api, cryptoService, nodesService, clientUid);
@@ -64,7 +64,7 @@ export type NodeCryptoSigningKeys = {
64
64
  export type EncryptedBlockMetadata = {
65
65
  encryptedSize: number;
66
66
  originalSize: number;
67
- hash: Uint8Array<ArrayBuffer>;
67
+ hashPromise: Promise<Uint8Array<ArrayBuffer>>;
68
68
  };
69
69
 
70
70
  export type EncryptedBlock = EncryptedBlockMetadata & {
@@ -27,7 +27,7 @@ async function mockEncryptBlock(
27
27
  verificationToken: 'verificationToken',
28
28
  originalSize: block.length,
29
29
  encryptedSize: block.length + BLOCK_ENCRYPTION_OVERHEAD,
30
- hash: 'blockHash',
30
+ hashPromise: Promise.resolve('blockHash'),
31
31
  };
32
32
  }
33
33
 
@@ -90,7 +90,7 @@ describe('StreamUploader', () => {
90
90
  encryptedData: thumbnail.thumbnail,
91
91
  originalSize: thumbnail.thumbnail.length,
92
92
  encryptedSize: thumbnail.thumbnail + 1000,
93
- hash: 'thumbnailHash',
93
+ hashPromise: Promise.resolve('thumbnailHash'),
94
94
  })),
95
95
  encryptBlock: jest.fn().mockImplementation(mockEncryptBlock),
96
96
  };
@@ -428,6 +428,37 @@ describe('StreamUploader', () => {
428
428
  expect((uploader as any).maxUploadingBlocks).toEqual(1);
429
429
  });
430
430
 
431
+ it('should not call onProgress after upload has failed', async () => {
432
+ let firstBlockPromise;
433
+
434
+ // Block 1 delays before reporting progress; block 2 fails immediately.
435
+ // This simulates block 1's progress callback firing after we've already
436
+ // entered the catch block.
437
+ apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
438
+ if (token === 'token/block:1') {
439
+ firstBlockPromise = new Promise((resolve) => setTimeout(resolve, 100));
440
+ await firstBlockPromise;
441
+ return mockUploadBlock(bareUrl, token, block, onProgress);
442
+ }
443
+ if (token === 'token/block:2') {
444
+ throw new Error('Failed to upload block');
445
+ }
446
+ return mockUploadBlock(bareUrl, token, block, onProgress);
447
+ });
448
+
449
+ const startPromise = uploader.start(stream, thumbnails, onProgress);
450
+ await expect(startPromise).rejects.toThrow('Failed to upload block');
451
+
452
+ expect(firstBlockPromise).toBeDefined();
453
+ await firstBlockPromise!;
454
+
455
+ // Mocked file has 3 blocks - 2x 4 MB blocks and 1x 2 MB block
456
+ // First block is delayed - should not be reported.
457
+ // Second block is failed - should not be reported.
458
+ // Third block is successfull before second block is failed - should be reported.
459
+ await verifyOnProgress([thumbnailSize, 2 * 1024 * 1024]);
460
+ });
461
+
431
462
  it('limitUploadCapacity should wait for the previous blocks to finish', async () => {
432
463
  const error = new Error('TimeoutError');
433
464
  error.name = 'TimeoutError';
@@ -496,8 +527,6 @@ describe('StreamUploader', () => {
496
527
  contentBlocks: [
497
528
  {
498
529
  index: 2,
499
- encryptedSize: 4 * 1024 * 1024 + 10000,
500
- hash: 'blockHash',
501
530
  armoredSignature: 'signature',
502
531
  verificationToken: 'verificationToken',
503
532
  },
@@ -121,7 +121,9 @@ export class StreamUploader {
121
121
  this.logger.info(`Starting upload`);
122
122
  await this.encryptAndUploadBlocks(stream, thumbnails, (uploadedBytes) => {
123
123
  fileProgress += uploadedBytes;
124
- onProgress?.(fileProgress);
124
+ if (!failure) {
125
+ onProgress?.(fileProgress);
126
+ }
125
127
  });
126
128
 
127
129
  this.logger.debug(`All blocks uploaded, committing`);
@@ -230,7 +232,7 @@ export class StreamUploader {
230
232
  };
231
233
  await this.uploadManager.commitDraft(
232
234
  this.revisionDraft,
233
- this.manifest,
235
+ await this.getManifest(),
234
236
  extendedAttributes,
235
237
  this.metadata.additionalMetadata,
236
238
  );
@@ -328,8 +330,6 @@ export class StreamUploader {
328
330
  contentBlocks: Array.from(
329
331
  this.encryptedBlocks.values().map((block) => ({
330
332
  index: block.index,
331
- encryptedSize: block.encryptedSize,
332
- hash: block.hash,
333
333
  armoredSignature: block.armoredSignature,
334
334
  verificationToken: block.verificationToken,
335
335
  })),
@@ -337,8 +337,6 @@ export class StreamUploader {
337
337
  thumbnails: Array.from(
338
338
  this.encryptedThumbnails.values().map((block) => ({
339
339
  type: block.type,
340
- encryptedSize: block.encryptedSize,
341
- hash: block.hash,
342
340
  })),
343
341
  ),
344
342
  },
@@ -422,7 +420,7 @@ export class StreamUploader {
422
420
  );
423
421
  this.uploadedThumbnails.push({
424
422
  type: encryptedThumbnail.type,
425
- hash: encryptedThumbnail.hash,
423
+ hashPromise: encryptedThumbnail.hashPromise,
426
424
  encryptedSize: encryptedThumbnail.encryptedSize,
427
425
  originalSize: encryptedThumbnail.originalSize,
428
426
  });
@@ -474,6 +472,10 @@ export class StreamUploader {
474
472
  let attempt = 0;
475
473
 
476
474
  while (true) {
475
+ if (this.isUploadAborted) {
476
+ throw this.error || new AbortError();
477
+ }
478
+
477
479
  attempt++;
478
480
  try {
479
481
  logger.debug(`Uploading`);
@@ -489,7 +491,7 @@ export class StreamUploader {
489
491
  );
490
492
  this.uploadedBlocks.push({
491
493
  index: encryptedBlock.index,
492
- hash: encryptedBlock.hash,
494
+ hashPromise: encryptedBlock.hashPromise,
493
495
  encryptedSize: encryptedBlock.encryptedSize,
494
496
  originalSize: encryptedBlock.originalSize,
495
497
  });
@@ -524,8 +526,6 @@ export class StreamUploader {
524
526
  contentBlocks: [
525
527
  {
526
528
  index: encryptedBlock.index,
527
- encryptedSize: encryptedBlock.encryptedSize,
528
- hash: encryptedBlock.hash,
529
529
  armoredSignature: encryptedBlock.armoredSignature,
530
530
  verificationToken: encryptedBlock.verificationToken,
531
531
  },
@@ -655,12 +655,12 @@ export class StreamUploader {
655
655
  return uploadedBlocks.map((block) => block.originalSize);
656
656
  }
657
657
 
658
- protected get manifest(): Uint8Array<ArrayBuffer> {
658
+ protected async getManifest(): Promise<Uint8Array<ArrayBuffer>> {
659
659
  this.uploadedThumbnails.sort((a, b) => a.type - b.type);
660
660
  this.uploadedBlocks.sort((a, b) => a.index - b.index);
661
661
  const hashes = [
662
- ...this.uploadedThumbnails.map(({ hash }) => hash),
663
- ...this.uploadedBlocks.map(({ hash }) => hash),
662
+ ...(await Promise.all(this.uploadedThumbnails.map(({ hashPromise }) => hashPromise))),
663
+ ...(await Promise.all(this.uploadedBlocks.map(({ hashPromise }) => hashPromise))),
664
664
  ];
665
665
  return mergeUint8Arrays(hashes);
666
666
  }
@@ -135,7 +135,7 @@ export class ProtonDriveClient {
135
135
 
136
136
  const fullConfig = getConfig(config);
137
137
  this.sdkEvents = new SDKEvents(telemetry);
138
- const cryptoModule = new DriveCrypto(openPGPCryptoModule, srpModule);
138
+ const cryptoModule = new DriveCrypto(telemetry, openPGPCryptoModule, srpModule);
139
139
  const apiService = new DriveAPIService(
140
140
  telemetry,
141
141
  this.sdkEvents,
@@ -178,6 +178,7 @@ export class ProtonDriveClient {
178
178
  cryptoModule,
179
179
  this.shares,
180
180
  this.nodes.access,
181
+ featureFlagProvider,
181
182
  fullConfig.clientUid,
182
183
  );
183
184
  this.devices = initDevicesModule(
@@ -18,6 +18,7 @@ import {
18
18
  ProtonInvitationWithNode,
19
19
  NodeResult,
20
20
  NodeResultWithError,
21
+ PhotoTag,
21
22
  } from './interface';
22
23
  import { getConfig } from './config';
23
24
  import { DriveCrypto } from './crypto';
@@ -41,11 +42,11 @@ import {
41
42
  initPhotosNodesModule,
42
43
  AlbumItem,
43
44
  TimelineItem,
44
- PhotoTag,
45
45
  } from './internal/photos';
46
46
  import { SDKEvents } from './internal/sdkEvents';
47
47
  import { initSharesModule } from './internal/shares';
48
48
  import { initSharingModule } from './internal/sharing';
49
+ import { NullFeatureFlagProvider } from './featureFlags';
49
50
 
50
51
  /**
51
52
  * ProtonDrivePhotosClient is the interface to access Photos functionality.
@@ -84,16 +85,20 @@ export class ProtonDrivePhotosClient {
84
85
  srpModule,
85
86
  config,
86
87
  telemetry,
88
+ featureFlagProvider,
87
89
  latestEventIdProvider,
88
90
  }: ProtonDriveClientContructorParameters) {
89
91
  if (!telemetry) {
90
92
  telemetry = new Telemetry();
91
93
  }
94
+ if (!featureFlagProvider) {
95
+ featureFlagProvider = new NullFeatureFlagProvider();
96
+ }
92
97
  this.logger = telemetry.getLogger('photos-interface');
93
98
 
94
99
  const fullConfig = getConfig(config);
95
100
  this.sdkEvents = new SDKEvents(telemetry);
96
- const cryptoModule = new DriveCrypto(openPGPCryptoModule, srpModule);
101
+ const cryptoModule = new DriveCrypto(telemetry, openPGPCryptoModule, srpModule);
97
102
  const apiService = new DriveAPIService(
98
103
  telemetry,
99
104
  this.sdkEvents,
@@ -147,6 +152,7 @@ export class ProtonDrivePhotosClient {
147
152
  cryptoModule,
148
153
  this.photoShares,
149
154
  this.nodes.access,
155
+ featureFlagProvider,
150
156
  fullConfig.clientUid,
151
157
  );
152
158
 
@@ -636,4 +642,35 @@ export class ProtonDrivePhotosClient {
636
642
  this.logger.info(`Removing ${photoNodeUids.length} photos from album ${getUid(albumNodeUid)}`);
637
643
  yield* this.photos.albums.removePhotos(getUid(albumNodeUid), getUids(photoNodeUids), signal);
638
644
  }
645
+
646
+ /**
647
+ * Updates photos with the given settings: add or remove tags.
648
+ *
649
+ * Assigning a favorite tag to a photo that is not in the timeline will
650
+ * result in a move operation to the timeline. The photo will stay in
651
+ * the album.
652
+ *
653
+ * @param nodeUids - The UIDs of the photos to update.
654
+ * @param settings - addTags: tags to add, removeTags: tags to remove.
655
+ * @param signal - An optional abort signal to cancel the operation.
656
+ * @returns An async generator of per-photo results.
657
+ */
658
+ async *updatePhotos(
659
+ photos: {
660
+ nodeUid: NodeOrUid;
661
+ tagsToAdd?: PhotoTag[];
662
+ tagsToRemove?: PhotoTag[];
663
+ }[],
664
+ signal?: AbortSignal,
665
+ ): AsyncGenerator<NodeResultWithError> {
666
+ this.logger.info(`Updating ${photos.length} photos`);
667
+ yield* this.photos.photos.updatePhotos(
668
+ photos.map((p) => ({
669
+ nodeUid: getUid(p.nodeUid),
670
+ tagsToAdd: p.tagsToAdd || [],
671
+ tagsToRemove: p.tagsToRemove || [],
672
+ })),
673
+ signal,
674
+ );
675
+ }
639
676
  }
@@ -20,6 +20,7 @@ import {
20
20
  NodeResult,
21
21
  SDKEvent,
22
22
  MemberRole,
23
+ FeatureFlagProvider,
23
24
  } from './interface';
24
25
  import { Telemetry } from './telemetry';
25
26
  import {
@@ -33,6 +34,7 @@ import { initDownloadModule } from './internal/download';
33
34
  import { SDKEvents } from './internal/sdkEvents';
34
35
  import { initSharingPublicModule, UnauthDriveAPIService } from './internal/sharingPublic';
35
36
  import { initUploadModule } from './internal/upload';
37
+ import { NullFeatureFlagProvider } from './featureFlags';
36
38
  import { NodesSecurityScanResult } from './internal/sharingPublic/nodesSecurity';
37
39
 
38
40
  /**
@@ -93,6 +95,7 @@ export class ProtonDrivePublicLinkClient {
93
95
  srpModule,
94
96
  config,
95
97
  telemetry,
98
+ featureFlagProvider,
96
99
  url,
97
100
  token,
98
101
  publicShareKey,
@@ -106,6 +109,7 @@ export class ProtonDrivePublicLinkClient {
106
109
  srpModule: SRPModule;
107
110
  config?: ProtonDriveConfig;
108
111
  telemetry?: ProtonDriveTelemetry;
112
+ featureFlagProvider?: FeatureFlagProvider;
109
113
  url: string;
110
114
  token: string;
111
115
  publicShareKey: PrivateKey;
@@ -116,6 +120,9 @@ export class ProtonDrivePublicLinkClient {
116
120
  if (!telemetry) {
117
121
  telemetry = new Telemetry();
118
122
  }
123
+ if (!featureFlagProvider) {
124
+ featureFlagProvider = new NullFeatureFlagProvider();
125
+ }
119
126
  this.logger = telemetry.getLogger('publicLink-interface');
120
127
 
121
128
  // Use only in memory cache for public link as there are no events to keep it up to date if persisted.
@@ -132,7 +139,7 @@ export class ProtonDrivePublicLinkClient {
132
139
  fullConfig.baseUrl,
133
140
  fullConfig.language,
134
141
  );
135
- const cryptoModule = new DriveCrypto(openPGPCryptoModule, srpModule);
142
+ const cryptoModule = new DriveCrypto(telemetry, openPGPCryptoModule, srpModule);
136
143
  this.sharingPublic = initSharingPublicModule(
137
144
  telemetry,
138
145
  apiService,
@@ -165,6 +172,7 @@ export class ProtonDrivePublicLinkClient {
165
172
  cryptoModule,
166
173
  this.sharingPublic.shares,
167
174
  this.sharingPublic.nodes.access,
175
+ featureFlagProvider,
168
176
  fullConfig.clientUid,
169
177
  );
170
178
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"albums.js","sourceRoot":"","sources":["../../../src/internal/photos/albums.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"albums.test.js","sourceRoot":"","sources":["../../../src/internal/photos/albums.test.ts"],"names":[],"mappings":"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"}