symmetric-encryption 4.1.4 → 4.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b359cc79bc655a202fa3dca0882e311ec6211f204243e04a1e0775588ba7c433
4
- data.tar.gz: '08f689c03556c00b15a3810205ba1aece5577def975b15fd51a5ab8c70f31198'
3
+ metadata.gz: 9a62a8497a82ccb4701f2301bc351ab8e054569a3cdc02a0e0f2e14cc9866776
4
+ data.tar.gz: f8867d2e9ced1fd3f7adb081a851481cb3abc11f067d67104324bce539911e26
5
5
  SHA512:
6
- metadata.gz: 4e7ab43644e0bf6efdeaf07c2afd46bf3c58a17bf4396942bf4e28ad675c3892cee42bb04d4a801f7079c9456f65debc4ff13b36c6ec918a80f4cc3991b85022
7
- data.tar.gz: a8db0726395db261acb25cab050af5e3f82f5ad0a4fe7db263de4f7555e1c51f62911350aca6a5f59eb6b4eb46e791a4c98e4dda680c0364494605fbf07d89d6
6
+ metadata.gz: b8feb0c726ca19c1a956c24b1ec74c11786e07dc1d5131741697b23c0ff9a4b692a3b24853040b73e1418321a761d7f0687f51f620332c7480be73f5b23935fb
7
+ data.tar.gz: 26fb41fd4d2dc609eb21c382399ed1656798071eedcef94f127e4f4054f7c46f268b94c344ed73cf4ea51583dcbff08deb602df02c04b3dfd5e8fb6a3ea0b73d
@@ -1,32 +1,4 @@
1
- # Used for compression
2
- require 'zlib'
3
- # Used to coerce data types between string and their actual types
4
- require 'coercible'
5
-
6
- require 'symmetric_encryption/version'
7
- require 'symmetric_encryption/cipher'
8
- require 'symmetric_encryption/symmetric_encryption'
9
- require 'symmetric_encryption/exception'
10
-
11
- # @formatter:off
12
- module SymmetricEncryption
13
- autoload :Coerce, 'symmetric_encryption/coerce'
14
- autoload :Config, 'symmetric_encryption/config'
15
- autoload :Encoder, 'symmetric_encryption/encoder'
16
- autoload :Generator, 'symmetric_encryption/generator'
17
- autoload :Header, 'symmetric_encryption/header'
18
- autoload :Key, 'symmetric_encryption/key'
19
- autoload :Reader, 'symmetric_encryption/reader'
20
- autoload :RSAKey, 'symmetric_encryption/rsa_key'
21
- autoload :Writer, 'symmetric_encryption/writer'
22
- autoload :CLI, 'symmetric_encryption/cli'
23
- autoload :Keystore, 'symmetric_encryption/keystore'
24
- module Utils
25
- autoload :Aws, 'symmetric_encryption/utils/aws'
26
- autoload :ReEncryptFiles, 'symmetric_encryption/utils/re_encrypt_files'
27
- end
28
- end
29
- # @formatter:on
1
+ require 'symmetric_encryption/core'
30
2
 
31
3
  # Add extensions. Gems are no longer order dependent.
32
4
  begin
@@ -36,26 +8,17 @@ rescue LoadError
36
8
  end
37
9
 
38
10
  begin
39
- require 'active_record'
40
- require 'symmetric_encryption/extensions/active_record/base'
41
- rescue LoadError
42
- end
43
-
44
- begin
45
- require 'active_model'
46
- require 'symmetric_encryption/railties/symmetric_encryption_validator'
47
- rescue LoadError
48
- end
11
+ require 'active_support'
12
+ ActiveSupport.on_load(:active_record) do
13
+ require 'symmetric_encryption/railties/attr_encrypted'
14
+ require 'symmetric_encryption/railties/symmetric_encryption_validator'
49
15
 
50
- begin
51
- require 'mongoid'
52
- require 'symmetric_encryption/extensions/mongoid/encrypted'
53
- rescue LoadError
54
- end
16
+ ActiveRecord::Base.include(SymmetricEncryption::Railties::AttrEncrypted)
17
+ end
55
18
 
56
- begin
57
- require 'mongo_mapper'
58
- warn 'MongoMapper support is deprecated. Please upgrade to Mongoid.'
59
- require 'symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key'
19
+ ActiveSupport.on_load(:mongoid) do
20
+ require 'symmetric_encryption/railties/mongoid_encrypted'
21
+ require 'symmetric_encryption/railties/symmetric_encryption_validator'
22
+ end
60
23
  rescue LoadError
61
24
  end
@@ -8,7 +8,7 @@ module SymmetricEncryption
8
8
  :environments, :cipher_name, :rolling_deploy, :rotate_keys, :rotate_kek, :prompt, :show_version,
9
9
  :cleanup_keys, :activate_key, :migrate, :regions
10
10
 
11
- KEYSTORES = %i[aws heroku environment file].freeze
11
+ KEYSTORES = %i[aws heroku environment file gcp].freeze
12
12
 
13
13
  def self.run!(argv)
14
14
  new(argv).run!
@@ -131,7 +131,7 @@ module SymmetricEncryption
131
131
  @generate = config
132
132
  end
133
133
 
134
- opts.on '-s', '--keystore heroku|environment|file|aws', 'Which keystore to use during generation or re-encryption.' do |keystore|
134
+ opts.on '-s', '--keystore heroku|environment|file|aws|gcp', 'Which keystore to use during generation or re-encryption.' do |keystore|
135
135
  @keystore = (keystore || 'file').downcase.to_sym
136
136
  end
137
137
 
@@ -0,0 +1,30 @@
1
+ # Used for compression
2
+ require 'zlib'
3
+ # Used to coerce data types between string and their actual types
4
+ require 'coercible'
5
+
6
+ require 'symmetric_encryption/version'
7
+ require 'symmetric_encryption/cipher'
8
+ require 'symmetric_encryption/symmetric_encryption'
9
+ require 'symmetric_encryption/exception'
10
+
11
+ # @formatter:off
12
+ module SymmetricEncryption
13
+ autoload :Coerce, 'symmetric_encryption/coerce'
14
+ autoload :Config, 'symmetric_encryption/config'
15
+ autoload :Encoder, 'symmetric_encryption/encoder'
16
+ autoload :Generator, 'symmetric_encryption/generator'
17
+ autoload :Header, 'symmetric_encryption/header'
18
+ autoload :Key, 'symmetric_encryption/key'
19
+ autoload :Reader, 'symmetric_encryption/reader'
20
+ autoload :RSAKey, 'symmetric_encryption/rsa_key'
21
+ autoload :Writer, 'symmetric_encryption/writer'
22
+ autoload :CLI, 'symmetric_encryption/cli'
23
+ autoload :Keystore, 'symmetric_encryption/keystore'
24
+ module Utils
25
+ autoload :Aws, 'symmetric_encryption/utils/aws'
26
+ autoload :Files, 'symmetric_encryption/utils/files'
27
+ autoload :ReEncryptFiles, 'symmetric_encryption/utils/re_encrypt_files'
28
+ end
29
+ end
30
+ # @formatter:on
@@ -4,6 +4,7 @@ module SymmetricEncryption
4
4
  # @formatter:off
5
5
  autoload :Aws, 'symmetric_encryption/keystore/aws'
6
6
  autoload :Environment, 'symmetric_encryption/keystore/environment'
7
+ autoload :Gcp, 'symmetric_encryption/keystore/gcp'
7
8
  autoload :File, 'symmetric_encryption/keystore/file'
8
9
  autoload :Heroku, 'symmetric_encryption/keystore/heroku'
9
10
  autoload :Memory, 'symmetric_encryption/keystore/memory'
@@ -1,4 +1,3 @@
1
- require 'base64'
2
1
  require 'aws-sdk-kms'
3
2
  module SymmetricEncryption
4
3
  module Keystore
@@ -51,6 +50,8 @@ module SymmetricEncryption
51
50
  # - Loss of access to AWS accounts.
52
51
  # - Loss of region(s) in which master keys are stored.
53
52
  class Aws
53
+ include Utils::Files
54
+
54
55
  attr_reader :region, :key_files, :master_key_alias
55
56
 
56
57
  # Returns [Hash] a new keystore configuration after generating the data key.
@@ -131,13 +132,8 @@ module SymmetricEncryption
131
132
  raise(SymmetricEncryption::ConfigError, "region: #{region} not available in the supplied key_files") unless key_file
132
133
 
133
134
  file_name = key_file[:file_name]
134
- raise(SymmetricEncryption::ConfigError, 'file_name is mandatory for each key_file entry') unless file_name
135
-
136
- raise(SymmetricEncryption::ConfigError, "File #{file_name} could not be found") unless ::File.exist?(file_name)
137
135
 
138
- # TODO: Validate that file is not globally readable.
139
- encoded_dek = ::File.open(file_name, 'rb', &:read)
140
- encrypted_data_key = Base64.strict_decode64(encoded_dek)
136
+ encrypted_data_key = read_file_and_decode(file_name)
141
137
  aws(region).decrypt(encrypted_data_key)
142
138
  end
143
139
 
@@ -150,24 +146,13 @@ module SymmetricEncryption
150
146
  raise(ArgumentError, 'region and file_name are mandatory for each key_file entry') unless region && file_name
151
147
 
152
148
  encrypted_data_key = aws(region).encrypt(data_key)
153
- encoded_dek = Base64.strict_encode64(encrypted_data_key)
154
- write_to_file(file_name, encoded_dek)
149
+ write_encoded_to_file(file_name, encrypted_data_key)
155
150
  end
156
151
  end
157
152
 
158
153
  def aws(region)
159
154
  Utils::Aws.new(region: region, master_key_alias: master_key_alias)
160
155
  end
161
-
162
- private
163
-
164
- # Write to the supplied file_name, backing up the existing file if present
165
- def write_to_file(file_name, data)
166
- path = ::File.dirname(file_name)
167
- ::FileUtils.mkdir_p(path) unless ::File.directory?(path)
168
- ::File.rename(file_name, "#{file_name}.#{Time.now.to_i}") if ::File.exist?(file_name)
169
- ::File.open(file_name, 'wb') { |file| file.write(data) }
170
- end
171
156
  end
172
157
  end
173
158
  end
@@ -1,6 +1,8 @@
1
1
  module SymmetricEncryption
2
2
  module Keystore
3
3
  class File
4
+ include Utils::Files
5
+
4
6
  attr_accessor :file_name, :key_encrypting_key
5
7
 
6
8
  # Returns [Hash] a new keystore configuration after generating the data key.
@@ -51,33 +53,18 @@ module SymmetricEncryption
51
53
  "Symmetric Encryption key file '#{file_name}' has the wrong "\
52
54
  "permissions: #{::File.stat(file_name).mode.to_s(8)}. Expected 100600.") unless correct_permissions?
53
55
 
54
- data = read_from_file
56
+ data = read_from_file(file_name)
55
57
  key_encrypting_key ? key_encrypting_key.decrypt(data) : data
56
58
  end
57
59
 
58
60
  # Encrypt and write the key to file.
59
61
  def write(key)
60
62
  data = key_encrypting_key ? key_encrypting_key.encrypt(key) : key
61
- write_to_file(data)
63
+ write_to_file(file_name, data)
62
64
  end
63
65
 
64
66
  private
65
67
 
66
- # Read from the file, raising an exception if it is not found
67
- def read_from_file
68
- ::File.open(file_name, 'rb', &:read)
69
- rescue Errno::ENOENT
70
- raise(SymmetricEncryption::ConfigError, "Symmetric Encryption key file: '#{file_name}' not found or readable")
71
- end
72
-
73
- # Write to the supplied file_name, backing up the existing file if present
74
- def write_to_file(data)
75
- key_path = ::File.dirname(file_name)
76
- ::FileUtils.mkdir_p(key_path) unless ::File.directory?(key_path)
77
- ::File.rename(file_name, "#{file_name}.#{Time.now.to_i}") if ::File.exist?(file_name)
78
- ::File.open(file_name, 'wb', 0600) { |file| file.write(data) }
79
- end
80
-
81
68
  # Returns true if the file is owned by the user running this code and it
82
69
  # has the correct mode - readable and writable by its owner and no one
83
70
  # else, much like the keys one has in ~/.ssh
@@ -0,0 +1,87 @@
1
+ require "google/cloud/kms/v1"
2
+
3
+ module SymmetricEncryption
4
+ module Keystore
5
+ class Gcp
6
+ include Utils::Files
7
+
8
+ def self.generate_data_key(version: 0, cipher_name:, app_name:, environment:, key_path:)
9
+ version >= 255 ? (version = 1) : (version += 1)
10
+
11
+ dek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
12
+ file_name = "#{key_path}/#{app_name}_#{environment}_v#{version}.encrypted_key"
13
+ keystore = new(
14
+ key_file: file_name,
15
+ app_name: app_name,
16
+ environment: environment
17
+ )
18
+ keystore.write(dek.key)
19
+
20
+ {
21
+ keystore: :gcp,
22
+ cipher_name: dek.cipher_name,
23
+ version: version,
24
+ key_file: file_name,
25
+ iv: dek.iv,
26
+ crypto_key: keystore.crypto_key
27
+ }
28
+ end
29
+
30
+ def initialize(key_file:, app_name: nil, environment: nil, key_encrypting_key: nil, crypto_key: nil, project_id: nil, credentials: nil, location_id: nil)
31
+ @crypto_key = crypto_key
32
+ @app_name = app_name
33
+ @environment = environment
34
+ @file_name = key_file
35
+ @project_id = project_id
36
+ @credentials = credentials
37
+ @location_id = location_id
38
+ end
39
+
40
+ def read
41
+ decrypt(read_file_and_decode(file_name))
42
+ end
43
+
44
+ def write(data_key)
45
+ write_encoded_to_file(file_name, encrypt(data_key))
46
+ end
47
+
48
+ def crypto_key
49
+ @crypto_key ||= self.class::KMS::KeyManagementServiceClient.crypto_key_path(project_id, location_id, app_name, environment.to_s)
50
+ end
51
+
52
+ private
53
+
54
+ KMS = Google::Cloud::Kms::V1
55
+
56
+ attr_reader :app_name, :environment
57
+
58
+ def encrypt(plaintext)
59
+ client.encrypt(crypto_key, plaintext).ciphertext
60
+ end
61
+
62
+ def decrypt(ciphertext)
63
+ client.decrypt(crypto_key, ciphertext).plaintext
64
+ end
65
+
66
+ def client
67
+ self.class::KMS::KeyManagementServiceClient.new(timeout: 2, credentials: credentials)
68
+ end
69
+
70
+ def project_id
71
+ @project_id ||= ENV["GOOGLE_CLOUD_PROJECT"]
72
+ raise 'GOOGLE_CLOUD_PROJECT must be set' if @project_id.nil?
73
+ @project_id
74
+ end
75
+
76
+ def credentials
77
+ @credentials ||= ENV['GOOGLE_CLOUD_KEYFILE']
78
+ raise 'GOOGLE_CLOUD_KEYFILE must be set' if @credentials.nil?
79
+ @credentials
80
+ end
81
+
82
+ def location_id
83
+ @location_id ||= ENV["GOOGLE_CLOUD_LOCATION"] || 'global'
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,118 @@
1
+ module SymmetricEncryption
2
+ module Railties
3
+ module AttrEncrypted
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ # Transparently encrypt and decrypt values stored via ActiveRecord.
10
+ #
11
+ # Parameters:
12
+ # * Symbolic names of each method to create which has a corresponding
13
+ # method already defined in rails starting with: encrypted_
14
+ # * Followed by an optional hash:
15
+ # :random_iv [true|false]
16
+ # Whether the encrypted value should use a random IV every time the
17
+ # field is encrypted.
18
+ # It is recommended to set this to true where feasible. If the encrypted
19
+ # value could be used as part of a SQL where clause, or as part
20
+ # of any lookup, then it must be false.
21
+ # Setting random_iv to true will result in a different encrypted output for
22
+ # the same input string.
23
+ # Note: Only set to true if the field will never be used as part of
24
+ # the where clause in an SQL query.
25
+ # Note: When random_iv is true it will add a 8 byte header, plus the bytes
26
+ # to store the random IV in every returned encrypted string, prior to the
27
+ # encoding if any.
28
+ # Default: false
29
+ # Highly Recommended where feasible: true
30
+ #
31
+ # :type [Symbol]
32
+ # The type for this field, #see SymmetricEncryption::COERCION_TYPES
33
+ # Default: :string
34
+ #
35
+ # :compress [true|false]
36
+ # Whether to compress str before encryption
37
+ # Should only be used for large strings since compression overhead and
38
+ # the overhead of adding the 'magic' header may exceed any benefits of
39
+ # compression
40
+ # Note: Adds a 6 byte header prior to encoding, only if :random_iv is false
41
+ # Default: false
42
+ def attr_encrypted(*params)
43
+ # Ensure ActiveRecord has created all its methods first
44
+ # Ignore failures since the table may not yet actually exist
45
+ begin
46
+ define_attribute_methods
47
+ rescue StandardError
48
+ nil
49
+ end
50
+
51
+ options = params.last.is_a?(Hash) ? params.pop.dup : {}
52
+
53
+ params.each do |attribute|
54
+ SymmetricEncryption::Generator.generate_decrypted_accessors(self, attribute, "encrypted_#{attribute}", options)
55
+ encrypted_attributes[attribute.to_sym] = "encrypted_#{attribute}".to_sym
56
+ end
57
+ end
58
+
59
+ # Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute
60
+ # names as values
61
+ #
62
+ # Example
63
+ #
64
+ # class User < ActiveRecord::Base
65
+ # attr_encrypted :email
66
+ # end
67
+ #
68
+ # User.encrypted_attributes => { email: encrypted_email }
69
+ def encrypted_attributes
70
+ @encrypted_attributes ||= superclass.respond_to?(:encrypted_attributes) ? superclass.encrypted_attributes.dup : {}
71
+ end
72
+
73
+ # Return the name of all encrypted virtual attributes as an Array of symbols
74
+ # Example: [:email, :password]
75
+ def encrypted_keys
76
+ @encrypted_keys ||= encrypted_attributes.keys
77
+ end
78
+
79
+ # Return the name of all encrypted columns as an Array of symbols
80
+ # Example: [:encrypted_email, :encrypted_password]
81
+ def encrypted_columns
82
+ @encrypted_columns ||= encrypted_attributes.values
83
+ end
84
+
85
+ # Returns whether an attribute has been configured to be encrypted
86
+ #
87
+ # Example
88
+ #
89
+ # class User < ActiveRecord::Base
90
+ # attr_accessor :name
91
+ # attr_encrypted :email
92
+ # end
93
+ #
94
+ # User.encrypted_attribute?(:name) # false
95
+ # User.encrypted_attribute?(:email) # true
96
+ def encrypted_attribute?(attribute)
97
+ encrypted_keys.include?(attribute)
98
+ end
99
+
100
+ # Returns whether the attribute is the database column to hold the
101
+ # encrypted data for a matching encrypted attribute
102
+ #
103
+ # Example
104
+ #
105
+ # class User < ActiveRecord::Base
106
+ # attr_accessor :name
107
+ # attr_encrypted :email
108
+ # end
109
+ #
110
+ # User.encrypted_column?(:encrypted_name) # false
111
+ # User.encrypted_column?(:encrypted_email) # true
112
+ def encrypted_column?(attribute)
113
+ encrypted_columns.include?(attribute)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,45 @@
1
+ module SymmetricEncryption
2
+ module Utils
3
+ module Files
4
+ private
5
+
6
+ attr_reader :file_name
7
+
8
+ def read_file_and_decode(file_name)
9
+ raise(SymmetricEncryption::ConfigError, 'file_name is mandatory for each key_file entry') unless file_name
10
+
11
+ raise(SymmetricEncryption::ConfigError, "File #{file_name} could not be found") unless ::File.exist?(file_name)
12
+
13
+ # TODO: Validate that file is not globally readable.
14
+ decode64(read_from_file(file_name))
15
+ end
16
+
17
+ def write_encoded_to_file(file_name, encrypted_data_key)
18
+ write_to_file(file_name, encode64(encrypted_data_key))
19
+ end
20
+
21
+ def encode64(data)
22
+ Base64.strict_encode64(data)
23
+ end
24
+
25
+ def decode64(data)
26
+ Base64.strict_decode64(data)
27
+ end
28
+
29
+ # Write to the supplied file_name, backing up the existing file if present
30
+ def write_to_file(file_name, data)
31
+ key_path = ::File.dirname(file_name)
32
+ ::FileUtils.mkdir_p(key_path) unless ::File.directory?(key_path)
33
+ ::File.rename(file_name, "#{file_name}.#{Time.now.to_i}") if ::File.exist?(file_name)
34
+ ::File.open(file_name, 'wb', 0600) { |file| file.write(data) }
35
+ end
36
+
37
+ # Read from the file, raising an exception if it is not found
38
+ def read_from_file(file_name)
39
+ ::File.open(file_name, 'rb', &:read)
40
+ rescue Errno::ENOENT
41
+ raise(SymmetricEncryption::ConfigError, "Symmetric Encryption key file: '#{file_name}' not found or readable")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module SymmetricEncryption
2
- VERSION = '4.1.4'.freeze
2
+ VERSION = '4.2.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symmetric-encryption
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.4
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-12 00:00:00.000000000 Z
11
+ date: 2019-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coercible
@@ -42,11 +42,9 @@ files:
42
42
  - lib/symmetric_encryption/cli.rb
43
43
  - lib/symmetric_encryption/coerce.rb
44
44
  - lib/symmetric_encryption/config.rb
45
+ - lib/symmetric_encryption/core.rb
45
46
  - lib/symmetric_encryption/encoder.rb
46
47
  - lib/symmetric_encryption/exception.rb
47
- - lib/symmetric_encryption/extensions/active_record/base.rb
48
- - lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb
49
- - lib/symmetric_encryption/extensions/mongoid/encrypted.rb
50
48
  - lib/symmetric_encryption/generator.rb
51
49
  - lib/symmetric_encryption/header.rb
52
50
  - lib/symmetric_encryption/key.rb
@@ -54,14 +52,18 @@ files:
54
52
  - lib/symmetric_encryption/keystore/aws.rb
55
53
  - lib/symmetric_encryption/keystore/environment.rb
56
54
  - lib/symmetric_encryption/keystore/file.rb
55
+ - lib/symmetric_encryption/keystore/gcp.rb
57
56
  - lib/symmetric_encryption/keystore/heroku.rb
58
57
  - lib/symmetric_encryption/keystore/memory.rb
59
58
  - lib/symmetric_encryption/railtie.rb
59
+ - lib/symmetric_encryption/railties/attr_encrypted.rb
60
+ - lib/symmetric_encryption/railties/mongoid_encrypted.rb
60
61
  - lib/symmetric_encryption/railties/symmetric_encryption_validator.rb
61
62
  - lib/symmetric_encryption/reader.rb
62
63
  - lib/symmetric_encryption/rsa_key.rb
63
64
  - lib/symmetric_encryption/symmetric_encryption.rb
64
65
  - lib/symmetric_encryption/utils/aws.rb
66
+ - lib/symmetric_encryption/utils/files.rb
65
67
  - lib/symmetric_encryption/utils/re_encrypt_files.rb
66
68
  - lib/symmetric_encryption/version.rb
67
69
  - lib/symmetric_encryption/writer.rb
@@ -1,110 +0,0 @@
1
- module ActiveRecord #:nodoc:
2
- class Base
3
- # Transparently encrypt and decrypt values stored via ActiveRecord.
4
- #
5
- # Parameters:
6
- # * Symbolic names of each method to create which has a corresponding
7
- # method already defined in rails starting with: encrypted_
8
- # * Followed by an optional hash:
9
- # :random_iv [true|false]
10
- # Whether the encrypted value should use a random IV every time the
11
- # field is encrypted.
12
- # It is recommended to set this to true where feasible. If the encrypted
13
- # value could be used as part of a SQL where clause, or as part
14
- # of any lookup, then it must be false.
15
- # Setting random_iv to true will result in a different encrypted output for
16
- # the same input string.
17
- # Note: Only set to true if the field will never be used as part of
18
- # the where clause in an SQL query.
19
- # Note: When random_iv is true it will add a 8 byte header, plus the bytes
20
- # to store the random IV in every returned encrypted string, prior to the
21
- # encoding if any.
22
- # Default: false
23
- # Highly Recommended where feasible: true
24
- #
25
- # :type [Symbol]
26
- # The type for this field, #see SymmetricEncryption::COERCION_TYPES
27
- # Default: :string
28
- #
29
- # :compress [true|false]
30
- # Whether to compress str before encryption
31
- # Should only be used for large strings since compression overhead and
32
- # the overhead of adding the 'magic' header may exceed any benefits of
33
- # compression
34
- # Note: Adds a 6 byte header prior to encoding, only if :random_iv is false
35
- # Default: false
36
- def self.attr_encrypted(*params)
37
- # Ensure ActiveRecord has created all its methods first
38
- # Ignore failures since the table may not yet actually exist
39
- begin
40
- define_attribute_methods
41
- rescue StandardError
42
- nil
43
- end
44
-
45
- options = params.last.is_a?(Hash) ? params.pop.dup : {}
46
-
47
- params.each do |attribute|
48
- SymmetricEncryption::Generator.generate_decrypted_accessors(self, attribute, "encrypted_#{attribute}", options)
49
- encrypted_attributes[attribute.to_sym] = "encrypted_#{attribute}".to_sym
50
- end
51
- end
52
-
53
- # Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute
54
- # names as values
55
- #
56
- # Example
57
- #
58
- # class User < ActiveRecord::Base
59
- # attr_encrypted :email
60
- # end
61
- #
62
- # User.encrypted_attributes => { email: encrypted_email }
63
- def self.encrypted_attributes
64
- @encrypted_attributes ||= superclass.respond_to?(:encrypted_attributes) ? superclass.encrypted_attributes.dup : {}
65
- end
66
-
67
- # Return the name of all encrypted virtual attributes as an Array of symbols
68
- # Example: [:email, :password]
69
- def self.encrypted_keys
70
- @encrypted_keys ||= encrypted_attributes.keys
71
- end
72
-
73
- # Return the name of all encrypted columns as an Array of symbols
74
- # Example: [:encrypted_email, :encrypted_password]
75
- def self.encrypted_columns
76
- @encrypted_columns ||= encrypted_attributes.values
77
- end
78
-
79
- # Returns whether an attribute has been configured to be encrypted
80
- #
81
- # Example
82
- #
83
- # class User < ActiveRecord::Base
84
- # attr_accessor :name
85
- # attr_encrypted :email
86
- # end
87
- #
88
- # User.encrypted_attribute?(:name) # false
89
- # User.encrypted_attribute?(:email) # true
90
- def self.encrypted_attribute?(attribute)
91
- encrypted_keys.include?(attribute)
92
- end
93
-
94
- # Returns whether the attribute is the database column to hold the
95
- # encrypted data for a matching encrypted attribute
96
- #
97
- # Example
98
- #
99
- # class User < ActiveRecord::Base
100
- # attr_accessor :name
101
- # attr_encrypted :email
102
- # end
103
- #
104
- # User.encrypted_column?(:encrypted_name) # false
105
- # User.encrypted_column?(:encrypted_email) # true
106
- def self.encrypted_column?(attribute)
107
- encrypted_columns.include?(attribute)
108
- end
109
- end
110
- end
@@ -1,41 +0,0 @@
1
- #
2
- # DEPRECATED !!!
3
- #
4
- module MongoMapper
5
- module Plugins
6
- module EncryptedKey
7
- extend ActiveSupport::Concern
8
-
9
- COERCION_MAP = {
10
- String => :string,
11
- Integer => :integer,
12
- Float => :float,
13
- BigDecimal => :decimal,
14
- DateTime => :datetime,
15
- Time => :time,
16
- Date => :date,
17
- Boolean => :boolean,
18
- Hash => :json
19
- }.freeze
20
-
21
- module ClassMethods
22
- def encrypted_key(key_name, type, full_options = {})
23
- full_options = full_options.is_a?(Hash) ? full_options.dup : {}
24
- options = full_options.delete(:encrypted) || {}
25
- # Support overriding the name of the decrypted attribute
26
- encrypted_key_name = options.delete(:encrypt_as) || "encrypted_#{key_name}"
27
- options[:type] = COERCION_MAP[type] unless %i[yaml json].include?(options[:type])
28
-
29
- raise(ArgumentError, "Invalid type: #{type.inspect}. Valid types: #{COERCION_MAP.keys.join(',')}") unless options[:type]
30
-
31
- SymmetricEncryption::Generator.generate_decrypted_accessors(self, key_name, encrypted_key_name, options)
32
-
33
- key(encrypted_key_name, String, full_options)
34
- end
35
- end
36
- end
37
- end
38
- end
39
-
40
- MongoMapper::Document.plugin(MongoMapper::Plugins::EncryptedKey)
41
- MongoMapper::EmbeddedDocument.plugin(MongoMapper::Plugins::EncryptedKey)