symmetric-encryption 4.1.0.beta1 → 4.1.0

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/symmetric_encryption/cipher.rb +9 -2
  3. data/lib/symmetric_encryption/cli.rb +13 -6
  4. data/lib/symmetric_encryption/config.rb +9 -6
  5. data/lib/symmetric_encryption/encoder.rb +6 -0
  6. data/lib/symmetric_encryption/extensions/mongoid/encrypted.rb +1 -0
  7. data/lib/symmetric_encryption/generator.rb +1 -1
  8. data/lib/symmetric_encryption/header.rb +7 -5
  9. data/lib/symmetric_encryption/key.rb +2 -0
  10. data/lib/symmetric_encryption/keystore/aws.rb +9 -9
  11. data/lib/symmetric_encryption/keystore/environment.rb +3 -2
  12. data/lib/symmetric_encryption/keystore/file.rb +1 -1
  13. data/lib/symmetric_encryption/keystore/memory.rb +1 -1
  14. data/lib/symmetric_encryption/keystore.rb +15 -16
  15. data/lib/symmetric_encryption/railtie.rb +7 -2
  16. data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -0
  17. data/lib/symmetric_encryption/reader.rb +50 -58
  18. data/lib/symmetric_encryption/symmetric_encryption.rb +2 -1
  19. data/lib/symmetric_encryption/utils/aws.rb +6 -4
  20. data/lib/symmetric_encryption/utils/re_encrypt_files.rb +2 -2
  21. data/lib/symmetric_encryption/version.rb +1 -1
  22. data/lib/symmetric_encryption/writer.rb +33 -27
  23. data/lib/symmetric_encryption.rb +26 -5
  24. data/test/active_record_test.rb +25 -25
  25. data/test/cipher_test.rb +3 -3
  26. data/test/header_test.rb +1 -1
  27. data/test/keystore/aws_test.rb +7 -7
  28. data/test/keystore/file_test.rb +1 -1
  29. data/test/keystore_test.rb +2 -2
  30. data/test/mongoid_test.rb +15 -15
  31. data/test/reader_test.rb +28 -8
  32. data/test/symmetric_encryption_test.rb +2 -2
  33. data/test/test_db.sqlite3 +0 -0
  34. data/test/utils/aws_test.rb +1 -2
  35. data/test/writer_test.rb +48 -46
  36. metadata +23 -23
@@ -29,8 +29,13 @@ module SymmetricEncryption #:nodoc:
29
29
  config.before_configuration do
30
30
  # Check if already configured
31
31
  unless ::SymmetricEncryption.cipher?
32
- app_name = Rails::Application.subclasses.first.parent.to_s.underscore
33
- config_file = Rails.root.join('config', 'symmetric-encryption.yml')
32
+ app_name = Rails::Application.subclasses.first.parent.to_s.underscore
33
+ config_file =
34
+ if (env_var = ENV['SYMMETRIC_ENCRYPTION_CONFIG'])
35
+ Pathname.new File.expand_path(env_var)
36
+ else
37
+ Rails.root.join('config', 'symmetric-encryption.yml')
38
+ end
34
39
  if config_file.file?
35
40
  begin
36
41
  ::SymmetricEncryption::Config.load!(file_name: config_file, env: ENV['SYMMETRIC_ENCRYPTION_ENV'] || Rails.env)
@@ -14,6 +14,7 @@
14
14
  class SymmetricEncryptionValidator < ActiveModel::EachValidator
15
15
  def validate_each(record, attribute, value)
16
16
  return if value.blank? || SymmetricEncryption.encrypted?(value)
17
+
17
18
  record.errors.add(attribute, 'must be a value encrypted using SymmetricEncryption.encrypt')
18
19
  end
19
20
  end
@@ -76,7 +76,7 @@ module SymmetricEncryption
76
76
  # Notes:
77
77
  # * Do not use this method for reading large files.
78
78
  def self.read(file_name_or_stream, **args)
79
- self.open(file_name_or_stream, **args, &:read)
79
+ Reader.open(file_name_or_stream, **args, &:read)
80
80
  end
81
81
 
82
82
  # Decrypt an entire file.
@@ -90,22 +90,10 @@ module SymmetricEncryption
90
90
  # target: [String|IO]
91
91
  # Target file_name or IOStream
92
92
  #
93
- # block_size: [Integer]
94
- # Number of bytes to read into memory for each read.
95
- # For very large files using a larger block size is faster.
96
- # Default: 65535
97
- #
98
93
  # Notes:
99
94
  # * The file contents are streamed so that the entire file is _not_ loaded into memory.
100
- def self.decrypt(source:, target:, block_size: 65_535, **args)
101
- target_ios = target.is_a?(String) ? ::File.open(target, 'wb') : target
102
- bytes_written = 0
103
- self.open(source, **args) do |input_ios|
104
- bytes_written += target_ios.write(input_ios.read(block_size)) until input_ios.eof?
105
- end
106
- bytes_written
107
- ensure
108
- target_ios.close if target_ios&.respond_to?(:closed?) && !target_ios.closed?
95
+ def self.decrypt(source:, target:, **args)
96
+ Reader.open(source, **args) { |input_file| IO.copy_stream(input_file, target) }
109
97
  end
110
98
 
111
99
  # Returns [true|false] whether the file or stream contains any data
@@ -132,6 +120,7 @@ module SymmetricEncryption
132
120
  @version = version
133
121
  @header_present = false
134
122
  @closed = false
123
+ @read_buffer = ''.b
135
124
 
136
125
  raise(ArgumentError, 'Buffer size cannot be smaller than 128') unless @buffer_size >= 128
137
126
 
@@ -170,6 +159,7 @@ module SymmetricEncryption
170
159
  # ensure that the encrypted stream is closed before the stream itself is closed
171
160
  def close(close_child_stream = true)
172
161
  return if closed?
162
+
173
163
  @ios.close if close_child_stream
174
164
  @closed = true
175
165
  end
@@ -194,35 +184,25 @@ module SymmetricEncryption
194
184
  #
195
185
  # At end of file, it returns nil if no more data is available, or the last
196
186
  # remaining bytes
197
- def read(length = nil)
198
- data = nil
199
- if length
200
- return '' if length.zero?
201
- return nil if eof?
202
- # Read length bytes
203
- read_block while (@read_buffer.length < length) && !@ios.eof?
204
- if @read_buffer.empty?
205
- data = nil
206
- elsif @read_buffer.length > length
207
- data = @read_buffer.slice!(0..length - 1)
187
+ def read(length = nil, outbuf = nil)
188
+ data = outbuf.to_s.clear
189
+ remaining_length = length
190
+
191
+ until remaining_length == 0 || eof?
192
+ read_block(remaining_length) if @read_buffer.empty?
193
+
194
+ if remaining_length && remaining_length < @read_buffer.length
195
+ data << @read_buffer.slice!(0, remaining_length)
208
196
  else
209
- data = @read_buffer
210
- @read_buffer = ''
211
- end
212
- else
213
- # Capture anything already in the buffer
214
- data = @read_buffer
215
- @read_buffer = ''
216
-
217
- unless @ios.eof?
218
- # Read entire file
219
- buf = @ios.read || ''
220
- data << @stream_cipher.update(buf) if buf && !buf.empty?
221
- data << @stream_cipher.final
197
+ data << @read_buffer
198
+ @read_buffer.clear
222
199
  end
200
+
201
+ remaining_length = length - data.length if length
223
202
  end
203
+
224
204
  @pos += data.length
225
- data
205
+ data unless data.empty? && length && length.positive?
226
206
  end
227
207
 
228
208
  # Reads a single decrypted line from the file up to and including the optional sep_string.
@@ -242,12 +222,14 @@ module SymmetricEncryption
242
222
  # Read more data until we get the sep_string
243
223
  while (index = @read_buffer.index(sep_string)).nil? && !@ios.eof?
244
224
  break if length && @read_buffer.length >= length
225
+
245
226
  read_block
246
227
  end
247
228
  index ||= -1
248
- data = @read_buffer.slice!(0..index)
249
- @pos += data.length
229
+ data = @read_buffer.slice!(0..index)
230
+ @pos += data.length
250
231
  return nil if data.empty? && eof?
232
+
251
233
  data
252
234
  end
253
235
 
@@ -272,7 +254,7 @@ module SymmetricEncryption
272
254
 
273
255
  # Rewind back to the beginning of the file
274
256
  def rewind
275
- @read_buffer = ''
257
+ @read_buffer.clear
276
258
  @ios.rewind
277
259
  read_header
278
260
  end
@@ -307,10 +289,10 @@ module SymmetricEncryption
307
289
  # Read and decrypt entire file a block at a time to get its total
308
290
  # unencrypted size
309
291
  size = 0
310
- until eof
292
+ until eof?
311
293
  read_block
312
- size += @read_buffer.size
313
- @read_buffer = ''
294
+ size += @read_buffer.size
295
+ @read_buffer.clear
314
296
  end
315
297
  rewind
316
298
  offset = size + amount
@@ -328,7 +310,7 @@ module SymmetricEncryption
328
310
  @pos = 0
329
311
 
330
312
  # Read first block and check for the header
331
- buf = @ios.read(@buffer_size)
313
+ buf = @ios.read(@buffer_size, @output_buffer ||= ''.b)
332
314
 
333
315
  # Use cipher specified in header, or global cipher if it has no header
334
316
  iv, key, cipher_name, cipher = nil
@@ -353,20 +335,30 @@ module SymmetricEncryption
353
335
  @stream_cipher.key = key || cipher.send(:key)
354
336
  @stream_cipher.iv = iv || cipher.iv
355
337
 
356
- # First call to #update should return an empty string anyway
357
- if buf && !buf.empty?
358
- @read_buffer = @stream_cipher.update(buf)
359
- @read_buffer << @stream_cipher.final if @ios.eof?
360
- else
361
- @read_buffer = ''
362
- end
338
+ decrypt(buf)
363
339
  end
364
340
 
365
341
  # Read a block of data and append the decrypted data in the read buffer
366
- def read_block
367
- buf = @ios.read(@buffer_size)
368
- @read_buffer << @stream_cipher.update(buf) if buf && !buf.empty?
369
- @read_buffer << @stream_cipher.final if @ios.eof?
342
+ def read_block(length = nil)
343
+ buf = @ios.read(length || @buffer_size, @output_buffer ||= ''.b)
344
+ decrypt(buf)
345
+ end
346
+
347
+ # Decrypts the given chunk of data and returns the result
348
+ if defined?(JRuby)
349
+ def decrypt(buf)
350
+ return if buf.nil? || buf.empty?
351
+
352
+ @read_buffer << @stream_cipher.update(buf)
353
+ @read_buffer << @stream_cipher.final if @ios.eof?
354
+ end
355
+ else
356
+ def decrypt(buf)
357
+ return if buf.nil? || buf.empty?
358
+
359
+ @read_buffer << @stream_cipher.update(buf, @cipher_buffer ||= ''.b)
360
+ @read_buffer << @stream_cipher.final if @ios.eof?
361
+ end
370
362
  end
371
363
 
372
364
  def closed?
@@ -55,6 +55,7 @@ module SymmetricEncryption
55
55
  end
56
56
 
57
57
  return @@cipher if version.nil? || (@@cipher.version == version)
58
+
58
59
  secondary_ciphers.find { |c| c.version == version } || (@@cipher if version.zero?)
59
60
  end
60
61
 
@@ -264,7 +265,7 @@ module SymmetricEncryption
264
265
  # encoded_str.end_with?("\n") ? SymmetricEncryption.cipher(0) : SymmetricEncryption.cipher
265
266
  # end
266
267
  def self.select_cipher(&block)
267
- @@select_cipher = block ? block : nil
268
+ @@select_cipher = block || nil
268
269
  end
269
270
 
270
271
  # Load the Encryption Configuration from a YAML file
@@ -15,7 +15,7 @@ module SymmetricEncryption
15
15
  AWS_KEY_SPEC_MAP = {
16
16
  'aes-256-cbc' => 'AES_256',
17
17
  'aes-128-cbc' => 'AES_128'
18
- }
18
+ }.freeze
19
19
 
20
20
  # TODO: Move to Keystore::Aws
21
21
  # Rotate the Customer Master key in each of the supplied regions.
@@ -68,6 +68,7 @@ module SymmetricEncryption
68
68
  def key_spec(cipher_name)
69
69
  key_spec = AWS_KEY_SPEC_MAP[cipher_name]
70
70
  raise("OpenSSL Cipher: #{cipher_name} has not yet been mapped to an AWS key spec.") unless key_spec
71
+
71
72
  key_spec
72
73
  end
73
74
 
@@ -112,9 +113,9 @@ module SymmetricEncryption
112
113
  resp = client.create_key(
113
114
  description: 'Symmetric Encryption for Ruby Customer Masker Key',
114
115
  tags: [
115
- {tag_key: 'CreatedAt', tag_value: Time.now.to_s},
116
- {tag_key: 'CreatedBy', tag_value: whoami}
117
- ]
116
+ {tag_key: 'CreatedAt', tag_value: Time.now.to_s},
117
+ {tag_key: 'CreatedBy', tag_value: whoami}
118
+ ]
118
119
  )
119
120
  resp.key_metadata.key_id
120
121
  end
@@ -130,6 +131,7 @@ module SymmetricEncryption
130
131
  yield
131
132
  rescue ::Aws::KMS::Errors::NotFoundException
132
133
  raise if attempt >= 2
134
+
133
135
  create_master_key
134
136
  attempt += 1
135
137
  retry
@@ -68,8 +68,8 @@ module SymmetricEncryption
68
68
  line.force_encoding(SymmetricEncryption::UTF8_ENCODING)
69
69
  output_lines <<
70
70
  if line.valid_encoding? && (result = line.match(r))
71
- encrypted = result[0]
72
- new_value = re_encrypt(encrypted)
71
+ encrypted = result[0]
72
+ new_value = re_encrypt(encrypted)
73
73
  if new_value != encrypted
74
74
  hits += 1
75
75
  line.gsub(encrypted, new_value)
@@ -1,3 +1,3 @@
1
1
  module SymmetricEncryption
2
- VERSION = '4.1.0.beta1'.freeze
2
+ VERSION = '4.1.0'.freeze
3
3
  end
@@ -21,7 +21,7 @@ module SymmetricEncryption
21
21
  # compress: [true|false]
22
22
  # Uses Zlib to compress the data before it is encrypted and
23
23
  # written to the file/stream.
24
- # Default: false
24
+ # Default: true, unless the file_name extension indicates it is already compressed.
25
25
  #
26
26
  # Note: Compression occurs before encryption
27
27
  #
@@ -47,11 +47,16 @@ module SymmetricEncryption
47
47
  # ensure
48
48
  # csv.close if csv
49
49
  # end
50
- def self.open(file_name_or_stream, compress: false, **args)
51
- ios = file_name_or_stream.is_a?(String) ? ::File.open(file_name_or_stream, 'wb') : file_name_or_stream
50
+ def self.open(file_name_or_stream, compress: nil, **args)
51
+ if file_name_or_stream.is_a?(String)
52
+ file_name_or_stream = ::File.open(file_name_or_stream, 'wb')
53
+ compress = !(/\.(zip|gz|gzip|xls.|)\z/i === file_name_or_stream) if compress.nil?
54
+ else
55
+ compress = true if compress.nil?
56
+ end
52
57
 
53
58
  begin
54
- file = new(ios, compress: compress, **args)
59
+ file = new(file_name_or_stream, compress: compress, **args)
55
60
  file = Zlib::GzipWriter.new(file) if compress
56
61
  block_given? ? yield(file) : file
57
62
  ensure
@@ -64,7 +69,7 @@ module SymmetricEncryption
64
69
  # Notes:
65
70
  # * Do not use this method for writing large files.
66
71
  def self.write(file_name_or_stream, data, **args)
67
- self.open(file_name_or_stream, **args) { |f| f.write(data) }
72
+ Writer.open(file_name_or_stream, **args) { |f| f.write(data) }
68
73
  end
69
74
 
70
75
  # Encrypt an entire file.
@@ -82,22 +87,10 @@ module SymmetricEncryption
82
87
  # Whether to compress the target file prior to encryption.
83
88
  # Default: false
84
89
  #
85
- # block_size: [Integer]
86
- # Number of bytes to read into memory for each read.
87
- # For very large files using a larger block size is faster.
88
- # Default: 65535
89
- #
90
90
  # Notes:
91
91
  # * The file contents are streamed so that the entire file is _not_ loaded into memory.
92
- def self.encrypt(source:, target:, block_size: 65_535, **args)
93
- source_ios = source.is_a?(String) ? ::File.open(source, 'rb') : source
94
- bytes_written = 0
95
- self.open(target, **args) do |output_file|
96
- bytes_written += output_file.write(source_ios.read(block_size)) until source_ios.eof?
97
- end
98
- bytes_written
99
- ensure
100
- source_ios.close if source_ios&.respond_to?(:closed?) && !source_ios.closed?
92
+ def self.encrypt(source:, target:, **args)
93
+ Writer.open(target, **args) { |output_file| IO.copy_stream(source, output_file) }
101
94
  end
102
95
 
103
96
  # Encrypt data before writing to the supplied stream
@@ -149,6 +142,7 @@ module SymmetricEncryption
149
142
  # ensure that the encrypted stream is closed before the stream itself is closed.
150
143
  def close(close_child_stream = true)
151
144
  return if closed?
145
+
152
146
  if size.positive?
153
147
  final = @stream_cipher.final
154
148
  @ios.write(final) unless final.empty?
@@ -160,14 +154,26 @@ module SymmetricEncryption
160
154
  # Write to the IO Stream as encrypted data.
161
155
  #
162
156
  # Returns [Integer] the number of bytes written.
163
- def write(data)
164
- return unless data
165
-
166
- bytes = data.to_s
167
- @size += bytes.size
168
- partial = @stream_cipher.update(bytes)
169
- @ios.write(partial) unless partial.empty?
170
- data.length
157
+ if defined?(JRuby)
158
+ def write(data)
159
+ return unless data
160
+
161
+ bytes = data.to_s
162
+ @size += bytes.size
163
+ partial = @stream_cipher.update(bytes)
164
+ @ios.write(partial) unless partial.empty?
165
+ data.length
166
+ end
167
+ else
168
+ def write(data)
169
+ return unless data
170
+
171
+ bytes = data.to_s
172
+ @size += bytes.size
173
+ partial = @stream_cipher.update(bytes, @cipher_buffer ||= ''.b)
174
+ @ios.write(partial) unless partial.empty?
175
+ data.length
176
+ end
171
177
  end
172
178
 
173
179
  # Write to the IO Stream as encrypted data.
@@ -29,12 +29,33 @@ end
29
29
  # @formatter:on
30
30
 
31
31
  # Add support for other libraries only if they have already been loaded
32
- require 'symmetric_encryption/railtie' if defined?(Rails)
33
- if defined?(ActiveRecord::Base) && !defined?(AttrEncrypted::Version)
34
- require 'symmetric_encryption/extensions/active_record/base'
32
+
33
+ begin
34
+ require 'rails/railtie'
35
+ require 'symmetric_encryption/railtie' if defined?(Rails)
36
+ rescue LoadError
35
37
  end
36
- require 'symmetric_encryption/railties/symmetric_encryption_validator' if defined?(ActiveModel)
37
- require 'symmetric_encryption/extensions/mongoid/encrypted' if defined?(Mongoid)
38
+
39
+ begin
40
+ require 'active_record'
41
+ if defined?(ActiveRecord::Base) && !defined?(AttrEncrypted::Version)
42
+ require 'symmetric_encryption/extensions/active_record/base'
43
+ end
44
+ rescue LoadError
45
+ end
46
+
47
+ begin
48
+ require 'active_model'
49
+ require 'symmetric_encryption/railties/symmetric_encryption_validator' if defined?(ActiveModel)
50
+ rescue LoadError
51
+ end
52
+
53
+ begin
54
+ require 'mongoid'
55
+ require 'symmetric_encryption/extensions/mongoid/encrypted' if defined?(Mongoid)
56
+ rescue LoadError
57
+ end
58
+
38
59
  if defined?(MongoMapper)
39
60
  warn 'MongoMapper support is deprecated. Upgrade to Mongoid.'
40
61
  require 'symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key'
@@ -119,26 +119,26 @@ class ActiveRecordTest < Minitest::Test
119
119
  let :user do
120
120
  User.new(
121
121
  # Encrypted Attribute
122
- bank_account_number: bank_account_number,
122
+ bank_account_number: bank_account_number,
123
123
  # Encrypted Attribute
124
124
  social_security_number: social_security_number,
125
125
  name: person_name,
126
126
  # data type specific fields
127
- string_value: STRING_VALUE,
128
- long_string_value: LONG_STRING_VALUE,
129
- binary_string_value: BINARY_STRING_VALUE,
130
- integer_value: INTEGER_VALUE,
131
- float_value: FLOAT_VALUE,
132
- decimal_value: DECIMAL_VALUE,
133
- datetime_value: DATETIME_VALUE,
134
- time_value: TIME_VALUE,
135
- date_value: DATE_VALUE,
136
- true_value: true,
137
- false_value: false,
138
- data_yaml: hash_data.dup,
139
- data_json: hash_data.dup,
140
- text: 'hello',
141
- number: '21'
127
+ string_value: STRING_VALUE,
128
+ long_string_value: LONG_STRING_VALUE,
129
+ binary_string_value: BINARY_STRING_VALUE,
130
+ integer_value: INTEGER_VALUE,
131
+ float_value: FLOAT_VALUE,
132
+ decimal_value: DECIMAL_VALUE,
133
+ datetime_value: DATETIME_VALUE,
134
+ time_value: TIME_VALUE,
135
+ date_value: DATE_VALUE,
136
+ true_value: true,
137
+ false_value: false,
138
+ data_yaml: hash_data.dup,
139
+ data_json: hash_data.dup,
140
+ text: 'hello',
141
+ number: '21'
142
142
  )
143
143
  end
144
144
 
@@ -167,17 +167,17 @@ class ActiveRecordTest < Minitest::Test
167
167
  describe ':random_iv' do
168
168
  it 'false' do
169
169
  user.social_security_number = social_security_number
170
- assert first_value = user.social_security_number
170
+ assert first_value = user.social_security_number
171
171
  # Assign the same value
172
172
  user.social_security_number = social_security_number
173
173
  assert_equal first_value, user.social_security_number
174
174
  end
175
175
 
176
176
  it 'true' do
177
- user.string_value = STRING_VALUE
177
+ user.string_value = STRING_VALUE
178
178
  assert first_value = user.encrypted_string_value
179
- user.string_value = 'blah'
180
- user.string_value = STRING_VALUE
179
+ user.string_value = 'blah'
180
+ user.string_value = STRING_VALUE
181
181
  refute_equal first_value, user.encrypted_string_value
182
182
  end
183
183
 
@@ -200,7 +200,7 @@ class ActiveRecordTest < Minitest::Test
200
200
 
201
201
  it 'does not change when equal' do
202
202
  user.save!
203
- before = user.encrypted_string_value
203
+ before = user.encrypted_string_value
204
204
  user.string_value = STRING_VALUE
205
205
  refute user.string_value_changed?
206
206
  assert_equal before, user.encrypted_string_value
@@ -405,7 +405,7 @@ class ActiveRecordTest < Minitest::Test
405
405
 
406
406
  describe '#reload' do
407
407
  it 'reverts changes' do
408
- new_bank_account_number = '444444444'
408
+ new_bank_account_number = '444444444'
409
409
  user.bank_account_number = new_bank_account_number
410
410
  assert_equal new_bank_account_number, user.bank_account_number
411
411
 
@@ -416,8 +416,8 @@ class ActiveRecordTest < Minitest::Test
416
416
  end
417
417
 
418
418
  it 'reverts changes to encrypted field' do
419
- new_bank_account_number = '111111111'
420
- new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
419
+ new_bank_account_number = '111111111'
420
+ new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
421
421
  user.encrypted_bank_account_number = new_encrypted_bank_account_number
422
422
  assert_equal new_encrypted_bank_account_number, user.encrypted_bank_account_number
423
423
  assert_equal new_bank_account_number, user.bank_account_number
@@ -591,7 +591,7 @@ class ActiveRecordTest < Minitest::Test
591
591
  UniqueUser.destroy_all
592
592
  @email = 'whatever@not-unique.com'
593
593
  @username = 'gibby007'
594
- user = UniqueUser.create!(email: @email)
594
+ user = UniqueUser.create!(email: @email)
595
595
  @email_user = UniqueUser.create!(username: @username)
596
596
  end
597
597