@opentdf/sdk 0.1.0-beta.1701
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 +52 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/src/access.js +155 -0
- package/dist/cjs/src/auth/Eas.js +60 -0
- package/dist/cjs/src/auth/auth.js +79 -0
- package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +26 -0
- package/dist/cjs/src/auth/oidc-externaljwt-provider.js +33 -0
- package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +34 -0
- package/dist/cjs/src/auth/oidc.js +222 -0
- package/dist/cjs/src/auth/providers.js +143 -0
- package/dist/cjs/src/encodings/base64.js +154 -0
- package/dist/cjs/src/encodings/hex.js +70 -0
- package/dist/cjs/src/encodings/index.js +29 -0
- package/dist/cjs/src/errors.js +138 -0
- package/dist/cjs/src/index.js +344 -0
- package/dist/cjs/src/nanotdf/Client.js +296 -0
- package/dist/cjs/src/nanotdf/NanoTDF.js +94 -0
- package/dist/cjs/src/nanotdf/browser-entry.js +19 -0
- package/dist/cjs/src/nanotdf/constants.js +5 -0
- package/dist/cjs/src/nanotdf/decrypt.js +17 -0
- package/dist/cjs/src/nanotdf/encrypt-dataset.js +38 -0
- package/dist/cjs/src/nanotdf/encrypt.js +132 -0
- package/dist/cjs/src/nanotdf/enum/CipherEnum.js +13 -0
- package/dist/cjs/src/nanotdf/enum/CurveNameEnum.js +15 -0
- package/dist/cjs/src/nanotdf/enum/EncodingEnum.js +8 -0
- package/dist/cjs/src/nanotdf/enum/PolicyTypeEnum.js +11 -0
- package/dist/cjs/src/nanotdf/enum/ProtocolEnum.js +10 -0
- package/dist/cjs/src/nanotdf/enum/ResourceLocatorIdentifierEnum.js +11 -0
- package/dist/cjs/src/nanotdf/helpers/calculateByCurve.js +29 -0
- package/dist/cjs/src/nanotdf/helpers/getHkdfSalt.js +11 -0
- package/dist/cjs/src/nanotdf/index.js +25 -0
- package/dist/cjs/src/nanotdf/interfaces/PolicyInterface.js +3 -0
- package/dist/cjs/src/nanotdf/models/Ciphers.js +61 -0
- package/dist/cjs/src/nanotdf/models/DefaultParams.js +27 -0
- package/dist/cjs/src/nanotdf/models/EcCurves.js +39 -0
- package/dist/cjs/src/nanotdf/models/Header.js +255 -0
- package/dist/cjs/src/nanotdf/models/Payload.js +158 -0
- package/dist/cjs/src/nanotdf/models/Policy/AbstractPolicy.js +73 -0
- package/dist/cjs/src/nanotdf/models/Policy/EmbeddedPolicy.js +82 -0
- package/dist/cjs/src/nanotdf/models/Policy/PolicyFactory.js +38 -0
- package/dist/cjs/src/nanotdf/models/Policy/RemotePolicy.js +62 -0
- package/dist/cjs/src/nanotdf/models/ResourceLocator.js +211 -0
- package/dist/cjs/src/nanotdf/models/Signature.js +77 -0
- package/dist/cjs/src/nanotdf-crypto/ciphers.js +17 -0
- package/dist/cjs/src/nanotdf-crypto/decrypt.js +24 -0
- package/dist/cjs/src/nanotdf-crypto/digest.js +7 -0
- package/dist/cjs/src/nanotdf-crypto/ecdsaSignature.js +83 -0
- package/dist/cjs/src/nanotdf-crypto/encrypt.js +24 -0
- package/dist/cjs/src/nanotdf-crypto/enums.js +52 -0
- package/dist/cjs/src/nanotdf-crypto/exportCryptoKey.js +20 -0
- package/dist/cjs/src/nanotdf-crypto/generateKeyPair.js +13 -0
- package/dist/cjs/src/nanotdf-crypto/generateRandomNumber.js +12 -0
- package/dist/cjs/src/nanotdf-crypto/importRawKey.js +18 -0
- package/dist/cjs/src/nanotdf-crypto/index.js +52 -0
- package/dist/cjs/src/nanotdf-crypto/keyAgreement.js +91 -0
- package/dist/cjs/src/nanotdf-crypto/pemPublicToCrypto.js +225 -0
- package/dist/cjs/src/policy/api.js +58 -0
- package/dist/cjs/src/policy/attributes.js +3 -0
- package/dist/cjs/src/policy/granter.js +146 -0
- package/dist/cjs/src/tdf/AttributeObject.js +15 -0
- package/dist/cjs/src/tdf/AttributeObjectJwt.js +3 -0
- package/dist/cjs/src/tdf/Crypto.js +47 -0
- package/dist/cjs/src/tdf/EntityObject.js +3 -0
- package/dist/cjs/src/tdf/NanoTDF/NanoTDF.js +38 -0
- package/dist/cjs/src/tdf/Policy.js +50 -0
- package/dist/cjs/src/tdf/PolicyObject.js +3 -0
- package/dist/cjs/src/tdf/TypedArray.js +3 -0
- package/dist/cjs/src/tdf/index.js +35 -0
- package/dist/cjs/src/types/index.js +3 -0
- package/dist/cjs/src/utils.js +147 -0
- package/dist/cjs/src/version.js +12 -0
- package/dist/cjs/tdf3/index.js +57 -0
- package/dist/cjs/tdf3/src/assertions.js +118 -0
- package/dist/cjs/tdf3/src/binary.js +153 -0
- package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +56 -0
- package/dist/cjs/tdf3/src/ciphers/algorithms.js +8 -0
- package/dist/cjs/tdf3/src/ciphers/index.js +8 -0
- package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +22 -0
- package/dist/cjs/tdf3/src/client/DecoratedReadableStream.js +116 -0
- package/dist/cjs/tdf3/src/client/builders.js +561 -0
- package/dist/cjs/tdf3/src/client/index.js +460 -0
- package/dist/cjs/tdf3/src/client/validation.js +63 -0
- package/dist/cjs/tdf3/src/crypto/crypto-utils.js +116 -0
- package/dist/cjs/tdf3/src/crypto/declarations.js +8 -0
- package/dist/cjs/tdf3/src/crypto/index.js +315 -0
- package/dist/cjs/tdf3/src/index.js +34 -0
- package/dist/cjs/tdf3/src/models/attribute-set.js +122 -0
- package/dist/cjs/tdf3/src/models/encryption-information.js +90 -0
- package/dist/cjs/tdf3/src/models/index.js +25 -0
- package/dist/cjs/tdf3/src/models/key-access.js +103 -0
- package/dist/cjs/tdf3/src/models/manifest.js +3 -0
- package/dist/cjs/tdf3/src/models/payload.js +3 -0
- package/dist/cjs/tdf3/src/models/policy.js +24 -0
- package/dist/cjs/tdf3/src/models/upsert-response.js +3 -0
- package/dist/cjs/tdf3/src/tdf.js +907 -0
- package/dist/cjs/tdf3/src/templates/default.html.js +98 -0
- package/dist/cjs/tdf3/src/templates/escaper.js +15 -0
- package/dist/cjs/tdf3/src/templates/index.js +12 -0
- package/dist/cjs/tdf3/src/utils/buffer-crc32.js +48 -0
- package/dist/cjs/tdf3/src/utils/chunkers.js +106 -0
- package/dist/cjs/tdf3/src/utils/index.js +296 -0
- package/dist/cjs/tdf3/src/utils/keysplit.js +61 -0
- package/dist/cjs/tdf3/src/utils/zip-reader.js +253 -0
- package/dist/cjs/tdf3/src/utils/zip-writer.js +308 -0
- package/dist/cjs/tdf3/src/version.js +6 -0
- package/dist/types/src/access.d.ts +47 -0
- package/dist/types/src/access.d.ts.map +1 -0
- package/dist/types/src/auth/Eas.d.ts +34 -0
- package/dist/types/src/auth/Eas.d.ts.map +1 -0
- package/dist/types/src/auth/auth.d.ts +86 -0
- package/dist/types/src/auth/auth.d.ts.map +1 -0
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +9 -0
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -0
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +10 -0
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -0
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +10 -0
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -0
- package/dist/types/src/auth/oidc.d.ts +104 -0
- package/dist/types/src/auth/oidc.d.ts.map +1 -0
- package/dist/types/src/auth/providers.d.ts +67 -0
- package/dist/types/src/auth/providers.d.ts.map +1 -0
- package/dist/types/src/encodings/base64.d.ts +18 -0
- package/dist/types/src/encodings/base64.d.ts.map +1 -0
- package/dist/types/src/encodings/hex.d.ts +5 -0
- package/dist/types/src/encodings/hex.d.ts.map +1 -0
- package/dist/types/src/encodings/index.d.ts +3 -0
- package/dist/types/src/encodings/index.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +72 -0
- package/dist/types/src/errors.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +138 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/nanotdf/Client.d.ts +95 -0
- package/dist/types/src/nanotdf/Client.d.ts.map +1 -0
- package/dist/types/src/nanotdf/NanoTDF.d.ts +25 -0
- package/dist/types/src/nanotdf/NanoTDF.d.ts.map +1 -0
- package/dist/types/src/nanotdf/browser-entry.d.ts +17 -0
- package/dist/types/src/nanotdf/browser-entry.d.ts.map +1 -0
- package/dist/types/src/nanotdf/constants.d.ts +2 -0
- package/dist/types/src/nanotdf/constants.d.ts.map +1 -0
- package/dist/types/src/nanotdf/decrypt.d.ts +9 -0
- package/dist/types/src/nanotdf/decrypt.d.ts.map +1 -0
- package/dist/types/src/nanotdf/encrypt-dataset.d.ts +12 -0
- package/dist/types/src/nanotdf/encrypt-dataset.d.ts.map +1 -0
- package/dist/types/src/nanotdf/encrypt.d.ts +14 -0
- package/dist/types/src/nanotdf/encrypt.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/CipherEnum.d.ts +10 -0
- package/dist/types/src/nanotdf/enum/CipherEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/CurveNameEnum.d.ts +12 -0
- package/dist/types/src/nanotdf/enum/CurveNameEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/EncodingEnum.d.ts +5 -0
- package/dist/types/src/nanotdf/enum/EncodingEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/PolicyTypeEnum.d.ts +8 -0
- package/dist/types/src/nanotdf/enum/PolicyTypeEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/ProtocolEnum.d.ts +7 -0
- package/dist/types/src/nanotdf/enum/ProtocolEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/enum/ResourceLocatorIdentifierEnum.d.ts +8 -0
- package/dist/types/src/nanotdf/enum/ResourceLocatorIdentifierEnum.d.ts.map +1 -0
- package/dist/types/src/nanotdf/helpers/calculateByCurve.d.ts +20 -0
- package/dist/types/src/nanotdf/helpers/calculateByCurve.d.ts.map +1 -0
- package/dist/types/src/nanotdf/helpers/getHkdfSalt.d.ts +9 -0
- package/dist/types/src/nanotdf/helpers/getHkdfSalt.d.ts.map +1 -0
- package/dist/types/src/nanotdf/index.d.ts +9 -0
- package/dist/types/src/nanotdf/index.d.ts.map +1 -0
- package/dist/types/src/nanotdf/interfaces/PolicyInterface.d.ts +17 -0
- package/dist/types/src/nanotdf/interfaces/PolicyInterface.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Ciphers.d.ts +14 -0
- package/dist/types/src/nanotdf/models/Ciphers.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/DefaultParams.d.ts +21 -0
- package/dist/types/src/nanotdf/models/DefaultParams.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/EcCurves.d.ts +15 -0
- package/dist/types/src/nanotdf/models/EcCurves.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Header.d.ts +73 -0
- package/dist/types/src/nanotdf/models/Header.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Payload.d.ts +47 -0
- package/dist/types/src/nanotdf/models/Payload.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Policy/AbstractPolicy.d.ts +52 -0
- package/dist/types/src/nanotdf/models/Policy/AbstractPolicy.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Policy/EmbeddedPolicy.d.ts +35 -0
- package/dist/types/src/nanotdf/models/Policy/EmbeddedPolicy.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Policy/PolicyFactory.d.ts +11 -0
- package/dist/types/src/nanotdf/models/Policy/PolicyFactory.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Policy/RemotePolicy.d.ts +31 -0
- package/dist/types/src/nanotdf/models/Policy/RemotePolicy.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/ResourceLocator.d.ts +65 -0
- package/dist/types/src/nanotdf/models/ResourceLocator.d.ts.map +1 -0
- package/dist/types/src/nanotdf/models/Signature.d.ts +33 -0
- package/dist/types/src/nanotdf/models/Signature.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/ciphers.d.ts +8 -0
- package/dist/types/src/nanotdf-crypto/ciphers.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/decrypt.d.ts +14 -0
- package/dist/types/src/nanotdf-crypto/decrypt.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/digest.d.ts +3 -0
- package/dist/types/src/nanotdf-crypto/digest.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/ecdsaSignature.d.ts +35 -0
- package/dist/types/src/nanotdf-crypto/ecdsaSignature.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/encrypt.d.ts +14 -0
- package/dist/types/src/nanotdf-crypto/encrypt.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/enums.d.ts +42 -0
- package/dist/types/src/nanotdf-crypto/enums.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/exportCryptoKey.d.ts +7 -0
- package/dist/types/src/nanotdf-crypto/exportCryptoKey.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/generateKeyPair.d.ts +10 -0
- package/dist/types/src/nanotdf-crypto/generateKeyPair.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/generateRandomNumber.d.ts +5 -0
- package/dist/types/src/nanotdf-crypto/generateRandomNumber.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/importRawKey.d.ts +13 -0
- package/dist/types/src/nanotdf-crypto/importRawKey.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/index.d.ts +12 -0
- package/dist/types/src/nanotdf-crypto/index.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/keyAgreement.d.ts +28 -0
- package/dist/types/src/nanotdf-crypto/keyAgreement.d.ts.map +1 -0
- package/dist/types/src/nanotdf-crypto/pemPublicToCrypto.d.ts +28 -0
- package/dist/types/src/nanotdf-crypto/pemPublicToCrypto.d.ts.map +1 -0
- package/dist/types/src/policy/api.d.ts +4 -0
- package/dist/types/src/policy/api.d.ts.map +1 -0
- package/dist/types/src/policy/attributes.d.ts +95 -0
- package/dist/types/src/policy/attributes.d.ts.map +1 -0
- package/dist/types/src/policy/granter.d.ts +23 -0
- package/dist/types/src/policy/granter.d.ts.map +1 -0
- package/dist/types/src/tdf/AttributeObject.d.ts +13 -0
- package/dist/types/src/tdf/AttributeObject.d.ts.map +1 -0
- package/dist/types/src/tdf/AttributeObjectJwt.d.ts +4 -0
- package/dist/types/src/tdf/AttributeObjectJwt.d.ts.map +1 -0
- package/dist/types/src/tdf/Crypto.d.ts +37 -0
- package/dist/types/src/tdf/Crypto.d.ts.map +1 -0
- package/dist/types/src/tdf/EntityObject.d.ts +18 -0
- package/dist/types/src/tdf/EntityObject.d.ts.map +1 -0
- package/dist/types/src/tdf/NanoTDF/NanoTDF.d.ts +99 -0
- package/dist/types/src/tdf/NanoTDF/NanoTDF.d.ts.map +1 -0
- package/dist/types/src/tdf/Policy.d.ts +28 -0
- package/dist/types/src/tdf/Policy.d.ts.map +1 -0
- package/dist/types/src/tdf/PolicyObject.d.ts +11 -0
- package/dist/types/src/tdf/PolicyObject.d.ts.map +1 -0
- package/dist/types/src/tdf/TypedArray.d.ts +3 -0
- package/dist/types/src/tdf/TypedArray.d.ts.map +1 -0
- package/dist/types/src/tdf/index.d.ts +7 -0
- package/dist/types/src/tdf/index.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +45 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/utils.d.ts +45 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/dist/types/src/version.d.ts +9 -0
- package/dist/types/src/version.d.ts.map +1 -0
- package/dist/types/tdf3/index.d.ts +16 -0
- package/dist/types/tdf3/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/assertions.d.ts +63 -0
- package/dist/types/tdf3/src/assertions.d.ts.map +1 -0
- package/dist/types/tdf3/src/binary.d.ts +38 -0
- package/dist/types/tdf3/src/binary.d.ts.map +1 -0
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +18 -0
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -0
- package/dist/types/tdf3/src/ciphers/algorithms.d.ts +4 -0
- package/dist/types/tdf3/src/ciphers/algorithms.d.ts.map +1 -0
- package/dist/types/tdf3/src/ciphers/index.d.ts +3 -0
- package/dist/types/tdf3/src/ciphers/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +14 -0
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -0
- package/dist/types/tdf3/src/client/DecoratedReadableStream.d.ts +53 -0
- package/dist/types/tdf3/src/client/DecoratedReadableStream.d.ts.map +1 -0
- package/dist/types/tdf3/src/client/builders.d.ts +436 -0
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -0
- package/dist/types/tdf3/src/client/index.d.ts +139 -0
- package/dist/types/tdf3/src/client/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/client/validation.d.ts +8 -0
- package/dist/types/tdf3/src/client/validation.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +34 -0
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/declarations.d.ts +60 -0
- package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/index.d.ts +103 -0
- package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/index.d.ts +5 -0
- package/dist/types/tdf3/src/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/attribute-set.d.ts +65 -0
- package/dist/types/tdf3/src/models/attribute-set.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/encryption-information.d.ts +49 -0
- package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/index.d.ts +9 -0
- package/dist/types/tdf3/src/models/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/key-access.d.ts +42 -0
- package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/manifest.d.ts +9 -0
- package/dist/types/tdf3/src/models/manifest.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/payload.d.ts +7 -0
- package/dist/types/tdf3/src/models/payload.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/policy.d.ts +13 -0
- package/dist/types/tdf3/src/models/policy.d.ts.map +1 -0
- package/dist/types/tdf3/src/models/upsert-response.d.ts +16 -0
- package/dist/types/tdf3/src/models/upsert-response.d.ts.map +1 -0
- package/dist/types/tdf3/src/tdf.d.ts +152 -0
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -0
- package/dist/types/tdf3/src/templates/default.html.d.ts +8 -0
- package/dist/types/tdf3/src/templates/default.html.d.ts.map +1 -0
- package/dist/types/tdf3/src/templates/escaper.d.ts +6 -0
- package/dist/types/tdf3/src/templates/escaper.d.ts.map +1 -0
- package/dist/types/tdf3/src/templates/index.d.ts +3 -0
- package/dist/types/tdf3/src/templates/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/buffer-crc32.d.ts +2 -0
- package/dist/types/tdf3/src/utils/buffer-crc32.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/chunkers.d.ts +29 -0
- package/dist/types/tdf3/src/utils/chunkers.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/index.d.ts +36 -0
- package/dist/types/tdf3/src/utils/index.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/keysplit.d.ts +19 -0
- package/dist/types/tdf3/src/utils/keysplit.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/zip-reader.d.ts +63 -0
- package/dist/types/tdf3/src/utils/zip-reader.d.ts.map +1 -0
- package/dist/types/tdf3/src/utils/zip-writer.d.ts +35 -0
- package/dist/types/tdf3/src/utils/zip-writer.d.ts.map +1 -0
- package/dist/types/tdf3/src/version.d.ts +3 -0
- package/dist/types/tdf3/src/version.d.ts.map +1 -0
- package/dist/web/package.json +3 -0
- package/dist/web/src/access.js +147 -0
- package/dist/web/src/auth/Eas.js +55 -0
- package/dist/web/src/auth/auth.js +71 -0
- package/dist/web/src/auth/oidc-clientcredentials-provider.js +22 -0
- package/dist/web/src/auth/oidc-externaljwt-provider.js +29 -0
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +30 -0
- package/dist/web/src/auth/oidc.js +215 -0
- package/dist/web/src/auth/providers.js +119 -0
- package/dist/web/src/encodings/base64.js +147 -0
- package/dist/web/src/encodings/hex.js +63 -0
- package/dist/web/src/encodings/index.js +3 -0
- package/dist/web/src/errors.js +123 -0
- package/dist/web/src/index.js +313 -0
- package/dist/web/src/nanotdf/Client.js +268 -0
- package/dist/web/src/nanotdf/NanoTDF.js +89 -0
- package/dist/web/src/nanotdf/browser-entry.js +14 -0
- package/dist/web/src/nanotdf/constants.js +2 -0
- package/dist/web/src/nanotdf/decrypt.js +14 -0
- package/dist/web/src/nanotdf/encrypt-dataset.js +32 -0
- package/dist/web/src/nanotdf/encrypt.js +126 -0
- package/dist/web/src/nanotdf/enum/CipherEnum.js +11 -0
- package/dist/web/src/nanotdf/enum/CurveNameEnum.js +13 -0
- package/dist/web/src/nanotdf/enum/EncodingEnum.js +6 -0
- package/dist/web/src/nanotdf/enum/PolicyTypeEnum.js +9 -0
- package/dist/web/src/nanotdf/enum/ProtocolEnum.js +8 -0
- package/dist/web/src/nanotdf/enum/ResourceLocatorIdentifierEnum.js +9 -0
- package/dist/web/src/nanotdf/helpers/calculateByCurve.js +24 -0
- package/dist/web/src/nanotdf/helpers/getHkdfSalt.js +8 -0
- package/dist/web/src/nanotdf/index.js +11 -0
- package/dist/web/src/nanotdf/interfaces/PolicyInterface.js +2 -0
- package/dist/web/src/nanotdf/models/Ciphers.js +54 -0
- package/dist/web/src/nanotdf/models/DefaultParams.js +22 -0
- package/dist/web/src/nanotdf/models/EcCurves.js +32 -0
- package/dist/web/src/nanotdf/models/Header.js +250 -0
- package/dist/web/src/nanotdf/models/Payload.js +156 -0
- package/dist/web/src/nanotdf/models/Policy/AbstractPolicy.js +71 -0
- package/dist/web/src/nanotdf/models/Policy/EmbeddedPolicy.js +77 -0
- package/dist/web/src/nanotdf/models/Policy/PolicyFactory.js +33 -0
- package/dist/web/src/nanotdf/models/Policy/RemotePolicy.js +57 -0
- package/dist/web/src/nanotdf/models/ResourceLocator.js +206 -0
- package/dist/web/src/nanotdf/models/Signature.js +74 -0
- package/dist/web/src/nanotdf-crypto/ciphers.js +14 -0
- package/dist/web/src/nanotdf-crypto/decrypt.js +21 -0
- package/dist/web/src/nanotdf-crypto/digest.js +4 -0
- package/dist/web/src/nanotdf-crypto/ecdsaSignature.js +77 -0
- package/dist/web/src/nanotdf-crypto/encrypt.js +21 -0
- package/dist/web/src/nanotdf-crypto/enums.js +49 -0
- package/dist/web/src/nanotdf-crypto/exportCryptoKey.js +17 -0
- package/dist/web/src/nanotdf-crypto/generateKeyPair.js +10 -0
- package/dist/web/src/nanotdf-crypto/generateRandomNumber.js +9 -0
- package/dist/web/src/nanotdf-crypto/importRawKey.js +15 -0
- package/dist/web/src/nanotdf-crypto/index.js +12 -0
- package/dist/web/src/nanotdf-crypto/keyAgreement.js +87 -0
- package/dist/web/src/nanotdf-crypto/pemPublicToCrypto.js +197 -0
- package/dist/web/src/policy/api.js +54 -0
- package/dist/web/src/policy/attributes.js +2 -0
- package/dist/web/src/policy/granter.js +141 -0
- package/dist/web/src/tdf/AttributeObject.js +11 -0
- package/dist/web/src/tdf/AttributeObjectJwt.js +2 -0
- package/dist/web/src/tdf/Crypto.js +44 -0
- package/dist/web/src/tdf/EntityObject.js +2 -0
- package/dist/web/src/tdf/NanoTDF/NanoTDF.js +35 -0
- package/dist/web/src/tdf/Policy.js +48 -0
- package/dist/web/src/tdf/PolicyObject.js +2 -0
- package/dist/web/src/tdf/TypedArray.js +2 -0
- package/dist/web/src/tdf/index.js +4 -0
- package/dist/web/src/types/index.js +2 -0
- package/dist/web/src/utils.js +133 -0
- package/dist/web/src/version.js +9 -0
- package/dist/web/tdf3/index.js +13 -0
- package/dist/web/tdf3/src/assertions.js +111 -0
- package/dist/web/tdf3/src/binary.js +149 -0
- package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +52 -0
- package/dist/web/tdf3/src/ciphers/algorithms.js +5 -0
- package/dist/web/tdf3/src/ciphers/index.js +3 -0
- package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +18 -0
- package/dist/web/tdf3/src/client/DecoratedReadableStream.js +107 -0
- package/dist/web/tdf3/src/client/builders.js +557 -0
- package/dist/web/tdf3/src/client/index.js +423 -0
- package/dist/web/tdf3/src/client/validation.js +58 -0
- package/dist/web/tdf3/src/crypto/crypto-utils.js +107 -0
- package/dist/web/tdf3/src/crypto/declarations.js +5 -0
- package/dist/web/tdf3/src/crypto/index.js +296 -0
- package/dist/web/tdf3/src/index.js +5 -0
- package/dist/web/tdf3/src/models/attribute-set.js +118 -0
- package/dist/web/tdf3/src/models/encryption-information.js +86 -0
- package/dist/web/tdf3/src/models/index.js +9 -0
- package/dist/web/tdf3/src/models/key-access.js +74 -0
- package/dist/web/tdf3/src/models/manifest.js +2 -0
- package/dist/web/tdf3/src/models/payload.js +2 -0
- package/dist/web/tdf3/src/models/policy.js +20 -0
- package/dist/web/tdf3/src/models/upsert-response.js +2 -0
- package/dist/web/tdf3/src/tdf.js +866 -0
- package/dist/web/tdf3/src/templates/default.html.js +96 -0
- package/dist/web/tdf3/src/templates/escaper.js +10 -0
- package/dist/web/tdf3/src/templates/index.js +3 -0
- package/dist/web/tdf3/src/utils/buffer-crc32.js +44 -0
- package/dist/web/tdf3/src/utils/chunkers.js +96 -0
- package/dist/web/tdf3/src/utils/index.js +248 -0
- package/dist/web/tdf3/src/utils/keysplit.js +55 -0
- package/dist/web/tdf3/src/utils/zip-reader.js +247 -0
- package/dist/web/tdf3/src/utils/zip-writer.js +302 -0
- package/dist/web/tdf3/src/version.js +3 -0
- package/package.json +126 -0
- package/src/access.ts +198 -0
- package/src/auth/Eas.ts +79 -0
- package/src/auth/auth.ts +141 -0
- package/src/auth/oidc-clientcredentials-provider.ts +32 -0
- package/src/auth/oidc-externaljwt-provider.ts +41 -0
- package/src/auth/oidc-refreshtoken-provider.ts +41 -0
- package/src/auth/oidc.ts +307 -0
- package/src/auth/providers.ts +139 -0
- package/src/encodings/base64.ts +160 -0
- package/src/encodings/hex.ts +69 -0
- package/src/encodings/index.ts +2 -0
- package/src/errors.ts +113 -0
- package/src/index.ts +441 -0
- package/src/nanotdf/Client.ts +349 -0
- package/src/nanotdf/NanoTDF.ts +121 -0
- package/src/nanotdf/browser-entry.ts +20 -0
- package/src/nanotdf/constants.ts +1 -0
- package/src/nanotdf/decrypt.ts +19 -0
- package/src/nanotdf/encrypt-dataset.ts +52 -0
- package/src/nanotdf/encrypt.ts +197 -0
- package/src/nanotdf/enum/CipherEnum.ts +10 -0
- package/src/nanotdf/enum/CurveNameEnum.ts +12 -0
- package/src/nanotdf/enum/EncodingEnum.ts +5 -0
- package/src/nanotdf/enum/PolicyTypeEnum.ts +8 -0
- package/src/nanotdf/enum/ProtocolEnum.ts +7 -0
- package/src/nanotdf/enum/ResourceLocatorIdentifierEnum.ts +8 -0
- package/src/nanotdf/helpers/calculateByCurve.ts +26 -0
- package/src/nanotdf/helpers/getHkdfSalt.ts +15 -0
- package/src/nanotdf/index.ts +10 -0
- package/src/nanotdf/interfaces/PolicyInterface.ts +27 -0
- package/src/nanotdf/models/Ciphers.ts +67 -0
- package/src/nanotdf/models/DefaultParams.ts +24 -0
- package/src/nanotdf/models/EcCurves.ts +40 -0
- package/src/nanotdf/models/Header.ts +322 -0
- package/src/nanotdf/models/Payload.ts +196 -0
- package/src/nanotdf/models/Policy/AbstractPolicy.ts +90 -0
- package/src/nanotdf/models/Policy/EmbeddedPolicy.ts +101 -0
- package/src/nanotdf/models/Policy/PolicyFactory.ts +48 -0
- package/src/nanotdf/models/Policy/RemotePolicy.ts +74 -0
- package/src/nanotdf/models/ResourceLocator.ts +212 -0
- package/src/nanotdf/models/Signature.ts +85 -0
- package/src/nanotdf-crypto/ciphers.ts +13 -0
- package/src/nanotdf-crypto/decrypt.ts +30 -0
- package/src/nanotdf-crypto/digest.ts +8 -0
- package/src/nanotdf-crypto/ecdsaSignature.ts +109 -0
- package/src/nanotdf-crypto/encrypt.ts +30 -0
- package/src/nanotdf-crypto/enums.ts +47 -0
- package/src/nanotdf-crypto/exportCryptoKey.ts +17 -0
- package/src/nanotdf-crypto/generateKeyPair.ts +19 -0
- package/src/nanotdf-crypto/generateRandomNumber.ts +8 -0
- package/src/nanotdf-crypto/importRawKey.ts +19 -0
- package/src/nanotdf-crypto/index.ts +11 -0
- package/src/nanotdf-crypto/keyAgreement.ts +139 -0
- package/src/nanotdf-crypto/pemPublicToCrypto.ts +232 -0
- package/src/package-lock.json +6 -0
- package/src/package.json +3 -0
- package/src/platform/authorization/authorization_connect.d.ts +44 -0
- package/src/platform/authorization/authorization_connect.js +44 -0
- package/src/platform/authorization/authorization_pb.d.ts +707 -0
- package/src/platform/authorization/authorization_pb.js +372 -0
- package/src/platform/common/common_pb.d.ts +129 -0
- package/src/platform/common/common_pb.js +58 -0
- package/src/platform/entityresolution/entity_resolution_connect.d.ts +35 -0
- package/src/platform/entityresolution/entity_resolution_connect.js +35 -0
- package/src/platform/entityresolution/entity_resolution_pb.d.ts +242 -0
- package/src/platform/entityresolution/entity_resolution_pb.js +139 -0
- package/src/platform/kas/kas_connect.d.ts +59 -0
- package/src/platform/kas/kas_connect.js +59 -0
- package/src/platform/kas/kas_pb.d.ts +200 -0
- package/src/platform/kas/kas_pb.js +84 -0
- package/src/platform/policy/attributes/attributes_connect.d.ts +168 -0
- package/src/platform/policy/attributes/attributes_connect.js +168 -0
- package/src/platform/policy/attributes/attributes_pb.d.ts +929 -0
- package/src/platform/policy/attributes/attributes_pb.js +363 -0
- package/src/platform/policy/kasregistry/key_access_server_registry_connect.d.ts +62 -0
- package/src/platform/policy/kasregistry/key_access_server_registry_connect.js +62 -0
- package/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts +283 -0
- package/src/platform/policy/kasregistry/key_access_server_registry_pb.js +113 -0
- package/src/platform/policy/namespaces/namespaces_connect.d.ts +62 -0
- package/src/platform/policy/namespaces/namespaces_connect.js +62 -0
- package/src/platform/policy/namespaces/namespaces_pb.d.ts +270 -0
- package/src/platform/policy/namespaces/namespaces_pb.js +110 -0
- package/src/platform/policy/objects_pb.d.ts +725 -0
- package/src/platform/policy/objects_pb.js +288 -0
- package/src/platform/policy/resourcemapping/resource_mapping_connect.d.ts +259 -0
- package/src/platform/policy/resourcemapping/resource_mapping_connect.js +259 -0
- package/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts +314 -0
- package/src/platform/policy/resourcemapping/resource_mapping_pb.js +142 -0
- package/src/platform/policy/selectors_pb.d.ts +269 -0
- package/src/platform/policy/selectors_pb.js +110 -0
- package/src/platform/policy/subjectmapping/subject_mapping_connect.d.ts +118 -0
- package/src/platform/policy/subjectmapping/subject_mapping_connect.js +118 -0
- package/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts +672 -0
- package/src/platform/policy/subjectmapping/subject_mapping_pb.js +260 -0
- package/src/platform/wellknownconfiguration/wellknown_configuration_connect.d.ts +26 -0
- package/src/platform/wellknownconfiguration/wellknown_configuration_connect.js +26 -0
- package/src/platform/wellknownconfiguration/wellknown_configuration_pb.d.ts +75 -0
- package/src/platform/wellknownconfiguration/wellknown_configuration_pb.js +35 -0
- package/src/policy/api.ts +61 -0
- package/src/policy/attributes.ts +117 -0
- package/src/policy/granter.ts +181 -0
- package/src/tdf/AttributeObject.ts +27 -0
- package/src/tdf/AttributeObjectJwt.ts +3 -0
- package/src/tdf/Crypto.ts +42 -0
- package/src/tdf/EntityObject.ts +18 -0
- package/src/tdf/NanoTDF/NanoTDF.ts +120 -0
- package/src/tdf/Policy.ts +51 -0
- package/src/tdf/PolicyObject.ts +12 -0
- package/src/tdf/TypedArray.ts +12 -0
- package/src/tdf/index.ts +6 -0
- package/src/types/index.ts +55 -0
- package/src/utils.ts +149 -0
- package/src/version.ts +9 -0
- package/tdf3/index.ts +91 -0
- package/tdf3/package-lock.json +6 -0
- package/tdf3/package.json +3 -0
- package/tdf3/src/assertions.ts +191 -0
- package/tdf3/src/binary.ts +195 -0
- package/tdf3/src/ciphers/aes-gcm-cipher.ts +76 -0
- package/tdf3/src/ciphers/algorithms.ts +9 -0
- package/tdf3/src/ciphers/index.ts +2 -0
- package/tdf3/src/ciphers/symmetric-cipher-base.ts +38 -0
- package/tdf3/src/client/DecoratedReadableStream.ts +148 -0
- package/tdf3/src/client/builders.ts +701 -0
- package/tdf3/src/client/index.ts +637 -0
- package/tdf3/src/client/validation.ts +79 -0
- package/tdf3/src/crypto/crypto-utils.ts +119 -0
- package/tdf3/src/crypto/declarations.ts +89 -0
- package/tdf3/src/crypto/index.ts +394 -0
- package/tdf3/src/index.ts +4 -0
- package/tdf3/src/models/attribute-set.ts +142 -0
- package/tdf3/src/models/encryption-information.ts +172 -0
- package/tdf3/src/models/index.ts +8 -0
- package/tdf3/src/models/key-access.ts +128 -0
- package/tdf3/src/models/manifest.ts +9 -0
- package/tdf3/src/models/payload.ts +6 -0
- package/tdf3/src/models/policy.ts +35 -0
- package/tdf3/src/models/upsert-response.ts +17 -0
- package/tdf3/src/tdf.ts +1351 -0
- package/tdf3/src/templates/default.html.ts +105 -0
- package/tdf3/src/templates/escaper.ts +10 -0
- package/tdf3/src/templates/index.ts +2 -0
- package/tdf3/src/utils/buffer-crc32.ts +46 -0
- package/tdf3/src/utils/chunkers.ts +118 -0
- package/tdf3/src/utils/index.ts +309 -0
- package/tdf3/src/utils/keysplit.ts +63 -0
- package/tdf3/src/utils/zip-reader.ts +341 -0
- package/tdf3/src/utils/zip-writer.ts +375 -0
- package/tdf3/src/version.ts +2 -0
- package/tdf3/types.d.ts +14 -0
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { unsigned } from './utils/buffer-crc32.js';
|
|
3
|
+
import { exportSPKI, importX509 } from 'jose';
|
|
4
|
+
import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
|
|
5
|
+
import { pemToCryptoPublicKey, validateSecureUrl } from '../../src/utils.js';
|
|
6
|
+
import * as assertions from './assertions.js';
|
|
7
|
+
import { isRemote as isRemoteKeyAccess, Remote as KeyAccessRemote, Wrapped as KeyAccessWrapped, } from './models/index.js';
|
|
8
|
+
import { base64 } from '../../src/encodings/index.js';
|
|
9
|
+
import { ZipReader, ZipWriter, base64ToBuffer, isAppIdProviderCheck, keyMerge, buffToString, concatUint8, } from './utils/index.js';
|
|
10
|
+
import { Binary } from './binary.js';
|
|
11
|
+
import { OriginAllowList } from '../../src/access.js';
|
|
12
|
+
import { ConfigurationError, DecryptError, InvalidFileError, IntegrityError, NetworkError, PermissionDeniedError, ServiceError, TdfError, UnauthenticatedError, UnsafeUrlError, UnsupportedFeatureError as UnsupportedError, } from '../../src/errors.js';
|
|
13
|
+
import { htmlWrapperTemplate } from './templates/index.js';
|
|
14
|
+
// configurable
|
|
15
|
+
// TODO: remove dependencies from ciphers so that we can open-source instead of relying on other Virtru libs
|
|
16
|
+
import { AesGcmCipher } from './ciphers/index.js';
|
|
17
|
+
import { reqSignature, } from '../../src/auth/auth.js';
|
|
18
|
+
// TODO: input validation on manifest JSON
|
|
19
|
+
const DEFAULT_SEGMENT_SIZE = 1024 * 1024;
|
|
20
|
+
/**
|
|
21
|
+
* If we have KAS url but not public key we can fetch it from KAS, fetching
|
|
22
|
+
* the value from `${kas}/kas_public_key`.
|
|
23
|
+
*/
|
|
24
|
+
export async function fetchKasPublicKey(kas, algorithm) {
|
|
25
|
+
if (!kas) {
|
|
26
|
+
throw new ConfigurationError('KAS definition not found');
|
|
27
|
+
}
|
|
28
|
+
// Logs insecure KAS. Secure is enforced in constructor
|
|
29
|
+
validateSecureUrl(kas);
|
|
30
|
+
const infoStatic = { url: kas, algorithm: algorithm || 'rsa:2048' };
|
|
31
|
+
const params = {};
|
|
32
|
+
if (algorithm) {
|
|
33
|
+
params.algorithm = algorithm;
|
|
34
|
+
}
|
|
35
|
+
const v2Url = `${kas}/v2/kas_public_key`;
|
|
36
|
+
try {
|
|
37
|
+
const response = await axios.get(v2Url, {
|
|
38
|
+
params: {
|
|
39
|
+
...params,
|
|
40
|
+
v: '2',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const publicKey = typeof response.data === 'string'
|
|
44
|
+
? await extractPemFromKeyString(response.data)
|
|
45
|
+
: response.data.publicKey;
|
|
46
|
+
return {
|
|
47
|
+
publicKey,
|
|
48
|
+
key: pemToCryptoPublicKey(publicKey),
|
|
49
|
+
...infoStatic,
|
|
50
|
+
...(typeof response.data !== 'string' && response.data.kid && { kid: response.data.kid }),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (cause) {
|
|
54
|
+
const status = cause?.response?.status;
|
|
55
|
+
switch (status) {
|
|
56
|
+
case 400:
|
|
57
|
+
case 404:
|
|
58
|
+
// KAS does not yet implement v2, maybe
|
|
59
|
+
break;
|
|
60
|
+
case 401:
|
|
61
|
+
throw new UnauthenticatedError(`[${v2Url}] requires auth`, cause);
|
|
62
|
+
case 403:
|
|
63
|
+
throw new PermissionDeniedError(`[${v2Url}] permission denied`, cause);
|
|
64
|
+
default:
|
|
65
|
+
if (status && status >= 400 && status < 500) {
|
|
66
|
+
throw new ConfigurationError(`[${v2Url}] request error [${status}] [${cause.name}] [${cause.message}]`, cause);
|
|
67
|
+
}
|
|
68
|
+
throw new NetworkError(`[${v2Url}] error [${status}] [${cause.name}] [${cause.message}]`, cause);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Retry with v1 params
|
|
72
|
+
const v1Url = `${kas}/kas_public_key`;
|
|
73
|
+
try {
|
|
74
|
+
const response = await axios.get(v1Url, {
|
|
75
|
+
params,
|
|
76
|
+
});
|
|
77
|
+
const publicKey = typeof response.data === 'string'
|
|
78
|
+
? await extractPemFromKeyString(response.data)
|
|
79
|
+
: response.data.publicKey;
|
|
80
|
+
// future proof: allow v2 response even if not specified.
|
|
81
|
+
return {
|
|
82
|
+
publicKey,
|
|
83
|
+
key: pemToCryptoPublicKey(publicKey),
|
|
84
|
+
...infoStatic,
|
|
85
|
+
...(typeof response.data !== 'string' && response.data.kid && { kid: response.data.kid }),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (cause) {
|
|
89
|
+
const status = cause?.response?.status;
|
|
90
|
+
switch (status) {
|
|
91
|
+
case 401:
|
|
92
|
+
throw new UnauthenticatedError(`[${v1Url}] requires auth`, cause);
|
|
93
|
+
case 403:
|
|
94
|
+
throw new PermissionDeniedError(`[${v1Url}] permission denied`, cause);
|
|
95
|
+
default:
|
|
96
|
+
if (status && status >= 400 && status < 500) {
|
|
97
|
+
throw new ConfigurationError(`[${v2Url}] request error [${status}] [${cause.name}] [${cause.message}]`, cause);
|
|
98
|
+
}
|
|
99
|
+
throw new NetworkError(`[${v1Url}] error [${status}] [${cause.name}] [${cause.message}]`, cause);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
*
|
|
105
|
+
* @param payload The TDF content to encode in HTML
|
|
106
|
+
* @param manifest A copy of the manifest
|
|
107
|
+
* @param transferUrl reader web-service start page
|
|
108
|
+
* @return utf-8 encoded HTML data
|
|
109
|
+
*/
|
|
110
|
+
export function wrapHtml(payload, manifest, transferUrl) {
|
|
111
|
+
const { origin } = new URL(transferUrl);
|
|
112
|
+
const exportManifest = typeof manifest === 'string' ? manifest : JSON.stringify(manifest);
|
|
113
|
+
const fullHtmlString = htmlWrapperTemplate({
|
|
114
|
+
transferUrl,
|
|
115
|
+
transferBaseUrl: origin,
|
|
116
|
+
manifest: base64.encode(exportManifest),
|
|
117
|
+
payload: buffToString(payload, 'base64'),
|
|
118
|
+
});
|
|
119
|
+
return new TextEncoder().encode(fullHtmlString);
|
|
120
|
+
}
|
|
121
|
+
export function unwrapHtml(htmlPayload) {
|
|
122
|
+
let html;
|
|
123
|
+
if (htmlPayload instanceof ArrayBuffer || ArrayBuffer.isView(htmlPayload)) {
|
|
124
|
+
html = new TextDecoder().decode(htmlPayload);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
html = htmlPayload.toString();
|
|
128
|
+
}
|
|
129
|
+
const payloadRe = /<input id=['"]?data-input['"]?[^>]*?value=['"]?([a-zA-Z0-9+/=]+)['"]?/;
|
|
130
|
+
const reResult = payloadRe.exec(html);
|
|
131
|
+
if (reResult === null) {
|
|
132
|
+
throw new InvalidFileError('Payload is missing');
|
|
133
|
+
}
|
|
134
|
+
const base64Payload = reResult[1];
|
|
135
|
+
try {
|
|
136
|
+
return base64ToBuffer(base64Payload);
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
throw new InvalidFileError('There was a problem extracting the TDF3 payload', e);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export async function extractPemFromKeyString(keyString) {
|
|
143
|
+
let pem = keyString;
|
|
144
|
+
// Skip the public key extraction if we find that the KAS url provides a
|
|
145
|
+
// PEM-encoded key instead of certificate
|
|
146
|
+
if (keyString.includes('CERTIFICATE')) {
|
|
147
|
+
const cert = await importX509(keyString, 'RS256', { extractable: true });
|
|
148
|
+
pem = await exportSPKI(cert);
|
|
149
|
+
}
|
|
150
|
+
return pem;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build a key access object and add it to the list. Can specify either
|
|
154
|
+
* a (url, publicKey) pair (legacy, deprecated) or an attribute URL (future).
|
|
155
|
+
* If all are missing then it attempts to use the default attribute. If that
|
|
156
|
+
* is missing it throws an error.
|
|
157
|
+
* @param {Object} options
|
|
158
|
+
* @param {String} options.type - enum representing how the object key is treated
|
|
159
|
+
* @param {String} options.attributeUrl - URL of the attribute to use for pubKey and kasUrl. Omit to use default.
|
|
160
|
+
* @param {String} options.url - directly set the KAS URL
|
|
161
|
+
* @param {String} options.publicKey - directly set the (KAS) public key
|
|
162
|
+
* @param {String?} options.kid - Key identifier of KAS public key
|
|
163
|
+
* @param {String? Object?} options.metadata - Metadata. Appears to be dead code.
|
|
164
|
+
* @return {KeyAccess}- the key access object loaded
|
|
165
|
+
*/
|
|
166
|
+
export async function buildKeyAccess({ attributeSet, type, url, publicKey, kid, attributeUrl, metadata, sid = '', }) {
|
|
167
|
+
/** Internal function to keep it DRY */
|
|
168
|
+
function createKeyAccess(type, kasUrl, kasKeyIdentifier, pubKey, metadata) {
|
|
169
|
+
switch (type) {
|
|
170
|
+
case 'wrapped':
|
|
171
|
+
return new KeyAccessWrapped(kasUrl, kasKeyIdentifier, pubKey, metadata, sid);
|
|
172
|
+
case 'remote':
|
|
173
|
+
return new KeyAccessRemote(kasUrl, kasKeyIdentifier, pubKey, metadata, sid);
|
|
174
|
+
default:
|
|
175
|
+
throw new ConfigurationError(`buildKeyAccess: Key access type ${type} is unknown`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// If an attributeUrl is provided try to load with that first.
|
|
179
|
+
if (attributeUrl && attributeSet) {
|
|
180
|
+
const attr = attributeSet.get(attributeUrl);
|
|
181
|
+
if (attr && attr.kasUrl && attr.pubKey) {
|
|
182
|
+
return createKeyAccess(type, attr.kasUrl, attr.kid, attr.pubKey, metadata);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// if url and pulicKey are specified load the key access object with them
|
|
186
|
+
if (url && publicKey) {
|
|
187
|
+
return createKeyAccess(type, url, kid, await extractPemFromKeyString(publicKey), metadata);
|
|
188
|
+
}
|
|
189
|
+
// Assume the default attribute is the source for kasUrl and pubKey
|
|
190
|
+
const defaultAttr = attributeSet?.getDefault();
|
|
191
|
+
if (defaultAttr) {
|
|
192
|
+
const { pubKey, kasUrl } = defaultAttr;
|
|
193
|
+
if (pubKey && kasUrl) {
|
|
194
|
+
return createKeyAccess(type, kasUrl, kid, await extractPemFromKeyString(pubKey), metadata);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// All failed. Raise an error.
|
|
198
|
+
throw new ConfigurationError('TDF.buildKeyAccess: No source for kasUrl or pubKey');
|
|
199
|
+
}
|
|
200
|
+
export function validatePolicyObject(policy) {
|
|
201
|
+
const missingFields = [];
|
|
202
|
+
if (!policy.uuid)
|
|
203
|
+
missingFields.push('uuid');
|
|
204
|
+
if (!policy.body)
|
|
205
|
+
missingFields.push('body', 'body.dissem');
|
|
206
|
+
if (policy.body && !policy.body.dissem)
|
|
207
|
+
missingFields.push('body.dissem');
|
|
208
|
+
if (missingFields.length) {
|
|
209
|
+
throw new ConfigurationError(`The given policy object requires the following properties: ${missingFields}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function _generateManifest(keyInfo, encryptionInformation, policy, mimeType) {
|
|
213
|
+
// (maybe) Fields are quoted to avoid renaming
|
|
214
|
+
const payload = {
|
|
215
|
+
type: 'reference',
|
|
216
|
+
url: '0.payload',
|
|
217
|
+
protocol: 'zip',
|
|
218
|
+
isEncrypted: true,
|
|
219
|
+
schemaVersion: '3.0.0',
|
|
220
|
+
...(mimeType && { mimeType }),
|
|
221
|
+
};
|
|
222
|
+
const encryptionInformationStr = await encryptionInformation.write(policy, keyInfo);
|
|
223
|
+
const assertions = [];
|
|
224
|
+
return {
|
|
225
|
+
payload,
|
|
226
|
+
// generate the manifest first, then insert integrity information into it
|
|
227
|
+
encryptionInformation: encryptionInformationStr,
|
|
228
|
+
assertions: assertions,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
async function getSignature(unwrappedKeyBinary, payloadBinary, algorithmType, cryptoService) {
|
|
232
|
+
switch (algorithmType.toUpperCase()) {
|
|
233
|
+
case 'GMAC':
|
|
234
|
+
// use the auth tag baked into the encrypted payload
|
|
235
|
+
return buffToString(Uint8Array.from(payloadBinary.asByteArray()).slice(-16), 'hex');
|
|
236
|
+
case 'HS256':
|
|
237
|
+
// simple hmac is the default
|
|
238
|
+
return await cryptoService.hmac(buffToString(new Uint8Array(unwrappedKeyBinary.asArrayBuffer()), 'hex'), buffToString(new Uint8Array(payloadBinary.asArrayBuffer()), 'utf-8'));
|
|
239
|
+
default:
|
|
240
|
+
throw new ConfigurationError(`Unsupported signature alg [${algorithmType}]`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function buildRequest(method, url, body) {
|
|
244
|
+
return {
|
|
245
|
+
headers: {},
|
|
246
|
+
method: method,
|
|
247
|
+
url: url,
|
|
248
|
+
body,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
export async function upsert({ allowedKases, allowList, authProvider, entity, privateKey, unsavedManifest, ignoreType, }) {
|
|
252
|
+
const allowed = (() => {
|
|
253
|
+
if (allowList) {
|
|
254
|
+
return allowList;
|
|
255
|
+
}
|
|
256
|
+
if (!allowedKases) {
|
|
257
|
+
throw new ConfigurationError('Upsert cannot be done without allowlist');
|
|
258
|
+
}
|
|
259
|
+
return new OriginAllowList(allowedKases);
|
|
260
|
+
})();
|
|
261
|
+
const { keyAccess, policy } = unsavedManifest.encryptionInformation;
|
|
262
|
+
const isAppIdProvider = authProvider && isAppIdProviderCheck(authProvider);
|
|
263
|
+
if (authProvider === undefined) {
|
|
264
|
+
throw new ConfigurationError('Upsert cannot be done without auth provider');
|
|
265
|
+
}
|
|
266
|
+
return Promise.all(keyAccess.map(async (keyAccessObject) => {
|
|
267
|
+
// We only care about remote key access objects for the policy sync portion
|
|
268
|
+
const isRemote = isRemoteKeyAccess(keyAccessObject);
|
|
269
|
+
if (!ignoreType && !isRemote) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (!allowed.allows(keyAccessObject.url)) {
|
|
273
|
+
throw new UnsafeUrlError(`Unexpected KAS url: [${keyAccessObject.url}]`);
|
|
274
|
+
}
|
|
275
|
+
const url = `${keyAccessObject.url}/${isAppIdProvider ? '' : 'v2/'}upsert`;
|
|
276
|
+
//TODO I dont' think we need a body at all for KAS requests
|
|
277
|
+
// Do we need ANY of this if it's already embedded in the EO in the Bearer OIDC token?
|
|
278
|
+
const body = {
|
|
279
|
+
keyAccess: keyAccessObject,
|
|
280
|
+
policy: unsavedManifest.encryptionInformation.policy,
|
|
281
|
+
entity: isAppIdProviderCheck(authProvider) ? entity : undefined,
|
|
282
|
+
authToken: undefined,
|
|
283
|
+
clientPayloadSignature: undefined,
|
|
284
|
+
};
|
|
285
|
+
if (isAppIdProviderCheck(authProvider)) {
|
|
286
|
+
body.authToken = await reqSignature({}, privateKey);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
body.clientPayloadSignature = await reqSignature(body, privateKey);
|
|
290
|
+
}
|
|
291
|
+
const httpReq = await authProvider.withCreds(buildRequest('POST', url, body));
|
|
292
|
+
try {
|
|
293
|
+
const response = await axios.post(httpReq.url, httpReq.body, {
|
|
294
|
+
headers: httpReq.headers,
|
|
295
|
+
});
|
|
296
|
+
// Remove additional properties which were needed to sync, but not that we want to save to
|
|
297
|
+
// the manifest
|
|
298
|
+
delete keyAccessObject.wrappedKey;
|
|
299
|
+
delete keyAccessObject.encryptedMetadata;
|
|
300
|
+
delete keyAccessObject.policyBinding;
|
|
301
|
+
if (isRemote) {
|
|
302
|
+
// Decode the policy and extract only the required info to save -- the uuid
|
|
303
|
+
const decodedPolicy = JSON.parse(base64.decode(policy));
|
|
304
|
+
unsavedManifest.encryptionInformation.policy = base64.encode(JSON.stringify({ uuid: decodedPolicy.uuid }));
|
|
305
|
+
}
|
|
306
|
+
return response.data;
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
if (e.response) {
|
|
310
|
+
if (e.response.status >= 500) {
|
|
311
|
+
throw new ServiceError('upsert failure', e);
|
|
312
|
+
}
|
|
313
|
+
else if (e.response.status === 403) {
|
|
314
|
+
throw new PermissionDeniedError('upsert failure', e);
|
|
315
|
+
}
|
|
316
|
+
else if (e.response.status === 401) {
|
|
317
|
+
throw new UnauthenticatedError('upsert auth failure', e);
|
|
318
|
+
}
|
|
319
|
+
else if (e.response.status === 400) {
|
|
320
|
+
throw new ConfigurationError('upsert bad request; likely a configuration error', e);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
throw new NetworkError('upsert server error', e);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else if (e.request) {
|
|
327
|
+
throw new NetworkError('upsert request failure', e);
|
|
328
|
+
}
|
|
329
|
+
throw new TdfError(`Unable to perform upsert operation on the KAS: [${e.name}: ${e.message}], response: [${e?.response?.body}]`, e);
|
|
330
|
+
}
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
export async function writeStream(cfg) {
|
|
334
|
+
if (!cfg.authProvider) {
|
|
335
|
+
throw new ConfigurationError('No authorization middleware defined');
|
|
336
|
+
}
|
|
337
|
+
if (!cfg.contentStream) {
|
|
338
|
+
throw new ConfigurationError('No input stream defined');
|
|
339
|
+
}
|
|
340
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
341
|
+
const segmentInfos = [];
|
|
342
|
+
cfg.byteLimit ??= Number.MAX_SAFE_INTEGER;
|
|
343
|
+
const entryInfos = [
|
|
344
|
+
{
|
|
345
|
+
filename: '0.payload',
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
filename: '0.manifest.json',
|
|
349
|
+
},
|
|
350
|
+
];
|
|
351
|
+
let currentBuffer = new Uint8Array();
|
|
352
|
+
let totalByteCount = 0;
|
|
353
|
+
let bytesProcessed = 0;
|
|
354
|
+
let crcCounter = 0;
|
|
355
|
+
let fileByteCount = 0;
|
|
356
|
+
let aggregateHash = '';
|
|
357
|
+
const zipWriter = new ZipWriter();
|
|
358
|
+
const manifest = await _generateManifest(cfg.keyForManifest, cfg.encryptionInformation, cfg.policy, cfg.mimeType);
|
|
359
|
+
if (!manifest) {
|
|
360
|
+
// Set in encrypt; should never be reached.
|
|
361
|
+
throw new ConfigurationError('internal: please use "loadTDFStream" first to load a manifest.');
|
|
362
|
+
}
|
|
363
|
+
const pkKeyLike = cfg.dpopKeys.privateKey;
|
|
364
|
+
// For all remote key access objects, sync its policy
|
|
365
|
+
const upsertResponse = await upsert({
|
|
366
|
+
allowedKases: cfg.allowList ? undefined : cfg.allowedKases,
|
|
367
|
+
allowList: cfg.allowList,
|
|
368
|
+
authProvider: cfg.authProvider,
|
|
369
|
+
entity: cfg.entity,
|
|
370
|
+
privateKey: pkKeyLike,
|
|
371
|
+
unsavedManifest: manifest,
|
|
372
|
+
});
|
|
373
|
+
// determine default segment size by writing empty buffer
|
|
374
|
+
const { segmentSizeDefault } = cfg;
|
|
375
|
+
const encryptedBlargh = await cfg.encryptionInformation.encrypt(Binary.fromArrayBuffer(new ArrayBuffer(segmentSizeDefault)), cfg.keyForEncryption.unwrappedKeyBinary);
|
|
376
|
+
const payloadBuffer = new Uint8Array(encryptedBlargh.payload.asByteArray());
|
|
377
|
+
const encryptedSegmentSizeDefault = payloadBuffer.length;
|
|
378
|
+
// start writing the content
|
|
379
|
+
entryInfos[0].filename = '0.payload';
|
|
380
|
+
entryInfos[0].offset = totalByteCount;
|
|
381
|
+
const sourceReader = cfg.contentStream.getReader();
|
|
382
|
+
/*
|
|
383
|
+
TODO: Code duplication should be addressed
|
|
384
|
+
- RCA operations require that the write stream has already finished executing it's .on('end') handler before being returned,
|
|
385
|
+
thus both handlers are wrapped in a encompassing promise when we have an RCA source. We should investigate
|
|
386
|
+
if this causes O(n) promises to be loaded into memory.
|
|
387
|
+
- LFS operations can have the write stream returned immediately after both .on('end') and .on('data') handlers
|
|
388
|
+
have been defined, thus not requiring the handlers to be wrapped in a promise.
|
|
389
|
+
*/
|
|
390
|
+
const underlingSource = {
|
|
391
|
+
start: (controller) => {
|
|
392
|
+
controller.enqueue(getHeader(entryInfos[0].filename));
|
|
393
|
+
_countChunk(getHeader(entryInfos[0].filename));
|
|
394
|
+
crcCounter = 0;
|
|
395
|
+
fileByteCount = 0;
|
|
396
|
+
},
|
|
397
|
+
pull: async (controller) => {
|
|
398
|
+
let isDone;
|
|
399
|
+
while (currentBuffer.length < segmentSizeDefault && !isDone) {
|
|
400
|
+
const { value, done } = await sourceReader.read();
|
|
401
|
+
isDone = done;
|
|
402
|
+
if (value) {
|
|
403
|
+
currentBuffer = concatUint8([currentBuffer, value]);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
while (currentBuffer.length >= segmentSizeDefault &&
|
|
407
|
+
!!controller.desiredSize &&
|
|
408
|
+
controller.desiredSize > 0) {
|
|
409
|
+
const segment = currentBuffer.slice(0, segmentSizeDefault);
|
|
410
|
+
const encryptedSegment = await _encryptAndCountSegment(segment);
|
|
411
|
+
controller.enqueue(encryptedSegment);
|
|
412
|
+
currentBuffer = currentBuffer.slice(segmentSizeDefault);
|
|
413
|
+
}
|
|
414
|
+
const isFinalChunkLeft = isDone && currentBuffer.length;
|
|
415
|
+
if (isFinalChunkLeft) {
|
|
416
|
+
const encryptedSegment = await _encryptAndCountSegment(currentBuffer);
|
|
417
|
+
controller.enqueue(encryptedSegment);
|
|
418
|
+
currentBuffer = new Uint8Array();
|
|
419
|
+
}
|
|
420
|
+
if (isDone && currentBuffer.length === 0) {
|
|
421
|
+
entryInfos[0].crcCounter = crcCounter;
|
|
422
|
+
entryInfos[0].fileByteCount = fileByteCount;
|
|
423
|
+
const payloadDataDescriptor = zipWriter.writeDataDescriptor(crcCounter, fileByteCount);
|
|
424
|
+
controller.enqueue(payloadDataDescriptor);
|
|
425
|
+
_countChunk(payloadDataDescriptor);
|
|
426
|
+
// prepare the manifest
|
|
427
|
+
entryInfos[1].filename = '0.manifest.json';
|
|
428
|
+
entryInfos[1].offset = totalByteCount;
|
|
429
|
+
controller.enqueue(getHeader(entryInfos[1].filename));
|
|
430
|
+
_countChunk(getHeader(entryInfos[1].filename));
|
|
431
|
+
crcCounter = 0;
|
|
432
|
+
fileByteCount = 0;
|
|
433
|
+
// hash the concat of all hashes
|
|
434
|
+
const payloadSigStr = await getSignature(cfg.keyForEncryption.unwrappedKeyBinary, Binary.fromString(aggregateHash), cfg.integrityAlgorithm, cfg.cryptoService);
|
|
435
|
+
manifest.encryptionInformation.integrityInformation.rootSignature.sig =
|
|
436
|
+
base64.encode(payloadSigStr);
|
|
437
|
+
manifest.encryptionInformation.integrityInformation.rootSignature.alg =
|
|
438
|
+
cfg.integrityAlgorithm;
|
|
439
|
+
manifest.encryptionInformation.integrityInformation.segmentSizeDefault = segmentSizeDefault;
|
|
440
|
+
manifest.encryptionInformation.integrityInformation.encryptedSegmentSizeDefault =
|
|
441
|
+
encryptedSegmentSizeDefault;
|
|
442
|
+
manifest.encryptionInformation.integrityInformation.segmentHashAlg =
|
|
443
|
+
cfg.segmentIntegrityAlgorithm;
|
|
444
|
+
manifest.encryptionInformation.integrityInformation.segments = segmentInfos;
|
|
445
|
+
manifest.encryptionInformation.method.isStreamable = true;
|
|
446
|
+
const signedAssertions = [];
|
|
447
|
+
if (cfg.assertionConfigs && cfg.assertionConfigs.length > 0) {
|
|
448
|
+
await Promise.all(cfg.assertionConfigs.map(async (assertionConfig) => {
|
|
449
|
+
// Create assertion using the assertionConfig values
|
|
450
|
+
const signingKey = assertionConfig.signingKey ?? {
|
|
451
|
+
alg: 'HS256',
|
|
452
|
+
key: new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
|
|
453
|
+
};
|
|
454
|
+
const assertion = await assertions.CreateAssertion(aggregateHash, {
|
|
455
|
+
...assertionConfig,
|
|
456
|
+
signingKey,
|
|
457
|
+
});
|
|
458
|
+
// Add signed assertion to the signedAssertions array
|
|
459
|
+
signedAssertions.push(assertion);
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
manifest.assertions = signedAssertions;
|
|
463
|
+
// write the manifest
|
|
464
|
+
const manifestBuffer = new TextEncoder().encode(JSON.stringify(manifest));
|
|
465
|
+
controller.enqueue(manifestBuffer);
|
|
466
|
+
_countChunk(manifestBuffer);
|
|
467
|
+
entryInfos[1].crcCounter = crcCounter;
|
|
468
|
+
entryInfos[1].fileByteCount = fileByteCount;
|
|
469
|
+
const manifestDataDescriptor = zipWriter.writeDataDescriptor(crcCounter, fileByteCount);
|
|
470
|
+
controller.enqueue(manifestDataDescriptor);
|
|
471
|
+
_countChunk(manifestDataDescriptor);
|
|
472
|
+
// write the central directory out
|
|
473
|
+
const centralDirectoryByteCount = totalByteCount;
|
|
474
|
+
for (let i = 0; i < entryInfos.length; i++) {
|
|
475
|
+
const entryInfo = entryInfos[i];
|
|
476
|
+
const result = zipWriter.writeCentralDirectoryRecord(entryInfo.fileByteCount || 0, entryInfo.filename, entryInfo.offset || 0, entryInfo.crcCounter || 0, 2175008768);
|
|
477
|
+
controller.enqueue(result);
|
|
478
|
+
_countChunk(result);
|
|
479
|
+
}
|
|
480
|
+
const endOfCentralDirectoryByteCount = totalByteCount - centralDirectoryByteCount;
|
|
481
|
+
const finalChunk = zipWriter.writeEndOfCentralDirectoryRecord(entryInfos.length, endOfCentralDirectoryByteCount, centralDirectoryByteCount);
|
|
482
|
+
controller.enqueue(finalChunk);
|
|
483
|
+
_countChunk(finalChunk);
|
|
484
|
+
controller.close();
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
const plaintextStream = new DecoratedReadableStream(underlingSource);
|
|
489
|
+
plaintextStream.manifest = manifest;
|
|
490
|
+
if (upsertResponse) {
|
|
491
|
+
plaintextStream.upsertResponse = upsertResponse;
|
|
492
|
+
plaintextStream.tdfSize = totalByteCount;
|
|
493
|
+
plaintextStream.algorithm = manifest.encryptionInformation.method.algorithm;
|
|
494
|
+
}
|
|
495
|
+
return plaintextStream;
|
|
496
|
+
// nested helper fn's
|
|
497
|
+
function getHeader(filename) {
|
|
498
|
+
return zipWriter.getLocalFileHeader(filename, 0, 0, 0);
|
|
499
|
+
}
|
|
500
|
+
function _countChunk(chunk) {
|
|
501
|
+
if (typeof chunk === 'string') {
|
|
502
|
+
chunk = new TextEncoder().encode(chunk);
|
|
503
|
+
}
|
|
504
|
+
totalByteCount += chunk.length;
|
|
505
|
+
if (totalByteCount > cfg.byteLimit) {
|
|
506
|
+
throw new ConfigurationError(`Safe byte limit (${cfg.byteLimit}) exceeded`);
|
|
507
|
+
}
|
|
508
|
+
//new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
509
|
+
crcCounter = unsigned(chunk, crcCounter);
|
|
510
|
+
fileByteCount += chunk.length;
|
|
511
|
+
}
|
|
512
|
+
async function _encryptAndCountSegment(chunk) {
|
|
513
|
+
bytesProcessed += chunk.length;
|
|
514
|
+
cfg.progressHandler?.(bytesProcessed);
|
|
515
|
+
// Don't pass in an IV here. The encrypt function will generate one for you, ensuring that each segment has a unique IV.
|
|
516
|
+
const encryptedResult = await cfg.encryptionInformation.encrypt(Binary.fromArrayBuffer(chunk.buffer), cfg.keyForEncryption.unwrappedKeyBinary);
|
|
517
|
+
const payloadBuffer = new Uint8Array(encryptedResult.payload.asByteArray());
|
|
518
|
+
const payloadSigStr = await getSignature(cfg.keyForEncryption.unwrappedKeyBinary, encryptedResult.payload, cfg.segmentIntegrityAlgorithm, cfg.cryptoService);
|
|
519
|
+
// combined string of all hashes for root signature
|
|
520
|
+
aggregateHash += payloadSigStr;
|
|
521
|
+
segmentInfos.push({
|
|
522
|
+
hash: base64.encode(payloadSigStr),
|
|
523
|
+
segmentSize: chunk.length === segmentSizeDefault ? undefined : chunk.length,
|
|
524
|
+
encryptedSegmentSize: payloadBuffer.length === encryptedSegmentSizeDefault ? undefined : payloadBuffer.length,
|
|
525
|
+
});
|
|
526
|
+
const result = new Uint8Array(encryptedResult.payload.asByteArray());
|
|
527
|
+
_countChunk(result);
|
|
528
|
+
return result;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
// load the TDF as a stream in memory, for further use in reading and key syncing
|
|
532
|
+
export async function loadTDFStream(chunker) {
|
|
533
|
+
const zipReader = new ZipReader(chunker);
|
|
534
|
+
const centralDirectory = await zipReader.getCentralDirectory();
|
|
535
|
+
const manifest = await zipReader.getManifest(centralDirectory, '0.manifest.json');
|
|
536
|
+
return { manifest, zipReader, centralDirectory };
|
|
537
|
+
}
|
|
538
|
+
export function splitLookupTableFactory(keyAccess, allowedKases) {
|
|
539
|
+
const allowed = (k) => allowedKases.allows(k.url);
|
|
540
|
+
const splitIds = new Set(keyAccess.map(({ sid }) => sid ?? ''));
|
|
541
|
+
const accessibleSplits = new Set(keyAccess.filter(allowed).map(({ sid }) => sid));
|
|
542
|
+
if (splitIds.size > accessibleSplits.size) {
|
|
543
|
+
const disallowedKases = new Set(keyAccess.filter((k) => !allowed(k)).map(({ url }) => url));
|
|
544
|
+
throw new UnsafeUrlError(`Unreconstructable key - disallowed KASes include: ${JSON.stringify([
|
|
545
|
+
...disallowedKases,
|
|
546
|
+
])} from splitIds ${JSON.stringify([...splitIds])}`, ...disallowedKases);
|
|
547
|
+
}
|
|
548
|
+
const splitPotentials = Object.fromEntries([...splitIds].map((s) => [s, {}]));
|
|
549
|
+
for (const kao of keyAccess) {
|
|
550
|
+
const disjunction = splitPotentials[kao.sid ?? ''];
|
|
551
|
+
if (kao.url in disjunction) {
|
|
552
|
+
throw new InvalidFileError(`TODO: Fallback to no split ids. Repetition found for [${kao.url}] on split [${kao.sid}]`);
|
|
553
|
+
}
|
|
554
|
+
if (allowed(kao)) {
|
|
555
|
+
disjunction[kao.url] = kao;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return splitPotentials;
|
|
559
|
+
}
|
|
560
|
+
async function unwrapKey({ manifest, allowedKases, authProvider, dpopKeys, entity, cryptoService, }) {
|
|
561
|
+
if (authProvider === undefined) {
|
|
562
|
+
throw new ConfigurationError('upsert requires auth provider; must be configured in client constructor');
|
|
563
|
+
}
|
|
564
|
+
const { keyAccess } = manifest.encryptionInformation;
|
|
565
|
+
const splitPotentials = splitLookupTableFactory(keyAccess, allowedKases);
|
|
566
|
+
const isAppIdProvider = authProvider && isAppIdProviderCheck(authProvider);
|
|
567
|
+
async function tryKasRewrap(keySplitInfo) {
|
|
568
|
+
const url = `${keySplitInfo.url}/${isAppIdProvider ? '' : 'v2/'}rewrap`;
|
|
569
|
+
const ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(await cryptoService.generateKeyPair());
|
|
570
|
+
const clientPublicKey = ephemeralEncryptionKeys.publicKey;
|
|
571
|
+
const requestBodyStr = JSON.stringify({
|
|
572
|
+
algorithm: 'RS256',
|
|
573
|
+
keyAccess: keySplitInfo,
|
|
574
|
+
policy: manifest.encryptionInformation.policy,
|
|
575
|
+
clientPublicKey,
|
|
576
|
+
});
|
|
577
|
+
const jwtPayload = { requestBody: requestBodyStr };
|
|
578
|
+
const signedRequestToken = await reqSignature(isAppIdProvider ? {} : jwtPayload, dpopKeys.privateKey);
|
|
579
|
+
let requestBody;
|
|
580
|
+
if (isAppIdProvider) {
|
|
581
|
+
requestBody = {
|
|
582
|
+
keyAccess: keySplitInfo,
|
|
583
|
+
policy: manifest.encryptionInformation.policy,
|
|
584
|
+
entity: {
|
|
585
|
+
...entity,
|
|
586
|
+
publicKey: clientPublicKey,
|
|
587
|
+
},
|
|
588
|
+
authToken: signedRequestToken,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
requestBody = {
|
|
593
|
+
signedRequestToken,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
const httpReq = await authProvider.withCreds(buildRequest('POST', url, requestBody));
|
|
597
|
+
const { data: { entityWrappedKey, metadata }, } = await axios.post(httpReq.url, httpReq.body, { headers: httpReq.headers });
|
|
598
|
+
const key = Binary.fromString(base64.decode(entityWrappedKey));
|
|
599
|
+
const decryptedKeyBinary = await cryptoService.decryptWithPrivateKey(key, ephemeralEncryptionKeys.privateKey);
|
|
600
|
+
return {
|
|
601
|
+
key: new Uint8Array(decryptedKeyBinary.asByteArray()),
|
|
602
|
+
metadata,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
// Get unique split IDs to determine if we have an OR or AND condition
|
|
606
|
+
const splitIds = new Set(Object.keys(splitPotentials));
|
|
607
|
+
// If we have only one split ID, it's an OR condition
|
|
608
|
+
if (splitIds.size === 1) {
|
|
609
|
+
const [splitId] = splitIds;
|
|
610
|
+
const potentials = splitPotentials[splitId];
|
|
611
|
+
try {
|
|
612
|
+
// OR condition: Try all KAS servers for this split, take first success
|
|
613
|
+
const result = await Promise.any(Object.values(potentials).map(async (keySplitInfo) => {
|
|
614
|
+
try {
|
|
615
|
+
return await tryKasRewrap(keySplitInfo);
|
|
616
|
+
}
|
|
617
|
+
catch (e) {
|
|
618
|
+
// Rethrow with more context
|
|
619
|
+
throw handleRewrapError(e);
|
|
620
|
+
}
|
|
621
|
+
}));
|
|
622
|
+
const reconstructedKey = keyMerge([result.key]);
|
|
623
|
+
return {
|
|
624
|
+
reconstructedKeyBinary: Binary.fromArrayBuffer(reconstructedKey),
|
|
625
|
+
metadata: result.metadata,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
if (error instanceof AggregateError) {
|
|
630
|
+
// All KAS servers failed
|
|
631
|
+
throw error.errors[0]; // Throw the first error since we've already wrapped them
|
|
632
|
+
}
|
|
633
|
+
throw error;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
// AND condition: We need successful results from all different splits
|
|
638
|
+
const splitResults = await Promise.all(Object.entries(splitPotentials).map(async ([splitId, potentials]) => {
|
|
639
|
+
if (!potentials || !Object.keys(potentials).length) {
|
|
640
|
+
throw new UnsafeUrlError(`Unreconstructable key - no valid KAS found for split ${JSON.stringify(splitId)}`, '');
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
// For each split, try all potential KAS servers until one succeeds
|
|
644
|
+
return await Promise.any(Object.values(potentials).map(async (keySplitInfo) => {
|
|
645
|
+
try {
|
|
646
|
+
return await tryKasRewrap(keySplitInfo);
|
|
647
|
+
}
|
|
648
|
+
catch (e) {
|
|
649
|
+
throw handleRewrapError(e);
|
|
650
|
+
}
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
if (error instanceof AggregateError) {
|
|
655
|
+
// All KAS servers for this split failed
|
|
656
|
+
throw error.errors[0]; // Throw the first error since we've already wrapped them
|
|
657
|
+
}
|
|
658
|
+
throw error;
|
|
659
|
+
}
|
|
660
|
+
}));
|
|
661
|
+
// Merge all the split keys
|
|
662
|
+
const reconstructedKey = keyMerge(splitResults.map((r) => r.key));
|
|
663
|
+
return {
|
|
664
|
+
reconstructedKeyBinary: Binary.fromArrayBuffer(reconstructedKey),
|
|
665
|
+
metadata: splitResults[0].metadata, // Use metadata from first split
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function handleRewrapError(error) {
|
|
670
|
+
if (axios.isAxiosError(error)) {
|
|
671
|
+
if (error.response?.status && error.response?.status >= 500) {
|
|
672
|
+
return new ServiceError('rewrap failure', error);
|
|
673
|
+
}
|
|
674
|
+
else if (error.response?.status === 403) {
|
|
675
|
+
return new PermissionDeniedError('rewrap failure', error);
|
|
676
|
+
}
|
|
677
|
+
else if (error.response?.status === 401) {
|
|
678
|
+
return new UnauthenticatedError('rewrap auth failure', error);
|
|
679
|
+
}
|
|
680
|
+
else if (error.response?.status === 400) {
|
|
681
|
+
return new InvalidFileError('rewrap bad request; could indicate an invalid policy binding or a configuration error', error);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return new NetworkError('rewrap server error', error);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
if (error.name === 'InvalidAccessError' || error.name === 'OperationError') {
|
|
689
|
+
return new DecryptError('unable to unwrap key from kas', error);
|
|
690
|
+
}
|
|
691
|
+
return new InvalidFileError(`Unable to decrypt the response from KAS: [${error.name}: ${error.message}]`, error);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
async function decryptChunk(encryptedChunk, reconstructedKeyBinary, hash, cipher, segmentIntegrityAlgorithm, cryptoService) {
|
|
695
|
+
if (segmentIntegrityAlgorithm !== 'GMAC' && segmentIntegrityAlgorithm !== 'HS256') {
|
|
696
|
+
}
|
|
697
|
+
const segmentHashStr = await getSignature(reconstructedKeyBinary, Binary.fromArrayBuffer(encryptedChunk.buffer), segmentIntegrityAlgorithm, cryptoService);
|
|
698
|
+
if (hash !== btoa(segmentHashStr)) {
|
|
699
|
+
throw new IntegrityError('Failed integrity check on segment hash');
|
|
700
|
+
}
|
|
701
|
+
return await cipher.decrypt(encryptedChunk, reconstructedKeyBinary);
|
|
702
|
+
}
|
|
703
|
+
async function updateChunkQueue(chunkMap, centralDirectory, zipReader, reconstructedKeyBinary, cipher, segmentIntegrityAlgorithm, cryptoService) {
|
|
704
|
+
const chunksInOneDownload = 500;
|
|
705
|
+
let requests = [];
|
|
706
|
+
const maxLength = 3;
|
|
707
|
+
for (let i = 0; i < chunkMap.length; i += chunksInOneDownload) {
|
|
708
|
+
if (requests.length === maxLength) {
|
|
709
|
+
await Promise.all(requests);
|
|
710
|
+
requests = [];
|
|
711
|
+
}
|
|
712
|
+
requests.push((async () => {
|
|
713
|
+
let buffer;
|
|
714
|
+
const slice = chunkMap.slice(i, i + chunksInOneDownload);
|
|
715
|
+
try {
|
|
716
|
+
const bufferSize = slice.reduce((currentVal, { encryptedSegmentSize }) => currentVal + encryptedSegmentSize, 0);
|
|
717
|
+
buffer = await zipReader.getPayloadSegment(centralDirectory, '0.payload', slice[0].encryptedOffset, bufferSize);
|
|
718
|
+
}
|
|
719
|
+
catch (e) {
|
|
720
|
+
if (e instanceof InvalidFileError) {
|
|
721
|
+
throw e;
|
|
722
|
+
}
|
|
723
|
+
throw new NetworkError('unable to fetch payload segment', e);
|
|
724
|
+
}
|
|
725
|
+
if (buffer) {
|
|
726
|
+
sliceAndDecrypt({
|
|
727
|
+
buffer,
|
|
728
|
+
cryptoService,
|
|
729
|
+
reconstructedKeyBinary,
|
|
730
|
+
slice,
|
|
731
|
+
cipher,
|
|
732
|
+
segmentIntegrityAlgorithm,
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
})());
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
export async function sliceAndDecrypt({ buffer, reconstructedKeyBinary, slice, cipher, cryptoService, segmentIntegrityAlgorithm, }) {
|
|
739
|
+
for (const index in slice) {
|
|
740
|
+
const { encryptedOffset, encryptedSegmentSize, _resolve, _reject } = slice[index];
|
|
741
|
+
const offset = slice[0].encryptedOffset === 0 ? encryptedOffset : encryptedOffset % slice[0].encryptedOffset;
|
|
742
|
+
const encryptedChunk = new Uint8Array(buffer.slice(offset, offset + encryptedSegmentSize));
|
|
743
|
+
try {
|
|
744
|
+
const result = await decryptChunk(encryptedChunk, reconstructedKeyBinary, slice[index]['hash'], cipher, segmentIntegrityAlgorithm, cryptoService);
|
|
745
|
+
slice[index].decryptedChunk = result;
|
|
746
|
+
if (_resolve) {
|
|
747
|
+
_resolve(null);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
catch (e) {
|
|
751
|
+
if (_reject) {
|
|
752
|
+
_reject(e);
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
throw e;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
export async function readStream(cfg) {
|
|
761
|
+
let { allowList } = cfg;
|
|
762
|
+
if (!allowList) {
|
|
763
|
+
if (!cfg.allowedKases) {
|
|
764
|
+
throw new ConfigurationError('Upsert cannot be done without allowlist');
|
|
765
|
+
}
|
|
766
|
+
allowList = new OriginAllowList(cfg.allowedKases);
|
|
767
|
+
}
|
|
768
|
+
const { manifest, zipReader, centralDirectory } = await loadTDFStream(cfg.chunker);
|
|
769
|
+
if (!manifest) {
|
|
770
|
+
throw new InvalidFileError('Missing manifest data');
|
|
771
|
+
}
|
|
772
|
+
cfg.keyMiddleware ??= async (key) => key;
|
|
773
|
+
const { encryptedSegmentSizeDefault: defaultSegmentSize, rootSignature, segmentHashAlg, segments, } = manifest.encryptionInformation.integrityInformation;
|
|
774
|
+
const { metadata, reconstructedKeyBinary } = await unwrapKey({
|
|
775
|
+
manifest,
|
|
776
|
+
authProvider: cfg.authProvider,
|
|
777
|
+
allowedKases: allowList,
|
|
778
|
+
dpopKeys: cfg.dpopKeys,
|
|
779
|
+
entity: cfg.entity,
|
|
780
|
+
cryptoService: cfg.cryptoService,
|
|
781
|
+
});
|
|
782
|
+
// async function unwrapKey(manifest: Manifest, allowedKases: string[], authProvider: AuthProvider | AppIdAuthProvider, publicKey: string, privateKey: string, entity: EntityObject) {
|
|
783
|
+
const keyForDecryption = await cfg.keyMiddleware(reconstructedKeyBinary);
|
|
784
|
+
const encryptedSegmentSizeDefault = defaultSegmentSize || DEFAULT_SEGMENT_SIZE;
|
|
785
|
+
// check the combined string of hashes
|
|
786
|
+
const aggregateHash = segments.map(({ hash }) => base64.decode(hash)).join('');
|
|
787
|
+
const integrityAlgorithm = rootSignature.alg;
|
|
788
|
+
if (integrityAlgorithm !== 'GMAC' && integrityAlgorithm !== 'HS256') {
|
|
789
|
+
throw new UnsupportedError(`Unsupported integrity alg [${integrityAlgorithm}]`);
|
|
790
|
+
}
|
|
791
|
+
const payloadSigStr = await getSignature(keyForDecryption, Binary.fromString(aggregateHash), integrityAlgorithm, cfg.cryptoService);
|
|
792
|
+
if (manifest.encryptionInformation.integrityInformation.rootSignature.sig !==
|
|
793
|
+
base64.encode(payloadSigStr)) {
|
|
794
|
+
throw new IntegrityError('Failed integrity check on root signature');
|
|
795
|
+
}
|
|
796
|
+
if (!cfg.noVerifyAssertions) {
|
|
797
|
+
for (const assertion of manifest.assertions || []) {
|
|
798
|
+
// Create a default assertion key
|
|
799
|
+
let assertionKey = {
|
|
800
|
+
alg: 'HS256',
|
|
801
|
+
key: new Uint8Array(reconstructedKeyBinary.asArrayBuffer()),
|
|
802
|
+
};
|
|
803
|
+
if (cfg.assertionVerificationKeys) {
|
|
804
|
+
const foundKey = cfg.assertionVerificationKeys.Keys[assertion.id];
|
|
805
|
+
if (foundKey) {
|
|
806
|
+
assertionKey = foundKey;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
await assertions.verify(assertion, aggregateHash, assertionKey);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
let mapOfRequestsOffset = 0;
|
|
813
|
+
const chunkMap = new Map(segments.map(({ hash, encryptedSegmentSize = encryptedSegmentSizeDefault }) => {
|
|
814
|
+
const result = (() => {
|
|
815
|
+
let _resolve, _reject;
|
|
816
|
+
const chunk = {
|
|
817
|
+
hash,
|
|
818
|
+
encryptedOffset: mapOfRequestsOffset,
|
|
819
|
+
encryptedSegmentSize,
|
|
820
|
+
promise: new Promise((resolve, reject) => {
|
|
821
|
+
_resolve = resolve;
|
|
822
|
+
_reject = reject;
|
|
823
|
+
}),
|
|
824
|
+
};
|
|
825
|
+
chunk._resolve = _resolve;
|
|
826
|
+
chunk._reject = _reject;
|
|
827
|
+
return chunk;
|
|
828
|
+
})();
|
|
829
|
+
mapOfRequestsOffset += encryptedSegmentSize || encryptedSegmentSizeDefault;
|
|
830
|
+
return [hash, result];
|
|
831
|
+
}));
|
|
832
|
+
const cipher = new AesGcmCipher(cfg.cryptoService);
|
|
833
|
+
const segmentIntegrityAlg = segmentHashAlg || integrityAlgorithm;
|
|
834
|
+
if (segmentIntegrityAlg !== 'GMAC' && segmentIntegrityAlg !== 'HS256') {
|
|
835
|
+
throw new UnsupportedError(`Unsupported segment hash alg [${segmentIntegrityAlg}]`);
|
|
836
|
+
}
|
|
837
|
+
// Not waiting for Promise to resolve
|
|
838
|
+
updateChunkQueue(Array.from(chunkMap.values()), centralDirectory, zipReader, keyForDecryption, cipher, segmentIntegrityAlg, cfg.cryptoService);
|
|
839
|
+
let progress = 0;
|
|
840
|
+
const underlyingSource = {
|
|
841
|
+
pull: async (controller) => {
|
|
842
|
+
if (chunkMap.size === 0) {
|
|
843
|
+
controller.close();
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const [hash, chunk] = chunkMap.entries().next().value;
|
|
847
|
+
if (!chunk.decryptedChunk) {
|
|
848
|
+
await chunk.promise;
|
|
849
|
+
}
|
|
850
|
+
const decryptedSegment = chunk.decryptedChunk;
|
|
851
|
+
controller.enqueue(new Uint8Array(decryptedSegment.payload.asByteArray()));
|
|
852
|
+
progress += chunk.encryptedSegmentSize;
|
|
853
|
+
cfg.progressHandler?.(progress);
|
|
854
|
+
chunk.decryptedChunk = null;
|
|
855
|
+
chunkMap.delete(hash);
|
|
856
|
+
},
|
|
857
|
+
...(cfg.fileStreamServiceWorker && { fileStreamServiceWorker: cfg.fileStreamServiceWorker }),
|
|
858
|
+
};
|
|
859
|
+
const outputStream = new DecoratedReadableStream(underlyingSource);
|
|
860
|
+
outputStream.manifest = manifest;
|
|
861
|
+
outputStream.emit('manifest', manifest);
|
|
862
|
+
outputStream.metadata = metadata;
|
|
863
|
+
outputStream.emit('rewrap', metadata);
|
|
864
|
+
return outputStream;
|
|
865
|
+
}
|
|
866
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGRmLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGRmMy9zcmMvdGRmLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBcUIsTUFBTSxPQUFPLENBQUM7QUFDMUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBRTlFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzdFLE9BQU8sS0FBSyxVQUFVLE1BQU0saUJBQWlCLENBQUM7QUFFOUMsT0FBTyxFQUVMLFFBQVEsSUFBSSxpQkFBaUIsRUFLN0IsTUFBTSxJQUFJLGVBQWUsRUFHekIsT0FBTyxJQUFJLGdCQUFnQixHQUk1QixNQUFNLG1CQUFtQixDQUFDO0FBQzNCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN0RCxPQUFPLEVBRUwsU0FBUyxFQUNULFNBQVMsRUFDVCxjQUFjLEVBQ2Qsb0JBQW9CLEVBQ3BCLFFBQVEsRUFDUixZQUFZLEVBQ1osV0FBVyxHQUNaLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLEVBQTJDLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQy9GLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsWUFBWSxFQUNaLHFCQUFxQixFQUNyQixZQUFZLEVBQ1osUUFBUSxFQUNSLG9CQUFvQixFQUNwQixjQUFjLEVBQ2QsdUJBQXVCLElBQUksZ0JBQWdCLEdBQzVDLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLG1CQUFt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
|