mongo 2.11.4 → 2.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +2 -1
  6. data/lib/mongo.rb +3 -0
  7. data/lib/mongo/address.rb +44 -19
  8. data/lib/mongo/auth.rb +1 -0
  9. data/lib/mongo/auth/credential_cache.rb +51 -0
  10. data/lib/mongo/auth/scram/conversation.rb +20 -16
  11. data/lib/mongo/auth/user.rb +0 -8
  12. data/lib/mongo/auth/user/view.rb +4 -4
  13. data/lib/mongo/background_thread.rb +1 -1
  14. data/lib/mongo/bulk_write.rb +5 -5
  15. data/lib/mongo/client.rb +143 -14
  16. data/lib/mongo/client_encryption.rb +103 -0
  17. data/lib/mongo/cluster.rb +8 -4
  18. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  19. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  20. data/lib/mongo/collection.rb +3 -3
  21. data/lib/mongo/collection/view.rb +1 -1
  22. data/lib/mongo/collection/view/aggregation.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +12 -3
  24. data/lib/mongo/collection/view/iterable.rb +14 -5
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  26. data/lib/mongo/collection/view/readable.rb +9 -7
  27. data/lib/mongo/collection/view/writable.rb +7 -7
  28. data/lib/mongo/crypt.rb +33 -0
  29. data/lib/mongo/crypt/auto_decryption_context.rb +40 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +179 -0
  31. data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
  32. data/lib/mongo/crypt/binary.rb +155 -0
  33. data/lib/mongo/crypt/binding.rb +1229 -0
  34. data/lib/mongo/crypt/context.rb +135 -0
  35. data/lib/mongo/crypt/data_key_context.rb +162 -0
  36. data/lib/mongo/crypt/encryption_io.rb +289 -0
  37. data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
  38. data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
  39. data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
  40. data/lib/mongo/crypt/handle.rb +315 -0
  41. data/lib/mongo/crypt/hooks.rb +90 -0
  42. data/lib/mongo/crypt/kms_context.rb +67 -0
  43. data/lib/mongo/crypt/status.rb +131 -0
  44. data/lib/mongo/cursor.rb +64 -32
  45. data/lib/mongo/database.rb +23 -6
  46. data/lib/mongo/database/view.rb +13 -4
  47. data/lib/mongo/dbref.rb +9 -2
  48. data/lib/mongo/error.rb +5 -1
  49. data/lib/mongo/error/bulk_write_error.rb +16 -14
  50. data/lib/mongo/error/crypt_error.rb +31 -0
  51. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  52. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  53. data/lib/mongo/error/kms_error.rb +22 -0
  54. data/lib/mongo/error/max_bson_size.rb +14 -3
  55. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  56. data/lib/mongo/error/no_server_available.rb +8 -3
  57. data/lib/mongo/error/notable.rb +0 -15
  58. data/lib/mongo/error/operation_failure.rb +1 -0
  59. data/lib/mongo/error/parser.rb +1 -1
  60. data/lib/mongo/grid/file.rb +5 -0
  61. data/lib/mongo/grid/file/chunk.rb +2 -0
  62. data/lib/mongo/grid/file/info.rb +3 -2
  63. data/lib/mongo/grid/fs_bucket.rb +15 -13
  64. data/lib/mongo/grid/stream/write.rb +9 -3
  65. data/lib/mongo/index/view.rb +3 -3
  66. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -1
  67. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  68. data/lib/mongo/operation/collections_info.rb +6 -3
  69. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  70. data/lib/mongo/operation/find/op_msg.rb +4 -1
  71. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  72. data/lib/mongo/operation/insert/command.rb +3 -2
  73. data/lib/mongo/operation/insert/legacy.rb +3 -2
  74. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  75. data/lib/mongo/operation/result.rb +36 -27
  76. data/lib/mongo/operation/shared/executable.rb +11 -9
  77. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  78. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  79. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  80. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  81. data/lib/mongo/operation/shared/read_preference_supported.rb +68 -19
  82. data/lib/mongo/operation/shared/response_handling.rb +1 -1
  83. data/lib/mongo/operation/shared/sessions_supported.rb +44 -3
  84. data/lib/mongo/operation/shared/write.rb +17 -10
  85. data/lib/mongo/operation/update/op_msg.rb +1 -1
  86. data/lib/mongo/protocol/bit_vector.rb +2 -1
  87. data/lib/mongo/protocol/compressed.rb +6 -5
  88. data/lib/mongo/protocol/insert.rb +3 -1
  89. data/lib/mongo/protocol/message.rb +94 -15
  90. data/lib/mongo/protocol/msg.rb +207 -37
  91. data/lib/mongo/protocol/query.rb +7 -9
  92. data/lib/mongo/protocol/serializers.rb +43 -15
  93. data/lib/mongo/retryable.rb +1 -1
  94. data/lib/mongo/server.rb +10 -4
  95. data/lib/mongo/server/connection.rb +20 -9
  96. data/lib/mongo/server/connection_base.rb +118 -18
  97. data/lib/mongo/server/connection_common.rb +61 -0
  98. data/lib/mongo/server/connection_pool.rb +37 -1
  99. data/lib/mongo/server/connection_pool/populator.rb +1 -1
  100. data/lib/mongo/server/description.rb +9 -11
  101. data/lib/mongo/server/monitor.rb +2 -0
  102. data/lib/mongo/server/monitor/connection.rb +3 -18
  103. data/lib/mongo/server/pending_connection.rb +2 -1
  104. data/lib/mongo/session.rb +3 -3
  105. data/lib/mongo/session/session_pool.rb +8 -3
  106. data/lib/mongo/socket.rb +29 -16
  107. data/lib/mongo/socket/ssl.rb +23 -8
  108. data/lib/mongo/socket/tcp.rb +12 -3
  109. data/lib/mongo/srv/monitor.rb +73 -42
  110. data/lib/mongo/srv/result.rb +0 -1
  111. data/lib/mongo/timeout.rb +49 -0
  112. data/lib/mongo/uri.rb +30 -1
  113. data/lib/mongo/uri/srv_protocol.rb +1 -1
  114. data/lib/mongo/version.rb +1 -1
  115. data/mongo.gemspec +1 -3
  116. data/spec/README.md +228 -7
  117. data/spec/integration/auth_spec.rb +53 -0
  118. data/spec/integration/bulk_write_spec.rb +19 -0
  119. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  120. data/spec/integration/client_construction_spec.rb +100 -1
  121. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +353 -0
  122. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +303 -0
  123. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +72 -0
  124. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +79 -0
  125. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +221 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +601 -0
  127. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +187 -0
  128. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +78 -0
  129. data/spec/integration/client_side_encryption/client_close_spec.rb +63 -0
  130. data/spec/integration/client_side_encryption/corpus_spec.rb +233 -0
  131. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  132. data/spec/integration/client_side_encryption/data_key_spec.rb +165 -0
  133. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  134. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +141 -0
  135. data/spec/integration/client_side_encryption/views_spec.rb +44 -0
  136. data/spec/integration/client_update_spec.rb +154 -0
  137. data/spec/integration/command_monitoring_spec.rb +3 -1
  138. data/spec/integration/command_spec.rb +44 -10
  139. data/spec/integration/connection_spec.rb +57 -0
  140. data/spec/integration/crud_spec.rb +89 -0
  141. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  142. data/spec/integration/read_preference_spec.rb +26 -0
  143. data/spec/integration/reconnect_spec.rb +7 -6
  144. data/spec/integration/size_limit_spec.rb +111 -0
  145. data/spec/integration/srv_monitoring_spec.rb +16 -8
  146. data/spec/integration/zlib_compression_spec.rb +25 -0
  147. data/spec/kerberos/kerberos_spec.rb +87 -0
  148. data/spec/lite_spec_helper.rb +34 -29
  149. data/spec/mongo/auth/cr_spec.rb +8 -0
  150. data/spec/mongo/auth/ldap_spec.rb +5 -1
  151. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  152. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  153. data/spec/mongo/auth/scram_spec.rb +45 -35
  154. data/spec/mongo/auth/user/view_spec.rb +3 -6
  155. data/spec/mongo/auth/x509_spec.rb +5 -1
  156. data/spec/mongo/bulk_write/result_spec.rb +11 -7
  157. data/spec/mongo/client_construction_spec.rb +206 -2
  158. data/spec/mongo/client_encryption_spec.rb +405 -0
  159. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  160. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  161. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  162. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  163. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  164. data/spec/mongo/collection/view_spec.rb +1 -1
  165. data/spec/mongo/collection_spec.rb +28 -9
  166. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  167. data/spec/mongo/crypt/auto_encrypter_spec.rb +187 -0
  168. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  169. data/spec/mongo/crypt/binary_spec.rb +115 -0
  170. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  171. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  172. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  173. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  174. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  175. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  176. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  177. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  178. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  179. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  180. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  181. data/spec/mongo/crypt/handle_spec.rb +232 -0
  182. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  183. data/spec/mongo/crypt/status_spec.rb +152 -0
  184. data/spec/mongo/cursor_spec.rb +24 -4
  185. data/spec/mongo/database_spec.rb +20 -0
  186. data/spec/mongo/error/bulk_write_error_spec.rb +49 -0
  187. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  188. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  189. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  190. data/spec/mongo/error/notable_spec.rb +59 -0
  191. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  192. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  193. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  194. data/spec/mongo/operation/command_spec.rb +3 -3
  195. data/spec/mongo/operation/create_index_spec.rb +3 -3
  196. data/spec/mongo/operation/create_user_spec.rb +3 -3
  197. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  198. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  199. data/spec/mongo/operation/delete_spec.rb +7 -7
  200. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  201. data/spec/mongo/operation/find/legacy_spec.rb +2 -1
  202. data/spec/mongo/operation/get_more_spec.rb +1 -1
  203. data/spec/mongo/operation/indexes_spec.rb +1 -1
  204. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  205. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  206. data/spec/mongo/operation/insert_spec.rb +12 -12
  207. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  208. data/spec/mongo/operation/read_preference_legacy_spec.rb +351 -0
  209. data/spec/mongo/operation/read_preference_op_msg_spec.rb +194 -0
  210. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  211. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  212. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  213. data/spec/mongo/operation/update_spec.rb +7 -7
  214. data/spec/mongo/operation/update_user_spec.rb +1 -1
  215. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  216. data/spec/mongo/protocol/delete_spec.rb +9 -8
  217. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  218. data/spec/mongo/protocol/insert_spec.rb +9 -8
  219. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  220. data/spec/mongo/protocol/msg_spec.rb +57 -53
  221. data/spec/mongo/protocol/query_spec.rb +12 -12
  222. data/spec/mongo/protocol/registry_spec.rb +1 -1
  223. data/spec/mongo/protocol/reply_spec.rb +1 -1
  224. data/spec/mongo/protocol/update_spec.rb +10 -9
  225. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  226. data/spec/mongo/server/connection_spec.rb +28 -7
  227. data/spec/mongo/socket_spec.rb +1 -1
  228. data/spec/mongo/srv/monitor_spec.rb +88 -69
  229. data/spec/mongo/timeout_spec.rb +85 -0
  230. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  231. data/spec/mongo/uri_spec.rb +52 -5
  232. data/spec/mongo/write_concern_spec.rb +13 -1
  233. data/spec/{support → runners}/auth.rb +14 -1
  234. data/spec/{support → runners}/change_streams.rb +1 -1
  235. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  236. data/spec/{support → runners}/cmap.rb +1 -1
  237. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  238. data/spec/{support → runners}/command_monitoring.rb +0 -0
  239. data/spec/runners/connection_string.rb +358 -4
  240. data/spec/{support → runners}/crud.rb +9 -9
  241. data/spec/{support → runners}/crud/context.rb +0 -0
  242. data/spec/{support → runners}/crud/operation.rb +7 -3
  243. data/spec/{support → runners}/crud/outcome.rb +0 -0
  244. data/spec/{support → runners}/crud/requirement.rb +1 -1
  245. data/spec/{support → runners}/crud/spec.rb +12 -1
  246. data/spec/{support → runners}/crud/test.rb +0 -0
  247. data/spec/{support → runners}/crud/test_base.rb +0 -0
  248. data/spec/{support → runners}/crud/verifier.rb +10 -12
  249. data/spec/{support → runners}/gridfs.rb +0 -0
  250. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  251. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  252. data/spec/{support → runners}/server_selection.rb +0 -0
  253. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  254. data/spec/{support → runners}/transactions.rb +9 -11
  255. data/spec/{support → runners}/transactions/context.rb +0 -0
  256. data/spec/{support → runners}/transactions/operation.rb +0 -0
  257. data/spec/{support → runners}/transactions/spec.rb +0 -0
  258. data/spec/{support → runners}/transactions/test.rb +37 -5
  259. data/spec/spec_helper.rb +0 -5
  260. data/spec/spec_tests/auth_spec.rb +3 -3
  261. data/spec/spec_tests/client_side_encryption_spec.rb +8 -0
  262. data/spec/spec_tests/connection_string_spec.rb +1 -1
  263. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  264. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  265. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  266. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  267. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  268. data/spec/spec_tests/data/client_side_encryption/bulk.yml +88 -0
  269. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  270. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  271. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  272. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  273. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  274. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  275. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  276. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  277. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  278. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  279. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  280. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  281. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  282. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  283. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  284. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  285. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  286. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  287. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  288. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +64 -0
  289. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  290. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  291. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  292. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +171 -0
  293. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  294. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  295. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  296. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  297. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  298. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  299. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  300. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  301. data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  302. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  303. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  304. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  305. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  306. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  307. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  308. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  309. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  310. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  311. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  312. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  313. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  314. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  315. data/spec/spec_tests/uri_options_spec.rb +6 -8
  316. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  317. data/spec/support/certificates/README.md +4 -0
  318. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  319. data/spec/support/certificates/server-second-level.crt +52 -52
  320. data/spec/support/certificates/server-second-level.key +25 -25
  321. data/spec/support/certificates/server-second-level.pem +77 -77
  322. data/spec/support/client_registry.rb +19 -3
  323. data/spec/support/cluster_config.rb +9 -1
  324. data/spec/support/cluster_tools.rb +6 -1
  325. data/spec/support/common_shortcuts.rb +12 -0
  326. data/spec/support/constraints.rb +16 -0
  327. data/spec/support/crypt.rb +154 -0
  328. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  329. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  330. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  331. data/spec/support/crypt/corpus/corpus.json +3657 -0
  332. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  333. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  334. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  335. data/spec/support/crypt/external/external-key.json +31 -0
  336. data/spec/support/crypt/external/external-schema.json +19 -0
  337. data/spec/support/crypt/limits/limits-doc.json +102 -0
  338. data/spec/support/crypt/limits/limits-key.json +31 -0
  339. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  340. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  341. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  342. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  343. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  344. data/spec/support/lite_constraints.rb +19 -1
  345. data/spec/support/matchers.rb +19 -0
  346. data/spec/support/shared/protocol.rb +2 -0
  347. data/spec/support/spec_config.rb +53 -13
  348. data/spec/support/utils.rb +140 -10
  349. metadata +894 -687
  350. metadata.gz.sig +0 -0
  351. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  352. data/lib/mongo/srv/warning_result.rb +0 -35
  353. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  354. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  355. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  356. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  357. data/spec/support/connection_string.rb +0 -354
@@ -0,0 +1,1229 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ unless ENV['LIBMONGOCRYPT_PATH']
16
+ # It seems that MRI maintains autoload configuration for a module until
17
+ # that module is defined, but JRuby removes autoload configuration as soon
18
+ # as the referenced file is attempted to be loaded, even if the module
19
+ # never ends up being defined.
20
+ if BSON::Environment.jruby?
21
+ module Mongo
22
+ module Crypt
23
+ autoload :Binding, 'mongo/crypt/binding'
24
+ end
25
+ end
26
+ end
27
+
28
+ raise LoadError, "Cannot load Mongo::Crypt::Binding because there is no path " +
29
+ "to libmongocrypt specified in the LIBMONGOCRYPT_PATH environment variable."
30
+ end
31
+
32
+ require 'ffi'
33
+
34
+ module Mongo
35
+ module Crypt
36
+
37
+ # @api private
38
+ def reset_autoload
39
+ remove_const(:Binding)
40
+ autoload(:Binding, 'mongo/crypt/binding')
41
+ end
42
+ module_function :reset_autoload
43
+
44
+ # A Ruby binding for the libmongocrypt C library
45
+ #
46
+ # @api private
47
+ class Binding
48
+ extend FFI::Library
49
+
50
+ begin
51
+ ffi_lib ENV['LIBMONGOCRYPT_PATH']
52
+ rescue LoadError => e
53
+ Crypt.reset_autoload
54
+ raise LoadError, "Cannot load Mongo::Crypt::Binding because the path to " +
55
+ "libmongocrypt specified in the LIBMONGOCRYPT_PATH environment variable " +
56
+ "is invalid: #{ENV['LIBMONGOCRYPT_PATH']}\n\n#{e.class}: #{e.message}"
57
+ end
58
+
59
+ # @!method self.mongocrypt_version(len)
60
+ # @api private
61
+ #
62
+ # Returns the version string of the libmongocrypt library.
63
+ # @param [ FFI::Pointer | nil ] len (out param) An optional pointer to a
64
+ # uint8 that will reference the length of the returned string.
65
+ # @return [ String ] A version string for libmongocrypt.
66
+ attach_function :mongocrypt_version, [:pointer], :string
67
+
68
+ # @!method self.mongocrypt_binary_new
69
+ # @api private
70
+ #
71
+ # Creates a new mongocrypt_binary_t object (a non-owning view of a byte
72
+ # array).
73
+ # @return [ FFI::Pointer ] A pointer to the newly-created
74
+ # mongocrypt_binary_t object.
75
+ attach_function :mongocrypt_binary_new, [], :pointer
76
+
77
+ # @!method self.mongocrypt_binary_new_from_data(data, len)
78
+ # @api private
79
+ #
80
+ # Create a new mongocrypt_binary_t object that maintains a pointer to
81
+ # the specified byte array.
82
+ # @param [ FFI::Pointer ] data A pointer to an array of bytes; the data
83
+ # is not copied and must outlive the mongocrypt_binary_t object.
84
+ # @param [ Integer ] len The length of the array argument.
85
+ # @return [ FFI::Pointer ] A pointer to the newly-created
86
+ # mongocrypt_binary_t object.
87
+ attach_function(
88
+ :mongocrypt_binary_new_from_data,
89
+ [:pointer, :int],
90
+ :pointer
91
+ )
92
+
93
+ # @!method self.mongocrypt_binary_data(binary)
94
+ # @api private
95
+ #
96
+ # Get the pointer to the underlying data for the mongocrypt_binary_t.
97
+ # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object.
98
+ # @return [ FFI::Pointer ] A pointer to the data array.
99
+ attach_function :mongocrypt_binary_data, [:pointer], :pointer
100
+
101
+ # @!method self.mongocrypt_binary_len(binary)
102
+ # @api private
103
+ #
104
+ # Get the length of the underlying data array.
105
+ # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object.
106
+ # @return [ Integer ] The length of the data array.
107
+ attach_function :mongocrypt_binary_len, [:pointer], :int
108
+
109
+ # @!method self.mongocrypt_binary_destroy(binary)
110
+ # @api private
111
+ #
112
+ # Destroy the mongocrypt_binary_t object.
113
+ # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object.
114
+ # @return [ nil ] Always nil.
115
+ attach_function :mongocrypt_binary_destroy, [:pointer], :void
116
+
117
+ # Enum labeling different status types
118
+ enum :status_type, [
119
+ :ok, 0,
120
+ :error_client, 1,
121
+ :error_kms, 2,
122
+ ]
123
+
124
+ # @!method self.mongocrypt_status_new
125
+ # @api private
126
+ #
127
+ # Create a new mongocrypt_status_t object.
128
+ # @return [ FFI::Pointer ] A pointer to the new mongocrypt_status_ts.
129
+ attach_function :mongocrypt_status_new, [], :pointer
130
+
131
+ # @!method self.mongocrypt_status_set(status, type, code, message, len)
132
+ # @api private
133
+ #
134
+ # Set a message, type, and code on an existing status.
135
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
136
+ # @param [ Symbol ] type The status type; possible values are defined
137
+ # by the status_type enum.
138
+ # @param [ Integer ] code The status code.
139
+ # @param [ String ] message The status message.
140
+ # @param [ Integer ] len The length of the message argument (or -1 for a
141
+ # null-terminated string).
142
+ # @return [ nil ] Always nil.
143
+ attach_function(
144
+ :mongocrypt_status_set,
145
+ [:pointer, :status_type, :int, :string, :int],
146
+ :void
147
+ )
148
+
149
+ # @!method self.mongocrypt_status_type(status)
150
+ # @api private
151
+ #
152
+ # Indicates the status type.
153
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
154
+ # @return [ Symbol ] The status type (as defined by the status_type enum).
155
+ attach_function :mongocrypt_status_type, [:pointer], :status_type
156
+
157
+ # @!method self.mongocrypt_status_code(status)
158
+ # @api private
159
+ #
160
+ # Return the status error code.
161
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
162
+ # @return [ Integer ] The status code.
163
+ attach_function :mongocrypt_status_code, [:pointer], :int
164
+
165
+ # @!method self.mongocrypt_status_message(status, len=nil)
166
+ # @api private
167
+ #
168
+ # Returns the status message.
169
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
170
+ # @param [ FFI::Pointer | nil ] len (out param) An optional pointer to a
171
+ # uint32, where the length of the retun string will be written.
172
+ # @return [ String ] The status message.
173
+ attach_function :mongocrypt_status_message, [:pointer, :pointer], :string
174
+
175
+ # @!method self.mongocrypt_status_ok(status)
176
+ # @api private
177
+ #
178
+ # Returns whether the status is ok or an error.
179
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
180
+ # @return [ Boolean ] Whether the status is ok.
181
+ attach_function :mongocrypt_status_ok, [:pointer], :bool
182
+
183
+ # @!method self.mongocrypt_status_destroy(status)
184
+ # @api private
185
+ #
186
+ # Destroys the reference to the mongocrypt_status_t object.
187
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t.
188
+ # @return [ nil ] Always nil.
189
+ attach_function :mongocrypt_status_destroy, [:pointer], :void
190
+
191
+ # Enum labeling the various log levels
192
+ enum :log_level, [
193
+ :fatal, 0,
194
+ :error, 1,
195
+ :warn, 2,
196
+ :info, 3,
197
+ :debug, 4,
198
+ ]
199
+
200
+ # @!method mongocrypt_log_fn_t(level, message, len, ctx)
201
+ # @api private
202
+ #
203
+ # A callback to the mongocrypt log function. Set a custom log callback
204
+ # with the mongocrypt_setopt_log_handler method
205
+ # @param [ Symbol ] level The log level; possible values defined by the
206
+ # log_level enum
207
+ # @param [ String ] message The log message
208
+ # @param [ Integer ] len The length of the message param, or -1 if the
209
+ # string is null terminated
210
+ # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context
211
+ # object when this callback was set
212
+ # @return [ nil ] Always nil.
213
+ #
214
+ # @note This defines a method signature for an FFI callback; it is not
215
+ # an instance method on the Binding class.
216
+ callback :mongocrypt_log_fn_t, [:log_level, :string, :int, :pointer], :void
217
+
218
+ # @!method self.ongocrypt_new
219
+ # @api private
220
+ #
221
+ # Creates a new mongocrypt_t object.
222
+ # @return [ FFI::Pointer ] A pointer to a new mongocrypt_t object.
223
+ attach_function :mongocrypt_new, [], :pointer
224
+
225
+ # @!method self.mongocrypt_setopt_log_handler(crypt, log_fn, log_ctx=nil)
226
+ # @api private
227
+ #
228
+ # Set the handler on the mongocrypt_t object to be called every time
229
+ # libmongocrypt logs a message.
230
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
231
+ # @param [ Method ] log_fn A logging callback method.
232
+ # @param [ FFI::Pointer | nil ] log_ctx An optional pointer to a context
233
+ # to be passed into the log callback on every invocation.
234
+ # @return [ Boolean ] Whether setting the callback was successful.
235
+ attach_function(
236
+ :mongocrypt_setopt_log_handler,
237
+ [:pointer, :mongocrypt_log_fn_t, :pointer],
238
+ :bool
239
+ )
240
+
241
+ # Set the logger callback function on the Mongo::Crypt::Handle object
242
+ #
243
+ # @param [ Mongo::Crypt::Handle ] handle
244
+ # @param [ Method ] log_callback
245
+ #
246
+ # @raise [ Mongo::Error::CryptError ] If the callback is not set successfully
247
+ def self.setopt_log_handler(handle, log_callback)
248
+ check_status(handle) do
249
+ mongocrypt_setopt_log_handler(handle, log_callback, nil)
250
+ end
251
+ end
252
+
253
+ # @!method self.mongocrypt_setopt_kms_provider_aws(crypt, aws_access_key_id, aws_access_key_id_len, aws_secret_access_key, aws_secret_access_key_len)
254
+ # @api private
255
+ #
256
+ # Configure mongocrypt_t object with AWS KMS provider options.
257
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
258
+ # @param [ String ] aws_access_key_id The AWS access key id.
259
+ # @param [ Integer ] aws_access_key_id_len The length of the AWS access
260
+ # key string (or -1 for a null-terminated string).
261
+ # @param [ String ] aws_secret_access_key The AWS secret access key.
262
+ # @param [ Integer ] aws_secret_access_key_len The length of the AWS
263
+ # secret access key (or -1 for a null-terminated string).
264
+ # @return [ Boolean ] Returns whether the option was set successfully.
265
+ attach_function(
266
+ :mongocrypt_setopt_kms_provider_aws,
267
+ [:pointer, :string, :int, :string, :int],
268
+ :bool
269
+ )
270
+
271
+ # Configure the Handle object with AWS KMS provider options
272
+ #
273
+ # @param [ Mongo::Crypt::Handle ] handle
274
+ # @param [ String ] aws_access_key The AWS access key
275
+ # @param [ String ] aws_secret_access_key The AWS secret access key
276
+ #
277
+ # @raise [ Mongo::Error::CryptError ] If the option is not set successfully
278
+ def self.setopt_kms_provider_aws(handle,
279
+ aws_access_key, aws_secret_access_key
280
+ )
281
+ check_status(handle) do
282
+ mongocrypt_setopt_kms_provider_aws(
283
+ handle.ref,
284
+ aws_access_key,
285
+ -1,
286
+ aws_secret_access_key,
287
+ -1
288
+ )
289
+ end
290
+ end
291
+
292
+ # @!method self.mongocrypt_setopt_kms_provider_local(crypt, key)
293
+ # @api private
294
+ #
295
+ # Configure mongocrypt_t object to take local KSM provider options.
296
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
297
+ # @param [ FFI::Pointer ] key A pointer to a mongocrypt_binary_t object
298
+ # that references the 96-byte local master key.
299
+ # @return [ Boolean ] Returns whether the option was set successfully.
300
+ attach_function(
301
+ :mongocrypt_setopt_kms_provider_local,
302
+ [:pointer, :pointer],
303
+ :bool
304
+ )
305
+
306
+ # Set local KMS provider options on the Mongo::Crypt::Handle object
307
+ #
308
+ # @param [ Mongo::Crypt::Handle ] handle
309
+ # @param [ String ] master_key The 96-byte local KMS master key
310
+ #
311
+ # @raise [ Mongo::Error::CryptError ] If the option is not set successfully
312
+ def self.setopt_kms_provider_local(handle, master_key)
313
+ Binary.wrap_string(master_key) do |master_key_p|
314
+ check_status(handle) do
315
+ mongocrypt_setopt_kms_provider_local(handle.ref, master_key_p)
316
+ end
317
+ end
318
+ end
319
+
320
+ # @!method self.mongocrypt_setopt_schema_map(crypt, schema_map)
321
+ # @api private
322
+ #
323
+ # Sets a local schema map for encryption.
324
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
325
+ # @param [ FFI::Pointer ] schema_map A pointer to a mongocrypt_binary_t.
326
+ # object that references the schema map as a BSON binary string.
327
+ # @return [ Boolean ] Returns whether the option was set successfully.
328
+ attach_function :mongocrypt_setopt_schema_map, [:pointer, :pointer], :bool
329
+
330
+ # Set schema map on the Mongo::Crypt::Handle object
331
+ #
332
+ # @param [ Mongo::Crypt::Handle ] handle
333
+ # @param [ BSON::Document ] schema_map_doc The schema map as a
334
+ # BSON::Document object
335
+ #
336
+ # @raise [ Mongo::Error::CryptError ] If the schema map is not set successfully
337
+ def self.setopt_schema_map(handle, schema_map_doc)
338
+ validate_document(schema_map_doc)
339
+ data = schema_map_doc.to_bson.to_s
340
+ Binary.wrap_string(data) do |data_p|
341
+ check_status(handle) do
342
+ mongocrypt_setopt_schema_map(handle.ref, data_p)
343
+ end
344
+ end
345
+ end
346
+
347
+ # @!method self.mongocrypt_init(crypt)
348
+ # @api private
349
+ #
350
+ # Initialize the mongocrypt_t object.
351
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
352
+ # @return [ Boolean ] Returns whether the crypt was initialized successfully.
353
+ attach_function :mongocrypt_init, [:pointer], :bool
354
+
355
+ # Initialize the Mongo::Crypt::Handle object
356
+ #
357
+ # @param [ Mongo::Crypt::Handle ] handle
358
+ #
359
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
360
+ def self.init(handle)
361
+ check_status(handle) do
362
+ mongocrypt_init(handle.ref)
363
+ end
364
+ end
365
+
366
+ # @!method self.mongocrypt_status(crypt, status)
367
+ # @api private
368
+ #
369
+ # Set the status information from the mongocrypt_t object on the
370
+ # mongocrypt_status_t object.
371
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
372
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object.
373
+ # @return [ Boolean ] Whether the status was successfully set.
374
+ attach_function :mongocrypt_status, [:pointer, :pointer], :bool
375
+
376
+ # @!method self.mongocrypt_destroy(crypt)
377
+ # @api private
378
+ #
379
+ # Destroy the reference the mongocrypt_t object.
380
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
381
+ # @return [ nil ] Always nil.
382
+ attach_function :mongocrypt_destroy, [:pointer], :void
383
+
384
+ # @!method self.mongocrypt_ctx_new(crypt)
385
+ # @api private
386
+ #
387
+ # Create a new mongocrypt_ctx_t object (a wrapper for the libmongocrypt
388
+ # state machine).
389
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
390
+ # @return [ FFI::Pointer ] A new mongocrypt_ctx_t object.
391
+ attach_function :mongocrypt_ctx_new, [:pointer], :pointer
392
+
393
+ # @!method self.mongocrypt_ctx_status(ctx, status)
394
+ # @api private
395
+ #
396
+ # Set the status information from the mongocrypt_ctx_t object on the
397
+ # mongocrypt_status_t object.
398
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
399
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object.
400
+ # @return [ Boolean ] Whether the status was successfully set.
401
+ attach_function :mongocrypt_ctx_status, [:pointer, :pointer], :bool
402
+
403
+ # @!method self.mongocrypt_ctx_setopt_key_id(ctx, key_id)
404
+ # @api private
405
+ #
406
+ # Set the key id used for explicit encryption.
407
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
408
+ # @param [ FFI::Pointer ] key_id A pointer to a mongocrypt_binary_t object
409
+ # that references the 16-byte key-id.
410
+ # @note Do not initialize ctx before calling this method.
411
+ # @return [ Boolean ] Whether the option was successfully set.
412
+ attach_function :mongocrypt_ctx_setopt_key_id, [:pointer, :pointer], :bool
413
+
414
+ # Sets the key id option on an explicit encryption context.
415
+ #
416
+ # @param [ Mongo::Crypt::Context ] context Explicit encryption context
417
+ # @param [ String ] key_id The key id
418
+ #
419
+ # @raise [ Mongo::Error::CryptError ] If the operation failed
420
+ def self.ctx_setopt_key_id(context, key_id)
421
+ Binary.wrap_string(key_id) do |key_id_p|
422
+ check_ctx_status(context) do
423
+ mongocrypt_ctx_setopt_key_id(context.ctx_p, key_id_p)
424
+ end
425
+ end
426
+ end
427
+
428
+ # @!method self.mongocrypt_ctx_setopt_key_alt_name(ctx, binary)
429
+ # @api private
430
+ #
431
+ # When creating a data key, set an alternate name on that key. When
432
+ # performing explicit encryption, specifying which data key to use for
433
+ # encryption based on its keyAltName field.
434
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
435
+ # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t
436
+ # object that references a BSON document in the format
437
+ # { "keyAltName": <BSON UTF8 value> }.
438
+ # @return [ Boolean ] Whether the alternative name was successfully set.
439
+ # @note Do not initialize ctx before calling this method.
440
+ attach_function(
441
+ :mongocrypt_ctx_setopt_key_alt_name,
442
+ [:pointer, :pointer],
443
+ :bool
444
+ )
445
+
446
+ # Set multiple alternate key names on data key creation
447
+ #
448
+ # @param [ Mongo::Crypt::Context ] context A DataKeyContext
449
+ # @param [ Array ] key_alt_names An array of alternate key names as strings
450
+ #
451
+ # @raise [ Mongo::Error::CryptError ] If any of the alternate names are
452
+ # not valid UTF8 strings
453
+ def self.ctx_setopt_key_alt_names(context, key_alt_names)
454
+ key_alt_names.each do |key_alt_name|
455
+ key_alt_name_bson = { :keyAltName => key_alt_name }.to_bson.to_s
456
+
457
+ Binary.wrap_string(key_alt_name_bson) do |key_alt_name_p|
458
+ check_ctx_status(context) do
459
+ mongocrypt_ctx_setopt_key_alt_name(context.ctx_p, key_alt_name_p)
460
+ end
461
+ end
462
+ end
463
+ end
464
+
465
+ # @!method self.mongocrypt_ctx_setopt_algorithm(ctx, algorithm, len)
466
+ # @api private
467
+ #
468
+ # Set the algorithm used for explicit encryption.
469
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
470
+ # @param [ String ] algorithm The algorithm name. Valid values are:
471
+ # - "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
472
+ # - "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
473
+ # @param [ Integer ] len The length of the algorithm string.
474
+ # @note Do not initialize ctx before calling this method.
475
+ # @return [ Boolean ] Whether the option was successfully set.
476
+ attach_function(
477
+ :mongocrypt_ctx_setopt_algorithm,
478
+ [:pointer, :string, :int],
479
+ :bool
480
+ )
481
+
482
+ # Set the algorithm on the context
483
+ #
484
+ # @param [ Mongo::Crypt::Context ] context
485
+ # @param [ String ] name The algorithm name. Valid values are:
486
+ # - "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
487
+ # - "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
488
+ #
489
+ # @raise [ Mongo::Error::CryptError ] If the operation failed
490
+ def self.ctx_setopt_algorithm(context, name)
491
+ check_ctx_status(context) do
492
+ mongocrypt_ctx_setopt_algorithm(context.ctx_p, name, -1)
493
+ end
494
+ end
495
+
496
+ # @!method self.mongocrypt_ctx_setopt_masterkey_aws(ctx, region, region_len, arn, arn_len)
497
+ # @api private
498
+ #
499
+ # Configure the ctx to take a master key from AWS.
500
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_object.
501
+ # @param [ String ] region The AWS region.
502
+ # @param [ Integer ] region_len The length of the region string (or -1
503
+ # for a null-terminated string).
504
+ # @param [ String ] arn The Amazon Resource Name (ARN) of the mater key.
505
+ # @param [ Integer ] arn_len The length of the ARN (or -1 for a
506
+ # null-terminated string).
507
+ # @return [ Boolean ] Returns whether the option was set successfully.
508
+ attach_function(
509
+ :mongocrypt_ctx_setopt_masterkey_aws,
510
+ [:pointer, :string, :int, :string, :int],
511
+ :bool
512
+ )
513
+
514
+ # Configure the Context object to take a master key from AWS
515
+ #
516
+ # @param [ Mongo::Crypt::Context ] context
517
+ # @param [ String ] region The AWS region (e.g. "us-east-2")
518
+ # @param [ String ] arn The master key Amazon Resource Name
519
+ #
520
+ # @raise [ Mongo::Error::CryptError ] If the operation failed
521
+ def self.ctx_setopt_master_key_aws(context, region, arn)
522
+ check_ctx_status(context) do
523
+ mongocrypt_ctx_setopt_masterkey_aws(
524
+ context.ctx_p,
525
+ region,
526
+ -1,
527
+ arn,
528
+ -1
529
+ )
530
+ end
531
+ end
532
+
533
+ # @!method self.mongocrypt_ctx_setopt_masterkey_aws_endpoint(ctx, endpoint, endpoint_len)
534
+ # @api private
535
+ #
536
+ # Set a custom endpoint at which to fetch the AWS master key
537
+ # @param [ FFI::Pointer ] ctx
538
+ # @param [ String ] endpoint The custom endpoint.
539
+ # @param [ Integer ] endpoint_len The length of the endpoint string (or
540
+ # -1 for a null-terminated string).
541
+ # @return [ Boolean ] Returns whether the option was set successfully.
542
+ attach_function(
543
+ :mongocrypt_ctx_setopt_masterkey_aws_endpoint,
544
+ [:pointer, :string, :int],
545
+ :bool
546
+ )
547
+
548
+ # Configure the Context object to take a masterk ey from AWS
549
+ #
550
+ # @param [ Mongo::Crypt::Context ] context
551
+ # @param [ String ] endpoint The custom AWS master key endpoint
552
+ #
553
+ # @raise [ Mongo::Error::CryptError ] If the operation failed
554
+ def self.ctx_setopt_master_key_aws_endpoint(context, endpoint)
555
+ check_ctx_status(context) do
556
+ mongocrypt_ctx_setopt_masterkey_aws_endpoint(
557
+ context.ctx_p,
558
+ endpoint,
559
+ -1,
560
+ )
561
+ end
562
+ end
563
+
564
+ # @!method self.mongocrypt_ctx_setopt_masterkey_local(ctx)
565
+ # @api private
566
+ #
567
+ # Set the ctx to take a local master key.
568
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
569
+ # @note Do not initialize ctx before calling this method.
570
+ # @return [ Boolean ] Whether the option was successfully set.
571
+ attach_function(
572
+ :mongocrypt_ctx_setopt_masterkey_local,
573
+ [:pointer],
574
+ :bool
575
+ )
576
+
577
+ # Tell the Context object to read the master key from local KMS options
578
+ #
579
+ # @param [ Mongo::Crypt::Context ] context
580
+ #
581
+ # @raise [ Mongo::Error::CryptError ] If the operation failed
582
+ def self.ctx_setopt_master_key_local(context)
583
+ check_ctx_status(context) do
584
+ mongocrypt_ctx_setopt_masterkey_local(context.ctx_p)
585
+ end
586
+ end
587
+
588
+ # @!method self.mongocrypt_ctx_datakey_init(ctx)
589
+ # @api private
590
+ #
591
+ # Initializes the ctx to create a data key.
592
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
593
+ # @note Before calling this method, master key options must be set.
594
+ # Set AWS master key by calling mongocrypt_ctx_setopt_masterkey_aws
595
+ # and mongocrypt_ctx_setopt_masterkey_aws_endpoint. Set local master
596
+ # key by calling mongocrypt_ctx_setopt_masterkey_local.
597
+ # @return [ Boolean ] Whether the initialization was successful.
598
+ attach_function :mongocrypt_ctx_datakey_init, [:pointer], :bool
599
+
600
+ # Initialize the Context to create a data key
601
+ #
602
+ # @param [ Mongo::Crypt::Context ] context
603
+ #
604
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
605
+ def self.ctx_datakey_init(context)
606
+ check_ctx_status(context) do
607
+ mongocrypt_ctx_datakey_init(context.ctx_p)
608
+ end
609
+ end
610
+
611
+ # @!method self.mongocrypt_ctx_encrypt_init(ctx, db, db_len, cmd)
612
+ # @api private
613
+ #
614
+ # Initializes the ctx for auto-encryption.
615
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
616
+ # @param [ String ] db The database name.
617
+ # @param [ Integer ] db_len The length of the database name argument
618
+ # (or -1 for a null-terminated string).
619
+ # @param [ FFI::Pointer ] cmd A pointer to a mongocrypt_binary_t object
620
+ # that references the database command as a binary string.
621
+ # @note This method expects the passed-in BSON to be in the format:
622
+ # { "v": BSON value to decrypt }.
623
+ # @return [ Boolean ] Whether the initialization was successful.
624
+ attach_function(
625
+ :mongocrypt_ctx_encrypt_init,
626
+ [:pointer, :string, :int, :pointer],
627
+ :bool
628
+ )
629
+
630
+ # Initialize the Context for auto-encryption
631
+ #
632
+ # @param [ Mongo::Crypt::Context ] context
633
+ # @param [ String ] db_name The name of the database against which the
634
+ # encrypted command is being performed
635
+ # @param [ Hash ] command The command to be encrypted
636
+ #
637
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
638
+ def self.ctx_encrypt_init(context, db_name, command)
639
+ validate_document(command)
640
+ data = command.to_bson.to_s
641
+ Binary.wrap_string(data) do |data_p|
642
+ check_ctx_status(context) do
643
+ mongocrypt_ctx_encrypt_init(context.ctx_p, db_name, -1, data_p)
644
+ end
645
+ end
646
+ end
647
+
648
+ # @!method self.mongocrypt_ctx_explicit_encrypt_init(ctx, msg)
649
+ # @api private
650
+ #
651
+ # Initializes the ctx for explicit encryption.
652
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
653
+ # @param [ FFI::Pointer ] msg A pointer to a mongocrypt_binary_t object
654
+ # that references the message to be encrypted as a binary string.
655
+ # @note Before calling this method, set a key_id, key_alt_name (optional),
656
+ # and encryption algorithm using the following methods:
657
+ # mongocrypt_ctx_setopt_key_id, mongocrypt_ctx_setopt_key_alt_name,
658
+ # and mongocrypt_ctx_setopt_algorithm.
659
+ # @return [ Boolean ] Whether the initialization was successful.
660
+ attach_function(
661
+ :mongocrypt_ctx_explicit_encrypt_init,
662
+ [:pointer, :pointer],
663
+ :bool
664
+ )
665
+
666
+ # Initialize the Context for explicit encryption
667
+ #
668
+ # @param [ Mongo::Crypt::Context ] context
669
+ # @param [ Hash ] doc A BSON document to encrypt
670
+ #
671
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
672
+ def self.ctx_explicit_encrypt_init(context, doc)
673
+ validate_document(doc)
674
+ data = doc.to_bson.to_s
675
+ Binary.wrap_string(data) do |data_p|
676
+ check_ctx_status(context) do
677
+ mongocrypt_ctx_explicit_encrypt_init(context.ctx_p, data_p)
678
+ end
679
+ end
680
+ end
681
+
682
+ # @!method self.mongocrypt_ctx_decrypt_init(ctx, doc)
683
+ # @api private
684
+ #
685
+ # Initializes the ctx for auto-decryption.
686
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
687
+ # @param [ FFI::Pointer ] doc A pointer to a mongocrypt_binary_t object
688
+ # that references the document to be decrypted as a BSON binary string.
689
+ # @return [ Boolean ] Whether the initialization was successful.
690
+ attach_function :mongocrypt_ctx_decrypt_init, [:pointer, :pointer], :bool
691
+
692
+ # Initialize the Context for auto-decryption
693
+ #
694
+ # @param [ Mongo::Crypt::Context ] context
695
+ # @param [ BSON::Document ] command A BSON document to decrypt
696
+ #
697
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
698
+ def self.ctx_decrypt_init(context, command)
699
+ validate_document(command)
700
+ data = command.to_bson.to_s
701
+ Binary.wrap_string(data) do |data_p|
702
+ check_ctx_status(context) do
703
+ mongocrypt_ctx_decrypt_init(context.ctx_p, data_p)
704
+ end
705
+ end
706
+ end
707
+
708
+ # @!method self.mongocrypt_ctx_explicit_decrypt_init(ctx, msg)
709
+ # @api private
710
+ #
711
+ # Initializes the ctx for explicit decryption.
712
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
713
+ # @param [ FFI::Pointer ] msg A pointer to a mongocrypt_binary_t object
714
+ # that references the message to be decrypted as a BSON binary string.
715
+ # @return [ Boolean ] Whether the initialization was successful.
716
+ attach_function(
717
+ :mongocrypt_ctx_explicit_decrypt_init,
718
+ [:pointer, :pointer],
719
+ :bool
720
+ )
721
+
722
+ # Initialize the Context for explicit decryption
723
+ #
724
+ # @param [ Mongo::Crypt::Context ] context
725
+ # @param [ Hash ] doc A BSON document to decrypt
726
+ #
727
+ # @raise [ Mongo::Error::CryptError ] If initialization fails
728
+ def self.ctx_explicit_decrypt_init(context, doc)
729
+ validate_document(doc)
730
+ data = doc.to_bson.to_s
731
+ Binary.wrap_string(data) do |data_p|
732
+ check_ctx_status(context) do
733
+ mongocrypt_ctx_explicit_decrypt_init(context.ctx_p, data_p)
734
+ end
735
+ end
736
+ end
737
+
738
+ # An enum labeling different libmognocrypt state machine states
739
+ enum :mongocrypt_ctx_state, [
740
+ :error, 0,
741
+ :need_mongo_collinfo, 1,
742
+ :need_mongo_markings, 2,
743
+ :need_mongo_keys, 3,
744
+ :need_kms, 4,
745
+ :ready, 5,
746
+ :done, 6,
747
+ ]
748
+
749
+ # @!method self.mongocrypt_ctx_state(ctx)
750
+ # @api private
751
+ #
752
+ # Get the current state of the ctx.
753
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
754
+ # @return [ Symbol ] The current state, will be one of the values defined
755
+ # by the mongocrypt_ctx_state enum.
756
+ attach_function :mongocrypt_ctx_state, [:pointer], :mongocrypt_ctx_state
757
+
758
+ # @!method self.mongocrypt_ctx_mongo_op(ctx, op_bson)
759
+ # @api private
760
+ #
761
+ # Get a BSON operation for the driver to run against the MongoDB
762
+ # collection, the key vault database, or mongocryptd.
763
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
764
+ # @param [ FFI::Pointer ] op_bson (out param) A pointer to a
765
+ # mongocrypt_binary_t object that will have a reference to the
766
+ # BSON operation written to it by libmongocrypt.
767
+ # @return [ Boolean ] A boolean indicating the success of the operation.
768
+ attach_function :mongocrypt_ctx_mongo_op, [:pointer, :pointer], :bool
769
+
770
+ # Returns a BSON::Document representing an operation that the
771
+ # driver must perform on behalf of libmongocrypt to get the
772
+ # information it needs in order to continue with
773
+ # encryption/decryption (for example, a filter for a key vault query).
774
+ #
775
+ # @param [ Mongo::Crypt::Context ] context
776
+ #
777
+ # @raise [ Mongo::Crypt ] If there is an error getting the operation
778
+ # @return [ BSON::Document ] The operation that the driver must perform
779
+ def self.ctx_mongo_op(context)
780
+ binary = Binary.new
781
+
782
+ check_ctx_status(context) do
783
+ mongocrypt_ctx_mongo_op(context.ctx_p, binary.ref)
784
+ end
785
+
786
+ # TODO since the binary references a C pointer, and ByteBuffer is
787
+ # written in C in MRI, we could omit a copy of the data by making
788
+ # ByteBuffer reference the string that is owned by libmongocrypt.
789
+ BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson)
790
+ end
791
+
792
+ # @!method self.mongocrypt_ctx_mongo_feed(ctx, reply)
793
+ # @api private
794
+ #
795
+ # Feed a BSON reply to libmongocrypt.
796
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
797
+ # @param [ FFI::Pointer ] reply A mongocrypt_binary_t object that
798
+ # references the BSON reply to feed to libmongocrypt.
799
+ # @return [ Boolean ] A boolean indicating the success of the operation.
800
+ attach_function :mongocrypt_ctx_mongo_feed, [:pointer, :pointer], :bool
801
+
802
+ # Feed a response from the driver back to libmongocrypt
803
+ #
804
+ # @param [ Mongo::Crypt::Context ] context
805
+ # @param [ BSON::Document ] doc The document representing the response
806
+ #
807
+ # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully
808
+ def self.ctx_mongo_feed(context, doc)
809
+ validate_document(doc)
810
+ data = doc.to_bson.to_s
811
+ Binary.wrap_string(data) do |data_p|
812
+ check_ctx_status(context) do
813
+ mongocrypt_ctx_mongo_feed(context.ctx_p, data_p)
814
+ end
815
+ end
816
+ end
817
+
818
+ # @!method self.mongocrypt_ctx_mongo_done(ctx)
819
+ # @api private
820
+ #
821
+ # Indicate to libmongocrypt that the driver is done feeding replies.
822
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
823
+ # @return [ Boolean ] A boolean indicating the success of the operation.
824
+ attach_function :mongocrypt_ctx_mongo_done, [:pointer], :bool
825
+
826
+ # @!method self.mongocrypt_ctx_mongo_next_kms_ctx(ctx)
827
+ # @api private
828
+ #
829
+ # Return a pointer to a mongocrypt_kms_ctx_t object or NULL.
830
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
831
+ # @return [ FFI::Pointer ] A pointer to a mongocrypt_kms_ctx_t object.
832
+ attach_function :mongocrypt_ctx_next_kms_ctx, [:pointer], :pointer
833
+
834
+ # Return a new KmsContext object needed by a Context object.
835
+ #
836
+ # @param [ Mongo::Crypt::Context ] context
837
+ #
838
+ # @return [ Mongo::Crypt::KmsContext | nil ] The KmsContext needed to
839
+ # fetch an AWS master key or nil, if no KmsContext is needed
840
+ def self.ctx_next_kms_ctx(context)
841
+ kms_ctx_p = mongocrypt_ctx_next_kms_ctx(context.ctx_p)
842
+
843
+ if kms_ctx_p.null?
844
+ nil
845
+ else
846
+ KmsContext.new(kms_ctx_p)
847
+ end
848
+ end
849
+
850
+ # @!method self.mongocrypt_kms_ctx_message(kms, msg)
851
+ # @api private
852
+ #
853
+ # Get the message needed to fetch the AWS KMS master key.
854
+ # @param [ FFI::Pointer ] kms Pointer to the mongocrypt_kms_ctx_t object
855
+ # @param [ FFI::Pointer ] msg (outparam) Pointer to a mongocrypt_binary_t
856
+ # object that will have the location of the message written to it by
857
+ # libmongocrypt.
858
+ # @return [ Boolean ] Whether the operation is successful.
859
+ attach_function :mongocrypt_kms_ctx_message, [:pointer, :pointer], :bool
860
+
861
+ # Get the HTTP message needed to fetch the AWS KMS master key from a
862
+ # KmsContext object.
863
+ #
864
+ # @param [ Mongo::Crypt::KmsContext ] kms_context
865
+ #
866
+ # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully
867
+ #
868
+ # @return [ String ] The HTTP message
869
+ def self.kms_ctx_message(kms_context)
870
+ binary = Binary.new
871
+
872
+ check_kms_ctx_status(kms_context) do
873
+ mongocrypt_kms_ctx_message(kms_context.kms_ctx_p, binary.ref)
874
+ end
875
+
876
+ return binary.to_s
877
+ end
878
+
879
+ # @!method self.mongocrypt_kms_ctx_endpoint(kms, endpoint)
880
+ # @api private
881
+ #
882
+ # Get the hostname with which to connect over TLS to get information about
883
+ # the AWS master key.
884
+ # @param [ FFI::Pointer ] kms A pointer to a mongocrypt_kms_ctx_t object.
885
+ # @param [ FFI::Pointer ] endpoint (out param) A pointer to which the
886
+ # endpoint string will be written by libmongocrypt.
887
+ # @return [ Boolean ] Whether the operation was successful.
888
+ attach_function :mongocrypt_kms_ctx_endpoint, [:pointer, :pointer], :bool
889
+
890
+ # Get the hostname with which to connect over TLS to get information
891
+ # about the AWS master key.
892
+ #
893
+ # @param [ Mongo::Crypt::KmsContext ] kms_context
894
+ #
895
+ # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully
896
+ #
897
+ # @return [ String | nil ] The hostname, or nil if none exists
898
+ def self.kms_ctx_endpoint(kms_context)
899
+ ptr = FFI::MemoryPointer.new(:pointer, 1)
900
+
901
+ check_kms_ctx_status(kms_context) do
902
+ mongocrypt_kms_ctx_endpoint(kms_context.kms_ctx_p, ptr)
903
+ end
904
+
905
+ str_ptr = ptr.read_pointer
906
+ str_ptr.null? ? nil : str_ptr.read_string.force_encoding('UTF-8')
907
+ end
908
+
909
+ # @!method self.mongocrypt_kms_ctx_bytes_needed(kms)
910
+ # @api private
911
+ #
912
+ # Get the number of bytes needed by the KMS context.
913
+ # @param [ FFI::Pointer ] kms The mongocrypt_kms_ctx_t object.
914
+ # @return [ Integer ] The number of bytes needed.
915
+ attach_function :mongocrypt_kms_ctx_bytes_needed, [:pointer], :int
916
+
917
+ # Get the number of bytes needed by the KmsContext.
918
+ #
919
+ # @param [ Mongo::Crypt::KmsContext ] kms_context
920
+ #
921
+ # @return [ Integer ] The number of bytes needed
922
+ def self.kms_ctx_bytes_needed(kms_context)
923
+ mongocrypt_kms_ctx_bytes_needed(kms_context.kms_ctx_p)
924
+ end
925
+
926
+ # @!method self.mongocrypt_kms_ctx_feed(kms, bytes)
927
+ # @api private
928
+ #
929
+ # Feed replies from the KMS back to libmongocrypt.
930
+ # @param [ FFI::Pointer ] kms A pointer to the mongocrypt_kms_ctx_t object.
931
+ # @param [ FFI::Pointer ] bytes A pointer to a mongocrypt_binary_t
932
+ # object that references the response from the KMS.
933
+ # @return [ Boolean ] Whether the operation was successful.
934
+ attach_function :mongocrypt_kms_ctx_feed, [:pointer, :pointer], :bool
935
+
936
+ # Feed replies from the KMS back to libmongocrypt.
937
+ #
938
+ # @param [ Mongo::Crypt::KmsContext ] kms_context
939
+ # @param [ String ] bytes The data to feed to libmongocrypt
940
+ #
941
+ # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully
942
+ def self.kms_ctx_feed(kms_context, bytes)
943
+ check_kms_ctx_status(kms_context) do
944
+ Binary.wrap_string(bytes) do |bytes_p|
945
+ mongocrypt_kms_ctx_feed(kms_context.kms_ctx_p, bytes_p)
946
+ end
947
+ end
948
+ end
949
+
950
+ # @!method self.mongocrypt_kms_ctx_status(kms, status)
951
+ # @api private
952
+ #
953
+ # Write status information about the mongocrypt_kms_ctx_t object
954
+ # to the mongocrypt_status_t object.
955
+ # @param [ FFI::Pointer ] kms A pointer to the mongocrypt_kms_ctx_t object.
956
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object.
957
+ # @return [ Boolean ] Whether the operation was successful.
958
+ attach_function :mongocrypt_kms_ctx_status, [:pointer, :pointer], :bool
959
+
960
+ # If the provided block returns false, raise a CryptError with the
961
+ # status information from the provided KmsContext object.
962
+ #
963
+ # @param [ Mongo::Crypt::KmsContext ] kms_context
964
+ #
965
+ # @raise [ Mongo::Error::CryptError ] If the provided block returns false
966
+ def self.check_kms_ctx_status(kms_context)
967
+ unless yield
968
+ status = Status.new
969
+
970
+ mongocrypt_kms_ctx_status(kms_context.kms_ctx_p, status.ref)
971
+ status.raise_crypt_error
972
+ end
973
+ end
974
+
975
+ # @!method self.mongocrypt_kms_ctx_done(ctx)
976
+ # @api private
977
+ #
978
+ # Indicate to libmongocrypt that it will receive no more replies from
979
+ # mongocrypt_kms_ctx_t objects.
980
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
981
+ # @return [ Boolean ] Whether the operation was successful.
982
+ attach_function :mongocrypt_ctx_kms_done, [:pointer], :bool
983
+
984
+ # Indicate to libmongocrypt that it will receive no more KMS replies.
985
+ #
986
+ # @param [ Mongo::Crypt::Context ] context
987
+ #
988
+ # @raise [ Mongo::Error::CryptError ] If the operation is unsuccessful
989
+ def self.ctx_kms_done(context)
990
+ check_ctx_status(context) do
991
+ mongocrypt_ctx_kms_done(context.ctx_p)
992
+ end
993
+ end
994
+
995
+ # @!method self.mongocrypt_ctx_finalize(ctx, op_bson)
996
+ # @api private
997
+ #
998
+ # Perform the final encryption or decryption and return a BSON document.
999
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
1000
+ # @param [ FFI::Pointer ] op_bson (out param) A pointer to a
1001
+ # mongocrypt_binary_t object that will have a reference to the
1002
+ # final encrypted BSON document.
1003
+ # @return [ Boolean ] A boolean indicating the success of the operation.
1004
+ attach_function :mongocrypt_ctx_finalize, [:pointer, :pointer], :void
1005
+
1006
+ # Finalize the state machine represented by the Context
1007
+ #
1008
+ # @param [ Mongo::Crypt::Context ] context
1009
+ #
1010
+ # @raise [ Mongo::Error::CryptError ] If the state machine is not successfully
1011
+ # finalized
1012
+ def self.ctx_finalize(context)
1013
+ binary = Binary.new
1014
+
1015
+ check_ctx_status(context) do
1016
+ mongocrypt_ctx_finalize(context.ctx_p, binary.ref)
1017
+ end
1018
+
1019
+ # TODO since the binary references a C pointer, and ByteBuffer is
1020
+ # written in C in MRI, we could omit a copy of the data by making
1021
+ # ByteBuffer reference the string that is owned by libmongocrypt.
1022
+ BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson)
1023
+ end
1024
+
1025
+ # @!method self.mongocrypt_ctx_destroy(ctx)
1026
+ # @api private
1027
+ #
1028
+ # Destroy the reference to the mongocrypt_ctx_t object.
1029
+ # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object.
1030
+ # @return [ nil ] Always nil.
1031
+ attach_function :mongocrypt_ctx_destroy, [:pointer], :void
1032
+
1033
+ # @!method mongocrypt_crypto_fn(ctx, key, iv, input, output, status)
1034
+ # @api private
1035
+ #
1036
+ # A callback to a function that performs AES encryption or decryption.
1037
+ # @param [ FFI::Pointer | nil] ctx An optional pointer to a context object
1038
+ # that may have been set when hooks were enabled.
1039
+ # @param [ FFI::Pointer ] key A pointer to a mongocrypt_binary_t object
1040
+ # that references the 32-byte AES encryption key.
1041
+ # @param [ FFI::Pointer ] iv A pointer to a mongocrypt_binary_t object
1042
+ # that references the 16-byte AES IV.
1043
+ # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object
1044
+ # that references the value to be encrypted/decrypted.
1045
+ # @param [ FFI::Pointer ] output (out param) A pointer to a
1046
+ # mongocrypt_binary_t object will have a reference to the encrypted/
1047
+ # decrypted value written to it by libmongocrypt.
1048
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t
1049
+ # object to which an error message will be written if encryption fails.
1050
+ # @return [ Bool ] Whether encryption/decryption was successful.
1051
+ #
1052
+ # @note This defines a method signature for an FFI callback; it is not
1053
+ # an instance method on the Binding class.
1054
+ callback(
1055
+ :mongocrypt_crypto_fn,
1056
+ [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer],
1057
+ :bool
1058
+ )
1059
+
1060
+ # @!method mongocrypt_hmac_fn(ctx, key, input, output, status)
1061
+ # @api private
1062
+ #
1063
+ # A callback to a function that performs HMAC SHA-512 or SHA-256.
1064
+ # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object
1065
+ # that may have been set when hooks were enabled.
1066
+ # @param [ FFI::Pointer ] key A pointer to a mongocrypt_binary_t object
1067
+ # that references the 32-byte HMAC SHA encryption key.
1068
+ # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object
1069
+ # that references the input value.
1070
+ # @param [ FFI::Pointer ] output (out param) A pointer to a
1071
+ # mongocrypt_binary_t object will have a reference to the output value
1072
+ # written to it by libmongocrypt.
1073
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t
1074
+ # object to which an error message will be written if encryption fails.
1075
+ # @return [ Bool ] Whether HMAC-SHA was successful.
1076
+ #
1077
+ # @note This defines a method signature for an FFI callback; it is not
1078
+ # an instance method on the Binding class.
1079
+ callback(
1080
+ :mongocrypt_hmac_fn,
1081
+ [:pointer, :pointer, :pointer, :pointer, :pointer],
1082
+ :bool
1083
+ )
1084
+
1085
+ # @!method mongocrypt_hash_fn(ctx, input, output, status)
1086
+ # @api private
1087
+ #
1088
+ # A callback to a SHA-256 hash function.
1089
+ # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object
1090
+ # that may have been set when hooks were enabled.
1091
+ # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object
1092
+ # that references the value to be hashed.
1093
+ # @param [ FFI::Pointer ] output (out param) A pointer to a
1094
+ # mongocrypt_binary_t object will have a reference to the output value
1095
+ # written to it by libmongocrypt.
1096
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t
1097
+ # object to which an error message will be written if encryption fails.
1098
+ # @return [ Bool ] Whether hashing was successful.
1099
+ #
1100
+ # @note This defines a method signature for an FFI callback; it is not
1101
+ # an instance method on the Binding class.
1102
+ callback :mongocrypt_hash_fn, [:pointer, :pointer, :pointer, :pointer], :bool
1103
+
1104
+ # @!method mongocrypt_random_fn(ctx, output, count, status)
1105
+ # @api private
1106
+ #
1107
+ # A callback to a crypto secure random function.
1108
+ # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object
1109
+ # that may have been set when hooks were enabled.
1110
+ # @param [ FFI::Pointer ] output (out param) A pointer to a
1111
+ # mongocrypt_binary_t object will have a reference to the output value
1112
+ # written to it by libmongocrypt.
1113
+ # @param [ Integer ] count The number of random bytes to return.
1114
+ # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t
1115
+ # object to which an error message will be written if encryption fails.
1116
+ # @return [ Bool ] Whether hashing was successful.
1117
+ #
1118
+ # @note This defines a method signature for an FFI callback; it is not
1119
+ # an instance method on the Binding class.
1120
+ callback :mongocrypt_random_fn, [:pointer, :pointer, :int, :pointer], :bool
1121
+
1122
+ # @!method self.mongocrypt_setopt_crypto_hooks(crypt, aes_enc_fn, aes_dec_fn, random_fn, sha_512_fn, sha_256_fn, hash_fn, ctx=nil)
1123
+ # @api private
1124
+ #
1125
+ # Set crypto hooks on the provided mongocrypt object.
1126
+ # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
1127
+ # @param [ Proc ] aes_enc_fn An AES encryption method.
1128
+ # @param [ Proc ] aes_dec_fn An AES decryption method.
1129
+ # @param [ Proc ] random_fn A random method.
1130
+ # @param [ Proc ] sha_512_fn A HMAC SHA-512 method.
1131
+ # @param [ Proc ] sha_256_fn A HMAC SHA-256 method.
1132
+ # @param [ Proc ] hash_fn A SHA-256 hash method.
1133
+ # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object
1134
+ # that may have been set when hooks were enabled.
1135
+ # @return [ Boolean ] Whether setting this option succeeded.
1136
+ attach_function(
1137
+ :mongocrypt_setopt_crypto_hooks,
1138
+ [
1139
+ :pointer,
1140
+ :mongocrypt_crypto_fn,
1141
+ :mongocrypt_crypto_fn,
1142
+ :mongocrypt_random_fn,
1143
+ :mongocrypt_hmac_fn,
1144
+ :mongocrypt_hmac_fn,
1145
+ :mongocrypt_hash_fn,
1146
+ :pointer
1147
+ ],
1148
+ :bool
1149
+ )
1150
+
1151
+ # Set crypto callbacks on the Handle
1152
+ #
1153
+ # @param [ Mongo::Crypt::Handle ] handle
1154
+ # @param [ Method ] aes_encrypt_cb An AES encryption method
1155
+ # @param [ Method ] aes_decrypt_cb A AES decryption method
1156
+ # @param [ Method ] random_cb A method that returns a string of random bytes
1157
+ # @param [ Method ] hmac_sha_512_cb A HMAC SHA-512 method
1158
+ # @param [ Method ] hmac_sha_256_cb A HMAC SHA-256 method
1159
+ # @param [ Method ] hmac_hash_cb A SHA-256 hash method
1160
+ #
1161
+ # @raise [ Mongo::Error::CryptError ] If the callbacks aren't set successfully
1162
+ def self.setopt_crypto_hooks(handle,
1163
+ aes_encrypt_cb, aes_decrypt_cb, random_cb,
1164
+ hmac_sha_512_cb, hmac_sha_256_cb, hmac_hash_cb
1165
+ )
1166
+ check_status(handle) do
1167
+ mongocrypt_setopt_crypto_hooks(handle.ref,
1168
+ aes_encrypt_cb, aes_decrypt_cb, random_cb,
1169
+ hmac_sha_512_cb, hmac_sha_256_cb, hmac_hash_cb, nil
1170
+ )
1171
+ end
1172
+ end
1173
+
1174
+ # Raise a Mongo::Error::CryptError based on the status of the underlying
1175
+ # mongocrypt_t object.
1176
+ #
1177
+ # @return [ nil ] Always nil.
1178
+ def self.check_status(handle)
1179
+ unless yield
1180
+ status = Status.new
1181
+
1182
+ mongocrypt_status(handle.ref, status.ref)
1183
+ status.raise_crypt_error
1184
+ end
1185
+ end
1186
+
1187
+ # Raise a Mongo::Error::CryptError based on the status of the underlying
1188
+ # mongocrypt_ctx_t object.
1189
+ #
1190
+ # @return [ nil ] Always nil.
1191
+ def self.check_ctx_status(context)
1192
+ if block_given?
1193
+ do_raise = !yield
1194
+ else
1195
+ do_raise = true
1196
+ end
1197
+
1198
+ if do_raise
1199
+ status = Status.new
1200
+
1201
+ mongocrypt_ctx_status(context.ctx_p, status.ref)
1202
+ status.raise_crypt_error
1203
+ end
1204
+ end
1205
+
1206
+ # Checks that the specified data is a Hash before serializing
1207
+ # it to BSON to prevent errors from libmongocrypt
1208
+ #
1209
+ # @note All BSON::Document instances are also Hash instances
1210
+ #
1211
+ # @param [ Object ] data The data to be passed to libmongocrypt
1212
+ #
1213
+ # @raise [ Mongo::Error::CryptError ] If the data is not a Hash
1214
+ def self.validate_document(data)
1215
+ return if data.is_a?(Hash)
1216
+
1217
+ if data.nil?
1218
+ message = "Attempted to pass nil data to libmongocrypt. " +
1219
+ "Data must be a Hash"
1220
+ else
1221
+ message = "Attempted to pass invalid data to libmongocrypt: #{data} " +
1222
+ "Data must be a Hash"
1223
+ end
1224
+
1225
+ raise Error::CryptError.new(message)
1226
+ end
1227
+ end
1228
+ end
1229
+ end