1
1
# frozen_string_literal: true
2
- # rubocop:todo all
3
2
4
3
# Copyright (C) 2014-2022 MongoDB Inc.
5
4
#
@@ -22,6 +21,8 @@ class Collection
22
21
#
23
22
# @api private
24
23
module QueryableEncryption
24
+ # The minimum wire version for QE2 support
25
+ QE2_MIN_WIRE_VERSION = 21
25
26
26
27
# Creates auxiliary collections and indices for queryable encryption if necessary.
27
28
#
@@ -32,32 +33,17 @@ module QueryableEncryption
32
33
#
33
34
# @return [ Result ] The result of provided block.
34
35
def maybe_create_qe_collections ( encrypted_fields , client , session )
35
- encrypted_fields = if encrypted_fields
36
- encrypted_fields
37
- elsif encrypted_fields_map
38
- encrypted_fields_map [ namespace ] || { }
39
- else
40
- { }
41
- end
42
- if encrypted_fields . empty?
43
- return yield
44
- end
36
+ encrypted_fields = encrypted_fields_from ( encrypted_fields )
37
+ return yield if encrypted_fields . empty?
38
+
39
+ check_wire_version!
45
40
46
41
emm_collections ( encrypted_fields ) . each do |coll |
47
42
context = Operation ::Context . new ( client : client , session : session )
48
- Operation ::Create . new (
49
- selector : {
50
- create : coll ,
51
- clusteredIndex : {
52
- key : {
53
- _id : 1
54
- } ,
55
- unique : true
56
- }
57
- } ,
58
- db_name : database . name ,
59
- ) . execute ( next_primary ( nil , session ) , context : context )
43
+ create_operation_for ( coll )
44
+ . execute ( next_primary ( nil , session ) , context : context )
60
45
end
46
+
61
47
yield ( encrypted_fields ) . tap do |result |
62
48
indexes . create_one ( __safeContent__ : 1 ) if result
63
49
end
@@ -73,31 +59,25 @@ def maybe_create_qe_collections(encrypted_fields, client, session)
73
59
# @return [ Result ] The result of provided block.
74
60
def maybe_drop_emm_collections ( encrypted_fields , client , session )
75
61
encrypted_fields = if encrypted_fields
76
- encrypted_fields
77
- elsif encrypted_fields_map
78
- if encrypted_fields_map [ namespace ]
79
- encrypted_fields_map [ namespace ]
80
- else
81
- database . list_collections ( filter : { name : name } )
82
- . first
83
- &.fetch ( :options , { } )
84
- &.fetch ( :encryptedFields , { } ) || { }
85
- end
86
- else
87
- { }
88
- end
89
- if encrypted_fields . empty?
90
- return yield
91
- end
62
+ encrypted_fields
63
+ elsif encrypted_fields_map
64
+ encrypted_fields_for_drop_from_map
65
+ else
66
+ { }
67
+ end
68
+
69
+ return yield if encrypted_fields . empty?
70
+
92
71
emm_collections ( encrypted_fields ) . each do |coll |
93
72
context = Operation ::Context . new ( client : client , session : session )
94
73
operation = Operation ::Drop . new (
95
74
selector : { drop : coll } ,
96
75
db_name : database . name ,
97
- session : session ,
76
+ session : session
98
77
)
99
78
do_drop ( operation , session , context )
100
79
end
80
+
101
81
yield
102
82
end
103
83
@@ -112,11 +92,66 @@ def maybe_drop_emm_collections(encrypted_fields, client, session)
112
92
def emm_collections ( encrypted_fields )
113
93
[
114
94
encrypted_fields [ 'escCollection' ] || "enxcol_.#{ name } .esc" ,
115
- encrypted_fields [ 'eccCollection' ] || "enxcol_.#{ name } .ecc" ,
116
95
encrypted_fields [ 'ecocCollection' ] || "enxcol_.#{ name } .ecoc" ,
117
96
]
118
97
end
119
98
99
+ # Creating encrypted collections is only supported on 7.0.0 and later
100
+ # (wire version 21+).
101
+ #
102
+ # @raise [ Mongo::Error ] if the wire version is not
103
+ # recent enough
104
+ def check_wire_version!
105
+ return unless next_primary . max_wire_version < QE2_MIN_WIRE_VERSION
106
+
107
+ raise Mongo ::Error ,
108
+ 'Driver support of Queryable Encryption is incompatible with server. ' \
109
+ 'Upgrade server to use Queryable Encryption.'
110
+ end
111
+
112
+ # Tries to return the encrypted fields from the argument. If the argument
113
+ # is nil, tries to find the encrypted fields from the
114
+ # encrypted_fields_map.
115
+ #
116
+ # @param [ Hash | nil ] fields the encrypted fields
117
+ #
118
+ # @return [ Hash ] the encrypted fields
119
+ def encrypted_fields_from ( fields )
120
+ fields ||
121
+ ( encrypted_fields_map && encrypted_fields_map [ namespace ] ) ||
122
+ { }
123
+ end
124
+
125
+ # Tries to return the encrypted fields from the {{encrypted_fields_map}}
126
+ # value, for the current namespace.
127
+ #
128
+ # @return [ Hash | nil ] the encrypted fields, if found
129
+ def encrypted_fields_for_drop_from_map
130
+ encrypted_fields_map [ namespace ] ||
131
+ database . list_collections ( filter : { name : name } )
132
+ . first
133
+ &.fetch ( :options , { } )
134
+ &.fetch ( :encryptedFields , { } ) ||
135
+ { }
136
+ end
137
+
138
+ # Returns a new create operation for the given collection.
139
+ #
140
+ # @param [ String ] coll the name of the collection to create.
141
+ #
142
+ # @return [ Operation::Create ] the new create operation.
143
+ def create_operation_for ( coll )
144
+ Operation ::Create . new (
145
+ selector : {
146
+ create : coll ,
147
+ clusteredIndex : {
148
+ key : { _id : 1 } ,
149
+ unique : true
150
+ }
151
+ } ,
152
+ db_name : database . name
153
+ )
154
+ end
120
155
end
121
156
end
122
157
end
0 commit comments