libmongocrypt-helper 1.8.0.0.1001 → 1.11.0.0.1001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (385) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libmongocrypt/libmongocrypt/CHANGELOG.md +33 -0
  3. data/ext/libmongocrypt/libmongocrypt/CMakeLists.txt +12 -1
  4. data/ext/libmongocrypt/libmongocrypt/CODEOWNERS +1 -4
  5. data/ext/libmongocrypt/libmongocrypt/Earthfile +151 -3
  6. data/ext/libmongocrypt/libmongocrypt/README.md +36 -40
  7. data/ext/libmongocrypt/libmongocrypt/bindings/cs/CMakeLists.txt +1 -0
  8. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Driver.snk +0 -0
  9. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/AssemblyInfo.cs +2 -2
  10. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/Binary.cs +16 -2
  11. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/CryptClientFactory.cs +8 -4
  12. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/Library.cs +10 -0
  13. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/LibraryLoader.cs +81 -44
  14. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.csproj +2 -1
  15. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj +2 -0
  16. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt.Test32/MongoDB.Libmongocrypt.Test32.csproj +2 -0
  17. data/ext/libmongocrypt/libmongocrypt/bindings/cs/README.md +3 -0
  18. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.cake +21 -26
  19. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.config +3 -0
  20. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.sh +0 -0
  21. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/build.gradle.kts +28 -0
  22. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/crypt/benchmark/BenchmarkRunner.java +217 -0
  23. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/src/main/resources/keyDocument.json +24 -0
  24. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/build.gradle.kts +21 -6
  25. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.jar +0 -0
  26. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.properties +1 -1
  27. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradlew +154 -108
  28. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradlew.bat +7 -18
  29. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/settings.gradle.kts +1 -0
  30. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java +41 -6
  31. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPIHelper.java +5 -5
  32. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CipherCallback.java +27 -1
  33. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java +34 -19
  34. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoExplicitEncryptOptions.java +6 -4
  35. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/resources/META-INF/native-image/jni-config.json +180 -0
  36. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/resources/META-INF/native-image/reflect-config.json +134 -0
  37. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/java/com/mongodb/crypt/capi/MongoCryptTest.java +44 -2
  38. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32/encrypted-payload.json +1 -1
  39. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32/rangeopts.json +3 -0
  40. data/ext/libmongocrypt/libmongocrypt/bindings/node/README.md +4 -900
  41. data/ext/libmongocrypt/libmongocrypt/bindings/python/CHANGELOG.rst +60 -0
  42. data/ext/libmongocrypt/libmongocrypt/bindings/python/README.rst +41 -20
  43. data/ext/libmongocrypt/libmongocrypt/bindings/python/RELEASE.rst +6 -24
  44. data/ext/libmongocrypt/libmongocrypt/bindings/python/build-manylinux-wheel.sh +4 -13
  45. data/ext/libmongocrypt/libmongocrypt/bindings/python/hatch_build.py +36 -0
  46. data/ext/libmongocrypt/libmongocrypt/bindings/python/libmongocrypt-version.txt +1 -0
  47. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/__init__.py +2 -2
  48. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/auto_encrypter.py +61 -0
  49. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/credentials.py +156 -0
  50. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/explicit_encrypter.py +156 -0
  51. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/state_machine.py +149 -0
  52. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/auto_encrypter.py +2 -46
  53. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/binary.py +14 -17
  54. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/binding.py +107 -61
  55. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/compat.py +6 -4
  56. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/credentials.py +2 -121
  57. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/crypto.py +31 -20
  58. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/errors.py +2 -2
  59. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/explicit_encrypter.py +2 -233
  60. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/mongocrypt.py +168 -238
  61. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/options.py +265 -0
  62. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/state_machine.py +2 -141
  63. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/auto_encrypter.py +61 -0
  64. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/credentials.py +156 -0
  65. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/explicit_encrypter.py +156 -0
  66. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/state_machine.py +149 -0
  67. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/version.py +2 -2
  68. data/ext/libmongocrypt/libmongocrypt/bindings/python/pyproject.toml +118 -0
  69. data/ext/libmongocrypt/libmongocrypt/bindings/python/release.sh +97 -61
  70. data/ext/libmongocrypt/libmongocrypt/bindings/python/{test-requirements.txt → requirements-test.txt} +4 -1
  71. data/ext/libmongocrypt/libmongocrypt/bindings/python/requirements.txt +4 -0
  72. data/ext/libmongocrypt/libmongocrypt/bindings/python/sbom.json +76 -0
  73. data/ext/libmongocrypt/libmongocrypt/bindings/python/strip_header.py +6 -7
  74. data/ext/libmongocrypt/libmongocrypt/bindings/python/synchro.py +64 -0
  75. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/__init__.py +1 -0
  76. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/collection-info.json +1 -1
  77. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/command.json +1 -1
  78. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/compact/success/encrypted-payload.json +21 -21
  79. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/encrypted-command-reply.json +1 -1
  80. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/encrypted-field-config-map.json +1 -1
  81. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-range-explicit-v2/int32/encrypted-payload.json +1 -1
  82. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-range-explicit-v2/int32/rangeopts.json +3 -0
  83. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/rangeopts.json +11 -0
  84. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/value-to-encrypt.json +20 -0
  85. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document-azure.json +1 -1
  86. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document-gcp.json +1 -1
  87. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document.json +1 -1
  88. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-filter.json +1 -1
  89. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/list-collections-filter.json +1 -1
  90. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/mongocryptd-command.json +1 -1
  91. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/mongocryptd-reply.json +1 -1
  92. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/schema-map.json +1 -1
  93. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/performance/keyDocument.json +24 -0
  94. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/performance/perf_test.py +165 -0
  95. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_binding.py +8 -12
  96. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_crypto.py +9 -11
  97. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_mongocrypt.py +988 -340
  98. data/ext/libmongocrypt/libmongocrypt/bindings/python/update-sbom.sh +14 -0
  99. data/ext/libmongocrypt/libmongocrypt/cmake/FetchMongoC.cmake +19 -1
  100. data/ext/libmongocrypt/libmongocrypt/cmake/ImportBSON.cmake +23 -0
  101. data/ext/libmongocrypt/libmongocrypt/cmake/IntelDFP.cmake +19 -227
  102. data/ext/libmongocrypt/libmongocrypt/cmake/Patch.cmake +54 -0
  103. data/ext/libmongocrypt/libmongocrypt/doc/img/cli-icon.png +0 -0
  104. data/ext/libmongocrypt/libmongocrypt/doc/img/reference-targets.png +0 -0
  105. data/ext/libmongocrypt/libmongocrypt/doc/releasing.md +153 -0
  106. data/ext/libmongocrypt/libmongocrypt/etc/calc_release_version.py +61 -28
  107. data/ext/libmongocrypt/libmongocrypt/etc/calc_release_version_selftest.sh +73 -0
  108. data/ext/libmongocrypt/libmongocrypt/etc/cyclonedx.sbom.json +108 -0
  109. data/ext/libmongocrypt/libmongocrypt/etc/format.sh +1 -1
  110. data/ext/libmongocrypt/libmongocrypt/etc/libbson-remove-GCC-diagnostic-pragma.patch +27 -0
  111. data/ext/libmongocrypt/libmongocrypt/etc/mongo-inteldfp-alpine-arm-fix.patch +17 -0
  112. data/ext/libmongocrypt/libmongocrypt/etc/packager.py +120 -91
  113. data/ext/libmongocrypt/libmongocrypt/etc/purls.txt +14 -0
  114. data/ext/libmongocrypt/libmongocrypt/etc/repo_config.yaml +56 -0
  115. data/ext/libmongocrypt/libmongocrypt/etc/silk-create-asset-group.sh +70 -0
  116. data/ext/libmongocrypt/libmongocrypt/etc/ssdlc_compliance_report.md +37 -0
  117. data/ext/libmongocrypt/libmongocrypt/etc/third_party_vulnerabilities.md +42 -0
  118. data/ext/libmongocrypt/libmongocrypt/integrating.md +18 -1
  119. data/ext/libmongocrypt/libmongocrypt/kms-message/CMakeLists.txt +11 -3
  120. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_gcp_request.c +1 -1
  121. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_reader_writer.c +17 -0
  122. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_reader_writer_private.h +6 -0
  123. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_request.c +211 -1
  124. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_response.c +163 -0
  125. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_tag_type_private.h +2 -1
  126. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_message/kms_kmip_request.h +17 -0
  127. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_message/kms_kmip_response.h +6 -0
  128. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_port.c +3 -2
  129. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_request.c +4 -2
  130. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_request_str.c +2 -2
  131. data/ext/libmongocrypt/libmongocrypt/kms-message/test/test_kmip_reader_writer.c +23 -2
  132. data/ext/libmongocrypt/libmongocrypt/src/crypto/libcrypto.c +13 -10
  133. data/ext/libmongocrypt/libmongocrypt/src/mc-dec128.h +1 -1
  134. data/ext/libmongocrypt/libmongocrypt/src/mc-efc-private.h +16 -2
  135. data/ext/libmongocrypt/libmongocrypt/src/mc-efc.c +94 -6
  136. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-encryption-placeholder-private.h +15 -5
  137. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-encryption-placeholder.c +114 -53
  138. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-private-v2.h +1 -1
  139. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-private.h +1 -1
  140. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-v2.c +2 -2
  141. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload.c +2 -2
  142. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-private-v2.h +21 -6
  143. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-private.h +5 -5
  144. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-v2.c +38 -2
  145. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload.c +1 -1
  146. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-private-v2.h +20 -7
  147. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-private.h +8 -8
  148. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-v2.c +89 -1
  149. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-payload-iev-v2.c +3 -3
  150. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-payload-iev.c +1 -23
  151. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-rfds-private.h +4 -3
  152. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-rfds.c +15 -12
  153. data/ext/libmongocrypt/libmongocrypt/src/mc-optional-private.h +11 -0
  154. data/ext/libmongocrypt/libmongocrypt/src/mc-range-edge-generation-private.h +16 -6
  155. data/ext/libmongocrypt/libmongocrypt/src/mc-range-edge-generation.c +64 -22
  156. data/ext/libmongocrypt/libmongocrypt/src/mc-range-encoding-private.h +23 -4
  157. data/ext/libmongocrypt/libmongocrypt/src/mc-range-encoding.c +359 -65
  158. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover-generator.template.h +26 -14
  159. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover-private.h +17 -6
  160. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover.c +31 -13
  161. data/ext/libmongocrypt/libmongocrypt/src/mc-rangeopts-private.h +16 -3
  162. data/ext/libmongocrypt/libmongocrypt/src/mc-rangeopts.c +259 -63
  163. data/ext/libmongocrypt/libmongocrypt/src/mc-tokens-private.h +40 -24
  164. data/ext/libmongocrypt/libmongocrypt/src/mc-tokens.c +57 -13
  165. data/ext/libmongocrypt/libmongocrypt/src/mlib/int128.h +17 -0
  166. data/ext/libmongocrypt/libmongocrypt/src/mlib/int128.test.cpp +5 -0
  167. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-binary-private.h +0 -5
  168. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-buffer.c +5 -7
  169. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-key.c +1 -0
  170. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-oauth-private.h +16 -18
  171. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-oauth.c +105 -76
  172. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-crypto.c +9 -3
  173. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-datakey.c +170 -89
  174. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-decrypt.c +5 -5
  175. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-encrypt.c +505 -124
  176. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-private.h +31 -6
  177. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx.c +81 -13
  178. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-dll-private.h +7 -0
  179. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kek-private.h +5 -1
  180. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kek.c +161 -103
  181. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key-broker-private.h +2 -7
  182. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key-broker.c +191 -69
  183. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key.c +1 -1
  184. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx-private.h +50 -15
  185. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx.c +365 -69
  186. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-marking-private.h +2 -1
  187. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-marking.c +200 -107
  188. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-opts-private.h +50 -5
  189. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-opts.c +591 -15
  190. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-private.h +6 -13
  191. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-util.c +3 -2
  192. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.c +47 -234
  193. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.h +75 -24
  194. data/ext/libmongocrypt/libmongocrypt/src/os_posix/os_dll.c +18 -2
  195. data/ext/libmongocrypt/libmongocrypt/src/os_win/os_dll.c +4 -0
  196. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/bypassQueryAnalysis/payload.json +53 -0
  197. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/jsonSchema/cmd-to-mongocryptd.json +23 -0
  198. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/jsonSchema/cmd.json +20 -0
  199. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/cmd-to-mongocryptd.json +50 -0
  200. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/cmd.json +20 -0
  201. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/collinfo.json +44 -0
  202. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/encrypted-field-map.json +24 -0
  203. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/encrypted-payload-pattern.json +53 -0
  204. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/mongocryptd-reply.json +62 -0
  205. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/cmd-to-mongocryptd.json +30 -0
  206. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/cmd.json +17 -0
  207. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/mongocryptd-reply.json +39 -0
  208. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/payload.json +21 -0
  209. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/missing-key-id/collinfo.json +20 -0
  210. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/no-fields/collinfo.json +9 -0
  211. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/no-fields/encrypted-payload.json +4 -0
  212. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/cmd.json +1 -0
  213. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/collinfo.json +63 -0
  214. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-field-config-map.json +61 -0
  215. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-payload-range-v2.json +37 -0
  216. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-payload.json +29 -0
  217. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/cmd.json +1 -0
  218. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/collinfo.json +64 -0
  219. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/encrypted-payload-range-v2.json +105 -0
  220. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/encrypted-payload.json +30 -0
  221. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/cmd.json +1 -0
  222. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/collinfo.json +49 -0
  223. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/encrypted-field-config-map.json +47 -0
  224. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/encrypted-payload.json +23 -0
  225. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/collinfo.json +15 -0
  226. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-field-config-map.json +10 -0
  227. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-payload-range-v2.json +104 -0
  228. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-payload.json +6 -0
  229. data/ext/libmongocrypt/libmongocrypt/test/data/fle2-explain/with-csfle/collinfo.json +4 -4
  230. data/ext/libmongocrypt/libmongocrypt/test/data/fle2-explain/with-csfle/encrypted-payload.json +3 -3
  231. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/decrypt-response.txt +16 -0
  232. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/encrypt-response.txt +16 -0
  233. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/oauth-response.txt +19 -0
  234. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/cmd.json +9 -0
  235. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/encrypted-field-map.json +19 -0
  236. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/encrypted-payload.json +62 -0
  237. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/mongocryptd-reply.json +69 -0
  238. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/cmd.json +11 -0
  239. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/encrypted-field-map.json +19 -0
  240. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/encrypted-payload.json +40 -0
  241. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/mongocryptd-reply.json +47 -0
  242. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_decimal128.cstruct +1 -1
  243. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_double.cstruct +8637 -7958
  244. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_int32.cstruct +5522 -1382
  245. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_int64.cstruct +5042 -1262
  246. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_decimal128.cstruct +1 -1
  247. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_decimal128_precision.cstruct +1 -1
  248. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_double.cstruct +1 -1
  249. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_double_precision.cstruct +2 -2
  250. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_int32.cstruct +1 -1
  251. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_int64.cstruct +1 -1
  252. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/cmd.json +8 -0
  253. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/encrypted-field-map.json +19 -0
  254. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/encrypted-payload.json +53 -0
  255. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/mongocryptd-reply.json +58 -0
  256. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/cmd.json +11 -0
  257. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/encrypted-field-map.json +19 -0
  258. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/encrypted-payload.json +40 -0
  259. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/mongocryptd-reply.json +45 -0
  260. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32/expected.json +26 -0
  261. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32/to-encrypt.json +20 -0
  262. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32-defaults/expected.json +26 -0
  263. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32-defaults/to-encrypt.json +20 -0
  264. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-double/expected.json +8 -0
  265. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-int32/expected.json +8 -0
  266. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-int32-defaults/expected.json +8 -0
  267. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/README.md +7 -4
  268. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/mc.json +9 -5
  269. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/server.json +9 -5
  270. data/ext/libmongocrypt/libmongocrypt/test/example-state-machine.c +1 -0
  271. data/ext/libmongocrypt/libmongocrypt/test/test-gcp-auth.c +8 -8
  272. data/ext/libmongocrypt/libmongocrypt/test/test-mc-efc.c +6 -4
  273. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-find-range-payload-v2.c +43 -3
  274. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-payload-iup-v2.c +76 -0
  275. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-rfds.c +5 -5
  276. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-edge-generation.c +89 -14
  277. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-encoding.c +342 -76
  278. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-mincover.c +94 -12
  279. data/ext/libmongocrypt/libmongocrypt/test/test-mc-rangeopts.c +205 -7
  280. data/ext/libmongocrypt/libmongocrypt/test/test-mc-tokens.c +49 -23
  281. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-assert-match-bson.c +16 -19
  282. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-assert-match-bson.h +22 -1
  283. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-cache-oauth.c +94 -11
  284. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-cleanup.c +374 -0
  285. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-compact.c +121 -42
  286. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-hooks.c +134 -4
  287. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-std-hooks.c +40 -0
  288. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-std-hooks.h +16 -0
  289. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-csfle-lib.c +11 -11
  290. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-decrypt.c +8 -5
  291. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-encrypt.c +922 -92
  292. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-rewrap-many-datakey.c +2 -2
  293. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-setopt.c +114 -12
  294. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-datakey.c +14 -9
  295. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-kms-ctx.c +424 -3
  296. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-log.c +1 -1
  297. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-marking.c +447 -28
  298. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-opts.c +42 -0
  299. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-traverse-util.c +30 -26
  300. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-util.c +7 -0
  301. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-util.h +3 -0
  302. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt.c +66 -14
  303. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt.h +11 -0
  304. data/ext/libmongocrypt/libmongocrypt/test/test-named-kms-providers.c +2381 -0
  305. data/ext/libmongocrypt/libmongocrypt/test/util/HELP.autogen +3 -1
  306. data/ext/libmongocrypt/libmongocrypt/test/util/README.md +1 -0
  307. data/ext/libmongocrypt/libmongocrypt/test/util/csfle.c +4 -0
  308. data/ext/libmongocrypt/libmongocrypt/test/util/make_includes.py +1 -1
  309. data/ext/libmongocrypt/libmongocrypt/test/util/util.c +38 -3
  310. data/lib/libmongocrypt_helper/version.rb +2 -2
  311. metadata +112 -106
  312. checksums.yaml.gz.sig +0 -0
  313. data/ext/libmongocrypt/libmongocrypt/VERSION_CURRENT +0 -1
  314. data/ext/libmongocrypt/libmongocrypt/bindings/cs/cs.sln +0 -79
  315. data/ext/libmongocrypt/libmongocrypt/bindings/node/CHANGELOG.md +0 -105
  316. data/ext/libmongocrypt/libmongocrypt/bindings/node/LICENSE +0 -201
  317. data/ext/libmongocrypt/libmongocrypt/bindings/node/binding.gyp +0 -79
  318. data/ext/libmongocrypt/libmongocrypt/bindings/node/etc/README.hbs +0 -44
  319. data/ext/libmongocrypt/libmongocrypt/bindings/node/etc/build-static.sh +0 -36
  320. data/ext/libmongocrypt/libmongocrypt/bindings/node/index.d.ts +0 -641
  321. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/autoEncrypter.js +0 -420
  322. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/buffer_pool.js +0 -123
  323. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/clientEncryption.js +0 -821
  324. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/common.js +0 -98
  325. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/cryptoCallbacks.js +0 -87
  326. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/errors.js +0 -75
  327. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/index.js +0 -73
  328. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/mongocryptdManager.js +0 -66
  329. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/aws.js +0 -26
  330. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/azure.js +0 -178
  331. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/gcp.js +0 -24
  332. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/index.js +0 -54
  333. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/utils.js +0 -39
  334. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/stateMachine.js +0 -492
  335. data/ext/libmongocrypt/libmongocrypt/bindings/node/package-lock.json +0 -15302
  336. data/ext/libmongocrypt/libmongocrypt/bindings/node/package.json +0 -100
  337. data/ext/libmongocrypt/libmongocrypt/bindings/node/src/mongocrypt.cc +0 -956
  338. data/ext/libmongocrypt/libmongocrypt/bindings/node/src/mongocrypt.h +0 -114
  339. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/autoEncrypter.test.js +0 -950
  340. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/buffer_pool.test.js +0 -91
  341. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/clientEncryption.test.js +0 -1093
  342. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/common.test.js +0 -94
  343. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/cryptoCallbacks.test.js +0 -240
  344. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/README.md +0 -5
  345. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/cmd.json +0 -6
  346. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/collection-info.json +0 -37
  347. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encrypted-document-nested.json +0 -8
  348. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encrypted-document.json +0 -11
  349. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encryptedFields.json +0 -30
  350. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/key-document.json +0 -32
  351. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/key1-document.json +0 -30
  352. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/mongocryptd-reply.json +0 -18
  353. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/index.test.js +0 -45
  354. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/mongocryptdManager.test.js +0 -48
  355. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/providers/credentialsProvider.test.js +0 -551
  356. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/release.test.js +0 -66
  357. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/requirements.helper.js +0 -51
  358. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/stateMachine.test.js +0 -331
  359. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/tools/chai-addons.js +0 -8
  360. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/tools/mongodb_reporter.js +0 -325
  361. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/types/index.test-d.ts +0 -63
  362. data/ext/libmongocrypt/libmongocrypt/bindings/python/setup.py +0 -89
  363. data/ext/libmongocrypt/libmongocrypt/debian/build_snapshot.sh +0 -79
  364. data/ext/libmongocrypt/libmongocrypt/debian/changelog +0 -105
  365. data/ext/libmongocrypt/libmongocrypt/debian/compat +0 -1
  366. data/ext/libmongocrypt/libmongocrypt/debian/control +0 -41
  367. data/ext/libmongocrypt/libmongocrypt/debian/copyright +0 -129
  368. data/ext/libmongocrypt/libmongocrypt/debian/gbp.conf +0 -23
  369. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt-dev.dirs +0 -2
  370. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt-dev.install +0 -5
  371. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt0.dirs +0 -1
  372. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt0.install +0 -1
  373. data/ext/libmongocrypt/libmongocrypt/debian/rules +0 -46
  374. data/ext/libmongocrypt/libmongocrypt/debian/source/format +0 -1
  375. data/ext/libmongocrypt/libmongocrypt/debian/source/lintian-overrides +0 -3
  376. data/ext/libmongocrypt/libmongocrypt/debian/source/options +0 -1
  377. data/ext/libmongocrypt/libmongocrypt/debian/watch +0 -3
  378. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/mongocryptd-reply.json +0 -72
  379. data.tar.gz.sig +0 -1
  380. metadata.gz.sig +0 -0
  381. /data/ext/libmongocrypt/libmongocrypt/{bindings/node/test/data/kms-decrypt-reply.txt → test/data/kms-aws/decrypt-response.txt} +0 -0
  382. /data/ext/libmongocrypt/libmongocrypt/{bindings/node/test/data/kms-encrypt-reply.txt → test/data/kms-aws/encrypt-response.txt} +0 -0
  383. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/decrypt-response.txt +0 -0
  384. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/encrypt-response.txt +0 -0
  385. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/oauth-response.txt +0 -0
@@ -16,101 +16,117 @@
16
16
 
17
17
  import base64
18
18
  import copy
19
- import json
20
19
  import os
21
20
  import sys
22
21
 
23
22
  import bson
24
- from bson.raw_bson import RawBSONDocument
23
+ import httpx
25
24
  from bson import json_util
26
25
  from bson.binary import Binary, UuidRepresentation
27
26
  from bson.codec_options import CodecOptions
28
27
  from bson.json_util import JSONOptions
28
+ from bson.raw_bson import RawBSONDocument
29
29
  from bson.son import SON
30
30
 
31
+ import pymongocrypt.mongocrypt
32
+ from pymongocrypt.binary import MongoCryptBinaryIn, MongoCryptBinaryOut
33
+ from pymongocrypt.options import MongoCryptOptions
34
+
31
35
  sys.path[0:0] = [""]
32
36
 
33
- import pymongocrypt.mongocrypt
37
+ import unittest
38
+ import unittest.mock
39
+
40
+ import respx
34
41
  from pymongo_auth_aws.auth import AwsCredential
35
- from pymongocrypt.auto_encrypter import AutoEncrypter
42
+
43
+ from pymongocrypt.asynchronous.auto_encrypter import AsyncAutoEncrypter
44
+ from pymongocrypt.asynchronous.explicit_encrypter import AsyncExplicitEncrypter
45
+ from pymongocrypt.asynchronous.state_machine import AsyncMongoCryptCallback
36
46
  from pymongocrypt.binding import lib
37
- from pymongocrypt.compat import unicode_type, PY3
47
+ from pymongocrypt.compat import PY3, unicode_type
38
48
  from pymongocrypt.errors import MongoCryptError
39
- from pymongocrypt.explicit_encrypter import ExplicitEncrypter
40
- from pymongocrypt.mongocrypt import (MongoCrypt,
41
- MongoCryptBinaryIn,
42
- MongoCryptBinaryOut,
43
- MongoCryptOptions)
44
- from pymongocrypt.state_machine import MongoCryptCallback
45
-
46
- from test import unittest, mock
47
-
48
- import requests.exceptions
49
- import requests_mock
50
-
49
+ from pymongocrypt.mongocrypt import MongoCrypt
50
+ from pymongocrypt.synchronous.auto_encrypter import AutoEncrypter
51
+ from pymongocrypt.synchronous.explicit_encrypter import ExplicitEncrypter
52
+ from pymongocrypt.synchronous.state_machine import MongoCryptCallback
51
53
 
52
54
  # Data for testing libbmongocrypt binding.
53
- DATA_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), 'data'))
55
+ DATA_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), "data"))
54
56
 
55
57
 
56
58
  def to_base64(data):
57
59
  b64 = base64.b64encode(data)
58
60
  if not PY3:
59
61
  return unicode_type(b64)
60
- return b64.decode('utf-8')
62
+ return b64.decode("utf-8")
61
63
 
62
64
 
63
65
  class TestMongoCryptBinary(unittest.TestCase):
64
-
65
66
  def test_mongocrypt_binary_in(self):
66
- with MongoCryptBinaryIn(b'1\x0023') as binary:
67
+ with MongoCryptBinaryIn(b"1\x0023") as binary:
67
68
  self.assertIsNotNone(binary.bin)
68
- self.assertEqual(binary.to_bytes(), b'1\x0023')
69
+ self.assertEqual(binary.to_bytes(), b"1\x0023")
69
70
  self.assertIsNone(binary.bin)
70
71
 
71
- with MongoCryptBinaryIn(b'') as binary:
72
+ with MongoCryptBinaryIn(b"") as binary:
72
73
  self.assertIsNotNone(binary.bin)
73
- self.assertEqual(binary.to_bytes(), b'')
74
+ self.assertEqual(binary.to_bytes(), b"")
74
75
  self.assertIsNone(binary.bin)
75
76
 
76
77
  # Memoryview
77
- with MongoCryptBinaryIn(memoryview(b'1\x0023')) as binary:
78
+ with MongoCryptBinaryIn(memoryview(b"1\x0023")) as binary:
78
79
  self.assertIsNotNone(binary.bin)
79
- self.assertEqual(binary.to_bytes(), b'1\x0023')
80
+ self.assertEqual(binary.to_bytes(), b"1\x0023")
80
81
  self.assertIsNone(binary.bin)
81
82
 
82
83
  def test_mongocrypt_binary_out(self):
83
84
  with MongoCryptBinaryOut() as binary:
84
85
  self.assertIsNotNone(binary.bin)
85
- self.assertEqual(binary.to_bytes(), b'')
86
+ self.assertEqual(binary.to_bytes(), b"")
86
87
  self.assertIsNone(binary.bin)
87
88
 
88
89
 
89
90
  class TestMongoCryptOptions(unittest.TestCase):
90
-
91
91
  def test_mongocrypt_options(self):
92
- schema_map = bson_data('schema-map.json')
92
+ schema_map = bson_data("schema-map.json")
93
93
  valid = [
94
- ({'local': {'key': b'1' * 96}}, None),
95
- ({ 'aws' : {} }, schema_map),
96
- ({'aws': {'accessKeyId': '', 'secretAccessKey': ''}}, schema_map),
97
- ({'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'foo'}}, None),
98
- ({'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'foo',
99
- 'sessionToken': 'token'}}, None),
100
- ({'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'foo'},
101
- 'local': {'key': b'1' * 96}}, None),
102
- ({'local': {'key': to_base64(b'1' * 96)}}, None),
103
- ({'local': {'key': Binary(b'1' * 96)}}, None),
104
- ({'azure': {}}, None),
105
- ({'azure': {'clientId': 'foo', 'clientSecret': 'bar'}}, None),
106
- ({'gcp': {}}, None),
107
- ({'gcp': {'email': 'foo@bar.baz',
108
- 'privateKey': b'1'}}, None),
109
- ({'gcp': {'email': 'foo@bar.baz',
110
- 'privateKey': to_base64(b'1')}}, None),
111
- ({'gcp': {'email': 'foo@bar.baz',
112
- 'privateKey': Binary(b'1')}}, None)
94
+ ({"local": {"key": b"1" * 96}}, None),
95
+ ({"aws": {}}, schema_map),
96
+ ({"aws": {"accessKeyId": "", "secretAccessKey": ""}}, schema_map),
97
+ ({"aws": {"accessKeyId": "foo", "secretAccessKey": "foo"}}, None),
98
+ (
99
+ {
100
+ "aws": {
101
+ "accessKeyId": "foo",
102
+ "secretAccessKey": "foo",
103
+ "sessionToken": "token",
104
+ }
105
+ },
106
+ None,
107
+ ),
108
+ (
109
+ {
110
+ "aws": {"accessKeyId": "foo", "secretAccessKey": "foo"},
111
+ "local": {"key": b"1" * 96},
112
+ },
113
+ None,
114
+ ),
115
+ ({"local": {"key": to_base64(b"1" * 96)}}, None),
116
+ ({"local": {"key": Binary(b"1" * 96)}}, None),
117
+ ({"azure": {}}, None),
118
+ ({"azure": {"clientId": "foo", "clientSecret": "bar"}}, None),
119
+ ({"gcp": {}}, None),
120
+ ({"gcp": {"email": "foo@bar.baz", "privateKey": b"1"}}, None),
121
+ ({"gcp": {"email": "foo@bar.baz", "privateKey": to_base64(b"1")}}, None),
122
+ ({"gcp": {"email": "foo@bar.baz", "privateKey": Binary(b"1")}}, None),
123
+ ({"kmip": {"endpoint": "localhost"}}, None),
113
124
  ]
125
+ # Add tests for named KMS providers.
126
+ for kms_providers, schema_map in valid:
127
+ for name, val in list(kms_providers.items()):
128
+ kms_providers[f"{name}:named"] = val
129
+
114
130
  for kms_providers, schema_map in valid:
115
131
  opts = MongoCryptOptions(kms_providers, schema_map)
116
132
  self.assertEqual(opts.kms_providers, kms_providers, msg=kms_providers)
@@ -118,40 +134,63 @@ class TestMongoCryptOptions(unittest.TestCase):
118
134
  self.assertIsNone(opts.encrypted_fields_map)
119
135
  self.assertFalse(opts.bypass_query_analysis)
120
136
 
121
- encrypted_fields_map = bson_data('encrypted-field-config-map.json')
122
- opts = MongoCryptOptions(valid[0][0], schema_map, encrypted_fields_map=encrypted_fields_map,
123
- bypass_query_analysis=True)
137
+ encrypted_fields_map = bson_data("encrypted-field-config-map.json")
138
+ opts = MongoCryptOptions(
139
+ valid[0][0],
140
+ schema_map,
141
+ encrypted_fields_map=encrypted_fields_map,
142
+ bypass_query_analysis=True,
143
+ )
124
144
  self.assertEqual(opts.encrypted_fields_map, encrypted_fields_map)
125
145
  self.assertTrue(opts.bypass_query_analysis)
126
146
 
127
147
  def test_mongocrypt_options_validation(self):
128
148
  with self.assertRaisesRegex(
129
- ValueError, 'at least one KMS provider must be configured'):
149
+ ValueError, "at least one KMS provider must be configured"
150
+ ):
130
151
  MongoCryptOptions({})
131
152
  for invalid_kms_providers in [
132
- {'aws': {'accessKeyId': 'foo'}},
133
- {'aws': {'secretAccessKey': 'foo'}}]:
153
+ {"aws": {"accessKeyId": "foo"}},
154
+ {"aws": {"secretAccessKey": "foo"}},
155
+ {"aws:foo": {"accessKeyId": "foo"}},
156
+ {"aws:foo": {"secretAccessKey": "foo"}},
157
+ ]:
158
+ name = next(iter(invalid_kms_providers))
134
159
  with self.assertRaisesRegex(
135
- ValueError, r"kms_providers\['aws'\] must contain "
136
- "'accessKeyId' and 'secretAccessKey'"):
160
+ ValueError,
161
+ rf"kms_providers\[{name!r}\] must contain "
162
+ "'accessKeyId' and 'secretAccessKey'",
163
+ ):
137
164
  MongoCryptOptions(invalid_kms_providers)
138
165
  with self.assertRaisesRegex(
139
- TypeError, r"kms_providers\['local'\]\['key'\] must be an "
140
- r"instance of bytes or str"):
141
- MongoCryptOptions({'local': {'key': None}})
166
+ TypeError,
167
+ r"kms_providers\['local'\]\['key'\] must be an "
168
+ r"instance of bytes or str",
169
+ ):
170
+ MongoCryptOptions({"local": {"key": None}})
142
171
  with self.assertRaisesRegex(
143
- TypeError, r"kms_providers\['gcp'\]\['privateKey'\] must be an "
144
- r"instance of bytes or str"):
145
- MongoCryptOptions({'gcp': {'email': "foo@bar.baz",
146
- "privateKey": None}})
147
-
148
- valid_kms = {'aws': {'accessKeyId': '', 'secretAccessKey': ''}}
172
+ TypeError,
173
+ r"kms_providers\['gcp'\]\['privateKey'\] must be an "
174
+ r"instance of bytes or str",
175
+ ):
176
+ MongoCryptOptions({"gcp": {"email": "foo@bar.baz", "privateKey": None}})
149
177
  with self.assertRaisesRegex(
150
- TypeError, "schema_map must be bytes or None"):
178
+ ValueError, r"kms_providers\['kmip'\] must contain 'endpoint'"
179
+ ):
180
+ MongoCryptOptions({"kmip": {}})
181
+ with self.assertRaisesRegex(
182
+ TypeError,
183
+ r"kms_providers\['kmip'\]\['endpoint'\] must be an instance of str",
184
+ ):
185
+ MongoCryptOptions({"kmip": {"endpoint": None}})
186
+
187
+ valid_kms = {"aws": {"accessKeyId": "", "secretAccessKey": ""}}
188
+ with self.assertRaisesRegex(TypeError, "schema_map must be bytes or None"):
151
189
  MongoCryptOptions(valid_kms, schema_map={})
152
190
 
153
191
  with self.assertRaisesRegex(
154
- TypeError, "encrypted_fields_map must be bytes or None"):
192
+ TypeError, "encrypted_fields_map must be bytes or None"
193
+ ):
155
194
  MongoCryptOptions(valid_kms, encrypted_fields_map={})
156
195
 
157
196
 
@@ -159,8 +198,7 @@ class TestMongoCrypt(unittest.TestCase):
159
198
  maxDiff = None
160
199
 
161
200
  def test_mongocrypt(self):
162
- kms_providers = {
163
- 'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'foo'}}
201
+ kms_providers = {"aws": {"accessKeyId": "foo", "secretAccessKey": "foo"}}
164
202
  opts = MongoCryptOptions(kms_providers)
165
203
  mc = MongoCrypt(opts, MockCallback())
166
204
  mc.close()
@@ -168,85 +206,96 @@ class TestMongoCrypt(unittest.TestCase):
168
206
 
169
207
  def test_mongocrypt_aws_session_token(self):
170
208
  kms_providers = {
171
- 'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'foo',
172
- 'sessionToken': 'token'}}
209
+ "aws": {
210
+ "accessKeyId": "foo",
211
+ "secretAccessKey": "foo",
212
+ "sessionToken": "token",
213
+ }
214
+ }
173
215
  opts = MongoCryptOptions(kms_providers)
174
216
  mc = MongoCrypt(opts, MockCallback())
175
217
  mc.close()
176
218
 
177
219
  def test_mongocrypt_validation(self):
178
220
  callback = MockCallback()
179
- options = MongoCryptOptions({'local': {'key': b'\x00' * 96}})
221
+ options = MongoCryptOptions({"local": {"key": b"\x00" * 96}})
180
222
 
181
- with self.assertRaisesRegex(
182
- TypeError, 'options must be a MongoCryptOptions'):
223
+ with self.assertRaisesRegex(TypeError, "options must be a MongoCryptOptions"):
183
224
  MongoCrypt({}, callback)
184
- with self.assertRaisesRegex(
185
- TypeError, 'options must be a MongoCryptOptions'):
225
+ with self.assertRaisesRegex(TypeError, "options must be a MongoCryptOptions"):
186
226
  MongoCrypt(None, callback)
187
227
 
188
228
  with self.assertRaisesRegex(
189
- TypeError, 'callback must be a MongoCryptCallback'):
229
+ TypeError,
230
+ "callback must be a MongoCryptCallback or AsyncMongoCryptCallback",
231
+ ):
190
232
  MongoCrypt(options, {})
191
233
  with self.assertRaisesRegex(
192
- TypeError, 'callback must be a MongoCryptCallback'):
234
+ TypeError,
235
+ "callback must be a MongoCryptCallback or AsyncMongoCryptCallback",
236
+ ):
193
237
  MongoCrypt(options, None)
194
238
 
195
- invalid_key_len_opts = MongoCryptOptions({'local': {'key': b'1'}})
196
- with self.assertRaisesRegex(
197
- MongoCryptError, "local key must be 96 bytes"):
239
+ invalid_key_len_opts = MongoCryptOptions({"local": {"key": b"1"}})
240
+ with self.assertRaisesRegex(MongoCryptError, "local key must be 96 bytes"):
198
241
  MongoCrypt(invalid_key_len_opts, callback)
199
242
 
200
243
  def test_setopt_kms_provider_base64_or_bytes(self):
201
244
  test_fields = [("local", "key"), ("gcp", "privateKey")]
202
245
  callback = MockCallback()
203
- base_kms_dict = {'local': {'key': b'\x00' * 96},
204
- 'gcp': {'email': 'foo@bar.baz',
205
- 'privateKey': b'\x00'}}
246
+ base_kms_dict = {
247
+ "local": {"key": b"\x00" * 96},
248
+ "gcp": {"email": "foo@bar.baz", "privateKey": b"\x00"},
249
+ }
206
250
 
207
251
  for f1, f2 in test_fields:
208
252
  kms_dict = copy.deepcopy(base_kms_dict)
209
253
 
210
254
  # Case 1: pass key as string containing bytes (valid)
211
- kms_dict[f1][f2] = b'\x00' * 96
255
+ kms_dict[f1][f2] = b"\x00" * 96
212
256
  options = MongoCryptOptions(kms_dict)
213
257
  mc = MongoCrypt(options, callback)
214
258
  mc.close()
215
259
 
216
260
  # Case 2: pass key as base64-encoded unicode literal (valid)
217
- kms_dict[f1][f2] = to_base64(b'\x00' * 96)
261
+ kms_dict[f1][f2] = to_base64(b"\x00" * 96)
218
262
  options = MongoCryptOptions(kms_dict)
219
263
  mc = MongoCrypt(options, callback)
220
264
  mc.close()
221
265
 
222
266
  # Case 3: pass key as unicode string containing bytes (invalid)
223
- kms_dict[f1][f2] = unicode_type(b'\x00' * 96)
267
+ kms_dict[f1][f2] = unicode_type(b"\x00" * 96)
224
268
  options = MongoCryptOptions(kms_dict)
225
269
  with self.assertRaisesRegex(
226
- MongoCryptError,
227
- "unable to parse base64 from UTF-8 field %s.%s" % (
228
- f1, f2)):
270
+ MongoCryptError, "unable to parse base64 from UTF-8 field"
271
+ ):
229
272
  MongoCrypt(options, callback)
230
273
 
231
274
  # Case 4: pass key as base64-encoded string (invalid)
232
275
  # Only applicable to "local" as key length is not validated for gcp.
233
276
  kms_dict = copy.deepcopy(base_kms_dict)
234
- kms_dict['local']['key'] = base64.b64encode(b'\x00' * 96)
277
+ kms_dict["local"]["key"] = base64.b64encode(b"\x00" * 96)
235
278
  options = MongoCryptOptions(kms_dict)
236
- with self.assertRaisesRegex(
237
- MongoCryptError, "local key must be 96 bytes"):
279
+ with self.assertRaisesRegex(MongoCryptError, "local key must be 96 bytes"):
238
280
  MongoCrypt(options, callback)
239
281
 
240
282
  @staticmethod
241
283
  def create_mongocrypt(**kwargs):
242
- return MongoCrypt(MongoCryptOptions({
243
- 'aws': {'accessKeyId': 'example', 'secretAccessKey': 'example'},
244
- 'local': {'key': b'\x00'*96}}, **kwargs), MockCallback())
284
+ return MongoCrypt(
285
+ MongoCryptOptions(
286
+ {
287
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
288
+ "local": {"key": b"\x00" * 96},
289
+ },
290
+ **kwargs,
291
+ ),
292
+ MockCallback(),
293
+ )
245
294
 
246
295
  def _test_kms_context(self, ctx):
247
296
  key_filter = ctx.mongo_operation()
248
- self.assertEqual(key_filter, bson_data('key-filter.json'))
249
- ctx.add_mongo_operation_result(bson_data('key-document.json'))
297
+ self.assertEqual(key_filter, bson_data("key-filter.json"))
298
+ ctx.add_mongo_operation_result(bson_data("key-document.json"))
250
299
  ctx.complete_mongo_operation()
251
300
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_KMS)
252
301
 
@@ -258,7 +307,7 @@ class TestMongoCrypt(unittest.TestCase):
258
307
  self.assertEqual(len(kms_ctx.message), 790)
259
308
  self.assertEqual(kms_ctx.bytes_needed, 1024)
260
309
 
261
- kms_ctx.feed(http_data('kms-reply.txt'))
310
+ kms_ctx.feed(http_data("kms-reply.txt"))
262
311
  self.assertEqual(kms_ctx.bytes_needed, 0)
263
312
  self.assertEqual(kms_ctx.kms_provider, "aws")
264
313
 
@@ -269,24 +318,26 @@ class TestMongoCrypt(unittest.TestCase):
269
318
  self.addCleanup(mc.close)
270
319
  if mc.crypt_shared_lib_version is not None:
271
320
  self.skipTest("this test must be skipped when crypt_shared is loaded")
272
- with mc.encryption_context('text', bson_data('command.json')) as ctx:
321
+ with mc.encryption_context("text", bson_data("command.json")) as ctx:
273
322
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO)
274
323
 
275
324
  list_colls_filter = ctx.mongo_operation()
276
- self.assertEqual(list_colls_filter,
277
- bson_data('list-collections-filter.json'))
325
+ self.assertEqual(
326
+ list_colls_filter, bson_data("list-collections-filter.json")
327
+ )
278
328
 
279
- ctx.add_mongo_operation_result(bson_data('collection-info.json'))
329
+ ctx.add_mongo_operation_result(bson_data("collection-info.json"))
280
330
  ctx.complete_mongo_operation()
281
331
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS)
282
332
 
283
333
  mongocryptd_cmd = ctx.mongo_operation()
284
- self.assertEqual(bson.decode(mongocryptd_cmd, OPTS),
285
- json_data('mongocryptd-command.json'))
286
- self.assertEqual(mongocryptd_cmd,
287
- bson_data('mongocryptd-command.json'))
334
+ self.assertEqual(
335
+ bson.decode(mongocryptd_cmd, OPTS),
336
+ json_data("mongocryptd-command.json"),
337
+ )
338
+ self.assertEqual(mongocryptd_cmd, bson_data("mongocryptd-command.json"))
288
339
 
289
- ctx.add_mongo_operation_result(bson_data('mongocryptd-reply.json'))
340
+ ctx.add_mongo_operation_result(bson_data("mongocryptd-reply.json"))
290
341
  ctx.complete_mongo_operation()
291
342
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
292
343
 
@@ -295,16 +346,16 @@ class TestMongoCrypt(unittest.TestCase):
295
346
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY)
296
347
 
297
348
  encrypted = ctx.finish()
298
- self.assertEqual(bson.decode(encrypted, OPTS),
299
- json_data('encrypted-command.json'))
300
- self.assertEqual(encrypted, bson_data('encrypted-command.json'))
349
+ self.assertEqual(
350
+ bson.decode(encrypted, OPTS), json_data("encrypted-command.json")
351
+ )
352
+ self.assertEqual(encrypted, bson_data("encrypted-command.json"))
301
353
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE)
302
354
 
303
355
  def test_decrypt(self):
304
356
  mc = self.create_mongocrypt()
305
357
  self.addCleanup(mc.close)
306
- with mc.decryption_context(
307
- bson_data('encrypted-command-reply.json')) as ctx:
358
+ with mc.decryption_context(bson_data("encrypted-command-reply.json")) as ctx:
308
359
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
309
360
 
310
361
  self._test_kms_context(ctx)
@@ -312,46 +363,67 @@ class TestMongoCrypt(unittest.TestCase):
312
363
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY)
313
364
 
314
365
  encrypted = ctx.finish()
315
- self.assertEqual(bson.decode(encrypted, OPTS),
316
- json_data('command-reply.json'))
317
- self.assertEqual(encrypted, bson_data('command-reply.json'))
366
+ self.assertEqual(
367
+ bson.decode(encrypted, OPTS), json_data("command-reply.json")
368
+ )
369
+ self.assertEqual(encrypted, bson_data("command-reply.json"))
318
370
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE)
319
371
 
320
372
  def test_encrypt_encrypted_fields_map(self):
321
- encrypted_fields_map = bson_data('compact/success/encrypted-field-config-map.json')
373
+ encrypted_fields_map = bson_data(
374
+ "compact/success/encrypted-field-config-map.json"
375
+ )
322
376
  mc = self.create_mongocrypt(encrypted_fields_map=encrypted_fields_map)
323
377
  self.addCleanup(mc.close)
324
- with mc.encryption_context('db', bson_data('compact/success/cmd.json')) as ctx:
378
+ with mc.encryption_context("db", bson_data("compact/success/cmd.json")) as ctx:
325
379
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
326
380
 
327
381
  ctx.mongo_operation()
328
- ctx.add_mongo_operation_result(bson_data(
329
- 'keys/12345678123498761234123456789012-local-document.json'))
382
+ ctx.add_mongo_operation_result(
383
+ bson_data("keys/12345678123498761234123456789012-local-document.json")
384
+ )
330
385
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
331
386
  ctx.mongo_operation()
332
- ctx.add_mongo_operation_result(bson_data(
333
- 'keys/ABCDEFAB123498761234123456789012-local-document.json'))
387
+ ctx.add_mongo_operation_result(
388
+ bson_data("keys/ABCDEFAB123498761234123456789012-local-document.json")
389
+ )
334
390
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
335
391
  ctx.mongo_operation()
336
- ctx.add_mongo_operation_result(bson_data(
337
- 'keys/12345678123498761234123456789013-local-document.json'))
392
+ ctx.add_mongo_operation_result(
393
+ bson_data("keys/12345678123498761234123456789013-local-document.json")
394
+ )
338
395
  ctx.complete_mongo_operation()
339
396
 
340
397
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY)
341
398
 
342
399
  encrypted = ctx.finish()
343
- self.assertEqual(bson.decode(encrypted, OPTS),
344
- json_data('compact/success/encrypted-payload.json'))
345
- self.assertEqual(encrypted, bson_data('compact/success/encrypted-payload.json'))
400
+ self.assertEqual(
401
+ bson.decode(encrypted, OPTS),
402
+ json_data("compact/success/encrypted-payload.json"),
403
+ )
404
+ self.assertEqual(
405
+ encrypted, bson_data("compact/success/encrypted-payload.json")
406
+ )
346
407
  self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE)
347
408
 
409
+ def test_pymongo_imports(self):
410
+ from pymongocrypt.auto_encrypter import AutoEncrypter # type:ignore[import]
411
+ from pymongocrypt.errors import MongoCryptError # type:ignore[import]
412
+ from pymongocrypt.explicit_encrypter import (
413
+ ExplicitEncrypter, # type:ignore[import]
414
+ )
415
+ from pymongocrypt.mongocrypt import MongoCryptOptions # type:ignore[import]
416
+ from pymongocrypt.state_machine import MongoCryptCallback # type:ignore[import]
417
+
348
418
 
349
419
  class MockCallback(MongoCryptCallback):
350
- def __init__(self,
351
- list_colls_result=None,
352
- mongocryptd_reply=None,
353
- key_docs=None,
354
- kms_reply=None):
420
+ def __init__(
421
+ self,
422
+ list_colls_result=None,
423
+ mongocryptd_reply=None,
424
+ key_docs=None,
425
+ kms_reply=None,
426
+ ):
355
427
  self.list_colls_result = list_colls_result
356
428
  self.mongocryptd_reply = mongocryptd_reply
357
429
  self.key_docs = key_docs
@@ -381,108 +453,549 @@ class MockCallback(MongoCryptCallback):
381
453
  pass
382
454
 
383
455
 
456
+ class MockAsyncCallback(AsyncMongoCryptCallback):
457
+ def __init__(
458
+ self,
459
+ list_colls_result=None,
460
+ mongocryptd_reply=None,
461
+ key_docs=None,
462
+ kms_reply=None,
463
+ ):
464
+ self.list_colls_result = list_colls_result
465
+ self.mongocryptd_reply = mongocryptd_reply
466
+ self.key_docs = key_docs
467
+ self.kms_reply = kms_reply
468
+ self.kms_endpoint = None
469
+
470
+ async def kms_request(self, kms_context):
471
+ self.kms_endpoint = kms_context.endpoint
472
+ kms_context.feed(self.kms_reply)
473
+
474
+ async def collection_info(self, ns, filter):
475
+ return self.list_colls_result
476
+
477
+ async def mark_command(self, ns, cmd):
478
+ return self.mongocryptd_reply
479
+
480
+ async def fetch_keys(self, filter):
481
+ return self.key_docs
482
+
483
+ async def insert_data_key(self, data_key):
484
+ raise NotImplementedError
485
+
486
+ def bson_encode(self, doc):
487
+ return bson.encode(doc)
488
+
489
+ async def close(self):
490
+ pass
491
+
492
+
384
493
  class TestMongoCryptCallback(unittest.TestCase):
385
494
  maxDiff = None
386
495
 
387
496
  @staticmethod
388
497
  def mongo_crypt_opts():
389
- return MongoCryptOptions({
390
- 'aws': {'accessKeyId': 'example', 'secretAccessKey': 'example'},
391
- 'local': {'key': b'\x00'*96}})
392
-
393
- @unittest.skipUnless(os.getenv("TEST_CRYPT_SHARED"), "this test requires TEST_CRYPT_SHARED=1")
498
+ return MongoCryptOptions(
499
+ {
500
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
501
+ "local": {"key": b"\x00" * 96},
502
+ }
503
+ )
504
+
505
+ @unittest.skipUnless(
506
+ os.getenv("TEST_CRYPT_SHARED"), "this test requires TEST_CRYPT_SHARED=1"
507
+ )
394
508
  def test_crypt_shared(self):
395
509
  kms_providers = {
396
- 'aws': {'accessKeyId': 'example', 'secretAccessKey': 'example'},
397
- 'local': {'key': b'\x00'*96}}
510
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
511
+ "local": {"key": b"\x00" * 96},
512
+ }
398
513
  mc = MongoCrypt(MongoCryptOptions(kms_providers), MockCallback())
399
514
  self.addCleanup(mc.close)
400
515
  self.assertIsNotNone(mc.crypt_shared_lib_version)
401
516
  # Test that we can pick up crypt_shared automatically
402
- encrypter = AutoEncrypter(MockCallback(), MongoCryptOptions(
403
- kms_providers,
404
- bypass_encryption=False,
405
- crypt_shared_lib_required=True))
517
+ encrypter = AutoEncrypter(
518
+ MockCallback(),
519
+ MongoCryptOptions(
520
+ kms_providers, bypass_encryption=False, crypt_shared_lib_required=True
521
+ ),
522
+ )
406
523
  self.addCleanup(encrypter.close)
407
- encrypter = AutoEncrypter(MockCallback(), MongoCryptOptions(
408
- kms_providers,
409
- crypt_shared_lib_path=os.environ["CRYPT_SHARED_PATH"],
410
- crypt_shared_lib_required=True))
524
+ encrypter = AutoEncrypter(
525
+ MockCallback(),
526
+ MongoCryptOptions(
527
+ kms_providers,
528
+ crypt_shared_lib_path=os.environ["CRYPT_SHARED_PATH"],
529
+ crypt_shared_lib_required=True,
530
+ ),
531
+ )
411
532
  self.addCleanup(encrypter.close)
412
533
  with self.assertRaisesRegex(MongoCryptError, "/doesnotexist"):
413
- AutoEncrypter(MockCallback(), MongoCryptOptions(
414
- kms_providers,
415
- crypt_shared_lib_path="/doesnotexist",
416
- crypt_shared_lib_required=True))
534
+ AutoEncrypter(
535
+ MockCallback(),
536
+ MongoCryptOptions(
537
+ kms_providers,
538
+ crypt_shared_lib_path="/doesnotexist",
539
+ crypt_shared_lib_required=True,
540
+ ),
541
+ )
417
542
 
418
543
  def test_encrypt(self):
419
- encrypter = AutoEncrypter(MockCallback(
420
- list_colls_result=bson_data('collection-info.json'),
421
- mongocryptd_reply=bson_data('mongocryptd-reply.json'),
422
- key_docs=[bson_data('key-document.json')],
423
- kms_reply=http_data('kms-reply.txt')), self.mongo_crypt_opts())
544
+ encrypter = AutoEncrypter(
545
+ MockCallback(
546
+ list_colls_result=bson_data("collection-info.json"),
547
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
548
+ key_docs=[bson_data("key-document.json")],
549
+ kms_reply=http_data("kms-reply.txt"),
550
+ ),
551
+ self.mongo_crypt_opts(),
552
+ )
424
553
  self.addCleanup(encrypter.close)
425
- encrypted = encrypter.encrypt('test', bson_data('command.json'))
426
- self.assertEqual(bson.decode(encrypted, OPTS),
427
- json_data('encrypted-command.json'))
428
- self.assertEqual(encrypted, bson_data('encrypted-command.json'))
554
+ encrypted = encrypter.encrypt("test", bson_data("command.json"))
555
+ self.assertEqual(
556
+ bson.decode(encrypted, OPTS), json_data("encrypted-command.json")
557
+ )
558
+ self.assertEqual(encrypted, bson_data("encrypted-command.json"))
429
559
 
430
560
  def test_decrypt(self):
431
- encrypter = AutoEncrypter(MockCallback(
432
- list_colls_result=bson_data('collection-info.json'),
433
- mongocryptd_reply=bson_data('mongocryptd-reply.json'),
434
- key_docs=[bson_data('key-document.json')],
435
- kms_reply=http_data('kms-reply.txt')), self.mongo_crypt_opts())
561
+ encrypter = AutoEncrypter(
562
+ MockCallback(
563
+ list_colls_result=bson_data("collection-info.json"),
564
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
565
+ key_docs=[bson_data("key-document.json")],
566
+ kms_reply=http_data("kms-reply.txt"),
567
+ ),
568
+ self.mongo_crypt_opts(),
569
+ )
436
570
  self.addCleanup(encrypter.close)
437
- decrypted = encrypter.decrypt(
438
- bson_data('encrypted-command-reply.json'))
439
- self.assertEqual(bson.decode(decrypted, OPTS),
440
- json_data('command-reply.json'))
441
- self.assertEqual(decrypted, bson_data('command-reply.json'))
571
+ decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json"))
572
+ self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json"))
573
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
442
574
 
443
575
  def test_need_kms_aws_credentials(self):
444
- kms_providers = { 'aws': {} }
576
+ kms_providers = {"aws": {}}
445
577
  opts = MongoCryptOptions(kms_providers)
446
578
  callback = MockCallback(
447
- list_colls_result=bson_data('collection-info.json'),
448
- mongocryptd_reply=bson_data('mongocryptd-reply.json'),
449
- key_docs=[bson_data('key-document.json')],
450
- kms_reply=http_data('kms-reply.txt'))
579
+ list_colls_result=bson_data("collection-info.json"),
580
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
581
+ key_docs=[bson_data("key-document.json")],
582
+ kms_reply=http_data("kms-reply.txt"),
583
+ )
451
584
  encrypter = AutoEncrypter(callback, opts)
452
585
  self.addCleanup(encrypter.close)
453
586
 
454
- with mock.patch("pymongocrypt.credentials.aws_temp_credentials") as m:
587
+ with unittest.mock.patch(
588
+ "pymongocrypt.synchronous.credentials.aws_temp_credentials"
589
+ ) as m:
455
590
  m.return_value = AwsCredential("example", "example", None)
456
- decrypted = encrypter.decrypt(
457
- bson_data('encrypted-command-reply.json'))
591
+ decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json"))
458
592
  self.assertTrue(m.called)
459
593
 
460
- self.assertEqual(bson.decode(decrypted, OPTS),
461
- json_data('command-reply.json'))
462
- self.assertEqual(decrypted, bson_data('command-reply.json'))
594
+ self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json"))
595
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
463
596
 
464
597
  def test_need_kms_gcp_credentials(self):
465
- kms_providers = { 'gcp': {} }
598
+ kms_providers = {"gcp": {}}
466
599
  opts = MongoCryptOptions(kms_providers)
467
600
  callback = MockCallback(
468
- list_colls_result=bson_data('collection-info.json'),
469
- mongocryptd_reply=bson_data('mongocryptd-reply.json'),
470
- key_docs=[bson_data('key-document-gcp.json')],
471
- kms_reply=http_data('kms-reply-gcp.txt'))
601
+ list_colls_result=bson_data("collection-info.json"),
602
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
603
+ key_docs=[bson_data("key-document-gcp.json")],
604
+ kms_reply=http_data("kms-reply-gcp.txt"),
605
+ )
472
606
  encrypter = AutoEncrypter(callback, opts)
473
607
  self.addCleanup(encrypter.close)
474
608
 
475
- with requests_mock.Mocker() as m:
609
+ with respx.mock() as router:
476
610
  data = {"access_token": "foo"}
477
611
  url = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
478
- m.get(url, text=json.dumps(data))
479
- decrypted = encrypter.decrypt(
480
- bson_data('encrypted-command-reply.json'))
481
- self.assertTrue(m.called)
482
-
483
- self.assertEqual(bson.decode(decrypted, OPTS),
484
- json_data('command-reply.json'))
485
- self.assertEqual(decrypted, bson_data('command-reply.json'))
612
+ router.add(
613
+ respx.get(url=url).mock(return_value=httpx.Response(200, json=data))
614
+ )
615
+ decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json"))
616
+ self.assertTrue(len(router.calls))
617
+
618
+ self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json"))
619
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
620
+
621
+
622
+ if sys.version_info >= (3, 8, 0): # noqa: UP036
623
+
624
+ class TestAsyncMongoCryptCallback(unittest.IsolatedAsyncioTestCase):
625
+ maxDiff = None
626
+
627
+ @staticmethod
628
+ def mongo_crypt_opts():
629
+ return MongoCryptOptions(
630
+ {
631
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
632
+ "local": {"key": b"\x00" * 96},
633
+ }
634
+ )
635
+
636
+ @unittest.skipUnless(
637
+ os.getenv("TEST_CRYPT_SHARED"), "this test requires TEST_CRYPT_SHARED=1"
638
+ )
639
+ async def test_crypt_shared(self):
640
+ kms_providers = {
641
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
642
+ "local": {"key": b"\x00" * 96},
643
+ }
644
+ mc = MongoCrypt(MongoCryptOptions(kms_providers), MockAsyncCallback())
645
+ self.addCleanup(mc.close)
646
+ self.assertIsNotNone(mc.crypt_shared_lib_version)
647
+ # Test that we can pick up crypt_shared automatically
648
+ encrypter = AsyncAutoEncrypter(
649
+ MockAsyncCallback(),
650
+ MongoCryptOptions(
651
+ kms_providers,
652
+ bypass_encryption=False,
653
+ crypt_shared_lib_required=True,
654
+ ),
655
+ )
656
+ self.addAsyncCleanup(encrypter.close)
657
+ encrypter = AsyncAutoEncrypter(
658
+ MockAsyncCallback(),
659
+ MongoCryptOptions(
660
+ kms_providers,
661
+ crypt_shared_lib_path=os.environ["CRYPT_SHARED_PATH"],
662
+ crypt_shared_lib_required=True,
663
+ ),
664
+ )
665
+ self.addAsyncCleanup(encrypter.close)
666
+ with self.assertRaisesRegex(MongoCryptError, "/doesnotexist"):
667
+ AsyncAutoEncrypter(
668
+ MockAsyncCallback(),
669
+ MongoCryptOptions(
670
+ kms_providers,
671
+ crypt_shared_lib_path="/doesnotexist",
672
+ crypt_shared_lib_required=True,
673
+ ),
674
+ )
675
+
676
+ async def test_encrypt(self):
677
+ encrypter = AsyncAutoEncrypter(
678
+ MockAsyncCallback(
679
+ list_colls_result=bson_data("collection-info.json"),
680
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
681
+ key_docs=[bson_data("key-document.json")],
682
+ kms_reply=http_data("kms-reply.txt"),
683
+ ),
684
+ self.mongo_crypt_opts(),
685
+ )
686
+ self.addAsyncCleanup(encrypter.close)
687
+ encrypted = await encrypter.encrypt("test", bson_data("command.json"))
688
+ self.assertEqual(
689
+ bson.decode(encrypted, OPTS), json_data("encrypted-command.json")
690
+ )
691
+ self.assertEqual(encrypted, bson_data("encrypted-command.json"))
692
+
693
+ async def test_decrypt(self):
694
+ encrypter = AsyncAutoEncrypter(
695
+ MockAsyncCallback(
696
+ list_colls_result=bson_data("collection-info.json"),
697
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
698
+ key_docs=[bson_data("key-document.json")],
699
+ kms_reply=http_data("kms-reply.txt"),
700
+ ),
701
+ self.mongo_crypt_opts(),
702
+ )
703
+ self.addAsyncCleanup(encrypter.close)
704
+ decrypted = await encrypter.decrypt(
705
+ bson_data("encrypted-command-reply.json")
706
+ )
707
+ self.assertEqual(
708
+ bson.decode(decrypted, OPTS), json_data("command-reply.json")
709
+ )
710
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
711
+
712
+ async def test_need_kms_aws_credentials(self):
713
+ kms_providers = {"aws": {}}
714
+ opts = MongoCryptOptions(kms_providers)
715
+ callback = MockAsyncCallback(
716
+ list_colls_result=bson_data("collection-info.json"),
717
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
718
+ key_docs=[bson_data("key-document.json")],
719
+ kms_reply=http_data("kms-reply.txt"),
720
+ )
721
+ encrypter = AsyncAutoEncrypter(callback, opts)
722
+ self.addAsyncCleanup(encrypter.close)
723
+
724
+ with unittest.mock.patch(
725
+ "pymongocrypt.asynchronous.credentials.aws_temp_credentials"
726
+ ) as m:
727
+ m.return_value = AwsCredential("example", "example", None)
728
+ decrypted = await encrypter.decrypt(
729
+ bson_data("encrypted-command-reply.json")
730
+ )
731
+ self.assertTrue(m.called)
732
+
733
+ self.assertEqual(
734
+ bson.decode(decrypted, OPTS), json_data("command-reply.json")
735
+ )
736
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
737
+
738
+ async def test_need_kms_gcp_credentials(self):
739
+ kms_providers = {"gcp": {}}
740
+ opts = MongoCryptOptions(kms_providers)
741
+ callback = MockAsyncCallback(
742
+ list_colls_result=bson_data("collection-info.json"),
743
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
744
+ key_docs=[bson_data("key-document-gcp.json")],
745
+ kms_reply=http_data("kms-reply-gcp.txt"),
746
+ )
747
+ encrypter = AsyncAutoEncrypter(callback, opts)
748
+ self.addAsyncCleanup(encrypter.close)
749
+
750
+ with respx.mock() as router:
751
+ data = {"access_token": "foo"}
752
+ url = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
753
+ router.add(
754
+ respx.get(url=url).mock(return_value=httpx.Response(200, json=data))
755
+ )
756
+ decrypted = await encrypter.decrypt(
757
+ bson_data("encrypted-command-reply.json")
758
+ )
759
+ self.assertTrue(len(router.calls))
760
+
761
+ self.assertEqual(
762
+ bson.decode(decrypted, OPTS), json_data("command-reply.json")
763
+ )
764
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
765
+
766
+ class TestAsyncExplicitEncryption(unittest.IsolatedAsyncioTestCase):
767
+ maxDiff = None
768
+
769
+ @staticmethod
770
+ def mongo_crypt_opts():
771
+ return MongoCryptOptions(
772
+ {
773
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
774
+ "local": {"key": b"\x00" * 96},
775
+ }
776
+ )
777
+
778
+ async def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None):
779
+ encrypter = AsyncExplicitEncrypter(
780
+ MockAsyncCallback(
781
+ key_docs=[bson_data("key-document.json")],
782
+ kms_reply=http_data("kms-reply.txt"),
783
+ ),
784
+ self.mongo_crypt_opts(),
785
+ )
786
+ self.addCleanup(encrypter.close)
787
+
788
+ val = {"v": "hello"}
789
+ encoded_val = bson.encode(val)
790
+ algo = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
791
+ encrypted = await encrypter.encrypt(
792
+ encoded_val, algo, key_id=key_id, key_alt_name=key_alt_name
793
+ )
794
+ self.assertEqual(
795
+ bson.decode(encrypted, OPTS), json_data("encrypted-value.json")
796
+ )
797
+ self.assertEqual(encrypted, bson_data("encrypted-value.json"))
798
+
799
+ decrypted = await encrypter.decrypt(encrypted)
800
+ self.assertEqual(bson.decode(decrypted, OPTS), val)
801
+ self.assertEqual(encoded_val, decrypted)
802
+
803
+ async def test_encrypt_decrypt(self):
804
+ key_id = json_data("key-document.json")["_id"]
805
+ await self._test_encrypt_decrypt(key_id=key_id)
806
+
807
+ async def test_encrypt_decrypt_key_alt_name(self):
808
+ key_alt_name = json_data("key-document.json")["keyAltNames"][0]
809
+ await self._test_encrypt_decrypt(key_alt_name=key_alt_name)
810
+
811
+ async def test_encrypt_errors(self):
812
+ key_id = json_data("key-document.json")["_id"]
813
+ encrypter = AsyncExplicitEncrypter(
814
+ MockAsyncCallback(key_docs=[]), self.mongo_crypt_opts()
815
+ )
816
+ self.addCleanup(encrypter.close)
817
+
818
+ val = {"v": "value123"}
819
+ encoded_val = bson.encode(val)
820
+ # Invalid algorithm.
821
+ with self.assertRaisesRegex(MongoCryptError, "algorithm"):
822
+ await encrypter.encrypt(encoded_val, "Invalid", key_id)
823
+ # Invalid query_type type.
824
+ with self.assertRaisesRegex(TypeError, "query_type"):
825
+ await encrypter.encrypt(encoded_val, "Indexed", key_id, query_type=42)
826
+ # Invalid query_type string.
827
+ with self.assertRaisesRegex(MongoCryptError, "query_type"):
828
+ await encrypter.encrypt(
829
+ encoded_val,
830
+ "Indexed",
831
+ key_id,
832
+ query_type="invalid query type string",
833
+ )
834
+ # Invalid contention_factor type.
835
+ with self.assertRaisesRegex(TypeError, "contention_factor"):
836
+ await encrypter.encrypt(
837
+ encoded_val, "Indexed", key_id, contention_factor="not an int"
838
+ )
839
+ with self.assertRaisesRegex(MongoCryptError, "contention"):
840
+ await encrypter.encrypt(
841
+ encoded_val, "Indexed", key_id, contention_factor=-1
842
+ )
843
+ # Invalid: Unindexed + query_type is an error.
844
+ with self.assertRaisesRegex(MongoCryptError, "query"):
845
+ await encrypter.encrypt(
846
+ encoded_val, "Unindexed", key_id, query_type="equality"
847
+ )
848
+ # Invalid: Unindexed + contention_factor is an error.
849
+ with self.assertRaisesRegex(MongoCryptError, "contention"):
850
+ await encrypter.encrypt(
851
+ encoded_val, "Unindexed", key_id, contention_factor=1
852
+ )
853
+
854
+ async def test_encrypt_indexed(self):
855
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
856
+ key_id = json_data(key_path)["_id"]
857
+ encrypter = AsyncExplicitEncrypter(
858
+ MockAsyncCallback(
859
+ key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
860
+ ),
861
+ self.mongo_crypt_opts(),
862
+ )
863
+ self.addCleanup(encrypter.close)
864
+
865
+ val = {"v": "value123"}
866
+ encoded_val = bson.encode(val)
867
+ for kwargs in [
868
+ dict(algorithm="Indexed", contention_factor=0),
869
+ dict(algorithm="Indexed", query_type="equality", contention_factor=0),
870
+ dict(algorithm="Indexed", contention_factor=100),
871
+ dict(algorithm="Unindexed"),
872
+ ]:
873
+ kwargs["key_id"] = key_id
874
+ encrypted = await encrypter.encrypt(encoded_val, **kwargs)
875
+ encrypted_val = bson.decode(encrypted, OPTS)["v"]
876
+ self.assertIsInstance(encrypted_val, Binary)
877
+ self.assertEqual(encrypted_val.subtype, 6)
878
+
879
+ # Queryable Encryption find payloads cannot be round-tripped.
880
+ if "query_type" not in kwargs:
881
+ decrypted = await encrypter.decrypt(encrypted)
882
+ self.assertEqual(bson.decode(decrypted, OPTS), val)
883
+ self.assertEqual(encoded_val, decrypted)
884
+
885
+ async def test_data_key_creation(self):
886
+ mock_key_vault = AsyncKeyVaultCallback(
887
+ kms_reply=http_data("kms-encrypt-reply.txt")
888
+ )
889
+ opts = MongoCryptOptions(
890
+ {
891
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
892
+ "aws:named": {
893
+ "accessKeyId": "example",
894
+ "secretAccessKey": "example",
895
+ },
896
+ "local": {"key": b"\x00" * 96},
897
+ "local:named": {"key": b"\x01" * 96},
898
+ }
899
+ )
900
+ encrypter = AsyncExplicitEncrypter(mock_key_vault, opts)
901
+ self.addCleanup(encrypter.close)
902
+
903
+ valid_args = [
904
+ ("local", None, ["first", "second"]),
905
+ ("local:named", None, ["local:named"]),
906
+ ("aws", {"region": "region", "key": "cmk"}, ["third", "forth"]),
907
+ ("aws:named", {"region": "region", "key": "cmk"}, ["aws:named"]),
908
+ # Unicode region and key
909
+ ("aws", {"region": "region-unicode", "key": "cmk-unicode"}, []),
910
+ # Endpoint
911
+ (
912
+ "aws",
913
+ {
914
+ "region": "region",
915
+ "key": "cmk",
916
+ "endpoint": "kms.us-east-1.amazonaws.com:443",
917
+ },
918
+ [],
919
+ ),
920
+ ]
921
+ for kms_provider, master_key, key_alt_names in valid_args:
922
+ key_id = await encrypter.create_data_key(
923
+ kms_provider, master_key=master_key, key_alt_names=key_alt_names
924
+ )
925
+ self.assertIsInstance(key_id, Binary)
926
+ self.assertEqual(key_id.subtype, 4)
927
+ data_key = bson.decode(mock_key_vault.data_key, OPTS)
928
+ # CDRIVER-3277 The order of key_alt_names is not maintained.
929
+ for name in key_alt_names:
930
+ self.assertIn(name, data_key["keyAltNames"])
931
+
932
+ # Assert that the custom endpoint is passed to libmongocrypt.
933
+ master_key = {"region": "region", "key": "key", "endpoint": "example.com"}
934
+ key_material = base64.b64decode(
935
+ "xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5"
936
+ )
937
+ if not PY3:
938
+ key_material = Binary(key_material)
939
+ await encrypter.create_data_key(
940
+ "aws", master_key=master_key, key_material=key_material
941
+ )
942
+ self.assertEqual("example.com:443", mock_key_vault.kms_endpoint)
943
+
944
+ async def test_data_key_creation_bad_key_material(self):
945
+ mock_key_vault = AsyncKeyVaultCallback(
946
+ kms_reply=http_data("kms-encrypt-reply.txt")
947
+ )
948
+ encrypter = AsyncExplicitEncrypter(mock_key_vault, self.mongo_crypt_opts())
949
+ self.addCleanup(encrypter.close)
950
+
951
+ key_material = Binary(b"0" * 97)
952
+ with self.assertRaisesRegex(
953
+ MongoCryptError, "keyMaterial should have length 96, but has length 97"
954
+ ):
955
+ await encrypter.create_data_key("local", key_material=key_material)
956
+
957
+ async def test_rewrap_many_data_key(self):
958
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
959
+ key_path2 = "keys/12345678123498761234123456789012-local-document.json"
960
+ encrypter = AsyncExplicitEncrypter(
961
+ MockAsyncCallback(key_docs=[bson_data(key_path), bson_data(key_path2)]),
962
+ self.mongo_crypt_opts(),
963
+ )
964
+ self.addCleanup(encrypter.close)
965
+
966
+ result = await encrypter.rewrap_many_data_key({})
967
+ raw_doc = RawBSONDocument(result)
968
+ assert len(raw_doc["v"]) == 2
969
+
970
+ async def test_range_query_int32(self):
971
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
972
+ key_id = json_data(key_path)["_id"]
973
+ encrypter = AsyncExplicitEncrypter(
974
+ MockAsyncCallback(
975
+ key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
976
+ ),
977
+ self.mongo_crypt_opts(),
978
+ )
979
+ self.addCleanup(encrypter.close)
980
+
981
+ range_opts = bson_data("fle2-find-range-explicit-v2/int32/rangeopts.json")
982
+ value = bson_data("fle2-find-range-explicit-v2/int32/value-to-encrypt.json")
983
+ expected = json_data(
984
+ "fle2-find-range-explicit-v2/int32/encrypted-payload.json"
985
+ )
986
+ encrypted = await encrypter.encrypt(
987
+ value,
988
+ "range",
989
+ key_id=key_id,
990
+ query_type="range",
991
+ contention_factor=4,
992
+ range_opts=range_opts,
993
+ is_expression=True,
994
+ )
995
+ encrypted_val = bson.decode(encrypted, OPTS)
996
+ self.assertEqual(
997
+ encrypted_val, adjust_range_counter(encrypted_val, expected)
998
+ )
486
999
 
487
1000
 
488
1001
  class TestNeedKMSAzureCredentials(unittest.TestCase):
@@ -490,129 +1003,156 @@ class TestNeedKMSAzureCredentials(unittest.TestCase):
490
1003
 
491
1004
  def get_encrypter(self, clear_cache=True):
492
1005
  if clear_cache:
493
- pymongocrypt.credentials._azure_creds_cache = None
494
- kms_providers = { 'azure': {} }
1006
+ pymongocrypt.synchronous.credentials._azure_creds_cache = None
1007
+ kms_providers = {"azure": {}}
495
1008
  opts = MongoCryptOptions(kms_providers)
496
1009
  callback = MockCallback(
497
- list_colls_result=bson_data('collection-info.json'),
498
- mongocryptd_reply=bson_data('mongocryptd-reply.json'),
499
- key_docs=[bson_data('key-document-azure.json')],
500
- kms_reply=http_data('kms-reply-azure.txt'))
1010
+ list_colls_result=bson_data("collection-info.json"),
1011
+ mongocryptd_reply=bson_data("mongocryptd-reply.json"),
1012
+ key_docs=[bson_data("key-document-azure.json")],
1013
+ kms_reply=http_data("kms-reply-azure.txt"),
1014
+ )
501
1015
  encrypter = AutoEncrypter(callback, opts)
502
1016
  self.addCleanup(encrypter.close)
503
1017
  return encrypter
504
1018
 
505
1019
  def test_success(self):
506
1020
  encrypter = self.get_encrypter()
507
- with requests_mock.Mocker() as m:
1021
+ with respx.mock() as router:
508
1022
  data = {"access_token": "foo", "expires_in": 4000}
509
1023
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
510
- m.get(url, text=json.dumps(data))
511
- decrypted = encrypter.decrypt(
512
- bson_data('encrypted-command-reply.json'))
513
- self.assertTrue(m.called)
1024
+ router.add(
1025
+ respx.get(url=url).mock(return_value=httpx.Response(200, json=data))
1026
+ )
1027
+ decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1028
+ self.assertTrue(len(router.calls))
514
1029
 
515
- self.assertEqual(bson.decode(decrypted, OPTS),
516
- json_data('command-reply.json'))
517
- self.assertEqual(decrypted, bson_data('command-reply.json'))
518
- self.assertIsNotNone(pymongocrypt.credentials._azure_creds_cache)
1030
+ self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json"))
1031
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
1032
+ self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
519
1033
 
520
1034
  def test_empty_json(self):
521
1035
  encrypter = self.get_encrypter()
522
- with requests_mock.Mocker() as m:
1036
+ with respx.mock() as router:
523
1037
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
524
- m.get(url, text=json.dumps({}))
525
- with self.assertRaisesRegex(MongoCryptError, "Azure IMDS response must contain"):
526
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
527
- self.assertTrue(m.called)
528
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1038
+ router.add(
1039
+ respx.get(url=url).mock(return_value=httpx.Response(200, json={}))
1040
+ )
1041
+ with self.assertRaisesRegex(
1042
+ MongoCryptError, "Azure IMDS response must contain"
1043
+ ):
1044
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1045
+ self.assertTrue(len(router.calls))
1046
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
529
1047
 
530
1048
  def test_bad_json(self):
531
1049
  encrypter = self.get_encrypter()
532
- with requests_mock.Mocker() as m:
1050
+ with respx.mock() as router:
533
1051
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
534
- m.get(url, text="a'")
535
- with self.assertRaisesRegex(MongoCryptError, "Azure IMDS response must be in JSON format"):
536
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
537
- self.assertTrue(m.called)
538
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1052
+ router.add(
1053
+ respx.get(url=url).mock(return_value=httpx.Response(200, text="a'"))
1054
+ )
1055
+ with self.assertRaisesRegex(
1056
+ MongoCryptError, "Azure IMDS response must be in JSON format"
1057
+ ):
1058
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1059
+ self.assertTrue(len(router.calls))
1060
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
539
1061
 
540
1062
  def test_http_404(self):
541
1063
  encrypter = self.get_encrypter()
542
- with requests_mock.Mocker() as m:
1064
+ with respx.mock() as router:
543
1065
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
544
- m.get(url, status_code=404)
545
- with self.assertRaisesRegex(MongoCryptError, "Failed to acquire IMDS access token."):
546
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
547
- self.assertTrue(m.called)
548
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1066
+ router.add(respx.get(url=url).mock(return_value=httpx.Response(404)))
1067
+ with self.assertRaisesRegex(
1068
+ MongoCryptError, "Failed to acquire IMDS access token."
1069
+ ):
1070
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1071
+ self.assertTrue(len(router.calls))
1072
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
549
1073
 
550
1074
  def test_http_500(self):
551
1075
  encrypter = self.get_encrypter()
552
- with requests_mock.Mocker() as m:
1076
+ with respx.mock() as router:
553
1077
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
554
- m.get(url, status_code=500)
555
- with self.assertRaisesRegex(MongoCryptError, "Failed to acquire IMDS access token."):
556
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
557
- self.assertTrue(m.called)
558
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1078
+ router.add(respx.get(url=url).mock(return_value=httpx.Response(500)))
1079
+ with self.assertRaisesRegex(
1080
+ MongoCryptError, "Failed to acquire IMDS access token."
1081
+ ):
1082
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1083
+ self.assertTrue(len(router.calls))
1084
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
559
1085
 
560
1086
  def test_slow_response(self):
561
1087
  encrypter = self.get_encrypter()
562
- with requests_mock.Mocker() as m:
1088
+ with respx.mock() as router:
563
1089
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
564
- m.get(url, exc=requests.exceptions.ConnectTimeout)
565
- with self.assertRaisesRegex(MongoCryptError, "Failed to acquire IMDS access token: "):
566
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
567
- self.assertTrue(m.called)
568
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1090
+ router.add(
1091
+ respx.get(url=url).mock(side_effect=httpx._exceptions.ConnectTimeout)
1092
+ )
1093
+ with self.assertRaisesRegex(
1094
+ MongoCryptError, "Failed to acquire IMDS access token: "
1095
+ ):
1096
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1097
+ self.assertTrue(len(router.calls))
1098
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
569
1099
 
570
1100
  def test_cache(self):
571
1101
  encrypter = self.get_encrypter()
572
- with requests_mock.Mocker() as m:
1102
+ with respx.mock() as router:
573
1103
  data = {"access_token": "foo", "expires_in": 4000}
574
1104
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
575
- m.get(url, text=json.dumps(data))
576
- decrypted = encrypter.decrypt(
577
- bson_data('encrypted-command-reply.json'))
578
- self.assertTrue(m.called)
1105
+ router.add(
1106
+ respx.get(url=url).mock(
1107
+ return_value=httpx.Response(status_code=200, json=data)
1108
+ )
1109
+ )
1110
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1111
+ self.assertTrue(len(router.calls))
579
1112
 
580
- self.assertIsNotNone(pymongocrypt.credentials._azure_creds_cache)
1113
+ self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
581
1114
 
582
1115
  # Should use the cached value.
583
- decrypted = encrypter.decrypt(bson_data('encrypted-command-reply.json'))
584
- self.assertEqual(decrypted, bson_data('command-reply.json'))
1116
+ decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1117
+ self.assertEqual(decrypted, bson_data("command-reply.json"))
585
1118
 
586
- self.assertIsNotNone(pymongocrypt.credentials._azure_creds_cache)
1119
+ self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
587
1120
 
588
1121
  def test_cache_expires_soon(self):
589
1122
  encrypter = self.get_encrypter()
590
- with requests_mock.Mocker() as m:
1123
+ with respx.mock() as router:
591
1124
  data = {"access_token": "foo", "expires_in": 10}
592
1125
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
593
- m.get(url, text=json.dumps(data))
594
- decrypted = encrypter.decrypt(
595
- bson_data('encrypted-command-reply.json'))
596
- self.assertTrue(m.called)
1126
+ router.add(
1127
+ respx.get(url=url).mock(
1128
+ return_value=httpx.Response(status_code=200, json=data)
1129
+ )
1130
+ )
1131
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1132
+ self.assertTrue(len(router.calls))
597
1133
 
598
- self.assertIsNotNone(pymongocrypt.credentials._azure_creds_cache)
1134
+ self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
599
1135
 
600
1136
  # Should not use the cached value.
601
1137
  encrypter = self.get_encrypter(False)
602
- self.assertIsNotNone(pymongocrypt.credentials._azure_creds_cache)
603
- with requests_mock.Mocker() as m:
1138
+ self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
1139
+ with respx.mock() as router:
604
1140
  url = "http://169.254.169.254/metadata/identity/oauth2/token"
605
- m.get(url, exc=requests.exceptions.ConnectTimeout)
606
- with self.assertRaisesRegex(MongoCryptError, "Failed to acquire IMDS access token: "):
607
- encrypter.decrypt(bson_data('encrypted-command-reply.json'))
608
- self.assertTrue(m.called)
1141
+ router.add(
1142
+ respx.get(url=url).mock(side_effect=httpx._exceptions.ConnectTimeout)
1143
+ )
1144
+ with self.assertRaisesRegex(
1145
+ MongoCryptError, "Failed to acquire IMDS access token: "
1146
+ ):
1147
+ encrypter.decrypt(bson_data("encrypted-command-reply.json"))
1148
+ self.assertTrue(len(router.calls))
609
1149
 
610
- self.assertIsNone(pymongocrypt.credentials._azure_creds_cache)
1150
+ self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache)
611
1151
 
612
1152
 
613
1153
  class KeyVaultCallback(MockCallback):
614
1154
  def __init__(self, kms_reply=None):
615
- super(KeyVaultCallback, self).__init__(kms_reply=kms_reply)
1155
+ super().__init__(kms_reply=kms_reply)
616
1156
  self.data_key = None
617
1157
 
618
1158
  def fetch_keys(self, filter):
@@ -620,7 +1160,41 @@ class KeyVaultCallback(MockCallback):
620
1160
 
621
1161
  def insert_data_key(self, data_key):
622
1162
  self.data_key = data_key
623
- return bson.decode(data_key, OPTS)['_id']
1163
+ return bson.decode(data_key, OPTS)["_id"]
1164
+
1165
+
1166
+ def adjust_range_counter(encrypted_val, expected):
1167
+ """Workaround for the internal range payload counter in libmongocrypt."""
1168
+ if encrypted_val != expected:
1169
+ _payload1 = expected["v"]["$and"][0]["age"]["$gte"]
1170
+ _payload2 = expected["v"]["$and"][1]["age"]["$lte"]
1171
+ _decoded1 = bson.decode(_payload1[1:])
1172
+ _decoded2 = bson.decode(_payload2[1:])
1173
+ for _ in range(10):
1174
+ _decoded1["payloadId"] += 1
1175
+ expected["v"]["$and"][0]["age"]["$gte"] = Binary(
1176
+ _payload1[0:1] + bson.encode(_decoded1), 6
1177
+ )
1178
+ _decoded2["payloadId"] += 1
1179
+ expected["v"]["$and"][1]["age"]["$lte"] = Binary(
1180
+ _payload2[0:1] + bson.encode(_decoded2), 6
1181
+ )
1182
+ if encrypted_val == expected:
1183
+ break
1184
+ return expected
1185
+
1186
+
1187
+ class AsyncKeyVaultCallback(MockAsyncCallback):
1188
+ def __init__(self, kms_reply=None):
1189
+ super().__init__(kms_reply=kms_reply)
1190
+ self.data_key = None
1191
+
1192
+ async def fetch_keys(self, filter):
1193
+ return self.data_key
1194
+
1195
+ async def insert_data_key(self, data_key):
1196
+ self.data_key = data_key
1197
+ return bson.decode(data_key, OPTS)["_id"]
624
1198
 
625
1199
 
626
1200
  class TestExplicitEncryption(unittest.TestCase):
@@ -628,43 +1202,54 @@ class TestExplicitEncryption(unittest.TestCase):
628
1202
 
629
1203
  @staticmethod
630
1204
  def mongo_crypt_opts():
631
- return MongoCryptOptions({
632
- 'aws': {'accessKeyId': 'example', 'secretAccessKey': 'example'},
633
- 'local': {'key': b'\x00'*96}})
1205
+ return MongoCryptOptions(
1206
+ {
1207
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
1208
+ "local": {"key": b"\x00" * 96},
1209
+ }
1210
+ )
634
1211
 
635
1212
  def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None):
636
- encrypter = ExplicitEncrypter(MockCallback(
637
- key_docs=[bson_data('key-document.json')],
638
- kms_reply=http_data('kms-reply.txt')), self.mongo_crypt_opts())
1213
+ encrypter = ExplicitEncrypter(
1214
+ MockCallback(
1215
+ key_docs=[bson_data("key-document.json")],
1216
+ kms_reply=http_data("kms-reply.txt"),
1217
+ ),
1218
+ self.mongo_crypt_opts(),
1219
+ )
639
1220
  self.addCleanup(encrypter.close)
640
1221
 
641
- val = {'v': 'hello'}
1222
+ val = {"v": "hello"}
642
1223
  encoded_val = bson.encode(val)
643
1224
  algo = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
644
1225
  encrypted = encrypter.encrypt(
645
- encoded_val, algo, key_id=key_id, key_alt_name=key_alt_name)
646
- self.assertEqual(bson.decode(encrypted, OPTS),
647
- json_data('encrypted-value.json'))
648
- self.assertEqual(encrypted, bson_data('encrypted-value.json'))
1226
+ encoded_val, algo, key_id=key_id, key_alt_name=key_alt_name
1227
+ )
1228
+ self.assertEqual(
1229
+ bson.decode(encrypted, OPTS), json_data("encrypted-value.json")
1230
+ )
1231
+ self.assertEqual(encrypted, bson_data("encrypted-value.json"))
649
1232
 
650
1233
  decrypted = encrypter.decrypt(encrypted)
651
1234
  self.assertEqual(bson.decode(decrypted, OPTS), val)
652
1235
  self.assertEqual(encoded_val, decrypted)
653
1236
 
654
1237
  def test_encrypt_decrypt(self):
655
- key_id = json_data('key-document.json')['_id']
1238
+ key_id = json_data("key-document.json")["_id"]
656
1239
  self._test_encrypt_decrypt(key_id=key_id)
657
1240
 
658
1241
  def test_encrypt_decrypt_key_alt_name(self):
659
- key_alt_name = json_data('key-document.json')['keyAltNames'][0]
1242
+ key_alt_name = json_data("key-document.json")["keyAltNames"][0]
660
1243
  self._test_encrypt_decrypt(key_alt_name=key_alt_name)
661
1244
 
662
1245
  def test_encrypt_errors(self):
663
- key_id = json_data('key-document.json')['_id']
664
- encrypter = ExplicitEncrypter(MockCallback(key_docs=[]), self.mongo_crypt_opts())
1246
+ key_id = json_data("key-document.json")["_id"]
1247
+ encrypter = ExplicitEncrypter(
1248
+ MockCallback(key_docs=[]), self.mongo_crypt_opts()
1249
+ )
665
1250
  self.addCleanup(encrypter.close)
666
1251
 
667
- val = {'v': 'value123'}
1252
+ val = {"v": "value123"}
668
1253
  encoded_val = bson.encode(val)
669
1254
  # Invalid algorithm.
670
1255
  with self.assertRaisesRegex(MongoCryptError, "algorithm"):
@@ -674,122 +1259,189 @@ class TestExplicitEncryption(unittest.TestCase):
674
1259
  encrypter.encrypt(encoded_val, "Indexed", key_id, query_type=42)
675
1260
  # Invalid query_type string.
676
1261
  with self.assertRaisesRegex(MongoCryptError, "query_type"):
677
- encrypter.encrypt(encoded_val, "Indexed", key_id, query_type='invalid query type string')
1262
+ encrypter.encrypt(
1263
+ encoded_val, "Indexed", key_id, query_type="invalid query type string"
1264
+ )
678
1265
  # Invalid contention_factor type.
679
1266
  with self.assertRaisesRegex(TypeError, "contention_factor"):
680
- encrypter.encrypt(encoded_val, "Indexed", key_id, contention_factor='not an int')
1267
+ encrypter.encrypt(
1268
+ encoded_val, "Indexed", key_id, contention_factor="not an int"
1269
+ )
681
1270
  with self.assertRaisesRegex(MongoCryptError, "contention"):
682
1271
  encrypter.encrypt(encoded_val, "Indexed", key_id, contention_factor=-1)
683
1272
  # Invalid: Unindexed + query_type is an error.
684
1273
  with self.assertRaisesRegex(MongoCryptError, "query"):
685
- encrypter.encrypt(encoded_val, "Unindexed", key_id, query_type='equality')
1274
+ encrypter.encrypt(encoded_val, "Unindexed", key_id, query_type="equality")
686
1275
  # Invalid: Unindexed + contention_factor is an error.
687
1276
  with self.assertRaisesRegex(MongoCryptError, "contention"):
688
1277
  encrypter.encrypt(encoded_val, "Unindexed", key_id, contention_factor=1)
689
1278
 
690
1279
  def test_encrypt_indexed(self):
691
- key_path = 'keys/ABCDEFAB123498761234123456789012-local-document.json'
692
- key_id = json_data(key_path)['_id']
693
- encrypter = ExplicitEncrypter(MockCallback(
694
- key_docs=[bson_data(key_path)],
695
- kms_reply=http_data('kms-reply.txt')), self.mongo_crypt_opts())
1280
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
1281
+ key_id = json_data(key_path)["_id"]
1282
+ encrypter = ExplicitEncrypter(
1283
+ MockCallback(
1284
+ key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
1285
+ ),
1286
+ self.mongo_crypt_opts(),
1287
+ )
696
1288
  self.addCleanup(encrypter.close)
697
1289
 
698
- val = {'v': 'value123'}
1290
+ val = {"v": "value123"}
699
1291
  encoded_val = bson.encode(val)
700
1292
  for kwargs in [
701
- dict(algorithm='Indexed', contention_factor=0),
702
- dict(algorithm='Indexed', query_type='equality', contention_factor=0),
703
- dict(algorithm='Indexed', contention_factor=100),
704
- dict(algorithm='Unindexed'),
1293
+ dict(algorithm="Indexed", contention_factor=0),
1294
+ dict(algorithm="Indexed", query_type="equality", contention_factor=0),
1295
+ dict(algorithm="Indexed", contention_factor=100),
1296
+ dict(algorithm="Unindexed"),
705
1297
  ]:
706
- kwargs['key_id'] = key_id
1298
+ kwargs["key_id"] = key_id
707
1299
  encrypted = encrypter.encrypt(encoded_val, **kwargs)
708
- encrypted_val = bson.decode(encrypted, OPTS)['v']
1300
+ encrypted_val = bson.decode(encrypted, OPTS)["v"]
709
1301
  self.assertIsInstance(encrypted_val, Binary)
710
1302
  self.assertEqual(encrypted_val.subtype, 6)
711
1303
 
712
1304
  # Queryable Encryption find payloads cannot be round-tripped.
713
- if 'query_type' not in kwargs:
1305
+ if "query_type" not in kwargs:
714
1306
  decrypted = encrypter.decrypt(encrypted)
715
1307
  self.assertEqual(bson.decode(decrypted, OPTS), val)
716
1308
  self.assertEqual(encoded_val, decrypted)
717
1309
 
718
1310
  def test_data_key_creation(self):
719
- mock_key_vault = KeyVaultCallback(
720
- kms_reply=http_data('kms-encrypt-reply.txt'))
721
- encrypter = ExplicitEncrypter(mock_key_vault, self.mongo_crypt_opts())
1311
+ mock_key_vault = KeyVaultCallback(kms_reply=http_data("kms-encrypt-reply.txt"))
1312
+ opts = MongoCryptOptions(
1313
+ {
1314
+ "aws": {"accessKeyId": "example", "secretAccessKey": "example"},
1315
+ "aws:named": {"accessKeyId": "example", "secretAccessKey": "example"},
1316
+ "local": {"key": b"\x00" * 96},
1317
+ "local:named": {"key": b"\x01" * 96},
1318
+ }
1319
+ )
1320
+ encrypter = ExplicitEncrypter(mock_key_vault, opts)
722
1321
  self.addCleanup(encrypter.close)
723
1322
 
724
1323
  valid_args = [
725
- ('local', None, ['first', 'second']),
726
- ('aws', {'region': 'region', 'key': 'cmk'}, ['third', 'forth']),
1324
+ ("local", None, ["first", "second"]),
1325
+ ("local:named", None, ["local:named"]),
1326
+ ("aws", {"region": "region", "key": "cmk"}, ["third", "forth"]),
1327
+ ("aws:named", {"region": "region", "key": "cmk"}, ["aws:named"]),
727
1328
  # Unicode region and key
728
- ('aws', {'region': u'region-unicode', 'key': u'cmk-unicode'}, []),
1329
+ ("aws", {"region": "region-unicode", "key": "cmk-unicode"}, []),
729
1330
  # Endpoint
730
- ('aws', {'region': 'region', 'key': 'cmk',
731
- 'endpoint': 'kms.us-east-1.amazonaws.com:443'}, []),
1331
+ (
1332
+ "aws",
1333
+ {
1334
+ "region": "region",
1335
+ "key": "cmk",
1336
+ "endpoint": "kms.us-east-1.amazonaws.com:443",
1337
+ },
1338
+ [],
1339
+ ),
732
1340
  ]
733
1341
  for kms_provider, master_key, key_alt_names in valid_args:
734
1342
  key_id = encrypter.create_data_key(
735
- kms_provider, master_key=master_key,
736
- key_alt_names=key_alt_names)
1343
+ kms_provider, master_key=master_key, key_alt_names=key_alt_names
1344
+ )
737
1345
  self.assertIsInstance(key_id, Binary)
738
1346
  self.assertEqual(key_id.subtype, 4)
739
1347
  data_key = bson.decode(mock_key_vault.data_key, OPTS)
740
1348
  # CDRIVER-3277 The order of key_alt_names is not maintained.
741
1349
  for name in key_alt_names:
742
- self.assertIn(name, data_key['keyAltNames'])
1350
+ self.assertIn(name, data_key["keyAltNames"])
743
1351
 
744
1352
  # Assert that the custom endpoint is passed to libmongocrypt.
745
- master_key = {
746
- "region": "region",
747
- "key": "key",
748
- "endpoint": "example.com"
749
- }
750
- key_material = base64.b64decode('xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5')
1353
+ master_key = {"region": "region", "key": "key", "endpoint": "example.com"}
1354
+ key_material = base64.b64decode(
1355
+ "xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5"
1356
+ )
751
1357
  if not PY3:
752
1358
  key_material = Binary(key_material)
753
- encrypter.create_data_key("aws", master_key=master_key, key_material=key_material)
1359
+ encrypter.create_data_key(
1360
+ "aws", master_key=master_key, key_material=key_material
1361
+ )
754
1362
  self.assertEqual("example.com:443", mock_key_vault.kms_endpoint)
755
1363
 
756
1364
  def test_data_key_creation_bad_key_material(self):
757
- mock_key_vault = KeyVaultCallback(
758
- kms_reply=http_data('kms-encrypt-reply.txt'))
1365
+ mock_key_vault = KeyVaultCallback(kms_reply=http_data("kms-encrypt-reply.txt"))
759
1366
  encrypter = ExplicitEncrypter(mock_key_vault, self.mongo_crypt_opts())
760
1367
  self.addCleanup(encrypter.close)
761
1368
 
762
- key_material = Binary(b'0' * 97)
763
- with self.assertRaisesRegex(MongoCryptError, "keyMaterial should have length 96, but has length 97"):
1369
+ key_material = Binary(b"0" * 97)
1370
+ with self.assertRaisesRegex(
1371
+ MongoCryptError, "keyMaterial should have length 96, but has length 97"
1372
+ ):
764
1373
  encrypter.create_data_key("local", key_material=key_material)
765
1374
 
766
1375
  def test_rewrap_many_data_key(self):
767
- key_path = 'keys/ABCDEFAB123498761234123456789012-local-document.json'
768
- key_path2 = 'keys/12345678123498761234123456789012-local-document.json'
769
- encrypter = ExplicitEncrypter(MockCallback(
770
- key_docs=[bson_data(key_path), bson_data(key_path2)]), self.mongo_crypt_opts())
1376
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
1377
+ key_path2 = "keys/12345678123498761234123456789012-local-document.json"
1378
+ encrypter = ExplicitEncrypter(
1379
+ MockCallback(key_docs=[bson_data(key_path), bson_data(key_path2)]),
1380
+ self.mongo_crypt_opts(),
1381
+ )
771
1382
  self.addCleanup(encrypter.close)
772
1383
 
773
1384
  result = encrypter.rewrap_many_data_key({})
774
1385
  raw_doc = RawBSONDocument(result)
775
- assert len(raw_doc['v']) == 2
1386
+ assert len(raw_doc["v"]) == 2
776
1387
 
777
1388
  def test_range_query_int32(self):
778
- key_path = 'keys/ABCDEFAB123498761234123456789012-local-document.json'
779
- key_id = json_data(key_path)['_id']
780
- encrypter = ExplicitEncrypter(MockCallback(
781
- key_docs=[bson_data(key_path)],
782
- kms_reply=http_data('kms-reply.txt')), self.mongo_crypt_opts())
1389
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
1390
+ key_id = json_data(key_path)["_id"]
1391
+ encrypter = ExplicitEncrypter(
1392
+ MockCallback(
1393
+ key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
1394
+ ),
1395
+ self.mongo_crypt_opts(),
1396
+ )
783
1397
  self.addCleanup(encrypter.close)
784
1398
 
785
1399
  range_opts = bson_data("fle2-find-range-explicit-v2/int32/rangeopts.json")
786
1400
  value = bson_data("fle2-find-range-explicit-v2/int32/value-to-encrypt.json")
787
1401
  expected = json_data("fle2-find-range-explicit-v2/int32/encrypted-payload.json")
788
1402
  encrypted = encrypter.encrypt(
789
- value, "rangePreview", key_id=key_id, query_type="rangePreview",
790
- contention_factor=4, range_opts=range_opts, is_expression=True)
1403
+ value,
1404
+ "range",
1405
+ key_id=key_id,
1406
+ query_type="range",
1407
+ contention_factor=4,
1408
+ range_opts=range_opts,
1409
+ is_expression=True,
1410
+ )
791
1411
  encrypted_val = bson.decode(encrypted, OPTS)
792
- self.assertEqual(encrypted_val, expected)
1412
+ self.assertEqual(encrypted_val, adjust_range_counter(encrypted_val, expected))
1413
+
1414
+ def test_rangePreview_query_int32(self):
1415
+ # Expect error attempting to use 'rangePreview'
1416
+ with self.assertRaisesRegex(
1417
+ MongoCryptError,
1418
+ "Algorithm 'rangePreview' is deprecated, please use 'range'",
1419
+ ):
1420
+ key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
1421
+ key_id = json_data(key_path)["_id"]
1422
+ encrypter = ExplicitEncrypter(
1423
+ MockCallback(
1424
+ key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
1425
+ ),
1426
+ self.mongo_crypt_opts(),
1427
+ )
1428
+ self.addCleanup(encrypter.close)
1429
+
1430
+ range_opts = bson_data(
1431
+ "fle2-find-rangePreview-explicit/int32/rangeopts.json"
1432
+ )
1433
+ value = bson_data(
1434
+ "fle2-find-rangePreview-explicit/int32/value-to-encrypt.json"
1435
+ )
1436
+ encrypter.encrypt(
1437
+ value,
1438
+ "rangePreview",
1439
+ key_id=key_id,
1440
+ query_type="rangePreview",
1441
+ contention_factor=4,
1442
+ range_opts=range_opts,
1443
+ is_expression=True,
1444
+ )
793
1445
 
794
1446
 
795
1447
  def read(filename, **kwargs):
@@ -799,13 +1451,9 @@ def read(filename, **kwargs):
799
1451
 
800
1452
  OPTS = CodecOptions(uuid_representation=UuidRepresentation.UNSPECIFIED)
801
1453
 
802
- # Use SON to preserve the order of fields while parsing json.
803
- if sys.version_info[:2] < (3, 6):
804
- document_class = SON
805
- else:
806
- document_class = dict
807
- JSON_OPTS = JSONOptions(document_class=document_class,
808
- uuid_representation=UuidRepresentation.UNSPECIFIED)
1454
+ JSON_OPTS = JSONOptions(
1455
+ document_class=dict, uuid_representation=UuidRepresentation.UNSPECIFIED
1456
+ )
809
1457
 
810
1458
 
811
1459
  def json_data(filename):
@@ -817,8 +1465,8 @@ def bson_data(filename):
817
1465
 
818
1466
 
819
1467
  def http_data(filename):
820
- data = read(filename, mode='rb')
821
- return data.replace(b'\n', b'\r\n')
1468
+ data = read(filename, mode="rb")
1469
+ return data.replace(b"\n", b"\r\n")
822
1470
 
823
1471
 
824
1472
  if __name__ == "__main__":