@protontech/drive-sdk 0.0.10
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/README.md +17 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interface.d.ts +105 -0
- package/dist/cache/interface.js +3 -0
- package/dist/cache/interface.js.map +1 -0
- package/dist/cache/memoryCache.d.ts +18 -0
- package/dist/cache/memoryCache.js +78 -0
- package/dist/cache/memoryCache.js.map +1 -0
- package/dist/cache/memoryCache.test.d.ts +1 -0
- package/dist/cache/memoryCache.test.js +121 -0
- package/dist/cache/memoryCache.test.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto/driveCrypto.d.ts +209 -0
- package/dist/crypto/driveCrypto.js +364 -0
- package/dist/crypto/driveCrypto.js.map +1 -0
- package/dist/crypto/driveCrypto.test.d.ts +1 -0
- package/dist/crypto/driveCrypto.test.js +42 -0
- package/dist/crypto/driveCrypto.test.js.map +1 -0
- package/dist/crypto/hmac.d.ts +22 -0
- package/dist/crypto/hmac.js +44 -0
- package/dist/crypto/hmac.js.map +1 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.js +13 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/interface.d.ts +125 -0
- package/dist/crypto/interface.js +10 -0
- package/dist/crypto/interface.js.map +1 -0
- package/dist/crypto/openPGPCrypto.d.ts +145 -0
- package/dist/crypto/openPGPCrypto.js +250 -0
- package/dist/crypto/openPGPCrypto.js.map +1 -0
- package/dist/crypto/utils.d.ts +2 -0
- package/dist/crypto/utils.js +35 -0
- package/dist/crypto/utils.js.map +1 -0
- package/dist/errors.d.ts +138 -0
- package/dist/errors.js +163 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/interface/account.d.ts +36 -0
- package/dist/interface/account.js +3 -0
- package/dist/interface/account.js.map +1 -0
- package/dist/interface/author.d.ts +26 -0
- package/dist/interface/author.js +3 -0
- package/dist/interface/author.js.map +1 -0
- package/dist/interface/devices.d.ts +18 -0
- package/dist/interface/devices.js +10 -0
- package/dist/interface/devices.js.map +1 -0
- package/dist/interface/download.d.ts +29 -0
- package/dist/interface/download.js +3 -0
- package/dist/interface/download.js.map +1 -0
- package/dist/interface/events.d.ts +26 -0
- package/dist/interface/events.js +11 -0
- package/dist/interface/events.js.map +1 -0
- package/dist/interface/httpClient.d.ts +38 -0
- package/dist/interface/httpClient.js +3 -0
- package/dist/interface/httpClient.js.map +1 -0
- package/dist/interface/index.d.ts +43 -0
- package/dist/interface/index.js +22 -0
- package/dist/interface/index.js.map +1 -0
- package/dist/interface/nodes.d.ts +161 -0
- package/dist/interface/nodes.js +21 -0
- package/dist/interface/nodes.js.map +1 -0
- package/dist/interface/result.d.ts +9 -0
- package/dist/interface/result.js +11 -0
- package/dist/interface/result.js.map +1 -0
- package/dist/interface/sharing.d.ts +73 -0
- package/dist/interface/sharing.js +9 -0
- package/dist/interface/sharing.js.map +1 -0
- package/dist/interface/telemetry.d.ts +61 -0
- package/dist/interface/telemetry.js +18 -0
- package/dist/interface/telemetry.js.map +1 -0
- package/dist/interface/thumbnail.d.ts +17 -0
- package/dist/interface/thumbnail.js +9 -0
- package/dist/interface/thumbnail.js.map +1 -0
- package/dist/interface/upload.d.ts +16 -0
- package/dist/interface/upload.js +3 -0
- package/dist/interface/upload.js.map +1 -0
- package/dist/internal/apiService/apiService.d.ts +51 -0
- package/dist/internal/apiService/apiService.js +305 -0
- package/dist/internal/apiService/apiService.js.map +1 -0
- package/dist/internal/apiService/apiService.test.d.ts +1 -0
- package/dist/internal/apiService/apiService.test.js +237 -0
- package/dist/internal/apiService/apiService.test.js.map +1 -0
- package/dist/internal/apiService/coreTypes.d.ts +24438 -0
- package/dist/internal/apiService/coreTypes.js +7 -0
- package/dist/internal/apiService/coreTypes.js.map +1 -0
- package/dist/internal/apiService/driveTypes.d.ts +11840 -0
- package/dist/internal/apiService/driveTypes.js +7 -0
- package/dist/internal/apiService/driveTypes.js.map +1 -0
- package/dist/internal/apiService/errorCodes.d.ts +30 -0
- package/dist/internal/apiService/errorCodes.js +11 -0
- package/dist/internal/apiService/errorCodes.js.map +1 -0
- package/dist/internal/apiService/errors.d.ts +19 -0
- package/dist/internal/apiService/errors.js +76 -0
- package/dist/internal/apiService/errors.js.map +1 -0
- package/dist/internal/apiService/errors.test.d.ts +1 -0
- package/dist/internal/apiService/errors.test.js +69 -0
- package/dist/internal/apiService/errors.test.js.map +1 -0
- package/dist/internal/apiService/index.d.ts +7 -0
- package/dist/internal/apiService/index.js +30 -0
- package/dist/internal/apiService/index.js.map +1 -0
- package/dist/internal/apiService/observerStream.d.ts +3 -0
- package/dist/internal/apiService/observerStream.js +15 -0
- package/dist/internal/apiService/observerStream.js.map +1 -0
- package/dist/internal/apiService/transformers.d.ts +4 -0
- package/dist/internal/apiService/transformers.js +48 -0
- package/dist/internal/apiService/transformers.js.map +1 -0
- package/dist/internal/batchLoading.d.ts +34 -0
- package/dist/internal/batchLoading.js +68 -0
- package/dist/internal/batchLoading.js.map +1 -0
- package/dist/internal/batchLoading.test.d.ts +1 -0
- package/dist/internal/batchLoading.test.js +50 -0
- package/dist/internal/batchLoading.test.js.map +1 -0
- package/dist/internal/devices/apiService.d.ts +38 -0
- package/dist/internal/devices/apiService.js +105 -0
- package/dist/internal/devices/apiService.js.map +1 -0
- package/dist/internal/devices/cryptoService.d.ts +30 -0
- package/dist/internal/devices/cryptoService.js +47 -0
- package/dist/internal/devices/cryptoService.js.map +1 -0
- package/dist/internal/devices/index.d.ts +15 -0
- package/dist/internal/devices/index.js +22 -0
- package/dist/internal/devices/index.js.map +1 -0
- package/dist/internal/devices/interface.d.ts +31 -0
- package/dist/internal/devices/interface.js +3 -0
- package/dist/internal/devices/interface.js.map +1 -0
- package/dist/internal/devices/manager.d.ts +18 -0
- package/dist/internal/devices/manager.js +103 -0
- package/dist/internal/devices/manager.js.map +1 -0
- package/dist/internal/devices/manager.test.d.ts +1 -0
- package/dist/internal/devices/manager.test.js +100 -0
- package/dist/internal/devices/manager.test.js.map +1 -0
- package/dist/internal/download/apiService.d.ts +27 -0
- package/dist/internal/download/apiService.js +110 -0
- package/dist/internal/download/apiService.js.map +1 -0
- package/dist/internal/download/controller.d.ts +8 -0
- package/dist/internal/download/controller.js +22 -0
- package/dist/internal/download/controller.js.map +1 -0
- package/dist/internal/download/cryptoService.d.ts +17 -0
- package/dist/internal/download/cryptoService.js +82 -0
- package/dist/internal/download/cryptoService.js.map +1 -0
- package/dist/internal/download/fileDownloader.d.ts +33 -0
- package/dist/internal/download/fileDownloader.js +226 -0
- package/dist/internal/download/fileDownloader.js.map +1 -0
- package/dist/internal/download/fileDownloader.test.d.ts +1 -0
- package/dist/internal/download/fileDownloader.test.js +324 -0
- package/dist/internal/download/fileDownloader.test.js.map +1 -0
- package/dist/internal/download/index.d.ts +10 -0
- package/dist/internal/download/index.js +82 -0
- package/dist/internal/download/index.js.map +1 -0
- package/dist/internal/download/interface.d.ts +35 -0
- package/dist/internal/download/interface.js +3 -0
- package/dist/internal/download/interface.js.map +1 -0
- package/dist/internal/download/queue.d.ts +5 -0
- package/dist/internal/download/queue.js +31 -0
- package/dist/internal/download/queue.js.map +1 -0
- package/dist/internal/download/telemetry.d.ts +14 -0
- package/dist/internal/download/telemetry.js +106 -0
- package/dist/internal/download/telemetry.js.map +1 -0
- package/dist/internal/download/telemetry.test.d.ts +1 -0
- package/dist/internal/download/telemetry.test.js +111 -0
- package/dist/internal/download/telemetry.test.js.map +1 -0
- package/dist/internal/download/thumbnailDownloader.d.ts +19 -0
- package/dist/internal/download/thumbnailDownloader.js +198 -0
- package/dist/internal/download/thumbnailDownloader.js.map +1 -0
- package/dist/internal/download/thumbnailDownloader.test.d.ts +1 -0
- package/dist/internal/download/thumbnailDownloader.test.js +179 -0
- package/dist/internal/download/thumbnailDownloader.test.js.map +1 -0
- package/dist/internal/errors.d.ts +6 -0
- package/dist/internal/errors.js +28 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/errors.test.d.ts +1 -0
- package/dist/internal/errors.test.js +22 -0
- package/dist/internal/errors.test.js.map +1 -0
- package/dist/internal/events/apiService.d.ts +18 -0
- package/dist/internal/events/apiService.js +81 -0
- package/dist/internal/events/apiService.js.map +1 -0
- package/dist/internal/events/cache.d.ts +28 -0
- package/dist/internal/events/cache.js +67 -0
- package/dist/internal/events/cache.js.map +1 -0
- package/dist/internal/events/cache.test.d.ts +1 -0
- package/dist/internal/events/cache.test.js +43 -0
- package/dist/internal/events/cache.test.js.map +1 -0
- package/dist/internal/events/coreEventManager.d.ts +25 -0
- package/dist/internal/events/coreEventManager.js +63 -0
- package/dist/internal/events/coreEventManager.js.map +1 -0
- package/dist/internal/events/eventManager.d.ts +62 -0
- package/dist/internal/events/eventManager.js +159 -0
- package/dist/internal/events/eventManager.js.map +1 -0
- package/dist/internal/events/eventManager.test.d.ts +1 -0
- package/dist/internal/events/eventManager.test.js +120 -0
- package/dist/internal/events/eventManager.test.js.map +1 -0
- package/dist/internal/events/index.d.ts +50 -0
- package/dist/internal/events/index.js +117 -0
- package/dist/internal/events/index.js.map +1 -0
- package/dist/internal/events/interface.d.ts +47 -0
- package/dist/internal/events/interface.js +12 -0
- package/dist/internal/events/interface.js.map +1 -0
- package/dist/internal/events/volumeEventManager.d.ts +27 -0
- package/dist/internal/events/volumeEventManager.js +69 -0
- package/dist/internal/events/volumeEventManager.js.map +1 -0
- package/dist/internal/nodes/apiService.d.ts +54 -0
- package/dist/internal/nodes/apiService.js +308 -0
- package/dist/internal/nodes/apiService.js.map +1 -0
- package/dist/internal/nodes/apiService.test.d.ts +1 -0
- package/dist/internal/nodes/apiService.test.js +344 -0
- package/dist/internal/nodes/apiService.test.js.map +1 -0
- package/dist/internal/nodes/cache.d.ts +57 -0
- package/dist/internal/nodes/cache.js +226 -0
- package/dist/internal/nodes/cache.js.map +1 -0
- package/dist/internal/nodes/cache.test.d.ts +1 -0
- package/dist/internal/nodes/cache.test.js +160 -0
- package/dist/internal/nodes/cache.test.js.map +1 -0
- package/dist/internal/nodes/cryptoCache.d.ts +16 -0
- package/dist/internal/nodes/cryptoCache.js +50 -0
- package/dist/internal/nodes/cryptoCache.js.map +1 -0
- package/dist/internal/nodes/cryptoCache.test.d.ts +1 -0
- package/dist/internal/nodes/cryptoCache.test.js +79 -0
- package/dist/internal/nodes/cryptoCache.test.js.map +1 -0
- package/dist/internal/nodes/cryptoService.d.ts +75 -0
- package/dist/internal/nodes/cryptoService.js +409 -0
- package/dist/internal/nodes/cryptoService.js.map +1 -0
- package/dist/internal/nodes/cryptoService.test.d.ts +1 -0
- package/dist/internal/nodes/cryptoService.test.js +698 -0
- package/dist/internal/nodes/cryptoService.test.js.map +1 -0
- package/dist/internal/nodes/events.d.ts +91 -0
- package/dist/internal/nodes/events.js +243 -0
- package/dist/internal/nodes/events.js.map +1 -0
- package/dist/internal/nodes/events.test.d.ts +1 -0
- package/dist/internal/nodes/events.test.js +318 -0
- package/dist/internal/nodes/events.test.js.map +1 -0
- package/dist/internal/nodes/extendedAttributes.d.ts +23 -0
- package/dist/internal/nodes/extendedAttributes.js +117 -0
- package/dist/internal/nodes/extendedAttributes.js.map +1 -0
- package/dist/internal/nodes/extendedAttributes.test.d.ts +1 -0
- package/dist/internal/nodes/extendedAttributes.test.js +176 -0
- package/dist/internal/nodes/extendedAttributes.test.js.map +1 -0
- package/dist/internal/nodes/index.d.ts +26 -0
- package/dist/internal/nodes/index.js +40 -0
- package/dist/internal/nodes/index.js.map +1 -0
- package/dist/internal/nodes/index.test.d.ts +1 -0
- package/dist/internal/nodes/index.test.js +112 -0
- package/dist/internal/nodes/index.test.js.map +1 -0
- package/dist/internal/nodes/interface.d.ts +135 -0
- package/dist/internal/nodes/interface.js +3 -0
- package/dist/internal/nodes/interface.js.map +1 -0
- package/dist/internal/nodes/mediaTypes.d.ts +2 -0
- package/dist/internal/nodes/mediaTypes.js +13 -0
- package/dist/internal/nodes/mediaTypes.js.map +1 -0
- package/dist/internal/nodes/nodesAccess.d.ts +49 -0
- package/dist/internal/nodes/nodesAccess.js +332 -0
- package/dist/internal/nodes/nodesAccess.js.map +1 -0
- package/dist/internal/nodes/nodesAccess.test.d.ts +1 -0
- package/dist/internal/nodes/nodesAccess.test.js +487 -0
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -0
- package/dist/internal/nodes/nodesManagement.d.ts +33 -0
- package/dist/internal/nodes/nodesManagement.js +222 -0
- package/dist/internal/nodes/nodesManagement.js.map +1 -0
- package/dist/internal/nodes/nodesManagement.test.d.ts +1 -0
- package/dist/internal/nodes/nodesManagement.test.js +178 -0
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -0
- package/dist/internal/nodes/nodesRevisions.d.ts +18 -0
- package/dist/internal/nodes/nodesRevisions.js +55 -0
- package/dist/internal/nodes/nodesRevisions.js.map +1 -0
- package/dist/internal/nodes/validations.d.ts +4 -0
- package/dist/internal/nodes/validations.js +21 -0
- package/dist/internal/nodes/validations.js.map +1 -0
- package/dist/internal/photos/albums.d.ts +13 -0
- package/dist/internal/photos/albums.js +30 -0
- package/dist/internal/photos/albums.js.map +1 -0
- package/dist/internal/photos/apiService.d.ts +8 -0
- package/dist/internal/photos/apiService.js +18 -0
- package/dist/internal/photos/apiService.js.map +1 -0
- package/dist/internal/photos/cache.d.ts +6 -0
- package/dist/internal/photos/cache.js +15 -0
- package/dist/internal/photos/cache.js.map +1 -0
- package/dist/internal/photos/index.d.ts +9 -0
- package/dist/internal/photos/index.js +18 -0
- package/dist/internal/photos/index.js.map +1 -0
- package/dist/internal/photos/interface.d.ts +6 -0
- package/dist/internal/photos/interface.js +3 -0
- package/dist/internal/photos/interface.js.map +1 -0
- package/dist/internal/photos/photosTimeline.d.ts +10 -0
- package/dist/internal/photos/photosTimeline.js +20 -0
- package/dist/internal/photos/photosTimeline.js.map +1 -0
- package/dist/internal/sdkEvents.d.ts +12 -0
- package/dist/internal/sdkEvents.js +44 -0
- package/dist/internal/sdkEvents.js.map +1 -0
- package/dist/internal/sdkEvents.test.d.ts +1 -0
- package/dist/internal/sdkEvents.test.js +45 -0
- package/dist/internal/sdkEvents.test.js.map +1 -0
- package/dist/internal/shares/apiService.d.ts +51 -0
- package/dist/internal/shares/apiService.js +128 -0
- package/dist/internal/shares/apiService.js.map +1 -0
- package/dist/internal/shares/cache.d.ts +15 -0
- package/dist/internal/shares/cache.js +63 -0
- package/dist/internal/shares/cache.js.map +1 -0
- package/dist/internal/shares/cache.test.d.ts +1 -0
- package/dist/internal/shares/cache.test.js +54 -0
- package/dist/internal/shares/cache.test.js.map +1 -0
- package/dist/internal/shares/cryptoCache.d.ts +20 -0
- package/dist/internal/shares/cryptoCache.js +35 -0
- package/dist/internal/shares/cryptoCache.js.map +1 -0
- package/dist/internal/shares/cryptoCache.test.d.ts +1 -0
- package/dist/internal/shares/cryptoCache.test.js +58 -0
- package/dist/internal/shares/cryptoCache.test.js.map +1 -0
- package/dist/internal/shares/cryptoService.d.ts +42 -0
- package/dist/internal/shares/cryptoService.js +126 -0
- package/dist/internal/shares/cryptoService.js.map +1 -0
- package/dist/internal/shares/cryptoService.test.d.ts +1 -0
- package/dist/internal/shares/cryptoService.test.js +120 -0
- package/dist/internal/shares/cryptoService.test.js.map +1 -0
- package/dist/internal/shares/index.d.ts +15 -0
- package/dist/internal/shares/index.js +26 -0
- package/dist/internal/shares/index.js.map +1 -0
- package/dist/internal/shares/interface.d.ts +94 -0
- package/dist/internal/shares/interface.js +11 -0
- package/dist/internal/shares/interface.js.map +1 -0
- package/dist/internal/shares/manager.d.ts +68 -0
- package/dist/internal/shares/manager.js +186 -0
- package/dist/internal/shares/manager.js.map +1 -0
- package/dist/internal/shares/manager.test.d.ts +1 -0
- package/dist/internal/shares/manager.test.js +176 -0
- package/dist/internal/shares/manager.test.js.map +1 -0
- package/dist/internal/sharing/apiService.d.ts +80 -0
- package/dist/internal/sharing/apiService.js +325 -0
- package/dist/internal/sharing/apiService.js.map +1 -0
- package/dist/internal/sharing/cache.d.ts +37 -0
- package/dist/internal/sharing/cache.js +105 -0
- package/dist/internal/sharing/cache.js.map +1 -0
- package/dist/internal/sharing/cache.test.d.ts +1 -0
- package/dist/internal/sharing/cache.test.js +82 -0
- package/dist/internal/sharing/cache.test.js.map +1 -0
- package/dist/internal/sharing/cryptoService.d.ts +112 -0
- package/dist/internal/sharing/cryptoService.js +269 -0
- package/dist/internal/sharing/cryptoService.js.map +1 -0
- package/dist/internal/sharing/events.d.ts +57 -0
- package/dist/internal/sharing/events.js +153 -0
- package/dist/internal/sharing/events.js.map +1 -0
- package/dist/internal/sharing/events.test.d.ts +1 -0
- package/dist/internal/sharing/events.test.js +246 -0
- package/dist/internal/sharing/events.test.js.map +1 -0
- package/dist/internal/sharing/index.d.ts +20 -0
- package/dist/internal/sharing/index.js +30 -0
- package/dist/internal/sharing/index.js.map +1 -0
- package/dist/internal/sharing/interface.d.ts +169 -0
- package/dist/internal/sharing/interface.js +9 -0
- package/dist/internal/sharing/interface.js.map +1 -0
- package/dist/internal/sharing/sharingAccess.d.ts +32 -0
- package/dist/internal/sharing/sharingAccess.js +119 -0
- package/dist/internal/sharing/sharingAccess.js.map +1 -0
- package/dist/internal/sharing/sharingAccess.test.d.ts +1 -0
- package/dist/internal/sharing/sharingAccess.test.js +84 -0
- package/dist/internal/sharing/sharingAccess.test.js.map +1 -0
- package/dist/internal/sharing/sharingManagement.d.ts +43 -0
- package/dist/internal/sharing/sharingManagement.js +439 -0
- package/dist/internal/sharing/sharingManagement.js.map +1 -0
- package/dist/internal/sharing/sharingManagement.test.d.ts +1 -0
- package/dist/internal/sharing/sharingManagement.test.js +788 -0
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -0
- package/dist/internal/uids.d.ts +38 -0
- package/dist/internal/uids.js +85 -0
- package/dist/internal/uids.js.map +1 -0
- package/dist/internal/upload/apiService.d.ts +65 -0
- package/dist/internal/upload/apiService.js +137 -0
- package/dist/internal/upload/apiService.js.map +1 -0
- package/dist/internal/upload/blockVerifier.d.ts +16 -0
- package/dist/internal/upload/blockVerifier.js +33 -0
- package/dist/internal/upload/blockVerifier.js.map +1 -0
- package/dist/internal/upload/chunkStreamReader.d.ts +13 -0
- package/dist/internal/upload/chunkStreamReader.js +46 -0
- package/dist/internal/upload/chunkStreamReader.js.map +1 -0
- package/dist/internal/upload/chunkStreamReader.test.d.ts +1 -0
- package/dist/internal/upload/chunkStreamReader.test.js +75 -0
- package/dist/internal/upload/chunkStreamReader.test.js.map +1 -0
- package/dist/internal/upload/controller.d.ts +8 -0
- package/dist/internal/upload/controller.js +25 -0
- package/dist/internal/upload/controller.js.map +1 -0
- package/dist/internal/upload/cryptoService.d.ts +29 -0
- package/dist/internal/upload/cryptoService.js +104 -0
- package/dist/internal/upload/cryptoService.js.map +1 -0
- package/dist/internal/upload/digests.d.ts +8 -0
- package/dist/internal/upload/digests.js +22 -0
- package/dist/internal/upload/digests.js.map +1 -0
- package/dist/internal/upload/fileUploader.d.ts +65 -0
- package/dist/internal/upload/fileUploader.js +463 -0
- package/dist/internal/upload/fileUploader.js.map +1 -0
- package/dist/internal/upload/fileUploader.test.d.ts +1 -0
- package/dist/internal/upload/fileUploader.test.js +393 -0
- package/dist/internal/upload/fileUploader.test.js.map +1 -0
- package/dist/internal/upload/index.d.ts +16 -0
- package/dist/internal/upload/index.js +77 -0
- package/dist/internal/upload/index.js.map +1 -0
- package/dist/internal/upload/interface.d.ts +117 -0
- package/dist/internal/upload/interface.js +3 -0
- package/dist/internal/upload/interface.js.map +1 -0
- package/dist/internal/upload/manager.d.ts +31 -0
- package/dist/internal/upload/manager.js +250 -0
- package/dist/internal/upload/manager.js.map +1 -0
- package/dist/internal/upload/manager.test.d.ts +1 -0
- package/dist/internal/upload/manager.test.js +349 -0
- package/dist/internal/upload/manager.test.js.map +1 -0
- package/dist/internal/upload/queue.d.ts +5 -0
- package/dist/internal/upload/queue.js +32 -0
- package/dist/internal/upload/queue.js.map +1 -0
- package/dist/internal/upload/telemetry.d.ts +15 -0
- package/dist/internal/upload/telemetry.js +111 -0
- package/dist/internal/upload/telemetry.js.map +1 -0
- package/dist/internal/upload/telemetry.test.d.ts +1 -0
- package/dist/internal/upload/telemetry.test.js +107 -0
- package/dist/internal/upload/telemetry.test.js.map +1 -0
- package/dist/internal/utils.d.ts +1 -0
- package/dist/internal/utils.js +13 -0
- package/dist/internal/utils.js.map +1 -0
- package/dist/internal/wait.d.ts +3 -0
- package/dist/internal/wait.js +28 -0
- package/dist/internal/wait.js.map +1 -0
- package/dist/internal/wait.test.d.ts +1 -0
- package/dist/internal/wait.test.js +21 -0
- package/dist/internal/wait.test.js.map +1 -0
- package/dist/protonDriveClient.d.ts +593 -0
- package/dist/protonDriveClient.js +768 -0
- package/dist/protonDriveClient.js.map +1 -0
- package/dist/protonDrivePhotosClient.d.ts +16 -0
- package/dist/protonDrivePhotosClient.js +46 -0
- package/dist/protonDrivePhotosClient.js.map +1 -0
- package/dist/telemetry.d.ts +187 -0
- package/dist/telemetry.js +297 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tests/logger.d.ts +2 -0
- package/dist/tests/logger.js +12 -0
- package/dist/tests/logger.js.map +1 -0
- package/dist/tests/telemetry.d.ts +2 -0
- package/dist/tests/telemetry.js +11 -0
- package/dist/tests/telemetry.js.map +1 -0
- package/dist/transformers.d.ts +17 -0
- package/dist/transformers.js +77 -0
- package/dist/transformers.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +49 -0
- package/src/cache/index.ts +2 -0
- package/src/cache/interface.ts +104 -0
- package/src/cache/memoryCache.test.ts +150 -0
- package/src/cache/memoryCache.ts +85 -0
- package/src/config.ts +9 -0
- package/src/crypto/driveCrypto.test.ts +45 -0
- package/src/crypto/driveCrypto.ts +696 -0
- package/src/crypto/hmac.ts +46 -0
- package/src/crypto/index.ts +6 -0
- package/src/crypto/interface.ts +230 -0
- package/src/crypto/openPGPCrypto.ts +398 -0
- package/src/crypto/utils.ts +40 -0
- package/src/errors.ts +168 -0
- package/src/index.ts +30 -0
- package/src/interface/account.ts +38 -0
- package/src/interface/author.ts +29 -0
- package/src/interface/devices.ts +21 -0
- package/src/interface/download.ts +32 -0
- package/src/interface/events.ts +30 -0
- package/src/interface/httpClient.ts +42 -0
- package/src/interface/index.ts +46 -0
- package/src/interface/nodes.ts +168 -0
- package/src/interface/result.ts +11 -0
- package/src/interface/sharing.ts +87 -0
- package/src/interface/telemetry.ts +107 -0
- package/src/interface/thumbnail.ts +14 -0
- package/src/interface/upload.ts +19 -0
- package/src/internal/apiService/apiService.test.ts +285 -0
- package/src/internal/apiService/apiService.ts +353 -0
- package/src/internal/apiService/coreTypes.ts +24439 -0
- package/src/internal/apiService/driveTypes.ts +11841 -0
- package/src/internal/apiService/errorCodes.ts +38 -0
- package/src/internal/apiService/errors.test.ts +63 -0
- package/src/internal/apiService/errors.ts +91 -0
- package/src/internal/apiService/index.ts +7 -0
- package/src/internal/apiService/observerStream.ts +10 -0
- package/src/internal/apiService/transformers.ts +45 -0
- package/src/internal/batchLoading.test.ts +58 -0
- package/src/internal/batchLoading.ts +74 -0
- package/src/internal/devices/apiService.ts +142 -0
- package/src/internal/devices/cryptoService.ts +65 -0
- package/src/internal/devices/index.ts +31 -0
- package/src/internal/devices/interface.ts +28 -0
- package/src/internal/devices/manager.test.ts +129 -0
- package/src/internal/devices/manager.ts +113 -0
- package/src/internal/download/apiService.ts +145 -0
- package/src/internal/download/controller.ts +22 -0
- package/src/internal/download/cryptoService.ts +96 -0
- package/src/internal/download/fileDownloader.test.ts +381 -0
- package/src/internal/download/fileDownloader.ts +266 -0
- package/src/internal/download/index.ts +122 -0
- package/src/internal/download/interface.ts +38 -0
- package/src/internal/download/queue.ts +30 -0
- package/src/internal/download/telemetry.test.ts +134 -0
- package/src/internal/download/telemetry.ts +115 -0
- package/src/internal/download/thumbnailDownloader.test.ts +226 -0
- package/src/internal/download/thumbnailDownloader.ts +250 -0
- package/src/internal/errors.test.ts +21 -0
- package/src/internal/errors.ts +28 -0
- package/src/internal/events/apiService.ts +87 -0
- package/src/internal/events/cache.test.ts +47 -0
- package/src/internal/events/cache.ts +80 -0
- package/src/internal/events/coreEventManager.ts +69 -0
- package/src/internal/events/eventManager.test.ts +139 -0
- package/src/internal/events/eventManager.ts +168 -0
- package/src/internal/events/index.ts +131 -0
- package/src/internal/events/interface.ts +51 -0
- package/src/internal/events/volumeEventManager.ts +74 -0
- package/src/internal/nodes/apiService.test.ts +394 -0
- package/src/internal/nodes/apiService.ts +455 -0
- package/src/internal/nodes/cache.test.ts +197 -0
- package/src/internal/nodes/cache.ts +240 -0
- package/src/internal/nodes/cryptoCache.test.ts +92 -0
- package/src/internal/nodes/cryptoCache.ts +47 -0
- package/src/internal/nodes/cryptoService.test.ts +814 -0
- package/src/internal/nodes/cryptoService.ts +550 -0
- package/src/internal/nodes/events.test.ts +383 -0
- package/src/internal/nodes/events.ts +271 -0
- package/src/internal/nodes/extendedAttributes.test.ts +177 -0
- package/src/internal/nodes/extendedAttributes.ts +180 -0
- package/src/internal/nodes/index.test.ts +135 -0
- package/src/internal/nodes/index.ts +52 -0
- package/src/internal/nodes/interface.ts +152 -0
- package/src/internal/nodes/mediaTypes.ts +10 -0
- package/src/internal/nodes/nodesAccess.test.ts +555 -0
- package/src/internal/nodes/nodesAccess.ts +360 -0
- package/src/internal/nodes/nodesManagement.test.ts +221 -0
- package/src/internal/nodes/nodesManagement.ts +272 -0
- package/src/internal/nodes/nodesRevisions.ts +58 -0
- package/src/internal/nodes/validations.ts +26 -0
- package/src/internal/photos/albums.ts +29 -0
- package/src/internal/photos/apiService.ts +16 -0
- package/src/internal/photos/cache.ts +11 -0
- package/src/internal/photos/index.ts +23 -0
- package/src/internal/photos/interface.ts +7 -0
- package/src/internal/photos/photosTimeline.ts +18 -0
- package/src/internal/sdkEvents.test.ts +55 -0
- package/src/internal/sdkEvents.ts +52 -0
- package/src/internal/shares/apiService.ts +176 -0
- package/src/internal/shares/cache.test.ts +58 -0
- package/src/internal/shares/cache.ts +64 -0
- package/src/internal/shares/cryptoCache.test.ts +70 -0
- package/src/internal/shares/cryptoCache.ts +35 -0
- package/src/internal/shares/cryptoService.test.ts +137 -0
- package/src/internal/shares/cryptoService.ts +143 -0
- package/src/internal/shares/index.ts +35 -0
- package/src/internal/shares/interface.ts +104 -0
- package/src/internal/shares/manager.test.ts +210 -0
- package/src/internal/shares/manager.ts +213 -0
- package/src/internal/sharing/apiService.ts +483 -0
- package/src/internal/sharing/cache.test.ts +99 -0
- package/src/internal/sharing/cache.ts +109 -0
- package/src/internal/sharing/cryptoService.ts +378 -0
- package/src/internal/sharing/events.test.ts +268 -0
- package/src/internal/sharing/events.ts +166 -0
- package/src/internal/sharing/index.ts +43 -0
- package/src/internal/sharing/interface.ts +177 -0
- package/src/internal/sharing/sharingAccess.test.ts +102 -0
- package/src/internal/sharing/sharingAccess.ts +133 -0
- package/src/internal/sharing/sharingManagement.test.ts +895 -0
- package/src/internal/sharing/sharingManagement.ts +521 -0
- package/src/internal/uids.ts +83 -0
- package/src/internal/upload/apiService.ts +243 -0
- package/src/internal/upload/blockVerifier.ts +40 -0
- package/src/internal/upload/chunkStreamReader.test.ts +89 -0
- package/src/internal/upload/chunkStreamReader.ts +49 -0
- package/src/internal/upload/controller.ts +25 -0
- package/src/internal/upload/cryptoService.ts +162 -0
- package/src/internal/upload/digests.ts +18 -0
- package/src/internal/upload/fileUploader.test.ts +513 -0
- package/src/internal/upload/fileUploader.ts +576 -0
- package/src/internal/upload/index.ts +126 -0
- package/src/internal/upload/interface.ts +128 -0
- package/src/internal/upload/manager.test.ts +390 -0
- package/src/internal/upload/manager.ts +320 -0
- package/src/internal/upload/queue.ts +31 -0
- package/src/internal/upload/telemetry.test.ts +129 -0
- package/src/internal/upload/telemetry.ts +121 -0
- package/src/internal/utils.ts +9 -0
- package/src/internal/wait.test.ts +21 -0
- package/src/internal/wait.ts +26 -0
- package/src/protonDriveClient.ts +861 -0
- package/src/protonDrivePhotosClient.ts +56 -0
- package/src/telemetry.ts +346 -0
- package/src/tests/logger.ts +10 -0
- package/src/tests/telemetry.ts +9 -0
- package/src/transformers.ts +98 -0
- package/src/version.ts +4 -0
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import { c } from "ttag";
|
|
2
|
+
|
|
3
|
+
import { Thumbnail, Logger, ThumbnailType, UploadMetadata } from "../../interface";
|
|
4
|
+
import { IntegrityError } from "../../errors";
|
|
5
|
+
import { LoggerWithPrefix } from "../../telemetry";
|
|
6
|
+
import { APIHTTPError, HTTPErrorCode, NotFoundAPIError } from "../apiService";
|
|
7
|
+
import { getErrorMessage } from "../errors";
|
|
8
|
+
import { mergeUint8Arrays } from "../utils";
|
|
9
|
+
import { waitForCondition } from '../wait';
|
|
10
|
+
import { UploadAPIService } from "./apiService";
|
|
11
|
+
import { BlockVerifier } from "./blockVerifier";
|
|
12
|
+
import { UploadController } from './controller';
|
|
13
|
+
import { UploadCryptoService } from "./cryptoService";
|
|
14
|
+
import { UploadDigests } from "./digests";
|
|
15
|
+
import { NodeRevisionDraft, EncryptedBlock, EncryptedThumbnail, EncryptedBlockMetadata } from "./interface";
|
|
16
|
+
import { UploadTelemetry } from './telemetry';
|
|
17
|
+
import { ChunkStreamReader } from './chunkStreamReader';
|
|
18
|
+
import { UploadManager } from "./manager";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* File chunk size in bytes representing the size of each block.
|
|
22
|
+
*/
|
|
23
|
+
export const FILE_CHUNK_SIZE = 4 * 1024 * 1024;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Maximum number of blocks that can be buffered before upload.
|
|
27
|
+
* This is to prevent using too much memory.
|
|
28
|
+
*/
|
|
29
|
+
const MAX_BUFFERED_BLOCKS = 15;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Maximum number of blocks that can be uploaded at the same time.
|
|
33
|
+
* This is to prevent overloading the server with too many requests.
|
|
34
|
+
*/
|
|
35
|
+
const MAX_UPLOADING_BLOCKS = 5;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Maximum number of retries for block encryption.
|
|
39
|
+
* This is to automatically retry random errors that can happen
|
|
40
|
+
* during encryption, for example bitflips.
|
|
41
|
+
*/
|
|
42
|
+
const MAX_BLOCK_ENCRYPTION_RETRIES = 1;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of retries for block upload.
|
|
46
|
+
* This is to ensure we don't end up in an infinite loop.
|
|
47
|
+
*/
|
|
48
|
+
const MAX_BLOCK_UPLOAD_RETRIES = 3;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Fileuploader is responsible for uploading file content to the server.
|
|
52
|
+
*
|
|
53
|
+
* It handles the encryption of file blocks and thumbnails, as well as
|
|
54
|
+
* the upload process itself. It manages the upload queue and ensures
|
|
55
|
+
* that the upload process is efficient and does not overload the server.
|
|
56
|
+
*/
|
|
57
|
+
export class Fileuploader {
|
|
58
|
+
private logger: Logger;
|
|
59
|
+
|
|
60
|
+
private digests: UploadDigests;
|
|
61
|
+
private controller: UploadController;
|
|
62
|
+
private abortController: AbortController;
|
|
63
|
+
|
|
64
|
+
private encryptedThumbnails = new Map<ThumbnailType, EncryptedThumbnail>();
|
|
65
|
+
private encryptedBlocks = new Map<number, EncryptedBlock>();
|
|
66
|
+
private encryptionFinished = false;
|
|
67
|
+
|
|
68
|
+
private ongoingUploads = new Map<string, {
|
|
69
|
+
uploadPromise: Promise<void>,
|
|
70
|
+
encryptedBlock: EncryptedBlock | EncryptedThumbnail,
|
|
71
|
+
}>();
|
|
72
|
+
private uploadedThumbnails: ({ type: ThumbnailType } & EncryptedBlockMetadata)[] = [];
|
|
73
|
+
private uploadedBlocks: ({ index: number } & EncryptedBlockMetadata)[] = [];
|
|
74
|
+
|
|
75
|
+
constructor(
|
|
76
|
+
private telemetry: UploadTelemetry,
|
|
77
|
+
private apiService: UploadAPIService,
|
|
78
|
+
private cryptoService: UploadCryptoService,
|
|
79
|
+
private uploadManager: UploadManager,
|
|
80
|
+
private blockVerifier: BlockVerifier,
|
|
81
|
+
private revisionDraft: NodeRevisionDraft,
|
|
82
|
+
private metadata: UploadMetadata,
|
|
83
|
+
private onFinish: (failure: boolean) => Promise<void>,
|
|
84
|
+
private signal?: AbortSignal,
|
|
85
|
+
) {
|
|
86
|
+
this.telemetry = telemetry;
|
|
87
|
+
this.logger = telemetry.getLoggerForRevision(revisionDraft.nodeRevisionUid);
|
|
88
|
+
this.apiService = apiService;
|
|
89
|
+
this.cryptoService = cryptoService;
|
|
90
|
+
this.blockVerifier = blockVerifier;
|
|
91
|
+
this.revisionDraft = revisionDraft;
|
|
92
|
+
this.metadata = metadata;
|
|
93
|
+
this.onFinish = onFinish;
|
|
94
|
+
|
|
95
|
+
this.signal = signal;
|
|
96
|
+
this.abortController = new AbortController();
|
|
97
|
+
if (signal) {
|
|
98
|
+
signal.addEventListener('abort', () => {
|
|
99
|
+
this.abortController.abort();
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.digests = new UploadDigests();
|
|
104
|
+
this.controller = new UploadController();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
writeFile(fileObject: File, thumbnails: Thumbnail[], onProgress?: (uploadedBytes: number) => void): UploadController {
|
|
108
|
+
if (this.controller.promise) {
|
|
109
|
+
throw new Error(`Upload already started`);
|
|
110
|
+
}
|
|
111
|
+
if (!this.metadata.mediaType) {
|
|
112
|
+
this.metadata.mediaType = fileObject.type;
|
|
113
|
+
}
|
|
114
|
+
if (!this.metadata.expectedSize) {
|
|
115
|
+
this.metadata.expectedSize = fileObject.size;
|
|
116
|
+
}
|
|
117
|
+
if (!this.metadata.modificationTime) {
|
|
118
|
+
this.metadata.modificationTime = new Date(fileObject.lastModified);
|
|
119
|
+
}
|
|
120
|
+
return this.writeStream(fileObject.stream(), thumbnails, onProgress);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
writeStream(stream: ReadableStream, thumbnails: Thumbnail[], onProgress?: (uploadedBytes: number) => void): UploadController {
|
|
124
|
+
if (this.controller.promise) {
|
|
125
|
+
throw new Error(`Upload already started`);
|
|
126
|
+
}
|
|
127
|
+
this.controller.promise = this.uploadStream(stream, thumbnails, onProgress);
|
|
128
|
+
return this.controller;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private async uploadStream(stream: ReadableStream, thumbnails: Thumbnail[], onProgress?: (uploadedBytes: number) => void): Promise<string> {
|
|
132
|
+
let failure = false;
|
|
133
|
+
|
|
134
|
+
// File progress is tracked for telemetry - to track at what
|
|
135
|
+
// point the download failed.
|
|
136
|
+
let fileProgress = 0;
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
this.logger.info(`Starting upload`);
|
|
140
|
+
await this.encryptAndUploadBlocks(stream, thumbnails, (uploadedBytes) => {
|
|
141
|
+
fileProgress += uploadedBytes;
|
|
142
|
+
onProgress?.(uploadedBytes);
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
this.logger.debug(`All blocks uploaded, committing`);
|
|
146
|
+
await this.commitFile(thumbnails);
|
|
147
|
+
|
|
148
|
+
void this.telemetry.uploadFinished(this.revisionDraft.nodeRevisionUid, fileProgress);
|
|
149
|
+
this.logger.info(`Upload succeeded`);
|
|
150
|
+
} catch (error: unknown) {
|
|
151
|
+
failure = true;
|
|
152
|
+
this.logger.error(`Upload failed`, error);
|
|
153
|
+
void this.telemetry.uploadFailed(this.revisionDraft.nodeRevisionUid, error, fileProgress, this.metadata.expectedSize);
|
|
154
|
+
throw error;
|
|
155
|
+
} finally {
|
|
156
|
+
this.logger.debug(`Upload cleanup`);
|
|
157
|
+
|
|
158
|
+
// Help the garbage collector to clean up the memory.
|
|
159
|
+
this.encryptedBlocks.clear();
|
|
160
|
+
this.encryptedThumbnails.clear();
|
|
161
|
+
this.ongoingUploads.clear();
|
|
162
|
+
this.uploadedBlocks = [];
|
|
163
|
+
this.uploadedThumbnails = [];
|
|
164
|
+
this.encryptionFinished = false;
|
|
165
|
+
|
|
166
|
+
await this.onFinish(failure);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this.revisionDraft.nodeRevisionUid;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private async encryptAndUploadBlocks(stream: ReadableStream, thumbnails: Thumbnail[], onProgress?: (uploadedBytes: number) => void) {
|
|
173
|
+
// We await for the encryption of thumbnails to finish before
|
|
174
|
+
// starting the upload. This is because we need to request the
|
|
175
|
+
// upload tokens for the thumbnails with the first blocks.
|
|
176
|
+
await this.encryptThumbnails(thumbnails);
|
|
177
|
+
|
|
178
|
+
// Encrypting blocks and uploading them is done in parallel.
|
|
179
|
+
// For that reason, we want to await for the encryption later.
|
|
180
|
+
// However, jest complains if encryptBlock rejects asynchronously.
|
|
181
|
+
// For that reason we handle manually to save error to the variable
|
|
182
|
+
// and throw if set after we await for the encryption.
|
|
183
|
+
let encryptionError;
|
|
184
|
+
const encryptBlocksPromise = this.encryptBlocks(stream).catch((error) => {
|
|
185
|
+
encryptionError = error;
|
|
186
|
+
void this.abortUpload(error);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
while (!encryptionError) {
|
|
190
|
+
await this.controller.waitIfPaused();
|
|
191
|
+
await this.waitForUploadCapacityAndBufferedBlocks();
|
|
192
|
+
|
|
193
|
+
if (this.isEncryptionFullyFinished) {
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
await this.requestAndInitiateUpload(onProgress);
|
|
198
|
+
|
|
199
|
+
if (this.isEncryptionFullyFinished) {
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.logger.debug(`All blocks uploading, waiting for them to finish`);
|
|
205
|
+
// Technically this is finished as while-block above will break
|
|
206
|
+
// when encryption is finished. But in case of error there could
|
|
207
|
+
// be a race condition that would cause the encryptionError to
|
|
208
|
+
// not be set yet.
|
|
209
|
+
await encryptBlocksPromise;
|
|
210
|
+
if (encryptionError) {
|
|
211
|
+
throw encryptionError;
|
|
212
|
+
}
|
|
213
|
+
await Promise.all(this.ongoingUploads.values().map(({ uploadPromise }) => uploadPromise));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private async commitFile(thumbnails: Thumbnail[]) {
|
|
217
|
+
this.verifyIntegrity(thumbnails);
|
|
218
|
+
|
|
219
|
+
const uploadedBlocks = Array.from(this.uploadedBlocks.values());
|
|
220
|
+
uploadedBlocks.sort((a, b) => a.index - b.index);
|
|
221
|
+
|
|
222
|
+
const extendedAttributes = {
|
|
223
|
+
modificationTime: this.metadata.modificationTime,
|
|
224
|
+
size: this.metadata.expectedSize,
|
|
225
|
+
blockSizes: uploadedBlocks.map(block => block.originalSize),
|
|
226
|
+
digests: this.digests.digests(),
|
|
227
|
+
};
|
|
228
|
+
const encryptedSize = uploadedBlocks.reduce((sum, block) => sum + block.encryptedSize, 0);
|
|
229
|
+
await this.uploadManager.commitDraft(
|
|
230
|
+
this.revisionDraft,
|
|
231
|
+
this.manifest,
|
|
232
|
+
this.metadata,
|
|
233
|
+
extendedAttributes,
|
|
234
|
+
encryptedSize,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async encryptThumbnails(thumbnails: Thumbnail[]) {
|
|
239
|
+
if (new Set(thumbnails.map(({ type }) => type)).size !== thumbnails.length) {
|
|
240
|
+
throw new Error(`Duplicate thumbnail types`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
for (const thumbnail of thumbnails) {
|
|
244
|
+
this.logger.debug(`Encrypting thumbnail ${thumbnail.type}`);
|
|
245
|
+
const encryptedThumbnail = await this.cryptoService.encryptThumbnail(this.revisionDraft.nodeKeys, thumbnail);
|
|
246
|
+
this.encryptedThumbnails.set(thumbnail.type, encryptedThumbnail);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private async encryptBlocks(stream: ReadableStream) {
|
|
251
|
+
try {
|
|
252
|
+
let index = 0;
|
|
253
|
+
const reader = new ChunkStreamReader(stream, FILE_CHUNK_SIZE);
|
|
254
|
+
for await (const block of reader.iterateChunks()) {
|
|
255
|
+
index++;
|
|
256
|
+
|
|
257
|
+
this.digests.update(block);
|
|
258
|
+
|
|
259
|
+
await this.controller.waitIfPaused();
|
|
260
|
+
await this.waitForBufferCapacity();
|
|
261
|
+
|
|
262
|
+
this.logger.debug(`Encrypting block ${index}`);
|
|
263
|
+
let attempt = 0;
|
|
264
|
+
let integrityError = false;
|
|
265
|
+
let encryptedBlock;
|
|
266
|
+
while (!encryptedBlock) {
|
|
267
|
+
attempt++;
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
encryptedBlock = await this.cryptoService.encryptBlock(
|
|
271
|
+
(encryptedBlock) => this.blockVerifier.verifyBlock(encryptedBlock),
|
|
272
|
+
this.revisionDraft.nodeKeys,
|
|
273
|
+
block,
|
|
274
|
+
index,
|
|
275
|
+
);
|
|
276
|
+
if (integrityError) {
|
|
277
|
+
void this.telemetry.logBlockVerificationError(true);
|
|
278
|
+
}
|
|
279
|
+
} catch (error: unknown) {
|
|
280
|
+
if (error instanceof IntegrityError) {
|
|
281
|
+
integrityError = true;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (attempt <= MAX_BLOCK_ENCRYPTION_RETRIES) {
|
|
285
|
+
this.logger.warn(`Block encryption failed #${attempt}, retrying: ${getErrorMessage(error)}`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
this.logger.error(`Failed to encrypt block ${index}`, error);
|
|
290
|
+
if (integrityError) {
|
|
291
|
+
void this.telemetry.logBlockVerificationError(false);
|
|
292
|
+
}
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
this.encryptedBlocks.set(index, encryptedBlock);
|
|
297
|
+
}
|
|
298
|
+
} finally {
|
|
299
|
+
this.encryptionFinished = true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private async requestAndInitiateUpload(onProgress?: (uploadedBytes: number) => void): Promise<void> {
|
|
304
|
+
this.logger.info(`Requesting upload tokens for ${this.encryptedBlocks.size} blocks`);
|
|
305
|
+
const uploadTokens = await this.apiService.requestBlockUpload(
|
|
306
|
+
this.revisionDraft.nodeRevisionUid,
|
|
307
|
+
this.revisionDraft.nodeKeys.signatureAddress.addressId,
|
|
308
|
+
{
|
|
309
|
+
contentBlocks: Array.from(this.encryptedBlocks.values().map(block => ({
|
|
310
|
+
index: block.index,
|
|
311
|
+
encryptedSize: block.encryptedSize,
|
|
312
|
+
hash: block.hash,
|
|
313
|
+
armoredSignature: block.armoredSignature,
|
|
314
|
+
verificationToken: block.verificationToken,
|
|
315
|
+
}))),
|
|
316
|
+
thumbnails: Array.from(this.encryptedThumbnails.values().map(block => ({
|
|
317
|
+
type: block.type,
|
|
318
|
+
encryptedSize: block.encryptedSize,
|
|
319
|
+
hash: block.hash,
|
|
320
|
+
}))),
|
|
321
|
+
},
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
for (const thumbnailToken of uploadTokens.thumbnailTokens) {
|
|
325
|
+
let encryptedThumbnail = this.encryptedThumbnails.get(thumbnailToken.type);
|
|
326
|
+
if (!encryptedThumbnail) {
|
|
327
|
+
throw new Error(`Thumbnail ${thumbnailToken.type} not found`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
this.encryptedThumbnails.delete(thumbnailToken.type);
|
|
331
|
+
|
|
332
|
+
const uploadKey = `thumbnail:${thumbnailToken.type}`;
|
|
333
|
+
this.ongoingUploads.set(uploadKey, {
|
|
334
|
+
uploadPromise: this.uploadThumbnail(
|
|
335
|
+
thumbnailToken,
|
|
336
|
+
encryptedThumbnail,
|
|
337
|
+
onProgress,
|
|
338
|
+
).finally(() => {
|
|
339
|
+
this.ongoingUploads.delete(uploadKey);
|
|
340
|
+
|
|
341
|
+
// Help the garbage collector to clean up the memory.
|
|
342
|
+
encryptedThumbnail = undefined;
|
|
343
|
+
}),
|
|
344
|
+
encryptedBlock: encryptedThumbnail,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
for (const blockToken of uploadTokens.blockTokens) {
|
|
349
|
+
let encryptedBlock = this.encryptedBlocks.get(blockToken.index);
|
|
350
|
+
if (!encryptedBlock) {
|
|
351
|
+
throw new Error(`Block ${blockToken.index} not found`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
this.encryptedBlocks.delete(blockToken.index);
|
|
355
|
+
|
|
356
|
+
const uploadKey = `block:${blockToken.index}`;
|
|
357
|
+
this.ongoingUploads.set(uploadKey, {
|
|
358
|
+
uploadPromise: this.uploadBlock(
|
|
359
|
+
blockToken,
|
|
360
|
+
encryptedBlock,
|
|
361
|
+
onProgress,
|
|
362
|
+
).finally(() => {
|
|
363
|
+
this.ongoingUploads.delete(uploadKey);
|
|
364
|
+
|
|
365
|
+
// Help the garbage collector to clean up the memory.
|
|
366
|
+
encryptedBlock = undefined;
|
|
367
|
+
}),
|
|
368
|
+
encryptedBlock,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
private async uploadThumbnail(
|
|
374
|
+
uploadToken: { bareUrl: string, token: string },
|
|
375
|
+
encryptedThumbnail: EncryptedThumbnail,
|
|
376
|
+
onProgress?: (uploadedBytes: number) => void,
|
|
377
|
+
) {
|
|
378
|
+
const logger = new LoggerWithPrefix(this.logger, `thubmnail ${uploadToken.token}`);
|
|
379
|
+
logger.info(`Upload started`);
|
|
380
|
+
|
|
381
|
+
let blockProgress = 0;
|
|
382
|
+
let attempt = 0;
|
|
383
|
+
|
|
384
|
+
while (true) {
|
|
385
|
+
attempt++;
|
|
386
|
+
try {
|
|
387
|
+
logger.debug(`Uploading`);
|
|
388
|
+
await this.apiService.uploadBlock(
|
|
389
|
+
uploadToken.bareUrl,
|
|
390
|
+
uploadToken.token,
|
|
391
|
+
encryptedThumbnail.encryptedData,
|
|
392
|
+
(uploadedBytes) => {
|
|
393
|
+
blockProgress += uploadedBytes;
|
|
394
|
+
onProgress?.(uploadedBytes);
|
|
395
|
+
},
|
|
396
|
+
this.abortController.signal,
|
|
397
|
+
)
|
|
398
|
+
this.uploadedThumbnails.push({
|
|
399
|
+
type: encryptedThumbnail.type,
|
|
400
|
+
hash: encryptedThumbnail.hash,
|
|
401
|
+
encryptedSize: encryptedThumbnail.encryptedSize,
|
|
402
|
+
originalSize: encryptedThumbnail.originalSize,
|
|
403
|
+
})
|
|
404
|
+
break;
|
|
405
|
+
} catch (error: unknown) {
|
|
406
|
+
if (blockProgress !== 0) {
|
|
407
|
+
onProgress?.(-blockProgress);
|
|
408
|
+
blockProgress = 0;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Note: We don't handle token expiration for thumbnails, because
|
|
412
|
+
// the API requires the thumbnails to be requested with the first
|
|
413
|
+
// upload block request. Thumbnails are tiny, so this edge case
|
|
414
|
+
// should be very rare and considering it is the beginning of the
|
|
415
|
+
// upload, the whole retry is cheap.
|
|
416
|
+
|
|
417
|
+
// Upload can fail for various reasons, for example integrity
|
|
418
|
+
// can fail due to bitflips. We want to retry and solve the issue
|
|
419
|
+
// seamlessly for the user. We retry only once, because we don't
|
|
420
|
+
// want to get stuck in a loop.
|
|
421
|
+
if (attempt <= MAX_BLOCK_UPLOAD_RETRIES) {
|
|
422
|
+
logger.warn(`Upload failed #${attempt}, retrying: ${getErrorMessage(error)}`);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
logger.error(`Upload failed`, error);
|
|
427
|
+
await this.abortUpload(error);
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
logger.info(`Uploaded`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private async uploadBlock(
|
|
436
|
+
uploadToken: { index: number, bareUrl: string, token: string },
|
|
437
|
+
encryptedBlock: EncryptedBlock,
|
|
438
|
+
onProgress?: (uploadedBytes: number) => void,
|
|
439
|
+
) {
|
|
440
|
+
const logger = new LoggerWithPrefix(this.logger, `block ${uploadToken.index}:${uploadToken.token}`);
|
|
441
|
+
logger.info(`Upload started`);
|
|
442
|
+
|
|
443
|
+
let blockProgress = 0;
|
|
444
|
+
let attempt = 0;
|
|
445
|
+
|
|
446
|
+
while (true) {
|
|
447
|
+
attempt++;
|
|
448
|
+
try {
|
|
449
|
+
logger.debug(`Uploading`);
|
|
450
|
+
await this.apiService.uploadBlock(
|
|
451
|
+
uploadToken.bareUrl,
|
|
452
|
+
uploadToken.token,
|
|
453
|
+
encryptedBlock.encryptedData,
|
|
454
|
+
(uploadedBytes) => {
|
|
455
|
+
blockProgress += uploadedBytes;
|
|
456
|
+
onProgress?.(uploadedBytes);
|
|
457
|
+
},
|
|
458
|
+
this.abortController.signal,
|
|
459
|
+
)
|
|
460
|
+
this.uploadedBlocks.push({
|
|
461
|
+
index: encryptedBlock.index,
|
|
462
|
+
hash: encryptedBlock.hash,
|
|
463
|
+
encryptedSize: encryptedBlock.encryptedSize,
|
|
464
|
+
originalSize: encryptedBlock.originalSize,
|
|
465
|
+
})
|
|
466
|
+
break;
|
|
467
|
+
} catch (error: unknown) {
|
|
468
|
+
if (blockProgress !== 0) {
|
|
469
|
+
onProgress?.(-blockProgress);
|
|
470
|
+
blockProgress = 0;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (
|
|
474
|
+
(error instanceof APIHTTPError && error.statusCode === HTTPErrorCode.NOT_FOUND) ||
|
|
475
|
+
(error instanceof NotFoundAPIError)
|
|
476
|
+
) {
|
|
477
|
+
logger.warn(`Token expired, fetching new token and retrying`);
|
|
478
|
+
const uploadTokens = await this.apiService.requestBlockUpload(
|
|
479
|
+
this.revisionDraft.nodeRevisionUid,
|
|
480
|
+
this.revisionDraft.nodeKeys.signatureAddress.addressId,
|
|
481
|
+
{
|
|
482
|
+
contentBlocks: [{
|
|
483
|
+
index: encryptedBlock.index,
|
|
484
|
+
encryptedSize: encryptedBlock.encryptedSize,
|
|
485
|
+
hash: encryptedBlock.hash,
|
|
486
|
+
armoredSignature: encryptedBlock.armoredSignature,
|
|
487
|
+
verificationToken: encryptedBlock.verificationToken,
|
|
488
|
+
}],
|
|
489
|
+
},
|
|
490
|
+
);
|
|
491
|
+
uploadToken = uploadTokens.blockTokens[0];
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Upload can fail for various reasons, for example integrity
|
|
496
|
+
// can fail due to bitflips. We want to retry and solve the issue
|
|
497
|
+
// seamlessly for the user. We retry only once, because we don't
|
|
498
|
+
// want to get stuck in a loop.
|
|
499
|
+
if (attempt <= MAX_BLOCK_UPLOAD_RETRIES) {
|
|
500
|
+
logger.warn(`Upload failed #${attempt}, retrying: ${getErrorMessage(error)}`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
logger.error(`Upload failed`, error);
|
|
505
|
+
await this.abortUpload(error);
|
|
506
|
+
throw error;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
logger.info(`Uploaded`);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
private async waitForBufferCapacity() {
|
|
514
|
+
if (this.encryptedBlocks.size >= MAX_BUFFERED_BLOCKS) {
|
|
515
|
+
await waitForCondition(() => this.encryptedBlocks.size < MAX_BUFFERED_BLOCKS);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private async waitForUploadCapacityAndBufferedBlocks() {
|
|
520
|
+
while (this.ongoingUploads.size >= MAX_UPLOADING_BLOCKS) {
|
|
521
|
+
await Promise.race(this.ongoingUploads.values().map(({ uploadPromise }) => uploadPromise));
|
|
522
|
+
}
|
|
523
|
+
await waitForCondition(() => this.encryptedBlocks.size > 0 || this.encryptionFinished);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private verifyIntegrity(thumbnails: Thumbnail[]) {
|
|
527
|
+
const expectedBlockCount = Math.ceil(this.metadata.expectedSize / FILE_CHUNK_SIZE) + (thumbnails ? thumbnails?.length : 0);
|
|
528
|
+
if (this.uploadedBlockCount !== expectedBlockCount) {
|
|
529
|
+
throw new IntegrityError(c('Error').t`Some file parts failed to upload`, {
|
|
530
|
+
uploadedBlockCount: this.uploadedBlockCount,
|
|
531
|
+
expectedBlockCount,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (this.uploadedOriginalFileSize !== this.metadata.expectedSize) {
|
|
535
|
+
throw new IntegrityError(c('Error').t`Some file bytes failed to upload`, {
|
|
536
|
+
uploadedOriginalFileSize: this.uploadedOriginalFileSize,
|
|
537
|
+
expectedFileSize: this.metadata.expectedSize,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Check if the encryption is fully finished.
|
|
544
|
+
* This means that all blocks and thumbnails have been encrypted and
|
|
545
|
+
* requested to be uploaded, and there are no more blocks or thumbnails
|
|
546
|
+
* to encrypt and upload.
|
|
547
|
+
*/
|
|
548
|
+
private get isEncryptionFullyFinished(): boolean {
|
|
549
|
+
return this.encryptionFinished && this.encryptedBlocks.size === 0 && this.encryptedThumbnails.size === 0;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
private get uploadedBlockCount(): number {
|
|
553
|
+
return this.uploadedBlocks.length + this.uploadedThumbnails.length;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
private get uploadedOriginalFileSize(): number {
|
|
557
|
+
return this.uploadedBlocks.reduce((sum, { originalSize }) => sum + originalSize, 0);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
private get manifest(): Uint8Array {
|
|
561
|
+
this.uploadedThumbnails.sort((a, b) => a.type - b.type);
|
|
562
|
+
this.uploadedBlocks.sort((a, b) => a.index - b.index);
|
|
563
|
+
const hashes = [
|
|
564
|
+
...this.uploadedThumbnails.map(({ hash }) => hash),
|
|
565
|
+
...this.uploadedBlocks.map(({ hash }) => hash),
|
|
566
|
+
];
|
|
567
|
+
return mergeUint8Arrays(hashes);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
private async abortUpload(error: unknown) {
|
|
571
|
+
if (this.abortController.signal.aborted || this.signal?.aborted) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
this.abortController.abort(error);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ProtonDriveTelemetry, UploadMetadata } from "../../interface";
|
|
2
|
+
import { DriveAPIService } from "../apiService";
|
|
3
|
+
import { DriveCrypto } from "../../crypto";
|
|
4
|
+
import { UploadAPIService } from "./apiService";
|
|
5
|
+
import { UploadCryptoService } from "./cryptoService";
|
|
6
|
+
import { UploadQueue } from "./queue";
|
|
7
|
+
import { NodesService, NodesEvents, SharesService } from "./interface";
|
|
8
|
+
import { Fileuploader } from "./fileUploader";
|
|
9
|
+
import { UploadTelemetry } from "./telemetry";
|
|
10
|
+
import { UploadManager } from "./manager";
|
|
11
|
+
import { BlockVerifier } from "./blockVerifier";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provides facade for the upload module.
|
|
15
|
+
*
|
|
16
|
+
* The upload module is responsible for handling file uploads, including
|
|
17
|
+
* metadata generation, content upload, API communication, encryption,
|
|
18
|
+
* and verifications.
|
|
19
|
+
*/
|
|
20
|
+
export function initUploadModule(
|
|
21
|
+
telemetry: ProtonDriveTelemetry,
|
|
22
|
+
apiService: DriveAPIService,
|
|
23
|
+
driveCrypto: DriveCrypto,
|
|
24
|
+
sharesService: SharesService,
|
|
25
|
+
nodesService: NodesService,
|
|
26
|
+
nodesEvents: NodesEvents,
|
|
27
|
+
) {
|
|
28
|
+
const api = new UploadAPIService(apiService);
|
|
29
|
+
const cryptoService = new UploadCryptoService(driveCrypto, nodesService);
|
|
30
|
+
|
|
31
|
+
const uploadTelemetry = new UploadTelemetry(telemetry, sharesService);
|
|
32
|
+
const manager = new UploadManager(telemetry, api, cryptoService, nodesService, nodesEvents);
|
|
33
|
+
|
|
34
|
+
const queue = new UploadQueue();
|
|
35
|
+
|
|
36
|
+
async function getFileUploader(
|
|
37
|
+
parentFolderUid: string,
|
|
38
|
+
name: string,
|
|
39
|
+
metadata: UploadMetadata,
|
|
40
|
+
signal?: AbortSignal,
|
|
41
|
+
): Promise<Fileuploader> {
|
|
42
|
+
await queue.waitForCapacity(signal);
|
|
43
|
+
|
|
44
|
+
let revisionDraft, blockVerifier;
|
|
45
|
+
try {
|
|
46
|
+
revisionDraft = await manager.createDraftNode(parentFolderUid, name, metadata);
|
|
47
|
+
|
|
48
|
+
blockVerifier = new BlockVerifier(api, cryptoService, revisionDraft.nodeKeys.key, revisionDraft.nodeRevisionUid);
|
|
49
|
+
await blockVerifier.loadVerificationData();
|
|
50
|
+
} catch (error: unknown) {
|
|
51
|
+
queue.releaseCapacity();
|
|
52
|
+
if (revisionDraft) {
|
|
53
|
+
await manager.deleteDraftNode(revisionDraft.nodeUid);
|
|
54
|
+
}
|
|
55
|
+
void uploadTelemetry.uploadInitFailed(parentFolderUid, error, metadata.expectedSize);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const onFinish = async (failure: boolean) => {
|
|
60
|
+
queue.releaseCapacity();
|
|
61
|
+
if (failure) {
|
|
62
|
+
await manager.deleteDraftNode(revisionDraft.nodeUid);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return new Fileuploader(
|
|
67
|
+
uploadTelemetry,
|
|
68
|
+
api,
|
|
69
|
+
cryptoService,
|
|
70
|
+
manager,
|
|
71
|
+
blockVerifier,
|
|
72
|
+
revisionDraft,
|
|
73
|
+
metadata,
|
|
74
|
+
onFinish,
|
|
75
|
+
signal,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function getFileRevisionUploader(
|
|
80
|
+
nodeUid: string,
|
|
81
|
+
metadata: UploadMetadata,
|
|
82
|
+
signal?: AbortSignal,
|
|
83
|
+
): Promise<Fileuploader> {
|
|
84
|
+
await queue.waitForCapacity(signal);
|
|
85
|
+
|
|
86
|
+
let revisionDraft, blockVerifier;
|
|
87
|
+
try {
|
|
88
|
+
revisionDraft = await manager.createDraftRevision(nodeUid, metadata);
|
|
89
|
+
|
|
90
|
+
blockVerifier = new BlockVerifier(api, cryptoService, revisionDraft.nodeKeys.key, revisionDraft.nodeRevisionUid);
|
|
91
|
+
await blockVerifier.loadVerificationData();
|
|
92
|
+
} catch (error: unknown) {
|
|
93
|
+
queue.releaseCapacity();
|
|
94
|
+
if (revisionDraft) {
|
|
95
|
+
await manager.deleteDraftRevision(revisionDraft.nodeRevisionUid);
|
|
96
|
+
}
|
|
97
|
+
void uploadTelemetry.uploadInitFailed(nodeUid, error, metadata.expectedSize);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const onFinish = async (failure: boolean) => {
|
|
102
|
+
queue.releaseCapacity();
|
|
103
|
+
if (failure) {
|
|
104
|
+
await manager.deleteDraftNode(revisionDraft.nodeUid);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return new Fileuploader(
|
|
109
|
+
uploadTelemetry,
|
|
110
|
+
api,
|
|
111
|
+
cryptoService,
|
|
112
|
+
manager,
|
|
113
|
+
blockVerifier,
|
|
114
|
+
revisionDraft,
|
|
115
|
+
metadata,
|
|
116
|
+
onFinish,
|
|
117
|
+
signal,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
getFileUploader,
|
|
124
|
+
getFileRevisionUploader,
|
|
125
|
+
}
|
|
126
|
+
}
|