@protontech/drive-sdk 0.1.0 → 0.1.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.
- package/dist/cache/memoryCache.js +0 -1
- package/dist/cache/memoryCache.js.map +1 -1
- package/dist/cache/memoryCache.test.js +2 -4
- package/dist/cache/memoryCache.test.js.map +1 -1
- package/dist/cache/nullCache.js +0 -1
- package/dist/cache/nullCache.js.map +1 -1
- package/dist/crypto/driveCrypto.d.ts +2 -5
- package/dist/crypto/driveCrypto.js +7 -12
- package/dist/crypto/driveCrypto.js.map +1 -1
- package/dist/crypto/driveCrypto.test.js +14 -14
- package/dist/crypto/openPGPCrypto.js +3 -3
- package/dist/crypto/openPGPCrypto.js.map +1 -1
- package/dist/diagnostic/eventsGenerator.js +1 -1
- package/dist/diagnostic/eventsGenerator.js.map +1 -1
- package/dist/diagnostic/httpClient.d.ts +1 -1
- package/dist/diagnostic/httpClient.js.map +1 -1
- package/dist/diagnostic/index.d.ts +3 -3
- package/dist/diagnostic/index.js.map +1 -1
- package/dist/diagnostic/integrityVerificationStream.js +1 -1
- package/dist/diagnostic/integrityVerificationStream.js.map +1 -1
- package/dist/diagnostic/interface.d.ts +2 -2
- package/dist/diagnostic/sdkDiagnostic.d.ts +3 -3
- package/dist/diagnostic/sdkDiagnostic.js +8 -2
- package/dist/diagnostic/sdkDiagnostic.js.map +1 -1
- package/dist/diagnostic/sdkDiagnosticFull.d.ts +4 -4
- package/dist/diagnostic/sdkDiagnosticFull.js.map +1 -1
- package/dist/diagnostic/telemetry.js.map +1 -1
- package/dist/diagnostic/zipGenerators.js +2 -2
- package/dist/diagnostic/zipGenerators.js.map +1 -1
- package/dist/diagnostic/zipGenerators.test.js +1 -1
- package/dist/diagnostic/zipGenerators.test.js.map +1 -1
- package/dist/interface/events.d.ts +2 -4
- package/dist/interface/events.js.map +1 -1
- package/dist/interface/index.d.ts +5 -5
- package/dist/interface/index.js +0 -1
- package/dist/interface/index.js.map +1 -1
- package/dist/interface/result.js.map +1 -1
- package/dist/interface/sharing.d.ts +1 -0
- package/dist/interface/sharing.js.map +1 -1
- package/dist/interface/telemetry.js +0 -8
- package/dist/interface/telemetry.js.map +1 -1
- package/dist/interface/thumbnail.js.map +1 -1
- package/dist/interface/upload.d.ts +1 -1
- package/dist/internal/apiService/apiService.d.ts +1 -1
- package/dist/internal/apiService/apiService.js +7 -11
- package/dist/internal/apiService/apiService.js.map +1 -1
- package/dist/internal/apiService/apiService.test.js +55 -48
- package/dist/internal/apiService/apiService.test.js.map +1 -1
- package/dist/internal/apiService/coreTypes.d.ts +2356 -2356
- package/dist/internal/apiService/driveTypes.d.ts +1680 -1680
- package/dist/internal/apiService/errors.js +14 -8
- package/dist/internal/apiService/errors.js.map +1 -1
- package/dist/internal/apiService/errors.test.js +17 -12
- package/dist/internal/apiService/errors.test.js.map +1 -1
- package/dist/internal/apiService/transformers.d.ts +1 -1
- package/dist/internal/apiService/transformers.js +1 -1
- package/dist/internal/asyncIteratorMap.test.js +2 -2
- package/dist/internal/asyncIteratorMap.test.js.map +1 -1
- package/dist/internal/asyncIteratorRace.d.ts +13 -0
- package/dist/internal/asyncIteratorRace.js +59 -0
- package/dist/internal/asyncIteratorRace.js.map +1 -0
- package/dist/internal/asyncIteratorRace.test.d.ts +1 -0
- package/dist/internal/asyncIteratorRace.test.js +119 -0
- package/dist/internal/asyncIteratorRace.test.js.map +1 -0
- package/dist/internal/batch.d.ts +1 -0
- package/dist/internal/batch.js +12 -0
- package/dist/internal/batch.js.map +1 -0
- package/dist/internal/batch.test.d.ts +1 -0
- package/dist/internal/batch.test.js +41 -0
- package/dist/internal/batch.test.js.map +1 -0
- package/dist/internal/batchLoading.js.map +1 -1
- package/dist/internal/batchLoading.test.js +13 -13
- package/dist/internal/batchLoading.test.js.map +1 -1
- package/dist/internal/devices/apiService.d.ts +3 -3
- package/dist/internal/devices/apiService.js +2 -2
- package/dist/internal/devices/apiService.js.map +1 -1
- package/dist/internal/devices/cryptoService.js +1 -2
- package/dist/internal/devices/cryptoService.js.map +1 -1
- package/dist/internal/devices/index.d.ts +5 -5
- package/dist/internal/devices/index.js.map +1 -1
- package/dist/internal/devices/interface.d.ts +3 -3
- package/dist/internal/devices/manager.js +2 -2
- package/dist/internal/devices/manager.js.map +1 -1
- package/dist/internal/devices/manager.test.js +38 -7
- package/dist/internal/devices/manager.test.js.map +1 -1
- package/dist/internal/download/apiService.d.ts +4 -4
- package/dist/internal/download/apiService.js +0 -1
- package/dist/internal/download/apiService.js.map +1 -1
- package/dist/internal/download/cryptoService.d.ts +4 -4
- package/dist/internal/download/cryptoService.js +6 -5
- package/dist/internal/download/cryptoService.js.map +1 -1
- package/dist/internal/download/fileDownloader.d.ts +4 -4
- package/dist/internal/download/fileDownloader.js +3 -2
- package/dist/internal/download/fileDownloader.js.map +1 -1
- package/dist/internal/download/fileDownloader.test.js +1 -1
- package/dist/internal/download/fileDownloader.test.js.map +1 -1
- package/dist/internal/download/index.d.ts +5 -5
- package/dist/internal/download/index.js +5 -5
- package/dist/internal/download/index.js.map +1 -1
- package/dist/internal/download/interface.d.ts +3 -4
- package/dist/internal/download/telemetry.d.ts +3 -3
- package/dist/internal/download/telemetry.js +4 -2
- package/dist/internal/download/telemetry.js.map +1 -1
- package/dist/internal/download/telemetry.test.js +8 -8
- package/dist/internal/download/telemetry.test.js.map +1 -1
- package/dist/internal/download/thumbnailDownloader.d.ts +4 -4
- package/dist/internal/download/thumbnailDownloader.js +6 -6
- package/dist/internal/download/thumbnailDownloader.js.map +1 -1
- package/dist/internal/download/thumbnailDownloader.test.js.map +1 -1
- package/dist/internal/errors.d.ts +1 -1
- package/dist/internal/errors.js +1 -3
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/events/apiService.d.ts +2 -2
- package/dist/internal/events/apiService.js +9 -5
- package/dist/internal/events/apiService.js.map +1 -1
- package/dist/internal/events/coreEventManager.d.ts +3 -3
- package/dist/internal/events/coreEventManager.js.map +1 -1
- package/dist/internal/events/coreEventManager.test.js +14 -14
- package/dist/internal/events/eventManager.d.ts +1 -1
- package/dist/internal/events/eventManager.js +0 -1
- package/dist/internal/events/eventManager.js.map +1 -1
- package/dist/internal/events/eventManager.test.js +34 -25
- package/dist/internal/events/eventManager.test.js.map +1 -1
- package/dist/internal/events/index.d.ts +6 -6
- package/dist/internal/events/index.js.map +1 -1
- package/dist/internal/events/interface.d.ts +1 -1
- package/dist/internal/events/interface.js +0 -1
- package/dist/internal/events/interface.js.map +1 -1
- package/dist/internal/events/volumeEventManager.d.ts +3 -3
- package/dist/internal/events/volumeEventManager.js.map +1 -1
- package/dist/internal/events/volumeEventManager.test.js +55 -55
- package/dist/internal/events/volumeEventManager.test.js.map +1 -1
- package/dist/internal/nodes/apiService.d.ts +4 -3
- package/dist/internal/nodes/apiService.js +36 -15
- package/dist/internal/nodes/apiService.js.map +1 -1
- package/dist/internal/nodes/apiService.test.js +60 -41
- package/dist/internal/nodes/apiService.test.js.map +1 -1
- package/dist/internal/nodes/cache.d.ts +5 -5
- package/dist/internal/nodes/cache.js +14 -7
- package/dist/internal/nodes/cache.js.map +1 -1
- package/dist/internal/nodes/cache.test.js +31 -9
- package/dist/internal/nodes/cache.test.js.map +1 -1
- package/dist/internal/nodes/cryptoCache.d.ts +2 -2
- package/dist/internal/nodes/cryptoCache.js.map +1 -1
- package/dist/internal/nodes/cryptoCache.test.js +24 -4
- package/dist/internal/nodes/cryptoCache.test.js.map +1 -1
- package/dist/internal/nodes/cryptoService.d.ts +3 -3
- package/dist/internal/nodes/cryptoService.js +11 -17
- package/dist/internal/nodes/cryptoService.js.map +1 -1
- package/dist/internal/nodes/cryptoService.test.js +320 -241
- package/dist/internal/nodes/cryptoService.test.js.map +1 -1
- package/dist/internal/nodes/events.d.ts +3 -3
- package/dist/internal/nodes/events.js.map +1 -1
- package/dist/internal/nodes/events.test.js +27 -21
- package/dist/internal/nodes/events.test.js.map +1 -1
- package/dist/internal/nodes/extendedAttributes.d.ts +1 -1
- package/dist/internal/nodes/extendedAttributes.js +3 -1
- package/dist/internal/nodes/extendedAttributes.js.map +1 -1
- package/dist/internal/nodes/extendedAttributes.test.js +7 -10
- package/dist/internal/nodes/extendedAttributes.test.js.map +1 -1
- package/dist/internal/nodes/index.d.ts +10 -10
- package/dist/internal/nodes/index.js.map +1 -1
- package/dist/internal/nodes/index.test.d.ts +1 -0
- package/dist/internal/nodes/index.test.js +106 -0
- package/dist/internal/nodes/index.test.js.map +1 -0
- package/dist/internal/nodes/interface.d.ts +2 -2
- package/dist/internal/nodes/nodesAccess.d.ts +7 -7
- package/dist/internal/nodes/nodesAccess.js +28 -16
- package/dist/internal/nodes/nodesAccess.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.test.js +39 -13
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.d.ts +6 -6
- package/dist/internal/nodes/nodesManagement.js +9 -7
- package/dist/internal/nodes/nodesManagement.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.test.js +9 -9
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
- package/dist/internal/nodes/nodesRevisions.d.ts +4 -4
- package/dist/internal/nodes/nodesRevisions.js.map +1 -1
- package/dist/internal/photos/albums.d.ts +3 -3
- package/dist/internal/photos/albums.js.map +1 -1
- package/dist/internal/photos/apiService.d.ts +1 -1
- package/dist/internal/photos/apiService.js +3 -6
- package/dist/internal/photos/apiService.js.map +1 -1
- package/dist/internal/photos/cache.d.ts +1 -1
- package/dist/internal/photos/index.d.ts +5 -5
- package/dist/internal/photos/index.js.map +1 -1
- package/dist/internal/photos/interface.d.ts +2 -2
- package/dist/internal/photos/photosTimeline.d.ts +3 -3
- package/dist/internal/photos/photosTimeline.js +1 -2
- package/dist/internal/photos/photosTimeline.js.map +1 -1
- package/dist/internal/sdkEvents.d.ts +1 -1
- package/dist/internal/sdkEvents.js +2 -7
- package/dist/internal/sdkEvents.js.map +1 -1
- package/dist/internal/sdkEvents.test.js +8 -8
- package/dist/internal/shares/apiService.d.ts +2 -2
- package/dist/internal/shares/apiService.js +5 -3
- package/dist/internal/shares/apiService.js.map +1 -1
- package/dist/internal/shares/cache.d.ts +2 -2
- package/dist/internal/shares/cache.js +12 -6
- package/dist/internal/shares/cache.js.map +1 -1
- package/dist/internal/shares/cache.test.js.map +1 -1
- package/dist/internal/shares/cryptoCache.d.ts +2 -2
- package/dist/internal/shares/cryptoCache.test.js +8 -2
- package/dist/internal/shares/cryptoCache.test.js.map +1 -1
- package/dist/internal/shares/cryptoService.d.ts +3 -3
- package/dist/internal/shares/cryptoService.js.map +1 -1
- package/dist/internal/shares/cryptoService.test.js +42 -42
- package/dist/internal/shares/cryptoService.test.js.map +1 -1
- package/dist/internal/shares/index.d.ts +4 -4
- package/dist/internal/shares/index.js.map +1 -1
- package/dist/internal/shares/interface.d.ts +2 -2
- package/dist/internal/shares/manager.d.ts +7 -7
- package/dist/internal/shares/manager.js.map +1 -1
- package/dist/internal/shares/manager.test.js +71 -63
- package/dist/internal/shares/manager.test.js.map +1 -1
- package/dist/internal/sharing/apiService.d.ts +4 -4
- package/dist/internal/sharing/apiService.js +4 -3
- package/dist/internal/sharing/apiService.js.map +1 -1
- package/dist/internal/sharing/cache.d.ts +1 -1
- package/dist/internal/sharing/cache.test.js +33 -33
- package/dist/internal/sharing/cryptoService.d.ts +3 -3
- package/dist/internal/sharing/cryptoService.js +3 -5
- package/dist/internal/sharing/cryptoService.js.map +1 -1
- package/dist/internal/sharing/cryptoService.test.js +39 -39
- package/dist/internal/sharing/cryptoService.test.js.map +1 -1
- package/dist/internal/sharing/events.d.ts +4 -4
- package/dist/internal/sharing/events.js +0 -1
- package/dist/internal/sharing/events.js.map +1 -1
- package/dist/internal/sharing/events.test.js +39 -40
- package/dist/internal/sharing/events.test.js.map +1 -1
- package/dist/internal/sharing/index.d.ts +6 -6
- package/dist/internal/sharing/index.js.map +1 -1
- package/dist/internal/sharing/interface.d.ts +5 -4
- package/dist/internal/sharing/sharingAccess.d.ts +6 -6
- package/dist/internal/sharing/sharingAccess.js +8 -4
- package/dist/internal/sharing/sharingAccess.js.map +1 -1
- package/dist/internal/sharing/sharingAccess.test.js +45 -39
- package/dist/internal/sharing/sharingAccess.test.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.d.ts +4 -4
- package/dist/internal/sharing/sharingManagement.js +5 -7
- package/dist/internal/sharing/sharingManagement.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.test.js +297 -248
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
- package/dist/internal/uids.js.map +1 -1
- package/dist/internal/upload/apiService.d.ts +3 -3
- package/dist/internal/upload/apiService.js +1 -1
- package/dist/internal/upload/apiService.js.map +1 -1
- package/dist/internal/upload/blockVerifier.d.ts +3 -3
- package/dist/internal/upload/blockVerifier.js +1 -1
- package/dist/internal/upload/blockVerifier.js.map +1 -1
- package/dist/internal/upload/chunkStreamReader.test.js +6 -6
- package/dist/internal/upload/cryptoService.d.ts +4 -4
- package/dist/internal/upload/cryptoService.js +4 -4
- package/dist/internal/upload/cryptoService.js.map +1 -1
- package/dist/internal/upload/digests.js.map +1 -1
- package/dist/internal/upload/fileUploader.d.ts +6 -6
- package/dist/internal/upload/fileUploader.js.map +1 -1
- package/dist/internal/upload/fileUploader.test.js.map +1 -1
- package/dist/internal/upload/index.d.ts +5 -5
- package/dist/internal/upload/index.js.map +1 -1
- package/dist/internal/upload/interface.d.ts +3 -3
- package/dist/internal/upload/manager.d.ts +4 -4
- package/dist/internal/upload/manager.js +7 -5
- package/dist/internal/upload/manager.js.map +1 -1
- package/dist/internal/upload/manager.test.js +137 -123
- package/dist/internal/upload/manager.test.js.map +1 -1
- package/dist/internal/upload/streamUploader.d.ts +6 -6
- package/dist/internal/upload/streamUploader.js +8 -6
- package/dist/internal/upload/streamUploader.js.map +1 -1
- package/dist/internal/upload/streamUploader.test.js +16 -11
- package/dist/internal/upload/streamUploader.test.js.map +1 -1
- package/dist/internal/upload/telemetry.d.ts +3 -3
- package/dist/internal/upload/telemetry.js +5 -3
- package/dist/internal/upload/telemetry.js.map +1 -1
- package/dist/internal/upload/telemetry.test.js +8 -8
- package/dist/internal/upload/telemetry.test.js.map +1 -1
- package/dist/protonDriveClient.d.ts +8 -8
- package/dist/protonDriveClient.js +12 -9
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePhotosClient.js.map +1 -1
- package/dist/telemetry.js +18 -15
- package/dist/telemetry.js.map +1 -1
- package/dist/tests/logger.js.map +1 -1
- package/dist/tests/telemetry.d.ts +1 -1
- package/dist/transformers.js +4 -2
- package/dist/transformers.js.map +1 -1
- package/package.json +1 -1
- package/src/cache/interface.ts +22 -22
- package/src/cache/memoryCache.test.ts +7 -7
- package/src/cache/memoryCache.ts +4 -4
- package/src/cache/nullCache.ts +1 -1
- package/src/config.ts +5 -5
- package/src/crypto/driveCrypto.test.ts +15 -15
- package/src/crypto/driveCrypto.ts +120 -156
- package/src/crypto/hmac.ts +1 -1
- package/src/crypto/interface.ts +63 -72
- package/src/crypto/openPGPCrypto.ts +74 -94
- package/src/crypto/utils.ts +1 -1
- package/src/diagnostic/eventsGenerator.ts +2 -2
- package/src/diagnostic/httpClient.ts +6 -2
- package/src/diagnostic/index.ts +12 -10
- package/src/diagnostic/integrityVerificationStream.ts +3 -4
- package/src/diagnostic/interface.ts +81 -81
- package/src/diagnostic/sdkDiagnostic.ts +35 -24
- package/src/diagnostic/sdkDiagnosticFull.ts +16 -19
- package/src/diagnostic/telemetry.ts +4 -1
- package/src/diagnostic/zipGenerators.test.ts +1 -1
- package/src/diagnostic/zipGenerators.ts +3 -3
- package/src/errors.ts +21 -21
- package/src/index.ts +3 -3
- package/src/interface/account.ts +10 -10
- package/src/interface/author.ts +6 -6
- package/src/interface/config.ts +4 -4
- package/src/interface/devices.ts +6 -6
- package/src/interface/download.ts +12 -9
- package/src/interface/events.ts +45 -39
- package/src/interface/httpClient.ts +11 -11
- package/src/interface/index.ts +76 -19
- package/src/interface/nodes.ts +47 -49
- package/src/interface/result.ts +1 -3
- package/src/interface/sharing.ts +60 -57
- package/src/interface/telemetry.ts +74 -74
- package/src/interface/thumbnail.ts +5 -6
- package/src/interface/upload.ts +20 -12
- package/src/internal/apiService/apiService.test.ts +109 -76
- package/src/internal/apiService/apiService.ts +40 -26
- package/src/internal/apiService/coreTypes.ts +2474 -2463
- package/src/internal/apiService/driveTypes.ts +1868 -1822
- package/src/internal/apiService/errorCodes.ts +4 -4
- package/src/internal/apiService/errors.test.ts +25 -23
- package/src/internal/apiService/errors.ts +15 -9
- package/src/internal/apiService/index.ts +1 -1
- package/src/internal/apiService/transformers.ts +2 -2
- package/src/internal/asyncIteratorMap.test.ts +4 -4
- package/src/internal/asyncIteratorMap.ts +1 -1
- package/src/internal/asyncIteratorRace.test.ts +149 -0
- package/src/internal/asyncIteratorRace.ts +79 -0
- package/src/internal/batch.test.ts +50 -0
- package/src/internal/batch.ts +9 -0
- package/src/internal/batchLoading.test.ts +13 -14
- package/src/internal/batchLoading.ts +8 -8
- package/src/internal/devices/apiService.ts +58 -51
- package/src/internal/devices/cryptoService.ts +22 -17
- package/src/internal/devices/index.ts +17 -10
- package/src/internal/devices/interface.ts +21 -12
- package/src/internal/devices/manager.test.ts +40 -9
- package/src/internal/devices/manager.ts +3 -3
- package/src/internal/download/apiService.ts +66 -49
- package/src/internal/download/cryptoService.ts +34 -18
- package/src/internal/download/fileDownloader.test.ts +25 -9
- package/src/internal/download/fileDownloader.ts +36 -18
- package/src/internal/download/index.ts +19 -19
- package/src/internal/download/interface.ts +19 -20
- package/src/internal/download/queue.ts +3 -3
- package/src/internal/download/telemetry.test.ts +11 -11
- package/src/internal/download/telemetry.ts +24 -14
- package/src/internal/download/thumbnailDownloader.test.ts +11 -6
- package/src/internal/download/thumbnailDownloader.ts +43 -32
- package/src/internal/errors.ts +7 -5
- package/src/internal/events/apiService.ts +30 -17
- package/src/internal/events/coreEventManager.test.ts +18 -18
- package/src/internal/events/coreEventManager.ts +9 -6
- package/src/internal/events/eventManager.test.ts +51 -46
- package/src/internal/events/eventManager.ts +6 -5
- package/src/internal/events/index.ts +24 -14
- package/src/internal/events/interface.ts +47 -39
- package/src/internal/events/volumeEventManager.test.ts +61 -65
- package/src/internal/events/volumeEventManager.ts +18 -9
- package/src/internal/nodes/apiService.test.ts +197 -147
- package/src/internal/nodes/apiService.ts +288 -174
- package/src/internal/nodes/cache.test.ts +48 -20
- package/src/internal/nodes/cache.ts +60 -44
- package/src/internal/nodes/cryptoCache.test.ts +34 -14
- package/src/internal/nodes/cryptoCache.ts +10 -5
- package/src/internal/nodes/cryptoService.test.ts +492 -351
- package/src/internal/nodes/cryptoService.ts +170 -88
- package/src/internal/nodes/events.test.ts +38 -28
- package/src/internal/nodes/events.ts +7 -5
- package/src/internal/nodes/extendedAttributes.test.ts +28 -24
- package/src/internal/nodes/extendedAttributes.ts +20 -15
- package/src/internal/nodes/index.test.ts +133 -0
- package/src/internal/nodes/index.ts +27 -15
- package/src/internal/nodes/interface.ts +42 -29
- package/src/internal/nodes/nodesAccess.test.ts +124 -58
- package/src/internal/nodes/nodesAccess.ts +73 -49
- package/src/internal/nodes/nodesManagement.test.ts +32 -31
- package/src/internal/nodes/nodesManagement.ts +39 -32
- package/src/internal/nodes/nodesRevisions.ts +7 -7
- package/src/internal/nodes/validations.ts +2 -2
- package/src/internal/photos/albums.ts +5 -5
- package/src/internal/photos/apiService.ts +4 -7
- package/src/internal/photos/cache.ts +1 -1
- package/src/internal/photos/index.ts +8 -8
- package/src/internal/photos/interface.ts +2 -2
- package/src/internal/photos/photosTimeline.ts +4 -5
- package/src/internal/sdkEvents.test.ts +10 -10
- package/src/internal/sdkEvents.ts +5 -13
- package/src/internal/shares/apiService.ts +44 -33
- package/src/internal/shares/cache.test.ts +6 -4
- package/src/internal/shares/cache.ts +21 -12
- package/src/internal/shares/cryptoCache.test.ts +17 -11
- package/src/internal/shares/cryptoCache.ts +4 -4
- package/src/internal/shares/cryptoService.test.ts +72 -74
- package/src/internal/shares/cryptoService.ts +48 -23
- package/src/internal/shares/index.ts +23 -11
- package/src/internal/shares/interface.ts +8 -8
- package/src/internal/shares/manager.test.ts +88 -80
- package/src/internal/shares/manager.ts +19 -19
- package/src/internal/sharing/apiService.ts +282 -175
- package/src/internal/sharing/cache.test.ts +35 -35
- package/src/internal/sharing/cache.ts +2 -2
- package/src/internal/sharing/cryptoService.test.ts +58 -46
- package/src/internal/sharing/cryptoService.ts +121 -84
- package/src/internal/sharing/events.test.ts +45 -49
- package/src/internal/sharing/events.ts +9 -6
- package/src/internal/sharing/index.ts +22 -11
- package/src/internal/sharing/interface.ts +40 -40
- package/src/internal/sharing/sharingAccess.test.ts +71 -65
- package/src/internal/sharing/sharingAccess.ts +39 -21
- package/src/internal/sharing/sharingManagement.test.ts +398 -298
- package/src/internal/sharing/sharingManagement.ts +138 -65
- package/src/internal/uids.ts +1 -1
- package/src/internal/upload/apiService.ts +167 -117
- package/src/internal/upload/blockVerifier.ts +8 -6
- package/src/internal/upload/chunkStreamReader.test.ts +7 -7
- package/src/internal/upload/cryptoService.ts +42 -36
- package/src/internal/upload/digests.ts +2 -2
- package/src/internal/upload/fileUploader.test.ts +15 -3
- package/src/internal/upload/fileUploader.ts +39 -17
- package/src/internal/upload/index.ts +13 -14
- package/src/internal/upload/interface.ts +78 -78
- package/src/internal/upload/manager.test.ts +170 -153
- package/src/internal/upload/manager.ts +59 -35
- package/src/internal/upload/queue.ts +3 -3
- package/src/internal/upload/streamUploader.test.ts +40 -26
- package/src/internal/upload/streamUploader.ts +87 -69
- package/src/internal/upload/telemetry.test.ts +11 -11
- package/src/internal/upload/telemetry.ts +25 -15
- package/src/internal/wait.test.ts +1 -1
- package/src/internal/wait.ts +3 -3
- package/src/protonDriveClient.ts +121 -39
- package/src/protonDrivePhotosClient.ts +16 -10
- package/src/telemetry.ts +60 -52
- package/src/tests/logger.ts +1 -1
- package/src/tests/telemetry.ts +2 -2
- package/src/transformers.ts +27 -21
- package/src/version.ts +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { DriveCrypto, PrivateKey, SessionKey, VERIFICATION_STATUS } from
|
|
2
|
-
import { ProtonDriveAccount, ProtonDriveTelemetry, RevisionState } from
|
|
3
|
-
import { getMockTelemetry } from
|
|
4
|
-
import { DecryptedNode, DecryptedNodeKeys, DecryptedUnparsedNode, EncryptedNode, SharesService } from
|
|
5
|
-
import { NodesCryptoService } from
|
|
1
|
+
import { DriveCrypto, PrivateKey, SessionKey, VERIFICATION_STATUS } from '../../crypto';
|
|
2
|
+
import { ProtonDriveAccount, ProtonDriveTelemetry, RevisionState } from '../../interface';
|
|
3
|
+
import { getMockTelemetry } from '../../tests/telemetry';
|
|
4
|
+
import { DecryptedNode, DecryptedNodeKeys, DecryptedUnparsedNode, EncryptedNode, SharesService } from './interface';
|
|
5
|
+
import { NodesCryptoService } from './cryptoService';
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe('nodesCryptoService', () => {
|
|
8
8
|
let telemetry: ProtonDriveTelemetry;
|
|
9
9
|
let driveCrypto: DriveCrypto;
|
|
10
10
|
let account: ProtonDriveAccount;
|
|
@@ -17,32 +17,44 @@ describe("nodesCryptoService", () => {
|
|
|
17
17
|
|
|
18
18
|
telemetry = getMockTelemetry();
|
|
19
19
|
driveCrypto = {
|
|
20
|
-
decryptKey: jest.fn(async () =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
20
|
+
decryptKey: jest.fn(async () =>
|
|
21
|
+
Promise.resolve({
|
|
22
|
+
passphrase: 'pass',
|
|
23
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
24
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
25
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
26
|
+
}),
|
|
27
|
+
),
|
|
28
|
+
decryptNodeName: jest.fn(async () =>
|
|
29
|
+
Promise.resolve({
|
|
30
|
+
name: 'name',
|
|
31
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
32
|
+
}),
|
|
33
|
+
),
|
|
34
|
+
decryptNodeHashKey: jest.fn(async () =>
|
|
35
|
+
Promise.resolve({
|
|
36
|
+
hashKey: new Uint8Array(),
|
|
37
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
38
|
+
}),
|
|
39
|
+
),
|
|
40
|
+
decryptExtendedAttributes: jest.fn(async () =>
|
|
41
|
+
Promise.resolve({
|
|
42
|
+
extendedAttributes: '{}',
|
|
43
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
encryptNodeName: jest.fn(async () =>
|
|
47
|
+
Promise.resolve({
|
|
48
|
+
armoredNodeName: 'armoredName',
|
|
49
|
+
}),
|
|
50
|
+
),
|
|
41
51
|
// @ts-expect-error No need to implement all methods for mocking
|
|
42
|
-
decryptAndVerifySessionKey: jest.fn(async () =>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
decryptAndVerifySessionKey: jest.fn(async () =>
|
|
53
|
+
Promise.resolve({
|
|
54
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
55
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_VALID,
|
|
56
|
+
}),
|
|
57
|
+
),
|
|
46
58
|
};
|
|
47
59
|
account = {
|
|
48
60
|
// @ts-expect-error No need to implement all methods for mocking
|
|
@@ -51,8 +63,8 @@ describe("nodesCryptoService", () => {
|
|
|
51
63
|
// @ts-expect-error No need to implement all methods for mocking
|
|
52
64
|
sharesService = {
|
|
53
65
|
getMyFilesShareMemberEmailKey: jest.fn(async () => ({
|
|
54
|
-
email:
|
|
55
|
-
addressKey:
|
|
66
|
+
email: 'email',
|
|
67
|
+
addressKey: 'key' as unknown as PrivateKey,
|
|
56
68
|
})),
|
|
57
69
|
getVolumeMetricContext: jest.fn().mockResolvedValue('own_volume'),
|
|
58
70
|
};
|
|
@@ -60,13 +72,13 @@ describe("nodesCryptoService", () => {
|
|
|
60
72
|
cryptoService = new NodesCryptoService(telemetry, driveCrypto, account, sharesService);
|
|
61
73
|
});
|
|
62
74
|
|
|
63
|
-
const parentKey =
|
|
75
|
+
const parentKey = 'parentKey' as unknown as PrivateKey;
|
|
64
76
|
|
|
65
77
|
function verifyLogEventVerificationError(options = {}) {
|
|
66
78
|
expect(telemetry.logEvent).toHaveBeenCalledTimes(1);
|
|
67
79
|
expect(telemetry.logEvent).toHaveBeenCalledWith({
|
|
68
|
-
eventName:
|
|
69
|
-
volumeType:
|
|
80
|
+
eventName: 'verificationError',
|
|
81
|
+
volumeType: 'own_volume',
|
|
70
82
|
fromBefore2024: false,
|
|
71
83
|
addressMatchingDefaultShare: false,
|
|
72
84
|
...options,
|
|
@@ -76,174 +88,206 @@ describe("nodesCryptoService", () => {
|
|
|
76
88
|
function verifyLogEventDecryptionError(options = {}) {
|
|
77
89
|
expect(telemetry.logEvent).toHaveBeenCalledTimes(1);
|
|
78
90
|
expect(telemetry.logEvent).toHaveBeenCalledWith({
|
|
79
|
-
eventName:
|
|
80
|
-
volumeType:
|
|
91
|
+
eventName: 'decryptionError',
|
|
92
|
+
volumeType: 'own_volume',
|
|
81
93
|
fromBefore2024: false,
|
|
82
94
|
...options,
|
|
83
95
|
});
|
|
84
96
|
}
|
|
85
97
|
|
|
86
|
-
describe(
|
|
98
|
+
describe('folder node', () => {
|
|
87
99
|
const encryptedNode = {
|
|
88
|
-
uid:
|
|
89
|
-
parentUid:
|
|
100
|
+
uid: 'volumeId~nodeId',
|
|
101
|
+
parentUid: 'volumeId~parentId',
|
|
90
102
|
encryptedCrypto: {
|
|
91
|
-
signatureEmail:
|
|
92
|
-
nameSignatureEmail:
|
|
93
|
-
armoredKey:
|
|
94
|
-
armoredNodePassphrase:
|
|
95
|
-
armoredNodePassphraseSignature:
|
|
103
|
+
signatureEmail: 'signatureEmail',
|
|
104
|
+
nameSignatureEmail: 'nameSignatureEmail',
|
|
105
|
+
armoredKey: 'armoredKey',
|
|
106
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
107
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
96
108
|
folder: {
|
|
97
|
-
armoredHashKey:
|
|
98
|
-
armoredExtendedAttributes:
|
|
109
|
+
armoredHashKey: 'armoredHashKey',
|
|
110
|
+
armoredExtendedAttributes: 'folderArmoredExtendedAttributes',
|
|
99
111
|
},
|
|
100
112
|
},
|
|
101
113
|
} as EncryptedNode;
|
|
102
114
|
|
|
103
115
|
function verifyResult(
|
|
104
|
-
result: { node: DecryptedUnparsedNode
|
|
116
|
+
result: { node: DecryptedUnparsedNode; keys?: DecryptedNodeKeys },
|
|
105
117
|
expectedNode: Partial<DecryptedUnparsedNode> = {},
|
|
106
118
|
expectedKeys: Partial<DecryptedNodeKeys> | 'noKeys' = {},
|
|
107
119
|
) {
|
|
108
120
|
expect(result).toMatchObject({
|
|
109
121
|
node: {
|
|
110
|
-
name: { ok: true, value:
|
|
111
|
-
keyAuthor: { ok: true, value:
|
|
112
|
-
nameAuthor: { ok: true, value:
|
|
122
|
+
name: { ok: true, value: 'name' },
|
|
123
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
124
|
+
nameAuthor: { ok: true, value: 'nameSignatureEmail' },
|
|
113
125
|
folder: {
|
|
114
|
-
extendedAttributes:
|
|
126
|
+
extendedAttributes: '{}',
|
|
115
127
|
},
|
|
116
128
|
activeRevision: undefined,
|
|
117
129
|
errors: undefined,
|
|
118
130
|
...expectedNode,
|
|
119
131
|
},
|
|
120
|
-
...expectedKeys === 'noKeys'
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
...(expectedKeys === 'noKeys'
|
|
133
|
+
? {}
|
|
134
|
+
: {
|
|
135
|
+
keys: {
|
|
136
|
+
passphrase: 'pass',
|
|
137
|
+
key: 'decryptedKey',
|
|
138
|
+
passphraseSessionKey: 'passphraseSessionKey',
|
|
139
|
+
hashKey: new Uint8Array(),
|
|
140
|
+
...expectedKeys,
|
|
141
|
+
},
|
|
142
|
+
}),
|
|
129
143
|
});
|
|
130
144
|
}
|
|
131
145
|
|
|
132
|
-
describe(
|
|
133
|
-
it(
|
|
146
|
+
describe('should decrypt successfuly', () => {
|
|
147
|
+
it('same author everywhere', async () => {
|
|
134
148
|
const encryptedNode = {
|
|
135
149
|
encryptedCrypto: {
|
|
136
|
-
signatureEmail:
|
|
137
|
-
nameSignatureEmail:
|
|
138
|
-
armoredKey:
|
|
139
|
-
armoredNodePassphrase:
|
|
140
|
-
armoredNodePassphraseSignature:
|
|
150
|
+
signatureEmail: 'signatureEmail',
|
|
151
|
+
nameSignatureEmail: 'signatureEmail',
|
|
152
|
+
armoredKey: 'armoredKey',
|
|
153
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
154
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
141
155
|
folder: {
|
|
142
|
-
armoredHashKey:
|
|
143
|
-
armoredExtendedAttributes:
|
|
156
|
+
armoredHashKey: 'armoredHashKey',
|
|
157
|
+
armoredExtendedAttributes: 'folderArmoredExtendedAttributes',
|
|
144
158
|
},
|
|
145
159
|
},
|
|
146
160
|
} as EncryptedNode;
|
|
147
161
|
|
|
148
162
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
149
163
|
verifyResult(result, {
|
|
150
|
-
keyAuthor: { ok: true, value:
|
|
151
|
-
nameAuthor: { ok: true, value:
|
|
164
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
165
|
+
nameAuthor: { ok: true, value: 'signatureEmail' },
|
|
152
166
|
});
|
|
153
167
|
|
|
154
168
|
expect(account.getPublicKeys).toHaveBeenCalledTimes(1);
|
|
155
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
169
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('signatureEmail');
|
|
156
170
|
expect(telemetry.logEvent).not.toHaveBeenCalled();
|
|
157
171
|
});
|
|
158
172
|
|
|
159
|
-
it(
|
|
173
|
+
it('different authors on key and name', async () => {
|
|
160
174
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
161
175
|
verifyResult(result);
|
|
162
176
|
expect(account.getPublicKeys).toHaveBeenCalledTimes(2);
|
|
163
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
164
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
177
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('signatureEmail');
|
|
178
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('nameSignatureEmail');
|
|
165
179
|
expect(telemetry.logEvent).not.toHaveBeenCalled();
|
|
166
180
|
});
|
|
167
181
|
});
|
|
168
182
|
|
|
169
|
-
describe(
|
|
170
|
-
it(
|
|
171
|
-
driveCrypto.decryptKey = jest.fn(async () =>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
describe('should decrypt with verification issues', () => {
|
|
184
|
+
it('on node key', async () => {
|
|
185
|
+
driveCrypto.decryptKey = jest.fn(async () =>
|
|
186
|
+
Promise.resolve({
|
|
187
|
+
passphrase: 'pass',
|
|
188
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
189
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
190
|
+
verified: VERIFICATION_STATUS.NOT_SIGNED,
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
177
193
|
|
|
178
194
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
179
195
|
verifyResult(result, {
|
|
180
|
-
keyAuthor: {
|
|
196
|
+
keyAuthor: {
|
|
197
|
+
ok: false,
|
|
198
|
+
error: { claimedAuthor: 'signatureEmail', error: 'Missing signature for key' },
|
|
199
|
+
},
|
|
181
200
|
});
|
|
182
201
|
verifyLogEventVerificationError({
|
|
183
202
|
field: 'nodeKey',
|
|
184
203
|
});
|
|
185
204
|
});
|
|
186
205
|
|
|
187
|
-
it(
|
|
188
|
-
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
206
|
+
it('on node name', async () => {
|
|
207
|
+
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
208
|
+
Promise.resolve({
|
|
209
|
+
name: 'name',
|
|
210
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
211
|
+
}),
|
|
212
|
+
);
|
|
192
213
|
|
|
193
214
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
194
215
|
verifyResult(result, {
|
|
195
|
-
nameAuthor: {
|
|
216
|
+
nameAuthor: {
|
|
217
|
+
ok: false,
|
|
218
|
+
error: { claimedAuthor: 'nameSignatureEmail', error: 'Signature verification for name failed' },
|
|
219
|
+
},
|
|
196
220
|
});
|
|
197
221
|
verifyLogEventVerificationError({
|
|
198
222
|
field: 'nodeName',
|
|
199
223
|
});
|
|
200
224
|
});
|
|
201
225
|
|
|
202
|
-
it(
|
|
203
|
-
driveCrypto.decryptNodeHashKey = jest.fn(async () =>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
226
|
+
it('on hash key', async () => {
|
|
227
|
+
driveCrypto.decryptNodeHashKey = jest.fn(async () =>
|
|
228
|
+
Promise.resolve({
|
|
229
|
+
hashKey: new Uint8Array(),
|
|
230
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
231
|
+
}),
|
|
232
|
+
);
|
|
207
233
|
|
|
208
234
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
209
235
|
verifyResult(result, {
|
|
210
|
-
keyAuthor: {
|
|
236
|
+
keyAuthor: {
|
|
237
|
+
ok: false,
|
|
238
|
+
error: { claimedAuthor: 'signatureEmail', error: 'Signature verification for hash key failed' },
|
|
239
|
+
},
|
|
211
240
|
});
|
|
212
241
|
verifyLogEventVerificationError({
|
|
213
242
|
field: 'nodeHashKey',
|
|
214
243
|
});
|
|
215
244
|
});
|
|
216
245
|
|
|
217
|
-
it(
|
|
218
|
-
driveCrypto.decryptKey = jest.fn(async () =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
246
|
+
it('on node key and hash key reports error from node key', async () => {
|
|
247
|
+
driveCrypto.decryptKey = jest.fn(async () =>
|
|
248
|
+
Promise.resolve({
|
|
249
|
+
passphrase: 'pass',
|
|
250
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
251
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
252
|
+
verified: VERIFICATION_STATUS.NOT_SIGNED,
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
255
|
+
driveCrypto.decryptNodeHashKey = jest.fn(async () =>
|
|
256
|
+
Promise.resolve({
|
|
257
|
+
hashKey: new Uint8Array(),
|
|
258
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
259
|
+
}),
|
|
260
|
+
);
|
|
228
261
|
|
|
229
262
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
230
263
|
verifyResult(result, {
|
|
231
|
-
keyAuthor: {
|
|
264
|
+
keyAuthor: {
|
|
265
|
+
ok: false,
|
|
266
|
+
error: { claimedAuthor: 'signatureEmail', error: 'Missing signature for key' },
|
|
267
|
+
},
|
|
232
268
|
});
|
|
233
269
|
verifyLogEventVerificationError({
|
|
234
270
|
field: 'nodeKey',
|
|
235
271
|
});
|
|
236
272
|
});
|
|
237
273
|
|
|
238
|
-
it(
|
|
239
|
-
driveCrypto.decryptExtendedAttributes = jest.fn(async () =>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
274
|
+
it('on folder extended attributes', async () => {
|
|
275
|
+
driveCrypto.decryptExtendedAttributes = jest.fn(async () =>
|
|
276
|
+
Promise.resolve({
|
|
277
|
+
extendedAttributes: '{}',
|
|
278
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
243
281
|
|
|
244
282
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
245
283
|
verifyResult(result, {
|
|
246
|
-
keyAuthor: {
|
|
284
|
+
keyAuthor: {
|
|
285
|
+
ok: false,
|
|
286
|
+
error: {
|
|
287
|
+
claimedAuthor: 'signatureEmail',
|
|
288
|
+
error: 'Signature verification for attributes failed',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
247
291
|
});
|
|
248
292
|
verifyLogEventVerificationError({
|
|
249
293
|
field: 'nodeExtendedAttributes',
|
|
@@ -251,61 +295,86 @@ describe("nodesCryptoService", () => {
|
|
|
251
295
|
});
|
|
252
296
|
});
|
|
253
297
|
|
|
254
|
-
describe(
|
|
255
|
-
it(
|
|
256
|
-
const error = new Error(
|
|
298
|
+
describe('should decrypt with decryption issues', () => {
|
|
299
|
+
it('on node key', async () => {
|
|
300
|
+
const error = new Error('Decryption error');
|
|
257
301
|
driveCrypto.decryptKey = jest.fn(async () => Promise.reject(error));
|
|
258
302
|
|
|
259
303
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
260
|
-
verifyResult(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
304
|
+
verifyResult(
|
|
305
|
+
result,
|
|
306
|
+
{
|
|
307
|
+
keyAuthor: {
|
|
308
|
+
ok: false,
|
|
309
|
+
error: {
|
|
310
|
+
claimedAuthor: 'signatureEmail',
|
|
311
|
+
error: 'Failed to decrypt node key: Decryption error',
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
errors: [new Error('Decryption error')],
|
|
315
|
+
folder: undefined,
|
|
316
|
+
},
|
|
317
|
+
'noKeys',
|
|
318
|
+
);
|
|
265
319
|
verifyLogEventDecryptionError({
|
|
266
320
|
field: 'nodeKey',
|
|
267
321
|
error,
|
|
268
322
|
});
|
|
269
323
|
});
|
|
270
324
|
|
|
271
|
-
it(
|
|
272
|
-
const error = new Error(
|
|
325
|
+
it('on node name', async () => {
|
|
326
|
+
const error = new Error('Decryption error');
|
|
273
327
|
driveCrypto.decryptNodeName = jest.fn(async () => Promise.reject(error));
|
|
274
328
|
|
|
275
329
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
276
|
-
verifyResult(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
330
|
+
verifyResult(
|
|
331
|
+
result,
|
|
332
|
+
{
|
|
333
|
+
name: { ok: false, error },
|
|
334
|
+
nameAuthor: {
|
|
335
|
+
ok: false,
|
|
336
|
+
error: { claimedAuthor: 'nameSignatureEmail', error: 'Decryption error' },
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
'noKeys',
|
|
340
|
+
);
|
|
280
341
|
verifyLogEventDecryptionError({
|
|
281
342
|
field: 'nodeName',
|
|
282
343
|
error,
|
|
283
344
|
});
|
|
284
345
|
});
|
|
285
346
|
|
|
286
|
-
it(
|
|
287
|
-
const error = new Error(
|
|
347
|
+
it('on hash key', async () => {
|
|
348
|
+
const error = new Error('Decryption error');
|
|
288
349
|
driveCrypto.decryptNodeHashKey = jest.fn(async () => Promise.reject(error));
|
|
289
350
|
|
|
290
351
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
291
|
-
verifyResult(
|
|
292
|
-
|
|
293
|
-
|
|
352
|
+
verifyResult(
|
|
353
|
+
result,
|
|
354
|
+
{
|
|
355
|
+
errors: [error],
|
|
356
|
+
},
|
|
357
|
+
'noKeys',
|
|
358
|
+
);
|
|
294
359
|
verifyLogEventDecryptionError({
|
|
295
360
|
field: 'nodeHashKey',
|
|
296
361
|
error,
|
|
297
362
|
});
|
|
298
363
|
});
|
|
299
364
|
|
|
300
|
-
it(
|
|
301
|
-
const error = new Error(
|
|
365
|
+
it('on folder extended attributes', async () => {
|
|
366
|
+
const error = new Error('Decryption error');
|
|
302
367
|
driveCrypto.decryptExtendedAttributes = jest.fn(async () => Promise.reject(error));
|
|
303
368
|
|
|
304
369
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
305
|
-
verifyResult(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
370
|
+
verifyResult(
|
|
371
|
+
result,
|
|
372
|
+
{
|
|
373
|
+
folder: undefined,
|
|
374
|
+
errors: [error],
|
|
375
|
+
},
|
|
376
|
+
'noKeys',
|
|
377
|
+
);
|
|
309
378
|
verifyLogEventDecryptionError({
|
|
310
379
|
field: 'nodeExtendedAttributes',
|
|
311
380
|
error,
|
|
@@ -313,175 +382,198 @@ describe("nodesCryptoService", () => {
|
|
|
313
382
|
});
|
|
314
383
|
});
|
|
315
384
|
|
|
316
|
-
it(
|
|
317
|
-
account.getPublicKeys = jest.fn().mockRejectedValue(new Error(
|
|
385
|
+
it('should fail when keys cannot be loaded', async () => {
|
|
386
|
+
account.getPublicKeys = jest.fn().mockRejectedValue(new Error('Failed to load keys'));
|
|
318
387
|
|
|
319
388
|
const result = cryptoService.decryptNode(encryptedNode, parentKey);
|
|
320
|
-
await expect(result).rejects.toThrow(
|
|
389
|
+
await expect(result).rejects.toThrow('Failed to load keys');
|
|
321
390
|
});
|
|
322
391
|
});
|
|
323
392
|
|
|
324
|
-
describe(
|
|
393
|
+
describe('file node', () => {
|
|
325
394
|
const encryptedNode = {
|
|
326
|
-
uid:
|
|
327
|
-
parentUid:
|
|
395
|
+
uid: 'volumeId~nodeId',
|
|
396
|
+
parentUid: 'volumeId~parentId',
|
|
328
397
|
encryptedCrypto: {
|
|
329
|
-
signatureEmail:
|
|
330
|
-
nameSignatureEmail:
|
|
331
|
-
armoredKey:
|
|
332
|
-
armoredNodePassphrase:
|
|
333
|
-
armoredNodePassphraseSignature:
|
|
398
|
+
signatureEmail: 'signatureEmail',
|
|
399
|
+
nameSignatureEmail: 'nameSignatureEmail',
|
|
400
|
+
armoredKey: 'armoredKey',
|
|
401
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
402
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
334
403
|
file: {
|
|
335
|
-
base64ContentKeyPacket:
|
|
404
|
+
base64ContentKeyPacket: 'base64ContentKeyPacket',
|
|
336
405
|
},
|
|
337
406
|
activeRevision: {
|
|
338
|
-
uid:
|
|
339
|
-
state:
|
|
340
|
-
signatureEmail:
|
|
341
|
-
armoredExtendedAttributes:
|
|
407
|
+
uid: 'revisionUid',
|
|
408
|
+
state: 'active',
|
|
409
|
+
signatureEmail: 'revisionSignatureEmail',
|
|
410
|
+
armoredExtendedAttributes: 'encryptedExtendedAttributes',
|
|
342
411
|
},
|
|
343
412
|
},
|
|
344
413
|
} as EncryptedNode;
|
|
345
414
|
|
|
346
415
|
function verifyResult(
|
|
347
|
-
result: { node: DecryptedUnparsedNode
|
|
416
|
+
result: { node: DecryptedUnparsedNode; keys?: DecryptedNodeKeys },
|
|
348
417
|
expectedNode: Partial<DecryptedUnparsedNode> = {},
|
|
349
418
|
expectedKeys: Partial<DecryptedNodeKeys> | 'noKeys' = {},
|
|
350
419
|
) {
|
|
351
420
|
expect(result).toMatchObject({
|
|
352
421
|
node: {
|
|
353
|
-
name: { ok: true, value:
|
|
354
|
-
keyAuthor: { ok: true, value:
|
|
355
|
-
nameAuthor: { ok: true, value:
|
|
422
|
+
name: { ok: true, value: 'name' },
|
|
423
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
424
|
+
nameAuthor: { ok: true, value: 'nameSignatureEmail' },
|
|
356
425
|
folder: undefined,
|
|
357
426
|
activeRevision: {
|
|
358
|
-
ok: true,
|
|
359
|
-
|
|
427
|
+
ok: true,
|
|
428
|
+
value: {
|
|
429
|
+
uid: 'revisionUid',
|
|
360
430
|
state: RevisionState.Active,
|
|
361
431
|
creationTime: undefined,
|
|
362
|
-
extendedAttributes:
|
|
363
|
-
contentAuthor: { ok: true, value:
|
|
364
|
-
}
|
|
432
|
+
extendedAttributes: '{}',
|
|
433
|
+
contentAuthor: { ok: true, value: 'revisionSignatureEmail' },
|
|
434
|
+
},
|
|
365
435
|
},
|
|
366
436
|
errors: undefined,
|
|
367
437
|
...expectedNode,
|
|
368
438
|
},
|
|
369
|
-
...expectedKeys === 'noKeys'
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
439
|
+
...(expectedKeys === 'noKeys'
|
|
440
|
+
? {}
|
|
441
|
+
: {
|
|
442
|
+
keys: {
|
|
443
|
+
passphrase: 'pass',
|
|
444
|
+
key: 'decryptedKey',
|
|
445
|
+
passphraseSessionKey: 'passphraseSessionKey',
|
|
446
|
+
hashKey: undefined,
|
|
447
|
+
contentKeyPacketSessionKey: 'contentKeyPacketSessionKey',
|
|
448
|
+
...expectedKeys,
|
|
449
|
+
},
|
|
450
|
+
}),
|
|
379
451
|
});
|
|
380
452
|
}
|
|
381
453
|
|
|
382
|
-
describe(
|
|
383
|
-
it(
|
|
454
|
+
describe('should decrypt successfuly', () => {
|
|
455
|
+
it('same author everywhere', async () => {
|
|
384
456
|
const encryptedNode = {
|
|
385
457
|
encryptedCrypto: {
|
|
386
|
-
signatureEmail:
|
|
387
|
-
nameSignatureEmail:
|
|
388
|
-
armoredKey:
|
|
389
|
-
armoredNodePassphrase:
|
|
390
|
-
armoredNodePassphraseSignature:
|
|
458
|
+
signatureEmail: 'signatureEmail',
|
|
459
|
+
nameSignatureEmail: 'signatureEmail',
|
|
460
|
+
armoredKey: 'armoredKey',
|
|
461
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
462
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
391
463
|
file: {
|
|
392
|
-
base64ContentKeyPacket:
|
|
464
|
+
base64ContentKeyPacket: 'base64ContentKeyPacket',
|
|
393
465
|
},
|
|
394
466
|
activeRevision: {
|
|
395
|
-
uid:
|
|
396
|
-
state:
|
|
397
|
-
signatureEmail:
|
|
398
|
-
armoredExtendedAttributes:
|
|
467
|
+
uid: 'revisionUid',
|
|
468
|
+
state: 'active',
|
|
469
|
+
signatureEmail: 'signatureEmail',
|
|
470
|
+
armoredExtendedAttributes: 'encryptedExtendedAttributes',
|
|
399
471
|
},
|
|
400
472
|
},
|
|
401
473
|
} as EncryptedNode;
|
|
402
474
|
|
|
403
475
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
404
476
|
verifyResult(result, {
|
|
405
|
-
keyAuthor: { ok: true, value:
|
|
406
|
-
nameAuthor: { ok: true, value:
|
|
477
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
478
|
+
nameAuthor: { ok: true, value: 'signatureEmail' },
|
|
407
479
|
activeRevision: {
|
|
408
|
-
ok: true,
|
|
409
|
-
|
|
480
|
+
ok: true,
|
|
481
|
+
value: {
|
|
482
|
+
uid: 'revisionUid',
|
|
410
483
|
state: RevisionState.Active,
|
|
411
484
|
// @ts-expect-error Ignore mocked data.
|
|
412
485
|
creationTime: undefined,
|
|
413
|
-
extendedAttributes:
|
|
414
|
-
contentAuthor: { ok: true, value:
|
|
415
|
-
}
|
|
486
|
+
extendedAttributes: '{}',
|
|
487
|
+
contentAuthor: { ok: true, value: 'signatureEmail' },
|
|
488
|
+
},
|
|
416
489
|
},
|
|
417
490
|
});
|
|
418
491
|
|
|
419
492
|
expect(account.getPublicKeys).toHaveBeenCalledTimes(2); // node + revision
|
|
420
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
493
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('signatureEmail');
|
|
421
494
|
expect(telemetry.logEvent).not.toHaveBeenCalled();
|
|
422
495
|
});
|
|
423
496
|
|
|
424
|
-
it(
|
|
497
|
+
it('different authors on key and name', async () => {
|
|
425
498
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
426
499
|
verifyResult(result);
|
|
427
500
|
expect(account.getPublicKeys).toHaveBeenCalledTimes(3);
|
|
428
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
429
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
430
|
-
expect(account.getPublicKeys).toHaveBeenCalledWith(
|
|
501
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('signatureEmail');
|
|
502
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('nameSignatureEmail');
|
|
503
|
+
expect(account.getPublicKeys).toHaveBeenCalledWith('revisionSignatureEmail');
|
|
431
504
|
expect(telemetry.logEvent).not.toHaveBeenCalled();
|
|
432
505
|
});
|
|
433
506
|
});
|
|
434
507
|
|
|
435
|
-
describe(
|
|
436
|
-
it(
|
|
437
|
-
driveCrypto.decryptKey = jest.fn(async () =>
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
508
|
+
describe('should decrypt with verification issues', () => {
|
|
509
|
+
it('on node key', async () => {
|
|
510
|
+
driveCrypto.decryptKey = jest.fn(async () =>
|
|
511
|
+
Promise.resolve({
|
|
512
|
+
passphrase: 'pass',
|
|
513
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
514
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
515
|
+
verified: VERIFICATION_STATUS.NOT_SIGNED,
|
|
516
|
+
}),
|
|
517
|
+
);
|
|
443
518
|
|
|
444
519
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
445
520
|
verifyResult(result, {
|
|
446
|
-
keyAuthor: {
|
|
521
|
+
keyAuthor: {
|
|
522
|
+
ok: false,
|
|
523
|
+
error: { claimedAuthor: 'signatureEmail', error: 'Missing signature for key' },
|
|
524
|
+
},
|
|
447
525
|
});
|
|
448
526
|
verifyLogEventVerificationError({
|
|
449
527
|
field: 'nodeKey',
|
|
450
528
|
});
|
|
451
529
|
});
|
|
452
530
|
|
|
453
|
-
it(
|
|
454
|
-
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
531
|
+
it('on node name', async () => {
|
|
532
|
+
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
533
|
+
Promise.resolve({
|
|
534
|
+
name: 'name',
|
|
535
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
536
|
+
}),
|
|
537
|
+
);
|
|
458
538
|
|
|
459
539
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
460
540
|
verifyResult(result, {
|
|
461
|
-
nameAuthor: {
|
|
541
|
+
nameAuthor: {
|
|
542
|
+
ok: false,
|
|
543
|
+
error: { claimedAuthor: 'nameSignatureEmail', error: 'Signature verification for name failed' },
|
|
544
|
+
},
|
|
462
545
|
});
|
|
463
546
|
verifyLogEventVerificationError({
|
|
464
547
|
field: 'nodeName',
|
|
465
548
|
});
|
|
466
549
|
});
|
|
467
550
|
|
|
468
|
-
it(
|
|
469
|
-
driveCrypto.decryptExtendedAttributes = jest.fn(async () =>
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
551
|
+
it('on folder extended attributes', async () => {
|
|
552
|
+
driveCrypto.decryptExtendedAttributes = jest.fn(async () =>
|
|
553
|
+
Promise.resolve({
|
|
554
|
+
extendedAttributes: '{}',
|
|
555
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
556
|
+
}),
|
|
557
|
+
);
|
|
473
558
|
|
|
474
559
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
475
560
|
verifyResult(result, {
|
|
476
561
|
activeRevision: {
|
|
477
|
-
ok: true,
|
|
478
|
-
|
|
479
|
-
|
|
562
|
+
ok: true,
|
|
563
|
+
value: {
|
|
564
|
+
uid: 'revisionUid',
|
|
565
|
+
extendedAttributes: '{}',
|
|
480
566
|
state: RevisionState.Active,
|
|
481
567
|
// @ts-expect-error Ignore mocked data.
|
|
482
568
|
creationTime: undefined,
|
|
483
|
-
contentAuthor: {
|
|
484
|
-
|
|
569
|
+
contentAuthor: {
|
|
570
|
+
ok: false,
|
|
571
|
+
error: {
|
|
572
|
+
claimedAuthor: 'revisionSignatureEmail',
|
|
573
|
+
error: 'Signature verification for attributes failed',
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
},
|
|
485
577
|
},
|
|
486
578
|
});
|
|
487
579
|
verifyLogEventVerificationError({
|
|
@@ -489,15 +581,24 @@ describe("nodesCryptoService", () => {
|
|
|
489
581
|
});
|
|
490
582
|
});
|
|
491
583
|
|
|
492
|
-
it(
|
|
493
|
-
driveCrypto.decryptAndVerifySessionKey = jest.fn(
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
584
|
+
it('on content key packet', async () => {
|
|
585
|
+
driveCrypto.decryptAndVerifySessionKey = jest.fn(
|
|
586
|
+
async () =>
|
|
587
|
+
Promise.resolve({
|
|
588
|
+
sessionKey: 'contentKeyPacketSessionKey',
|
|
589
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
590
|
+
}) as any,
|
|
591
|
+
);
|
|
497
592
|
|
|
498
593
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
499
594
|
verifyResult(result, {
|
|
500
|
-
keyAuthor: {
|
|
595
|
+
keyAuthor: {
|
|
596
|
+
ok: false,
|
|
597
|
+
error: {
|
|
598
|
+
claimedAuthor: 'signatureEmail',
|
|
599
|
+
error: 'Signature verification for content key failed',
|
|
600
|
+
},
|
|
601
|
+
},
|
|
501
602
|
});
|
|
502
603
|
verifyLogEventVerificationError({
|
|
503
604
|
field: 'nodeContentKey',
|
|
@@ -505,46 +606,66 @@ describe("nodesCryptoService", () => {
|
|
|
505
606
|
});
|
|
506
607
|
});
|
|
507
608
|
|
|
508
|
-
describe(
|
|
509
|
-
it(
|
|
510
|
-
const error = new Error(
|
|
609
|
+
describe('should decrypt with decryption issues', () => {
|
|
610
|
+
it('on node key', async () => {
|
|
611
|
+
const error = new Error('Decryption error');
|
|
511
612
|
driveCrypto.decryptKey = jest.fn(async () => Promise.reject(error));
|
|
512
613
|
|
|
513
614
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
514
|
-
verifyResult(
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
615
|
+
verifyResult(
|
|
616
|
+
result,
|
|
617
|
+
{
|
|
618
|
+
keyAuthor: {
|
|
619
|
+
ok: false,
|
|
620
|
+
error: {
|
|
621
|
+
claimedAuthor: 'signatureEmail',
|
|
622
|
+
error: 'Failed to decrypt node key: Decryption error',
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
activeRevision: { ok: false, error: new Error('Failed to decrypt node key: Decryption error') },
|
|
626
|
+
errors: [new Error('Decryption error')],
|
|
627
|
+
folder: undefined,
|
|
628
|
+
},
|
|
629
|
+
'noKeys',
|
|
630
|
+
);
|
|
520
631
|
verifyLogEventDecryptionError({
|
|
521
632
|
field: 'nodeKey',
|
|
522
633
|
error,
|
|
523
634
|
});
|
|
524
635
|
});
|
|
525
636
|
|
|
526
|
-
it(
|
|
527
|
-
const error = new Error(
|
|
637
|
+
it('on node name', async () => {
|
|
638
|
+
const error = new Error('Decryption error');
|
|
528
639
|
driveCrypto.decryptNodeName = jest.fn(async () => Promise.reject(error));
|
|
529
640
|
|
|
530
641
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
531
|
-
verifyResult(
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
642
|
+
verifyResult(
|
|
643
|
+
result,
|
|
644
|
+
{
|
|
645
|
+
name: { ok: false, error },
|
|
646
|
+
nameAuthor: {
|
|
647
|
+
ok: false,
|
|
648
|
+
error: { claimedAuthor: 'nameSignatureEmail', error: 'Decryption error' },
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
'noKeys',
|
|
652
|
+
);
|
|
535
653
|
verifyLogEventDecryptionError({
|
|
536
654
|
field: 'nodeName',
|
|
537
655
|
error,
|
|
538
656
|
});
|
|
539
657
|
});
|
|
540
658
|
|
|
541
|
-
it(
|
|
542
|
-
const error = new Error(
|
|
659
|
+
it('on file extended attributes', async () => {
|
|
660
|
+
const error = new Error('Decryption error');
|
|
543
661
|
driveCrypto.decryptExtendedAttributes = jest.fn(async () => Promise.reject(error));
|
|
544
662
|
|
|
545
663
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
546
664
|
verifyResult(result, {
|
|
547
|
-
activeRevision: {
|
|
665
|
+
activeRevision: {
|
|
666
|
+
ok: false,
|
|
667
|
+
error: new Error('Failed to decrypt active revision: Decryption error'),
|
|
668
|
+
},
|
|
548
669
|
});
|
|
549
670
|
verifyLogEventDecryptionError({
|
|
550
671
|
field: 'nodeExtendedAttributes',
|
|
@@ -552,17 +673,27 @@ describe("nodesCryptoService", () => {
|
|
|
552
673
|
});
|
|
553
674
|
});
|
|
554
675
|
|
|
555
|
-
it(
|
|
556
|
-
const error = new Error(
|
|
676
|
+
it('on content key packet', async () => {
|
|
677
|
+
const error = new Error('Decryption error');
|
|
557
678
|
driveCrypto.decryptAndVerifySessionKey = jest.fn(async () => Promise.reject(error));
|
|
558
679
|
|
|
559
680
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
560
|
-
verifyResult(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
681
|
+
verifyResult(
|
|
682
|
+
result,
|
|
683
|
+
{
|
|
684
|
+
keyAuthor: {
|
|
685
|
+
ok: false,
|
|
686
|
+
error: {
|
|
687
|
+
claimedAuthor: 'signatureEmail',
|
|
688
|
+
error: 'Failed to decrypt content key: Decryption error',
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
errors: [error],
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
contentKeyPacketSessionKey: undefined,
|
|
695
|
+
},
|
|
696
|
+
);
|
|
566
697
|
verifyLogEventDecryptionError({
|
|
567
698
|
field: 'nodeContentKey',
|
|
568
699
|
error,
|
|
@@ -570,45 +701,45 @@ describe("nodesCryptoService", () => {
|
|
|
570
701
|
});
|
|
571
702
|
});
|
|
572
703
|
|
|
573
|
-
it(
|
|
574
|
-
account.getPublicKeys = jest.fn().mockRejectedValue(new Error(
|
|
704
|
+
it('should fail when keys cannot be loaded', async () => {
|
|
705
|
+
account.getPublicKeys = jest.fn().mockRejectedValue(new Error('Failed to load keys'));
|
|
575
706
|
|
|
576
707
|
const result = cryptoService.decryptNode(encryptedNode, parentKey);
|
|
577
|
-
await expect(result).rejects.toThrow(
|
|
708
|
+
await expect(result).rejects.toThrow('Failed to load keys');
|
|
578
709
|
});
|
|
579
710
|
});
|
|
580
711
|
|
|
581
|
-
describe(
|
|
712
|
+
describe('album node', () => {
|
|
582
713
|
const encryptedNode = {
|
|
583
|
-
uid:
|
|
584
|
-
parentUid:
|
|
714
|
+
uid: 'volumeId~nodeId',
|
|
715
|
+
parentUid: 'volumeId~parentId',
|
|
585
716
|
encryptedCrypto: {
|
|
586
|
-
signatureEmail:
|
|
587
|
-
nameSignatureEmail:
|
|
588
|
-
armoredKey:
|
|
589
|
-
armoredNodePassphrase:
|
|
590
|
-
armoredNodePassphraseSignature:
|
|
717
|
+
signatureEmail: 'signatureEmail',
|
|
718
|
+
nameSignatureEmail: 'nameSignatureEmail',
|
|
719
|
+
armoredKey: 'armoredKey',
|
|
720
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
721
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
591
722
|
},
|
|
592
723
|
} as EncryptedNode;
|
|
593
724
|
|
|
594
|
-
it(
|
|
725
|
+
it('should decrypt successfuly', async () => {
|
|
595
726
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
596
727
|
|
|
597
728
|
expect(result).toMatchObject({
|
|
598
729
|
node: {
|
|
599
|
-
name: { ok: true, value:
|
|
600
|
-
keyAuthor: { ok: true, value:
|
|
601
|
-
nameAuthor: { ok: true, value:
|
|
730
|
+
name: { ok: true, value: 'name' },
|
|
731
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
732
|
+
nameAuthor: { ok: true, value: 'nameSignatureEmail' },
|
|
602
733
|
folder: undefined,
|
|
603
734
|
activeRevision: undefined,
|
|
604
735
|
errors: undefined,
|
|
605
736
|
},
|
|
606
737
|
keys: {
|
|
607
|
-
passphrase:
|
|
608
|
-
key:
|
|
609
|
-
passphraseSessionKey:
|
|
738
|
+
passphrase: 'pass',
|
|
739
|
+
key: 'decryptedKey',
|
|
740
|
+
passphraseSessionKey: 'passphraseSessionKey',
|
|
610
741
|
hashKey: new Uint8Array(),
|
|
611
|
-
}
|
|
742
|
+
},
|
|
612
743
|
});
|
|
613
744
|
|
|
614
745
|
expect(account.getPublicKeys).toHaveBeenCalledTimes(2);
|
|
@@ -616,24 +747,24 @@ describe("nodesCryptoService", () => {
|
|
|
616
747
|
});
|
|
617
748
|
});
|
|
618
749
|
|
|
619
|
-
describe(
|
|
750
|
+
describe('anonymous node', () => {
|
|
620
751
|
const encryptedNode = {
|
|
621
|
-
uid:
|
|
622
|
-
parentUid:
|
|
752
|
+
uid: 'volumeId~nodeId',
|
|
753
|
+
parentUid: 'volumeId~parentId',
|
|
623
754
|
encryptedCrypto: {
|
|
624
755
|
signatureEmail: undefined,
|
|
625
756
|
nameSignatureEmail: undefined,
|
|
626
|
-
armoredKey:
|
|
627
|
-
armoredNodePassphrase:
|
|
628
|
-
armoredNodePassphraseSignature:
|
|
757
|
+
armoredKey: 'armoredKey',
|
|
758
|
+
armoredNodePassphrase: 'armoredNodePassphrase',
|
|
759
|
+
armoredNodePassphraseSignature: 'armoredNodePassphraseSignature',
|
|
629
760
|
file: {
|
|
630
|
-
base64ContentKeyPacket:
|
|
761
|
+
base64ContentKeyPacket: 'base64ContentKeyPacket',
|
|
631
762
|
},
|
|
632
763
|
activeRevision: {
|
|
633
|
-
uid:
|
|
634
|
-
state:
|
|
635
|
-
signatureEmail:
|
|
636
|
-
armoredExtendedAttributes:
|
|
764
|
+
uid: 'revisionUid',
|
|
765
|
+
state: 'active',
|
|
766
|
+
signatureEmail: 'revisionSignatureEmail',
|
|
767
|
+
armoredExtendedAttributes: 'encryptedExtendedAttributes',
|
|
637
768
|
},
|
|
638
769
|
},
|
|
639
770
|
} as EncryptedNode;
|
|
@@ -641,61 +772,74 @@ describe("nodesCryptoService", () => {
|
|
|
641
772
|
const encryptedNodeWithoutParent = {
|
|
642
773
|
...encryptedNode,
|
|
643
774
|
parentUid: undefined,
|
|
644
|
-
}
|
|
775
|
+
};
|
|
645
776
|
|
|
646
777
|
function verifyResult(
|
|
647
|
-
result: { node: DecryptedUnparsedNode
|
|
778
|
+
result: { node: DecryptedUnparsedNode; keys?: DecryptedNodeKeys },
|
|
648
779
|
expectedNode: Partial<DecryptedUnparsedNode> = {},
|
|
649
780
|
expectedKeys: Partial<DecryptedNodeKeys> | 'noKeys' = {},
|
|
650
781
|
) {
|
|
651
782
|
expect(result).toMatchObject({
|
|
652
783
|
node: {
|
|
653
|
-
name: { ok: true, value:
|
|
654
|
-
keyAuthor: { ok: true, value:
|
|
655
|
-
nameAuthor: { ok: true, value:
|
|
784
|
+
name: { ok: true, value: 'name' },
|
|
785
|
+
keyAuthor: { ok: true, value: 'signatureEmail' },
|
|
786
|
+
nameAuthor: { ok: true, value: 'nameSignatureEmail' },
|
|
656
787
|
folder: undefined,
|
|
657
788
|
activeRevision: {
|
|
658
|
-
ok: true,
|
|
659
|
-
|
|
789
|
+
ok: true,
|
|
790
|
+
value: {
|
|
791
|
+
uid: 'revisionUid',
|
|
660
792
|
state: RevisionState.Active,
|
|
661
793
|
creationTime: undefined,
|
|
662
|
-
extendedAttributes:
|
|
663
|
-
contentAuthor: { ok: true, value:
|
|
664
|
-
}
|
|
794
|
+
extendedAttributes: '{}',
|
|
795
|
+
contentAuthor: { ok: true, value: 'revisionSignatureEmail' },
|
|
796
|
+
},
|
|
665
797
|
},
|
|
666
798
|
errors: undefined,
|
|
667
799
|
...expectedNode,
|
|
668
800
|
},
|
|
669
|
-
...expectedKeys === 'noKeys'
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
801
|
+
...(expectedKeys === 'noKeys'
|
|
802
|
+
? {}
|
|
803
|
+
: {
|
|
804
|
+
keys: {
|
|
805
|
+
passphrase: 'pass',
|
|
806
|
+
key: 'decryptedKey',
|
|
807
|
+
passphraseSessionKey: 'passphraseSessionKey',
|
|
808
|
+
hashKey: undefined,
|
|
809
|
+
contentKeyPacketSessionKey: 'contentKeyPacketSessionKey',
|
|
810
|
+
...expectedKeys,
|
|
811
|
+
},
|
|
812
|
+
}),
|
|
679
813
|
});
|
|
680
814
|
}
|
|
681
815
|
|
|
682
|
-
describe(
|
|
683
|
-
it(
|
|
684
|
-
driveCrypto.decryptKey = jest.fn(async () =>
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
816
|
+
describe('should decrypt with verification issues', () => {
|
|
817
|
+
it('on node key and name with access to parent node', async () => {
|
|
818
|
+
driveCrypto.decryptKey = jest.fn(async () =>
|
|
819
|
+
Promise.resolve({
|
|
820
|
+
passphrase: 'pass',
|
|
821
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
822
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
823
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
824
|
+
}),
|
|
825
|
+
);
|
|
826
|
+
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
827
|
+
Promise.resolve({
|
|
828
|
+
name: 'name',
|
|
829
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
830
|
+
}),
|
|
831
|
+
);
|
|
694
832
|
|
|
695
833
|
const result = await cryptoService.decryptNode(encryptedNode, parentKey);
|
|
696
834
|
verifyResult(result, {
|
|
697
|
-
keyAuthor: {
|
|
698
|
-
|
|
835
|
+
keyAuthor: {
|
|
836
|
+
ok: false,
|
|
837
|
+
error: { claimedAuthor: undefined, error: 'Signature verification for key failed' },
|
|
838
|
+
},
|
|
839
|
+
nameAuthor: {
|
|
840
|
+
ok: false,
|
|
841
|
+
error: { claimedAuthor: undefined, error: 'Signature verification for name failed' },
|
|
842
|
+
},
|
|
699
843
|
});
|
|
700
844
|
verifyLogEventVerificationError({
|
|
701
845
|
field: 'nodeName',
|
|
@@ -708,24 +852,26 @@ describe("nodesCryptoService", () => {
|
|
|
708
852
|
[parentKey],
|
|
709
853
|
[parentKey],
|
|
710
854
|
);
|
|
711
|
-
expect(driveCrypto.decryptNodeName).toHaveBeenCalledWith(
|
|
712
|
-
encryptedNode.encryptedName,
|
|
855
|
+
expect(driveCrypto.decryptNodeName).toHaveBeenCalledWith(encryptedNode.encryptedName, parentKey, [
|
|
713
856
|
parentKey,
|
|
714
|
-
|
|
715
|
-
);
|
|
857
|
+
]);
|
|
716
858
|
});
|
|
717
859
|
|
|
718
|
-
it(
|
|
719
|
-
driveCrypto.decryptKey = jest.fn(async () =>
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
860
|
+
it('on anonymous node key and name without access to parent node', async () => {
|
|
861
|
+
driveCrypto.decryptKey = jest.fn(async () =>
|
|
862
|
+
Promise.resolve({
|
|
863
|
+
passphrase: 'pass',
|
|
864
|
+
key: 'decryptedKey' as unknown as PrivateKey,
|
|
865
|
+
passphraseSessionKey: 'passphraseSessionKey' as unknown as SessionKey,
|
|
866
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
867
|
+
}),
|
|
868
|
+
);
|
|
869
|
+
driveCrypto.decryptNodeName = jest.fn(async () =>
|
|
870
|
+
Promise.resolve({
|
|
871
|
+
name: 'name',
|
|
872
|
+
verified: VERIFICATION_STATUS.SIGNED_AND_INVALID,
|
|
873
|
+
}),
|
|
874
|
+
);
|
|
729
875
|
|
|
730
876
|
const result = await cryptoService.decryptNode(encryptedNodeWithoutParent, parentKey);
|
|
731
877
|
verifyResult(result, {
|
|
@@ -740,11 +886,7 @@ describe("nodesCryptoService", () => {
|
|
|
740
886
|
[parentKey],
|
|
741
887
|
[],
|
|
742
888
|
);
|
|
743
|
-
expect(driveCrypto.decryptNodeName).toHaveBeenCalledWith(
|
|
744
|
-
encryptedNode.encryptedName,
|
|
745
|
-
parentKey,
|
|
746
|
-
[],
|
|
747
|
-
);
|
|
889
|
+
expect(driveCrypto.decryptNodeName).toHaveBeenCalledWith(encryptedNode.encryptedName, parentKey, []);
|
|
748
890
|
});
|
|
749
891
|
});
|
|
750
892
|
});
|
|
@@ -791,17 +933,14 @@ describe("nodesCryptoService", () => {
|
|
|
791
933
|
'testFile.txt',
|
|
792
934
|
keys.nameSessionKey,
|
|
793
935
|
parentKeys.key,
|
|
794
|
-
address.addressKey
|
|
795
|
-
);
|
|
796
|
-
expect(driveCrypto.generateLookupHash).toHaveBeenCalledWith(
|
|
797
|
-
'testFile.txt',
|
|
798
|
-
parentKeys.hashKey
|
|
936
|
+
address.addressKey,
|
|
799
937
|
);
|
|
938
|
+
expect(driveCrypto.generateLookupHash).toHaveBeenCalledWith('testFile.txt', parentKeys.hashKey);
|
|
800
939
|
expect(driveCrypto.encryptPassphrase).toHaveBeenCalledWith(
|
|
801
940
|
keys.passphrase,
|
|
802
941
|
keys.passphraseSessionKey,
|
|
803
942
|
[parentKeys.key],
|
|
804
|
-
address.addressKey
|
|
943
|
+
address.addressKey,
|
|
805
944
|
);
|
|
806
945
|
});
|
|
807
946
|
|
|
@@ -823,8 +962,9 @@ describe("nodesCryptoService", () => {
|
|
|
823
962
|
addressKey: 'addressKey' as any,
|
|
824
963
|
};
|
|
825
964
|
|
|
826
|
-
await expect(cryptoService.moveNode(node, keys as any, parentKeys, address))
|
|
827
|
-
|
|
965
|
+
await expect(cryptoService.moveNode(node, keys as any, parentKeys, address)).rejects.toThrow(
|
|
966
|
+
'Moving item to a non-folder is not allowed',
|
|
967
|
+
);
|
|
828
968
|
});
|
|
829
969
|
|
|
830
970
|
it('should throw error when node has invalid name', async () => {
|
|
@@ -845,8 +985,9 @@ describe("nodesCryptoService", () => {
|
|
|
845
985
|
addressKey: 'addressKey' as any,
|
|
846
986
|
};
|
|
847
987
|
|
|
848
|
-
await expect(cryptoService.moveNode(node, keys as any, parentKeys, address))
|
|
849
|
-
|
|
988
|
+
await expect(cryptoService.moveNode(node, keys as any, parentKeys, address)).rejects.toThrow(
|
|
989
|
+
'Cannot move item without a valid name, please rename the item first',
|
|
990
|
+
);
|
|
850
991
|
});
|
|
851
992
|
});
|
|
852
993
|
});
|