@protontech/drive-sdk 0.7.2 → 0.8.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.
- package/dist/crypto/driveCrypto.js +1 -1
- package/dist/crypto/driveCrypto.js.map +1 -1
- package/dist/crypto/interface.d.ts +3 -1
- package/dist/crypto/openPGPCrypto.d.ts +4 -1
- package/dist/crypto/openPGPCrypto.js +2 -1
- package/dist/crypto/openPGPCrypto.js.map +1 -1
- package/dist/interface/account.d.ts +6 -0
- package/dist/internal/apiService/driveTypes.d.ts +197 -22
- package/dist/internal/nodes/apiService.d.ts +1 -1
- package/dist/internal/nodes/apiService.js +2 -2
- package/dist/internal/nodes/apiService.js.map +1 -1
- package/dist/internal/nodes/cryptoService.d.ts +1 -0
- package/dist/internal/nodes/cryptoService.js +28 -4
- package/dist/internal/nodes/cryptoService.js.map +1 -1
- package/dist/internal/nodes/cryptoService.test.js +70 -2
- package/dist/internal/nodes/cryptoService.test.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.d.ts +1 -1
- package/dist/internal/nodes/nodesManagement.js +1 -1
- package/dist/internal/nodes/nodesManagement.js.map +1 -1
- package/dist/internal/photos/timeline.d.ts +1 -1
- package/dist/internal/photos/timeline.js +4 -4
- package/dist/internal/photos/timeline.js.map +1 -1
- package/dist/internal/photos/timeline.test.js +34 -7
- package/dist/internal/photos/timeline.test.js.map +1 -1
- package/dist/internal/shares/apiService.js +2 -0
- package/dist/internal/shares/apiService.js.map +1 -1
- package/dist/internal/sharingPublic/nodes.d.ts +1 -1
- package/dist/internal/sharingPublic/nodes.js +2 -2
- package/dist/internal/sharingPublic/nodes.js.map +1 -1
- package/dist/protonDriveClient.d.ts +1 -1
- package/dist/protonDriveClient.js +2 -2
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePhotosClient.d.ts +20 -0
- package/dist/protonDrivePhotosClient.js +25 -2
- package/dist/protonDrivePhotosClient.js.map +1 -1
- package/dist/protonDrivePublicLinkClient.d.ts +3 -1
- package/dist/protonDrivePublicLinkClient.js +4 -2
- package/dist/protonDrivePublicLinkClient.js.map +1 -1
- package/package.json +1 -1
- package/src/crypto/driveCrypto.ts +1 -0
- package/src/crypto/interface.ts +1 -0
- package/src/crypto/openPGPCrypto.ts +3 -0
- package/src/interface/account.ts +6 -0
- package/src/internal/apiService/driveTypes.ts +197 -22
- package/src/internal/nodes/apiService.ts +13 -6
- package/src/internal/nodes/cryptoService.test.ts +113 -2
- package/src/internal/nodes/cryptoService.ts +53 -8
- package/src/internal/nodes/nodesManagement.ts +1 -1
- package/src/internal/photos/timeline.test.ts +39 -7
- package/src/internal/photos/timeline.ts +4 -4
- package/src/internal/shares/apiService.ts +3 -1
- package/src/internal/sharingPublic/nodes.ts +2 -2
- package/src/protonDriveClient.ts +2 -2
- package/src/protonDrivePhotosClient.ts +26 -2
- package/src/protonDrivePublicLinkClient.ts +4 -2
|
@@ -491,7 +491,8 @@ export interface paths {
|
|
|
491
491
|
get?: never;
|
|
492
492
|
put?: never;
|
|
493
493
|
/**
|
|
494
|
-
* Delete
|
|
494
|
+
* Delete drafts from folder
|
|
495
|
+
* @deprecated
|
|
495
496
|
* @description Permanently delete children from folder, skipping trash. Can only be done for draft links.
|
|
496
497
|
*/
|
|
497
498
|
post: operations["post_drive-shares-{shareID}-folders-{linkID}-delete_multiple"];
|
|
@@ -531,8 +532,8 @@ export interface paths {
|
|
|
531
532
|
get?: never;
|
|
532
533
|
put?: never;
|
|
533
534
|
/**
|
|
534
|
-
* Trash children
|
|
535
|
-
* @
|
|
535
|
+
* Trash children from folder
|
|
536
|
+
* @deprecated
|
|
536
537
|
*/
|
|
537
538
|
post: operations["post_drive-shares-{shareID}-folders-{linkID}-trash_multiple"];
|
|
538
539
|
delete?: never;
|
|
@@ -672,8 +673,8 @@ export interface paths {
|
|
|
672
673
|
get?: never;
|
|
673
674
|
put?: never;
|
|
674
675
|
/**
|
|
675
|
-
* Delete
|
|
676
|
-
* @description Permanently delete
|
|
676
|
+
* Delete drafts
|
|
677
|
+
* @description Permanently delete files, skipping trash. Can only be done for draft links.
|
|
677
678
|
*/
|
|
678
679
|
post: operations["post_drive-v2-volumes-{volumeID}-delete_multiple"];
|
|
679
680
|
delete?: never;
|
|
@@ -815,6 +816,32 @@ export interface paths {
|
|
|
815
816
|
patch?: never;
|
|
816
817
|
trace?: never;
|
|
817
818
|
};
|
|
819
|
+
"/drive/v2/volumes/{volumeID}/remove-mine": {
|
|
820
|
+
parameters: {
|
|
821
|
+
query?: never;
|
|
822
|
+
header?: never;
|
|
823
|
+
path?: never;
|
|
824
|
+
cookie?: never;
|
|
825
|
+
};
|
|
826
|
+
get?: never;
|
|
827
|
+
put?: never;
|
|
828
|
+
/**
|
|
829
|
+
* Remove my nodes skipping trash
|
|
830
|
+
* @description This is called by Web SDK on public sharing to remove active nodes created by the same user
|
|
831
|
+
* as a way to delete wrongly uploaded files without going to trash. It's supported on the following conditions:
|
|
832
|
+
* - anonymous users must have created the node in their own session
|
|
833
|
+
* - for authenticated users the signature email must match
|
|
834
|
+
* - file/folder must have been created within the last 1 hour
|
|
835
|
+
* - folders must be empty
|
|
836
|
+
* - files must have all revisions created by this user
|
|
837
|
+
*/
|
|
838
|
+
post: operations["post_drive-v2-volumes-{volumeID}-remove-mine"];
|
|
839
|
+
delete?: never;
|
|
840
|
+
options?: never;
|
|
841
|
+
head?: never;
|
|
842
|
+
patch?: never;
|
|
843
|
+
trace?: never;
|
|
844
|
+
};
|
|
818
845
|
"/drive/v2/volumes/{volumeID}/links/{linkID}/rename": {
|
|
819
846
|
parameters: {
|
|
820
847
|
query?: never;
|
|
@@ -829,6 +856,11 @@ export interface paths {
|
|
|
829
856
|
*
|
|
830
857
|
* Clients renaming a file or folder MUST reuse the existing session key
|
|
831
858
|
* for the name as it is also used by shares pointing to the link.
|
|
859
|
+
*
|
|
860
|
+
* Users with access only through a public sharing URL (no editor membership) are limited to renaming
|
|
861
|
+
* their own files and folders:
|
|
862
|
+
* - Unauthenticated users must have created them in their session
|
|
863
|
+
* - Authenticated users' email must match the signature email on the node for folders or active revision for files
|
|
832
864
|
*/
|
|
833
865
|
put: operations["put_drive-v2-volumes-{volumeID}-links-{linkID}-rename"];
|
|
834
866
|
post?: never;
|
|
@@ -852,6 +884,11 @@ export interface paths {
|
|
|
852
884
|
*
|
|
853
885
|
* Clients renaming a file or folder MUST reuse the existing session key
|
|
854
886
|
* for the name as it is also used by shares pointing to the link.
|
|
887
|
+
*
|
|
888
|
+
* Users with access only through a public sharing URL (no editor membership) are limited to renaming
|
|
889
|
+
* their own files and folders:
|
|
890
|
+
* - Unauthenticated users must have created them in their session
|
|
891
|
+
* - Authenticated users' email must match the signature email on the node for folders or active revision for files
|
|
855
892
|
*/
|
|
856
893
|
put: operations["put_drive-shares-{shareID}-links-{linkID}-rename"];
|
|
857
894
|
post?: never;
|
|
@@ -2227,7 +2264,7 @@ export interface paths {
|
|
|
2227
2264
|
get?: never;
|
|
2228
2265
|
put?: never;
|
|
2229
2266
|
/**
|
|
2230
|
-
* Delete
|
|
2267
|
+
* Delete drafts
|
|
2231
2268
|
* @description See /drive/v2/volumes/{volumeID}/delete_multiple for full documentation
|
|
2232
2269
|
*/
|
|
2233
2270
|
post: operations["post_drive-unauth-v2-volumes-{volumeID}-delete_multiple"];
|
|
@@ -2297,6 +2334,26 @@ export interface paths {
|
|
|
2297
2334
|
patch?: never;
|
|
2298
2335
|
trace?: never;
|
|
2299
2336
|
};
|
|
2337
|
+
"/drive/unauth/v2/volumes/{volumeID}/remove-mine": {
|
|
2338
|
+
parameters: {
|
|
2339
|
+
query?: never;
|
|
2340
|
+
header?: never;
|
|
2341
|
+
path?: never;
|
|
2342
|
+
cookie?: never;
|
|
2343
|
+
};
|
|
2344
|
+
get?: never;
|
|
2345
|
+
put?: never;
|
|
2346
|
+
/**
|
|
2347
|
+
* Remove my nodes skipping trash
|
|
2348
|
+
* @description See /drive/v2/volumes/{volumeID}/remove-mine for full documentation
|
|
2349
|
+
*/
|
|
2350
|
+
post: operations["post_drive-unauth-v2-volumes-{volumeID}-remove-mine"];
|
|
2351
|
+
delete?: never;
|
|
2352
|
+
options?: never;
|
|
2353
|
+
head?: never;
|
|
2354
|
+
patch?: never;
|
|
2355
|
+
trace?: never;
|
|
2356
|
+
};
|
|
2300
2357
|
"/drive/unauth/v2/volumes/{volumeID}/links/{linkID}/rename": {
|
|
2301
2358
|
parameters: {
|
|
2302
2359
|
query?: never;
|
|
@@ -2978,6 +3035,30 @@ export interface paths {
|
|
|
2978
3035
|
patch?: never;
|
|
2979
3036
|
trace?: never;
|
|
2980
3037
|
};
|
|
3038
|
+
"/drive/organization/volumes": {
|
|
3039
|
+
parameters: {
|
|
3040
|
+
query?: never;
|
|
3041
|
+
header?: never;
|
|
3042
|
+
path?: never;
|
|
3043
|
+
cookie?: never;
|
|
3044
|
+
};
|
|
3045
|
+
get?: never;
|
|
3046
|
+
put?: never;
|
|
3047
|
+
/**
|
|
3048
|
+
* Create Organization volume
|
|
3049
|
+
* @description Only allowed to Org administrators
|
|
3050
|
+
*
|
|
3051
|
+
* This new volume would have:
|
|
3052
|
+
* + OwnerOrgID filled with the orgID of the request
|
|
3053
|
+
* + specific membership for the owner (OrgAdmin to true)
|
|
3054
|
+
*/
|
|
3055
|
+
post: operations["post_drive-organization-volumes"];
|
|
3056
|
+
delete?: never;
|
|
3057
|
+
options?: never;
|
|
3058
|
+
head?: never;
|
|
3059
|
+
patch?: never;
|
|
3060
|
+
trace?: never;
|
|
3061
|
+
};
|
|
2981
3062
|
"/drive/volumes": {
|
|
2982
3063
|
parameters: {
|
|
2983
3064
|
query?: never;
|
|
@@ -4852,6 +4933,31 @@ export interface components {
|
|
|
4852
4933
|
/** @description Order and visibility of Photo Tags, tags not in the list should not be shown; Use defaults when NULL; Show no tags if empty array. */
|
|
4853
4934
|
PhotoTags?: components["schemas"]["TagType"][] | null;
|
|
4854
4935
|
};
|
|
4936
|
+
CreateOrgVolumeRequestDto: {
|
|
4937
|
+
AddressID: components["schemas"]["AddressID"];
|
|
4938
|
+
/** @description XX's encrypted AddressKeyID. Must be the primary key from the AddressID */
|
|
4939
|
+
AddressKeyID: string;
|
|
4940
|
+
ShareKey: components["schemas"]["PGPPrivateKey"];
|
|
4941
|
+
SharePassphrase: components["schemas"]["PGPMessage"];
|
|
4942
|
+
SharePassphraseSignature: components["schemas"]["PGPSignature"];
|
|
4943
|
+
FolderName: components["schemas"]["PGPMessage"];
|
|
4944
|
+
FolderKey: components["schemas"]["PGPPrivateKey"];
|
|
4945
|
+
FolderPassphrase: components["schemas"]["PGPMessage"];
|
|
4946
|
+
FolderPassphraseSignature: components["schemas"]["PGPSignature"];
|
|
4947
|
+
FolderHashKey: components["schemas"]["PGPMessage"];
|
|
4948
|
+
OrganizationID: components["schemas"]["Id"];
|
|
4949
|
+
/** @description Name of the org. volume. It's plain text so that name can be displayed in UI menu */
|
|
4950
|
+
VolumeName: string;
|
|
4951
|
+
};
|
|
4952
|
+
GetVolumeResponseDto: {
|
|
4953
|
+
Volume: components["schemas"]["VolumeResponseDto"];
|
|
4954
|
+
/**
|
|
4955
|
+
* ProtonResponseCode
|
|
4956
|
+
* @example 1000
|
|
4957
|
+
* @enum {integer}
|
|
4958
|
+
*/
|
|
4959
|
+
Code: 1000;
|
|
4960
|
+
};
|
|
4855
4961
|
CreateVolumeRequestDto: {
|
|
4856
4962
|
AddressID: components["schemas"]["AddressID"];
|
|
4857
4963
|
ShareKey: components["schemas"]["PGPPrivateKey"];
|
|
@@ -4875,15 +4981,6 @@ export interface components {
|
|
|
4875
4981
|
*/
|
|
4876
4982
|
ShareName: string | null;
|
|
4877
4983
|
};
|
|
4878
|
-
GetVolumeResponseDto: {
|
|
4879
|
-
Volume: components["schemas"]["VolumeResponseDto"];
|
|
4880
|
-
/**
|
|
4881
|
-
* ProtonResponseCode
|
|
4882
|
-
* @example 1000
|
|
4883
|
-
* @enum {integer}
|
|
4884
|
-
*/
|
|
4885
|
-
Code: 1000;
|
|
4886
|
-
};
|
|
4887
4984
|
ListVolumesResponseDto: {
|
|
4888
4985
|
Volumes: components["schemas"]["VolumeResponseDto"][];
|
|
4889
4986
|
/**
|
|
@@ -6213,20 +6310,20 @@ export interface components {
|
|
|
6213
6310
|
Album: null | null;
|
|
6214
6311
|
};
|
|
6215
6312
|
/**
|
|
6216
|
-
* @description <p>1=Main, 2=Standard, 3=Device, 4=Photo</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Name</th><th>Description</th></tr><tr><td>1</td><td>Main</td><td>* Root share for my files</td></tr><tr><td>2</td><td>Standard</td><td>* Collaborative share anywhere in the link tree (but not at the root folder as it cannot be shared)</td></tr><tr><td>3</td><td>Device</td><td>* Root share of devices</td></tr><tr><td>4</td><td>Photo</td><td>* Root share for photos</td></tr></table></details></details>
|
|
6313
|
+
* @description <p>1=Main, 2=Standard, 3=Device, 4=Photo</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Name</th><th>Description</th></tr><tr><td>1</td><td>Main</td><td>* Root share for my files</td></tr><tr><td>2</td><td>Standard</td><td>* Collaborative share anywhere in the link tree (but not at the root folder as it cannot be shared)</td></tr><tr><td>3</td><td>Device</td><td>* Root share of devices</td></tr><tr><td>4</td><td>Photo</td><td>* Root share for photos</td></tr><tr><td>5</td><td>Organization</td><td>* Root share for organization</td></tr></table></details></details>
|
|
6217
6314
|
* @enum {integer}
|
|
6218
6315
|
*/
|
|
6219
|
-
ShareType: 1 | 2 | 3 | 4;
|
|
6316
|
+
ShareType: 1 | 2 | 3 | 4 | 5;
|
|
6220
6317
|
/**
|
|
6221
6318
|
* @description <p>1=Active, 3=Restored</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Active</td></tr><tr><td>2</td><td>Deleted</td></tr><tr><td>3</td><td>Restored</td></tr><tr><td>6</td><td>Locked</td></tr></table></details></details>
|
|
6222
6319
|
* @enum {integer}
|
|
6223
6320
|
*/
|
|
6224
6321
|
ShareState: 1 | 2 | 3 | 6;
|
|
6225
6322
|
/**
|
|
6226
|
-
* @description <p>1=Regular, 2=Photo</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Regular</td></tr><tr><td>2</td><td>Photo</td></tr></table></details></details>
|
|
6323
|
+
* @description <p>1=Regular, 2=Photo</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Regular</td></tr><tr><td>2</td><td>Photo</td></tr><tr><td>3</td><td>Organization</td></tr></table></details></details>
|
|
6227
6324
|
* @enum {integer}
|
|
6228
6325
|
*/
|
|
6229
|
-
VolumeType: 1 | 2;
|
|
6326
|
+
VolumeType: 1 | 2 | 3;
|
|
6230
6327
|
/**
|
|
6231
6328
|
* @description <p>1=folder, 2=file</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Folder</td></tr><tr><td>2</td><td>File</td></tr><tr><td>3</td><td>Album</td></tr></table></details></details>
|
|
6232
6329
|
* @enum {integer}
|
|
@@ -6776,10 +6873,10 @@ export interface components {
|
|
|
6776
6873
|
LinkID: components["schemas"]["Id2"];
|
|
6777
6874
|
};
|
|
6778
6875
|
/**
|
|
6779
|
-
* @description <details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Regular</td></tr><tr><td>2</td><td>Photo</td></tr></table></details></details>
|
|
6876
|
+
* @description <details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>1</td><td>Regular</td></tr><tr><td>2</td><td>Photo</td></tr><tr><td>3</td><td>Organization</td></tr></table></details></details>
|
|
6780
6877
|
* @enum {integer}
|
|
6781
6878
|
*/
|
|
6782
|
-
VolumeType2: 1 | 2;
|
|
6879
|
+
VolumeType2: 1 | 2 | 3;
|
|
6783
6880
|
/**
|
|
6784
6881
|
* @description <p>Can be null if the Link was deleted</p><details><summary>See values descriptions</summary><details><summary>See values descriptions</summary><table><tr><th>Value</th><th>Description</th></tr><tr><td>0</td><td>Draft</td></tr><tr><td>1</td><td>Active</td></tr><tr><td>2</td><td>Trashed</td></tr></table></details></details>
|
|
6785
6882
|
* @enum {integer}
|
|
@@ -9119,6 +9216,36 @@ export interface operations {
|
|
|
9119
9216
|
};
|
|
9120
9217
|
};
|
|
9121
9218
|
};
|
|
9219
|
+
"post_drive-v2-volumes-{volumeID}-remove-mine": {
|
|
9220
|
+
parameters: {
|
|
9221
|
+
query?: never;
|
|
9222
|
+
header?: never;
|
|
9223
|
+
path: {
|
|
9224
|
+
volumeID: string;
|
|
9225
|
+
};
|
|
9226
|
+
cookie?: never;
|
|
9227
|
+
};
|
|
9228
|
+
requestBody?: {
|
|
9229
|
+
content: {
|
|
9230
|
+
"application/json": components["schemas"]["LinkIDsRequestDto"];
|
|
9231
|
+
};
|
|
9232
|
+
};
|
|
9233
|
+
responses: {
|
|
9234
|
+
/** @description Ok */
|
|
9235
|
+
200: {
|
|
9236
|
+
headers: {
|
|
9237
|
+
[name: string]: unknown;
|
|
9238
|
+
};
|
|
9239
|
+
content: {
|
|
9240
|
+
"application/json": {
|
|
9241
|
+
/** @enum {integer} */
|
|
9242
|
+
Code?: 1001;
|
|
9243
|
+
Responses?: components["schemas"]["MultiDeleteTransformer"][];
|
|
9244
|
+
};
|
|
9245
|
+
};
|
|
9246
|
+
};
|
|
9247
|
+
};
|
|
9248
|
+
};
|
|
9122
9249
|
"put_drive-v2-volumes-{volumeID}-links-{linkID}-rename": {
|
|
9123
9250
|
parameters: {
|
|
9124
9251
|
query?: never;
|
|
@@ -12150,6 +12277,29 @@ export interface operations {
|
|
|
12150
12277
|
};
|
|
12151
12278
|
};
|
|
12152
12279
|
};
|
|
12280
|
+
"post_drive-unauth-v2-volumes-{volumeID}-remove-mine": {
|
|
12281
|
+
parameters: {
|
|
12282
|
+
query?: never;
|
|
12283
|
+
header?: never;
|
|
12284
|
+
path: {
|
|
12285
|
+
volumeID: string;
|
|
12286
|
+
};
|
|
12287
|
+
cookie?: never;
|
|
12288
|
+
};
|
|
12289
|
+
requestBody?: {
|
|
12290
|
+
content: {
|
|
12291
|
+
"application/json": components["schemas"]["LinkIDsRequestDto"];
|
|
12292
|
+
};
|
|
12293
|
+
};
|
|
12294
|
+
responses: {
|
|
12295
|
+
default: {
|
|
12296
|
+
headers: {
|
|
12297
|
+
[name: string]: unknown;
|
|
12298
|
+
};
|
|
12299
|
+
content?: never;
|
|
12300
|
+
};
|
|
12301
|
+
};
|
|
12302
|
+
};
|
|
12153
12303
|
"put_drive-unauth-v2-volumes-{volumeID}-links-{linkID}-rename": {
|
|
12154
12304
|
parameters: {
|
|
12155
12305
|
query?: never;
|
|
@@ -12404,7 +12554,7 @@ export interface operations {
|
|
|
12404
12554
|
/** @description Show disabled shares as well, i.e. Shares where the ShareMemberShip for the user is non-active (locked), otherwise only return with active Membership */
|
|
12405
12555
|
ShowAll?: 0 | 1;
|
|
12406
12556
|
/** @description Filter on Share Type */
|
|
12407
|
-
ShareType?: 1 | 2 | 3 | 4;
|
|
12557
|
+
ShareType?: 1 | 2 | 3 | 4 | 5;
|
|
12408
12558
|
};
|
|
12409
12559
|
header?: never;
|
|
12410
12560
|
path?: never;
|
|
@@ -13477,6 +13627,31 @@ export interface operations {
|
|
|
13477
13627
|
};
|
|
13478
13628
|
};
|
|
13479
13629
|
};
|
|
13630
|
+
"post_drive-organization-volumes": {
|
|
13631
|
+
parameters: {
|
|
13632
|
+
query?: never;
|
|
13633
|
+
header?: never;
|
|
13634
|
+
path?: never;
|
|
13635
|
+
cookie?: never;
|
|
13636
|
+
};
|
|
13637
|
+
requestBody?: {
|
|
13638
|
+
content: {
|
|
13639
|
+
"application/json": components["schemas"]["CreateOrgVolumeRequestDto"];
|
|
13640
|
+
};
|
|
13641
|
+
};
|
|
13642
|
+
responses: {
|
|
13643
|
+
/** @description Success */
|
|
13644
|
+
200: {
|
|
13645
|
+
headers: {
|
|
13646
|
+
"x-pm-code": 1000;
|
|
13647
|
+
[name: string]: unknown;
|
|
13648
|
+
};
|
|
13649
|
+
content: {
|
|
13650
|
+
"application/json": components["schemas"]["GetVolumeResponseDto"];
|
|
13651
|
+
};
|
|
13652
|
+
};
|
|
13653
|
+
};
|
|
13654
|
+
};
|
|
13480
13655
|
"get_drive-volumes": {
|
|
13481
13656
|
parameters: {
|
|
13482
13657
|
query?: {
|
|
@@ -71,13 +71,20 @@ type PutRestoreNodesRequest = Extract<
|
|
|
71
71
|
type PutRestoreNodesResponse =
|
|
72
72
|
drivePaths['/drive/v2/volumes/{volumeID}/trash/restore_multiple']['put']['responses']['200']['content']['application/json'];
|
|
73
73
|
|
|
74
|
-
type
|
|
74
|
+
type PostDeleteTrashedNodesRequest = Extract<
|
|
75
75
|
drivePaths['/drive/v2/volumes/{volumeID}/trash/delete_multiple']['post']['requestBody'],
|
|
76
76
|
{ content: object }
|
|
77
77
|
>['content']['application/json'];
|
|
78
|
-
type
|
|
78
|
+
type PostDeleteTrashedNodesResponse =
|
|
79
79
|
drivePaths['/drive/v2/volumes/{volumeID}/trash/delete_multiple']['post']['responses']['200']['content']['application/json'];
|
|
80
80
|
|
|
81
|
+
type PostDeleteMyNodesRequest = Extract<
|
|
82
|
+
drivePaths['/drive/v2/volumes/{volumeID}/remove-mine']['post']['requestBody'],
|
|
83
|
+
{ content: object }
|
|
84
|
+
>['content']['application/json'];
|
|
85
|
+
type PostDeleteMyNodesResponse =
|
|
86
|
+
drivePaths['/drive/v2/volumes/{volumeID}/remove-mine']['post']['responses']['200']['content']['application/json'];
|
|
87
|
+
|
|
81
88
|
type PostCreateFolderRequest = Extract<
|
|
82
89
|
drivePaths['/drive/v2/volumes/{volumeID}/folders']['post']['requestBody'],
|
|
83
90
|
{ content: object }
|
|
@@ -446,7 +453,7 @@ export abstract class NodeAPIServiceBase<
|
|
|
446
453
|
|
|
447
454
|
async *deleteTrashedNodes(nodeUids: string[], signal?: AbortSignal): AsyncGenerator<NodeResult> {
|
|
448
455
|
for (const { volumeId, batchNodeIds, batchNodeUids } of groupNodeUidsByVolumeAndIteratePerBatch(nodeUids)) {
|
|
449
|
-
const response = await this.apiService.post<
|
|
456
|
+
const response = await this.apiService.post<PostDeleteTrashedNodesRequest, PostDeleteTrashedNodesResponse>(
|
|
450
457
|
`drive/v2/volumes/${volumeId}/trash/delete_multiple`,
|
|
451
458
|
{
|
|
452
459
|
LinkIDs: batchNodeIds,
|
|
@@ -459,10 +466,10 @@ export abstract class NodeAPIServiceBase<
|
|
|
459
466
|
}
|
|
460
467
|
}
|
|
461
468
|
|
|
462
|
-
async *
|
|
469
|
+
async *deleteMyNodes(nodeUids: string[], signal?: AbortSignal): AsyncGenerator<NodeResult> {
|
|
463
470
|
for (const { volumeId, batchNodeIds, batchNodeUids } of groupNodeUidsByVolumeAndIteratePerBatch(nodeUids)) {
|
|
464
|
-
const response = await this.apiService.post<
|
|
465
|
-
`drive/v2/volumes/${volumeId}/
|
|
471
|
+
const response = await this.apiService.post<PostDeleteMyNodesRequest, PostDeleteMyNodesResponse>(
|
|
472
|
+
`drive/v2/volumes/${volumeId}/remove-mine`,
|
|
466
473
|
{
|
|
467
474
|
LinkIDs: batchNodeIds,
|
|
468
475
|
},
|
|
@@ -20,6 +20,9 @@ describe('nodesCryptoService', () => {
|
|
|
20
20
|
|
|
21
21
|
let cryptoService: NodesCryptoService;
|
|
22
22
|
|
|
23
|
+
const publicAddressKey = { _idx: 21312 };
|
|
24
|
+
const ownPrivateAddressKey = { id: 'id', key: 'key' as unknown as PrivateKey };
|
|
25
|
+
|
|
23
26
|
beforeEach(() => {
|
|
24
27
|
jest.clearAllMocks();
|
|
25
28
|
|
|
@@ -71,7 +74,15 @@ describe('nodesCryptoService', () => {
|
|
|
71
74
|
};
|
|
72
75
|
account = {
|
|
73
76
|
// @ts-expect-error No need to implement all methods for mocking
|
|
74
|
-
getPublicKeys: jest.fn(async () => [
|
|
77
|
+
getPublicKeys: jest.fn(async () => [publicAddressKey]),
|
|
78
|
+
getOwnAddresses: jest.fn(async () => [
|
|
79
|
+
{
|
|
80
|
+
email: 'email',
|
|
81
|
+
addressId: 'addressId',
|
|
82
|
+
primaryKeyIndex: 0,
|
|
83
|
+
keys: [ownPrivateAddressKey],
|
|
84
|
+
},
|
|
85
|
+
]),
|
|
75
86
|
};
|
|
76
87
|
// @ts-expect-error No need to implement all methods for mocking
|
|
77
88
|
sharesService = {
|
|
@@ -576,6 +587,7 @@ describe('nodesCryptoService', () => {
|
|
|
576
587
|
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
577
588
|
file: {
|
|
578
589
|
base64ContentKeyPacket: 'base64ContentKeyPacket',
|
|
590
|
+
armoredContentKeyPacketSignature: 'armoredContentKeyPacketSignature',
|
|
579
591
|
},
|
|
580
592
|
activeRevision: {
|
|
581
593
|
uid: 'revisionUid',
|
|
@@ -764,7 +776,7 @@ describe('nodesCryptoService', () => {
|
|
|
764
776
|
});
|
|
765
777
|
});
|
|
766
778
|
|
|
767
|
-
it('on content key packet', async () => {
|
|
779
|
+
it('on content key packet without fallback verification', async () => {
|
|
768
780
|
driveCrypto.decryptAndVerifySessionKey = jest.fn(
|
|
769
781
|
async () =>
|
|
770
782
|
Promise.resolve({
|
|
@@ -789,6 +801,105 @@ describe('nodesCryptoService', () => {
|
|
|
789
801
|
error: 'verification error',
|
|
790
802
|
});
|
|
791
803
|
});
|
|
804
|
+
|
|
805
|
+
it('on content key packet with successful fallback verification', async () => {
|
|
806
|
+
driveCrypto.decryptAndVerifySessionKey = jest
|
|
807
|
+
.fn()
|
|
808
|
+
.mockImplementationOnce(
|
|
809
|
+
async () =>
|
|
810
|
+
Promise.resolve({
|
|
811
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
812
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
813
|
+
verificationErrors: [new Error('verification error')],
|
|
814
|
+
}) as any,
|
|
815
|
+
)
|
|
816
|
+
.mockImplementationOnce(
|
|
817
|
+
async () =>
|
|
818
|
+
Promise.resolve({
|
|
819
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
820
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
821
|
+
}) as any,
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
const result = await cryptoService.decryptNode(
|
|
825
|
+
{
|
|
826
|
+
...encryptedNode,
|
|
827
|
+
creationTime: new Date('2022-01-01'),
|
|
828
|
+
},
|
|
829
|
+
parentKey,
|
|
830
|
+
);
|
|
831
|
+
verifyResult(result);
|
|
832
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledTimes(2);
|
|
833
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledWith(
|
|
834
|
+
'base64ContentKeyPacket',
|
|
835
|
+
'armoredContentKeyPacketSignature',
|
|
836
|
+
'decryptedKey',
|
|
837
|
+
['decryptedKey', publicAddressKey],
|
|
838
|
+
);
|
|
839
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledWith(
|
|
840
|
+
'base64ContentKeyPacket',
|
|
841
|
+
'armoredContentKeyPacketSignature',
|
|
842
|
+
'decryptedKey',
|
|
843
|
+
[ownPrivateAddressKey.key],
|
|
844
|
+
);
|
|
845
|
+
expect(telemetry.recordMetric).not.toHaveBeenCalled();
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
it('on content key packet with failed fallback verification', async () => {
|
|
849
|
+
driveCrypto.decryptAndVerifySessionKey = jest
|
|
850
|
+
.fn()
|
|
851
|
+
.mockImplementationOnce(
|
|
852
|
+
async () =>
|
|
853
|
+
Promise.resolve({
|
|
854
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
855
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
856
|
+
verificationErrors: [new Error('verification error')],
|
|
857
|
+
}) as any,
|
|
858
|
+
)
|
|
859
|
+
.mockImplementationOnce(
|
|
860
|
+
async () =>
|
|
861
|
+
Promise.resolve({
|
|
862
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
863
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
864
|
+
verificationErrors: [new Error('fallback verification error')],
|
|
865
|
+
}) as any,
|
|
866
|
+
);
|
|
867
|
+
|
|
868
|
+
const result = await cryptoService.decryptNode(
|
|
869
|
+
{
|
|
870
|
+
...encryptedNode,
|
|
871
|
+
creationTime: new Date('2022-01-01'),
|
|
872
|
+
},
|
|
873
|
+
parentKey,
|
|
874
|
+
);
|
|
875
|
+
verifyResult(result, {
|
|
876
|
+
keyAuthor: {
|
|
877
|
+
ok: false,
|
|
878
|
+
error: {
|
|
879
|
+
claimedAuthor: 'signatureEmail',
|
|
880
|
+
error: 'Signature verification for content key failed: verification error',
|
|
881
|
+
},
|
|
882
|
+
},
|
|
883
|
+
});
|
|
884
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledTimes(2);
|
|
885
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledWith(
|
|
886
|
+
'base64ContentKeyPacket',
|
|
887
|
+
'armoredContentKeyPacketSignature',
|
|
888
|
+
'decryptedKey',
|
|
889
|
+
['decryptedKey', publicAddressKey],
|
|
890
|
+
);
|
|
891
|
+
expect(driveCrypto.decryptAndVerifySessionKey).toHaveBeenCalledWith(
|
|
892
|
+
'base64ContentKeyPacket',
|
|
893
|
+
'armoredContentKeyPacketSignature',
|
|
894
|
+
'decryptedKey',
|
|
895
|
+
[ownPrivateAddressKey.key],
|
|
896
|
+
);
|
|
897
|
+
verifyLogEventVerificationError({
|
|
898
|
+
field: 'nodeContentKey',
|
|
899
|
+
error: 'verification error',
|
|
900
|
+
fromBefore2024: true,
|
|
901
|
+
});
|
|
902
|
+
});
|
|
792
903
|
});
|
|
793
904
|
|
|
794
905
|
describe('should decrypt with decryption issues', () => {
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
EncryptedRevision,
|
|
26
26
|
DecryptedUnparsedRevision,
|
|
27
27
|
NodeSigningKeys,
|
|
28
|
+
EncryptedNodeFileCrypto,
|
|
28
29
|
} from './interface';
|
|
29
30
|
|
|
30
31
|
export interface NodesCryptoReporter {
|
|
@@ -200,14 +201,7 @@ export class NodesCryptoService {
|
|
|
200
201
|
if ('file' in node.encryptedCrypto) {
|
|
201
202
|
const [activeRevisionPromise, contentKeyPacketSessionKeyPromise] = [
|
|
202
203
|
this.decryptRevision(node.uid, node.encryptedCrypto.activeRevision, key),
|
|
203
|
-
this.
|
|
204
|
-
node.encryptedCrypto.file.base64ContentKeyPacket,
|
|
205
|
-
node.encryptedCrypto.file.armoredContentKeyPacketSignature,
|
|
206
|
-
key,
|
|
207
|
-
// Content key packet is signed with the node key, but
|
|
208
|
-
// in the past some clients signed with the address key.
|
|
209
|
-
[key, ...keyVerificationKeys],
|
|
210
|
-
),
|
|
204
|
+
this.decryptContentKeyPacket(node, node.encryptedCrypto, key, keyVerificationKeys),
|
|
211
205
|
];
|
|
212
206
|
|
|
213
207
|
try {
|
|
@@ -502,6 +496,57 @@ export class NodesCryptoService {
|
|
|
502
496
|
};
|
|
503
497
|
}
|
|
504
498
|
|
|
499
|
+
private async decryptContentKeyPacket(
|
|
500
|
+
node: EncryptedNode,
|
|
501
|
+
encryptedCrypto: EncryptedNodeFileCrypto,
|
|
502
|
+
key: PrivateKey,
|
|
503
|
+
keyVerificationKeys: PublicKey[],
|
|
504
|
+
): Promise<{
|
|
505
|
+
sessionKey: SessionKey;
|
|
506
|
+
verified?: VERIFICATION_STATUS;
|
|
507
|
+
verificationErrors?: Error[];
|
|
508
|
+
}> {
|
|
509
|
+
const result = await this.driveCrypto.decryptAndVerifySessionKey(
|
|
510
|
+
encryptedCrypto.file.base64ContentKeyPacket,
|
|
511
|
+
encryptedCrypto.file.armoredContentKeyPacketSignature,
|
|
512
|
+
key,
|
|
513
|
+
// Content key packet is signed with the node key, but
|
|
514
|
+
// in the past some clients signed with the address key.
|
|
515
|
+
[key, ...keyVerificationKeys],
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
// Return right away if the verification is signed or not signed.
|
|
519
|
+
// If the verification is failing and the file is before 2023, try
|
|
520
|
+
// to decrypt with all owners keys. Because of the old nodes signed
|
|
521
|
+
// with address key instead of node key, when the node was renamed
|
|
522
|
+
// or moved, it could change the address but without updating the
|
|
523
|
+
// content key packet, which is now failing.
|
|
524
|
+
if (result.verified !== VERIFICATION_STATUS.SIGNED_AND_INVALID || node.creationTime > new Date(2023, 0, 1)) {
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const allAddresses = await this.account.getOwnAddresses();
|
|
529
|
+
const allKeys = allAddresses.flatMap((address) => address.keys.map(({ key }) => key));
|
|
530
|
+
|
|
531
|
+
const resultWithAllKeys = await this.driveCrypto.decryptAndVerifySessionKey(
|
|
532
|
+
encryptedCrypto.file.base64ContentKeyPacket,
|
|
533
|
+
encryptedCrypto.file.armoredContentKeyPacketSignature,
|
|
534
|
+
key,
|
|
535
|
+
// Content key packet is signed with the node key, but
|
|
536
|
+
// in the past some clients signed with the address key.
|
|
537
|
+
allKeys,
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
// Return original result with original error if the fallback verification also fails.
|
|
541
|
+
if (resultWithAllKeys.verified === VERIFICATION_STATUS.SIGNED_AND_VALID) {
|
|
542
|
+
this.logger.warn(
|
|
543
|
+
'Content key packet signature verification failed, but fallback to all addresses succeeded',
|
|
544
|
+
);
|
|
545
|
+
return resultWithAllKeys;
|
|
546
|
+
}
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
|
|
505
550
|
private async decryptExtendedAttributes(
|
|
506
551
|
node: { uid: string; creationTime: Date },
|
|
507
552
|
encryptedExtendedAttributes: string | undefined,
|
|
@@ -293,7 +293,7 @@ export abstract class NodesManagementBase<
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
async *
|
|
296
|
+
async *deleteTrashedNodes(nodeUids: string[], signal?: AbortSignal): AsyncGenerator<NodeResult> {
|
|
297
297
|
for await (const result of this.apiService.deleteTrashedNodes(nodeUids, signal)) {
|
|
298
298
|
if (result.ok) {
|
|
299
299
|
await this.nodesAccess.notifyNodeDeleted(result.uid);
|