attr_encryptor 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 15fa84f14870e8333f343f5ce8d2e56b71e7c576
4
+ data.tar.gz: de53d4a0d42aa01b867d29834a056224d4173caf
5
+ SHA512:
6
+ metadata.gz: 78abb59d5e439b54eb77f7eb4b786669457039a7dcc7724014caed61f941b664e0b2a2fb77f6e22f431c5d70b7fe1b4c38cb0580166725fe166092e4c5da8da5
7
+ data.tar.gz: ace36c9f963ab74233525b8a2e6ea9a3f41d3db9ec626b298305f30ddddcd94ac51f948fd1582c36a3c693275b4b936e7e916067c26bebd61478827c0031a6b8
@@ -0,0 +1 @@
1
+ attr_encrypted
@@ -0,0 +1 @@
1
+ 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ ruby '2.0.0'
2
+ source 'https://rubygems.org'
3
+
4
+
5
+ gem 'encryptor2'
6
+
7
+ group :development do
8
+ gem 'pry'
9
+ gem 'activerecord'
10
+ gem 'datamapper'
11
+ gem 'mocha'
12
+ gem 'sequel'
13
+ gem 'dm-sqlite-adapter'
14
+ gem 'sqlite3'
15
+ end
@@ -0,0 +1,108 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activemodel (4.0.0)
5
+ activesupport (= 4.0.0)
6
+ builder (~> 3.1.0)
7
+ activerecord (4.0.0)
8
+ activemodel (= 4.0.0)
9
+ activerecord-deprecated_finders (~> 1.0.2)
10
+ activesupport (= 4.0.0)
11
+ arel (~> 4.0.0)
12
+ activerecord-deprecated_finders (1.0.3)
13
+ activesupport (4.0.0)
14
+ i18n (~> 0.6, >= 0.6.4)
15
+ minitest (~> 4.2)
16
+ multi_json (~> 1.3)
17
+ thread_safe (~> 0.1)
18
+ tzinfo (~> 0.3.37)
19
+ addressable (2.3.5)
20
+ arel (4.0.0)
21
+ atomic (1.1.10)
22
+ bcrypt-ruby (3.1.1)
23
+ builder (3.1.4)
24
+ coderay (1.0.9)
25
+ data_objects (0.10.13)
26
+ addressable (~> 2.1)
27
+ datamapper (1.2.0)
28
+ dm-aggregates (~> 1.2.0)
29
+ dm-constraints (~> 1.2.0)
30
+ dm-core (~> 1.2.0)
31
+ dm-migrations (~> 1.2.0)
32
+ dm-serializer (~> 1.2.0)
33
+ dm-timestamps (~> 1.2.0)
34
+ dm-transactions (~> 1.2.0)
35
+ dm-types (~> 1.2.0)
36
+ dm-validations (~> 1.2.0)
37
+ dm-aggregates (1.2.0)
38
+ dm-core (~> 1.2.0)
39
+ dm-constraints (1.2.0)
40
+ dm-core (~> 1.2.0)
41
+ dm-core (1.2.1)
42
+ addressable (~> 2.3)
43
+ dm-do-adapter (1.2.0)
44
+ data_objects (~> 0.10.6)
45
+ dm-core (~> 1.2.0)
46
+ dm-migrations (1.2.0)
47
+ dm-core (~> 1.2.0)
48
+ dm-serializer (1.2.2)
49
+ dm-core (~> 1.2.0)
50
+ fastercsv (~> 1.5)
51
+ json (~> 1.6)
52
+ json_pure (~> 1.6)
53
+ multi_json (~> 1.0)
54
+ dm-sqlite-adapter (1.2.0)
55
+ dm-do-adapter (~> 1.2.0)
56
+ do_sqlite3 (~> 0.10.6)
57
+ dm-timestamps (1.2.0)
58
+ dm-core (~> 1.2.0)
59
+ dm-transactions (1.2.0)
60
+ dm-core (~> 1.2.0)
61
+ dm-types (1.2.2)
62
+ bcrypt-ruby (~> 3.0)
63
+ dm-core (~> 1.2.0)
64
+ fastercsv (~> 1.5)
65
+ json (~> 1.6)
66
+ multi_json (~> 1.0)
67
+ stringex (~> 1.4)
68
+ uuidtools (~> 2.1)
69
+ dm-validations (1.2.0)
70
+ dm-core (~> 1.2.0)
71
+ do_sqlite3 (0.10.13)
72
+ data_objects (= 0.10.13)
73
+ encryptor2 (1.0.0)
74
+ fastercsv (1.5.5)
75
+ i18n (0.6.4)
76
+ json (1.8.0)
77
+ json_pure (1.8.0)
78
+ metaclass (0.0.1)
79
+ method_source (0.8.1)
80
+ minitest (4.7.5)
81
+ mocha (0.14.0)
82
+ metaclass (~> 0.0.1)
83
+ multi_json (1.7.7)
84
+ pry (0.9.12.2)
85
+ coderay (~> 1.0.5)
86
+ method_source (~> 0.8)
87
+ slop (~> 3.4)
88
+ sequel (4.0.0)
89
+ slop (3.4.5)
90
+ sqlite3 (1.3.7)
91
+ stringex (1.5.1)
92
+ thread_safe (0.1.0)
93
+ atomic
94
+ tzinfo (0.3.37)
95
+ uuidtools (2.1.4)
96
+
97
+ PLATFORMS
98
+ ruby
99
+
100
+ DEPENDENCIES
101
+ activerecord
102
+ datamapper
103
+ dm-sqlite-adapter
104
+ encryptor2
105
+ mocha
106
+ pry
107
+ sequel
108
+ sqlite3
data/README.md CHANGED
@@ -15,7 +15,7 @@ It works with ANY class, however, you get a few extra features when you're using
15
15
 
16
16
  Encrypting attributes has never been easier:
17
17
 
18
- ### You database
18
+ ### Your database
19
19
 
20
20
  add a `encrypted_ssn`, `encrypted_ssn_salt`, `encrypted_ssn_iv`. All of
21
21
  them will be populated automatically
@@ -23,6 +23,7 @@ them will be populated automatically
23
23
  create_table :google_apps_admins do |t|
24
24
  t.string :username
25
25
  t.string :encrypted_password
26
+ t.string :encrypted_password_salt
26
27
  t.string :encrypted_password_iv
27
28
  t.string :domain
28
29
  t.timestamps
@@ -243,6 +244,14 @@ encrypted string. I've had this problem myself using MySQL. You can simply pass
243
244
 
244
245
  The default encoding is `m*` (base64). You can change this by setting `:encode => 'some encoding'`. See the `Array#pack` method at http://www.ruby-doc.org/core/classes/Array.html#M002245 for more encoding options.
245
246
 
247
+ ### String Encoding/Charset
248
+
249
+ If you are trying to store UTF-8 (or other non-english charsets) strings in your encrypted parameters, you may get the decrypted string back as a US-ASCII or ASCII-8BIT string.
250
+
251
+ To fix this, add the `:charset => 'UTF-8'` option to your encrypted attribute definitions.
252
+ This option defaults to whatever your `Encoding.default_internal` is set to. `:charset => :default` will force it to use the default value.
253
+
254
+ This option only applies to encrypted strings and will be ignored when encrypting marshalled objects.
246
255
 
247
256
  ### Marshaling
248
257
 
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
- require 'rake/rdoctask'
3
+ require 'rdoc/task'
4
4
 
5
5
  desc 'Default: run unit tests.'
6
6
  task :default => :test
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.author = 'Daniel Palacio'
18
18
  s.email = 'danpal@gmail.com'
19
- s.homepage = 'http://github.com/danpal/attr_encrypted'
19
+ s.homepage = 'http://github.com/danpal/attr_encryptor'
20
20
 
21
21
  s.has_rdoc = false
22
22
  s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
@@ -69,6 +69,8 @@ module AttrEncryptor
69
69
  # :unless => Attributes are only encrypted if this option evaluates to false. If you pass a symbol representing an instance
70
70
  # method then the result of the method will be evaluated. Any objects that respond to <tt>:call</tt> are evaluated as well.
71
71
  # Defaults to false.
72
+ # :charset => Forces the decrypted string to be interpreted as the specified encoding. Does not change the underlying bits.
73
+ # Use :default to use Ruby's default encoding.
72
74
  #
73
75
  # You can specify your own default options
74
76
  #
@@ -111,10 +113,12 @@ module AttrEncryptor
111
113
  :load_method => 'load',
112
114
  :encryptor => Encryptor,
113
115
  :encrypt_method => 'encrypt',
114
- :decrypt_method => 'decrypt'
116
+ :decrypt_method => 'decrypt',
117
+ :charset => :default
115
118
  }.merge!(attr_encrypted_options).merge!(attributes.last.is_a?(Hash) ? attributes.pop : {})
116
119
 
117
120
  options[:encode] = options[:default_encoding] if options[:encode] == true
121
+ options[:charset] = Encoding.default_internal if options[:charset] == :default
118
122
 
119
123
  attributes.each do |attribute|
120
124
  encrypted_attribute_name = (options[:attribute] ? options[:attribute] : [options[:prefix], attribute, options[:suffix]].join).to_sym
@@ -122,27 +126,27 @@ module AttrEncryptor
122
126
  instance_methods_as_symbols = instance_methods.collect { |method| method.to_sym }
123
127
  attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
124
128
  attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
125
-
129
+
126
130
  attr_reader (encrypted_attribute_name.to_s + "_iv").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_iv").to_sym )
127
131
  attr_writer (encrypted_attribute_name.to_s + "_iv").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_iv").to_sym )
128
-
132
+
129
133
  attr_reader (encrypted_attribute_name.to_s + "_salt").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_salt").to_sym )
130
134
  attr_writer (encrypted_attribute_name.to_s + "_salt").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_salt").to_sym )
131
135
 
132
136
 
133
137
 
134
138
  define_method(attribute) do
135
-
139
+
136
140
  load_iv_for_attribute(attribute,encrypted_attribute_name, options[:algorithm])
137
- load_salt_for_attribute(attribute,encrypted_attribute_name)
141
+ load_salt_for_attribute(attribute,encrypted_attribute_name)
138
142
 
139
143
  instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
140
144
  end
141
145
 
142
146
  define_method("#{attribute}=") do |value|
143
147
  load_iv_for_attribute(attribute, encrypted_attribute_name, options[:algorithm])
144
- load_salt_for_attribute(attribute, encrypted_attribute_name)
145
-
148
+ load_salt_for_attribute(attribute, encrypted_attribute_name)
149
+
146
150
  #this add's the iv and salt on the options for this instance
147
151
  send("#{encrypted_attribute_name}=", encrypt(attribute, value))
148
152
  instance_variable_set("@#{attribute}", value)
@@ -195,10 +199,16 @@ module AttrEncryptor
195
199
  encrypted_value = encrypted_value.unpack(options[:encode]).first if options[:encode]
196
200
  value = options[:encryptor].send(options[:decrypt_method], options.merge!(:value => encrypted_value))
197
201
  value = options[:marshaler].send(options[:load_method], value) if options[:marshal]
198
- value
202
+ return_value = value
199
203
  else
200
- encrypted_value
204
+ return_value = encrypted_value
201
205
  end
206
+
207
+ if RUBY_VERSION > '1.9' && options[:charset].present? && return_value.present? && return_value.is_a?(String)
208
+ return_value.force_encoding(options[:charset])
209
+ end
210
+
211
+ return_value
202
212
  end
203
213
 
204
214
  # Encrypts a value for the attribute specified
@@ -292,10 +302,7 @@ module AttrEncryptor
292
302
  def encrypt(attribute, value)
293
303
  self.class.encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
294
304
  end
295
-
296
- def foo
297
305
 
298
- end
299
306
  protected
300
307
 
301
308
  # Returns attr_encrypted options evaluated in the current object's scope for the attribute specified
@@ -319,7 +326,7 @@ module AttrEncryptor
319
326
  def load_iv_for_attribute (attribute, encrypted_attribute_name, algorithm)
320
327
  iv = send("#{encrypted_attribute_name.to_s + "_iv"}")
321
328
  if(iv == nil)
322
- begin
329
+ begin
323
330
  algorithm = algorithm || "aes-256-cbc"
324
331
  algo = OpenSSL::Cipher::Cipher.new(algorithm)
325
332
  iv = [algo.random_iv].pack("m")
@@ -331,10 +338,10 @@ module AttrEncryptor
331
338
  end
332
339
 
333
340
  def load_salt_for_attribute(attribute, encrypted_attribute_name)
334
- salt = send("#{encrypted_attribute_name.to_s + "_salt"}") || send("#{encrypted_attribute_name.to_s + "_salt"}=", Time.now.to_i.to_s)
341
+ salt = send("#{encrypted_attribute_name.to_s + "_salt"}") || send("#{encrypted_attribute_name.to_s + "_salt"}=", Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15])
335
342
  self.class.encrypted_attributes[attribute.to_sym] = self.class.encrypted_attributes[attribute.to_sym].merge(:salt => salt)
336
343
  end
337
-
344
+
338
345
 
339
346
  end
340
347
  end
@@ -4,19 +4,26 @@ if defined?(ActiveRecord::Base)
4
4
  module ActiveRecord
5
5
  def self.extended(base) # :nodoc:
6
6
  base.class_eval do
7
+ class << self
8
+ alias_method_chain :attr_encrypted, :defined_attributes
9
+ alias_method_chain :attr_encryptor, :defined_attributes
10
+ end
11
+
7
12
  attr_encrypted_options[:encode] = true
8
13
  end
9
14
  end
10
15
 
11
16
  protected
12
17
 
13
- # Ensures the attribute methods for db fields have been defined before calling the original
14
- # <tt>attr_encrypted</tt> method
15
- def attr_encrypted(*attrs)
16
- define_attribute_methods rescue nil
17
- super
18
- attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
19
- end
18
+ # Ensures the attribute methods for db fields have been defined before calling the original
19
+ # <tt>attr_encrypted</tt> method
20
+ def attr_encrypted_with_defined_attributes(*attrs)
21
+ define_attribute_methods rescue nil
22
+ attr_encrypted_without_defined_attributes *attrs
23
+ attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
24
+ end
25
+
26
+ alias attr_encryptor_with_defined_attributes attr_encrypted_with_defined_attributes
20
27
  end
21
28
  end
22
29
  end
@@ -1,9 +1,9 @@
1
1
  module AttrEncryptor
2
2
  # Contains information about this gem's version
3
3
  module Version
4
- MAJOR = 1
4
+ MAJOR = 2
5
5
  MINOR = 0
6
- PATCH = 2
6
+ PATCH = 0
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
@@ -30,8 +30,8 @@ create_tables
30
30
  ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
31
31
 
32
32
  class Person < ActiveRecord::Base
33
- attr_encrypted :email, :key => "secret"
34
- attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'secret_key') }, :marshal => true
33
+ attr_encrypted :email, :key => SECRET_KEY
34
+ attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY) }, :marshal => true
35
35
 
36
36
 
37
37
  after_initialize :initialize_salt_and_credentials
@@ -39,7 +39,7 @@ class Person < ActiveRecord::Base
39
39
  protected
40
40
 
41
41
  def initialize_salt_and_credentials
42
- self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
42
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15]
43
43
  self.credentials ||= { :username => 'example', :password => 'test' }
44
44
  end
45
45
  end
@@ -58,43 +58,42 @@ class ActiveRecordTest < Test::Unit::TestCase
58
58
  def setup
59
59
  ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
60
60
  create_tables
61
- Account.create!(:key => "secret", :password => "password")
61
+ Account.create!(:key => SECRET_KEY, :password => "password")
62
62
  end
63
63
 
64
- def _test_should_encrypt_email
64
+ def test_should_encrypt_email
65
65
  @person = Person.create :email => 'test@example.com'
66
66
  assert_not_nil @person.encrypted_email
67
67
  assert_not_equal @person.email, @person.encrypted_email
68
68
  assert_equal @person.email, Person.find(:first).email
69
69
  end
70
70
 
71
- def _test_should_marshal_and_encrypt_credentials
71
+ def test_should_marshal_and_encrypt_credentials
72
72
  @person = Person.create
73
73
  assert_not_nil @person.encrypted_credentials
74
74
  assert_not_equal @person.credentials, @person.encrypted_credentials
75
75
  assert_equal @person.credentials, Person.find(:first).credentials
76
76
  end
77
77
 
78
- def _test_should_encode_by_default
78
+ def test_should_encode_by_default
79
79
  assert Person.attr_encrypted_options[:encode]
80
80
  end
81
81
 
82
- def _test_should_validate_presence_of_email
82
+ def test_should_validate_presence_of_email
83
83
  @person = PersonWithValidation.new
84
84
  assert !@person.valid?
85
85
  assert !@person.errors[:email].empty? || @person.errors.on(:email)
86
86
  end
87
87
 
88
- def _test_should_encrypt_decrypt_with_iv
88
+ def test_should_encrypt_decrypt_with_iv
89
89
  @person = Person.create :email => 'test@example.com'
90
90
  @person2 = Person.find(@person.id)
91
91
  assert_not_nil @person2.encrypted_email_iv
92
92
  assert_equal 'test@example.com', @person2.email
93
93
  end
94
-
94
+
95
95
  def _test_should_create_an_account_regardless_of_arguments_order
96
- Account.create!(:key => "secret", :password => "password")
97
- Account.create!(:password => "password" , :key => "secret")
96
+ Account.create!(:key => SECRET_KEY, :password => "password")
97
+ Account.create!(:password => "password" , :key => SECRET_KEY)
98
98
  end
99
-
100
99
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require File.expand_path('../test_helper', __FILE__)
2
3
 
3
4
  class SillyEncryptor
@@ -11,22 +12,26 @@ class SillyEncryptor
11
12
  end
12
13
 
13
14
  class User
14
- self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
15
+ self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
15
16
 
16
- attr_encrypted :email, :without_encoding, :key => 'secret key'
17
+ attr_encrypted :email, :without_encoding, :key => SECRET_KEY
17
18
  attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
18
- attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
19
+ attr_encrypted :ssn, :key => :secret_key, :attribute => 'ssn_encrypted'
19
20
  attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
20
- attr_encrypted :with_encoding, :key => 'secret key', :encode => true
21
- attr_encrypted :with_custom_encoding, :key => 'secret key', :encode => 'm'
22
- attr_encrypted :with_marshaling, :key => 'secret key', :marshal => true
23
- attr_encrypted :with_true_if, :key => 'secret key', :if => true
24
- attr_encrypted :with_false_if, :key => 'secret key', :if => false
25
- attr_encrypted :with_true_unless, :key => 'secret key', :unless => true
26
- attr_encrypted :with_false_unless, :key => 'secret key', :unless => false
27
- attr_encrypted :with_if_changed, :key => 'secret key', :if => :should_encrypt
21
+ attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
22
+ attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
23
+ attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
24
+ attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true
25
+ attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false
26
+ attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true
27
+ attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false
28
+ attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
28
29
 
29
- attr_encryptor :aliased, :key => 'secret_key'
30
+ attr_encrypted :utf8, :key => SECRET_KEY, :charset => 'UTF-8'
31
+ attr_encrypted :default_enc, :key => SECRET_KEY
32
+ attr_encrypted :us_ascii, :key => SECRET_KEY, :charset => 'US-ASCII'
33
+
34
+ attr_encryptor :aliased, :key => SECRET_KEY
30
35
 
31
36
  attr_accessor :salt
32
37
  attr_accessor :should_encrypt
@@ -35,6 +40,10 @@ class User
35
40
  self.salt = Time.now.to_i.to_s
36
41
  self.should_encrypt = true
37
42
  end
43
+
44
+ def secret_key
45
+ SECRET_KEY
46
+ end
38
47
  end
39
48
 
40
49
  class Admin < User
@@ -158,7 +167,8 @@ class AttrEncryptorTest < Test::Unit::TestCase
158
167
  assert_nil @user.ssn_encrypted
159
168
  @user.ssn = 'testing'
160
169
  assert_not_nil @user.ssn_encrypted
161
- assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => Time.now.to_i.to_s), @user.ssn_encrypted
170
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt )
171
+ assert_equal encrypted, @user.ssn_encrypted
162
172
  end
163
173
 
164
174
  def test_should_evaluate_a_key_passed_as_a_proc
@@ -166,7 +176,8 @@ class AttrEncryptorTest < Test::Unit::TestCase
166
176
  assert_nil @user.crypted_password_test
167
177
  @user.password = 'testing'
168
178
  assert_not_nil @user.crypted_password_test
169
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User', :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => Time.now.to_i.to_s), @user.crypted_password_test
179
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
180
+ assert_equal encrypted, @user.crypted_password_test
170
181
  end
171
182
 
172
183
  def test_should_use_options_found_in_the_attr_encrypted_options_attribute
@@ -174,8 +185,9 @@ class AttrEncryptorTest < Test::Unit::TestCase
174
185
  assert_nil @user.crypted_password_test
175
186
  @user.password = 'testing'
176
187
  assert_not_nil @user.crypted_password_test
177
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User', :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => Time.now.to_i.to_s), @user.crypted_password_test
178
- end
188
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
189
+ assert_equal encrypted, @user.crypted_password_test
190
+ end
179
191
 
180
192
  def test_should_inherit_encrypted_attributes
181
193
  assert_equal [User.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, Admin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
@@ -216,7 +228,8 @@ class AttrEncryptorTest < Test::Unit::TestCase
216
228
  assert_nil @user.encrypted_with_true_if
217
229
  @user.with_true_if = 'testing'
218
230
  assert_not_nil @user.encrypted_with_true_if
219
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => Time.now.to_i.to_s), @user.encrypted_with_true_if
231
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt)
232
+ assert_equal encrypted, @user.encrypted_with_true_if
220
233
  end
221
234
 
222
235
  def test_should_not_encrypt_with_false_if
@@ -232,7 +245,8 @@ class AttrEncryptorTest < Test::Unit::TestCase
232
245
  assert_nil @user.encrypted_with_false_unless
233
246
  @user.with_false_unless = 'testing'
234
247
  assert_not_nil @user.encrypted_with_false_unless
235
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => Time.now.to_i.to_s,), @user.encrypted_with_false_unless
248
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt)
249
+ assert_equal encrypted, @user.encrypted_with_false_unless
236
250
  end
237
251
 
238
252
  def test_should_not_encrypt_with_true_unless
@@ -252,7 +266,7 @@ class AttrEncryptorTest < Test::Unit::TestCase
252
266
  @user.with_if_changed = "encrypt_stuff"
253
267
  @user.stubs(:instance_variable_get).returns(nil)
254
268
  @user.stubs(:instance_variable_set).raises("BadStuff")
255
- assert_raise RuntimeError do
269
+ assert_raise RuntimeError do
256
270
  @user.with_if_changed
257
271
  end
258
272
 
@@ -269,6 +283,29 @@ class AttrEncryptorTest < Test::Unit::TestCase
269
283
  assert_equal '3', User.decrypt_email(string_encrypted_email)
270
284
  end
271
285
 
286
+ def test_should_force_utf8_charset_on_decrypted_string
287
+ utf8_str = 'thïs should bé UTF-8'.force_encoding('UTF-8')
288
+ encrypted_utf8 = User.encrypt_utf8(utf8_str)
289
+ decrypted_utf8 = User.decrypt_utf8(encrypted_utf8)
290
+ assert_equal decrypted_utf8.encoding, Encoding::UTF_8
291
+ end
292
+
293
+ def test_should_force_default_encoding_on_decrypted_string
294
+ Encoding.default_internal = 'ASCII-8BIT' #Provide a default.
295
+ default_str = 'this is a default encoding'
296
+ encrypted_def = User.encrypt_default_enc(default_str)
297
+ decrypted_def = User.decrypt_default_enc(encrypted_def)
298
+ assert_equal decrypted_def.encoding, Encoding.default_internal
299
+ Encoding.default_internal = nil
300
+ end
301
+
302
+ def test_should_force_ascii_charset_on_decrypted_string
303
+ ascii_str = 'this should be US-ASCII'.force_encoding('US-ASCII')
304
+ encrypted_ascii = User.encrypt_us_ascii(ascii_str)
305
+ decrypted_ascii = User.decrypt_us_ascii(encrypted_ascii)
306
+ assert_equal decrypted_ascii.encoding, Encoding::US_ASCII
307
+ end
308
+
272
309
  def test_should_create_query_accessor
273
310
  @user = User.new
274
311
  assert !@user.email?
@@ -13,9 +13,9 @@ class Client
13
13
  property :encrypted_credentials, Text
14
14
  property :encrypted_credentials_iv, Text
15
15
  property :encrypted_credentials_salt, Text
16
-
17
- attr_encrypted :email, :key => 'a secret key'
18
- attr_encrypted :credentials, :key => 'some private key', :marshal => true
16
+
17
+ attr_encrypted :email, :key => SECRET_KEY
18
+ attr_encrypted :credentials, :key => SECRET_KEY, :marshal => true
19
19
 
20
20
  def initialize(attrs = {})
21
21
  super attrs
@@ -13,9 +13,9 @@ DB.create_table :humans do
13
13
  column :encrypted_credentials_salt, String
14
14
  end
15
15
 
16
- class Human < Sequel::Model(:humans)
17
- attr_encrypted :email, :key => 'a secret key'
18
- attr_encrypted :credentials, :key => 'some private key', :marshal => true
16
+ class Human < Sequel::Model(:humans)
17
+ attr_encrypted :email, :key => SECRET_KEY
18
+ attr_encrypted :credentials, :key => SECRET_KEY, :marshal => true
19
19
 
20
20
  def after_initialize(attrs = {})
21
21
  self.credentials ||= { :username => 'example', :password => 'test' }
@@ -29,7 +29,6 @@ class SequelTest < Test::Unit::TestCase
29
29
  end
30
30
 
31
31
  def test_should_encrypt_email
32
- require 'ruby-debug'
33
32
  @human = Human.new :email => 'test@example.com'
34
33
  assert @human.save
35
34
  assert_not_nil @human.encrypted_email
@@ -39,7 +38,7 @@ class SequelTest < Test::Unit::TestCase
39
38
 
40
39
  def test_should_marshal_and_encrypt_credentials
41
40
 
42
- @human = Human.new
41
+ @human = Human.new :credentials => { :username => 'example', :password => 'test' }
43
42
  assert @human.save
44
43
  assert_not_nil @human.encrypted_credentials
45
44
  assert_not_equal @human.credentials, @human.encrypted_credentials
@@ -5,10 +5,12 @@ gem 'activerecord', ENV['ACTIVE_RECORD_VERSION'] if ENV['ACTIVE_RECORD_VERSION']
5
5
  require 'active_record'
6
6
  require 'data_mapper'
7
7
  require 'sequel'
8
- require 'mocha'
8
+ require 'mocha/setup'
9
9
 
10
10
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
11
  $:.unshift(File.dirname(__FILE__))
12
12
  require 'attr_encryptor'
13
13
 
14
14
  puts "\nTesting with ActiveRecord #{ActiveRecord::VERSION::STRING rescue ENV['ACTIVE_RECORD_VERSION']}"
15
+
16
+ SECRET_KEY = 4.times.map { Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s) }.join
metadata CHANGED
@@ -1,93 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_encryptor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Daniel Palacio
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-01-07 00:00:00.000000000Z
11
+ date: 2013-07-17 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: encryptor2
16
- requirement: &70193477683240 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: 1.0.0
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *70193477683240
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: activerecord
27
- requirement: &70193477682720 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ! '>='
31
+ - - '>='
31
32
  - !ruby/object:Gem::Version
32
33
  version: 2.0.0
33
34
  type: :development
34
35
  prerelease: false
35
- version_requirements: *70193477682720
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: datamapper
38
- requirement: &70193477682340 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ! '>='
45
+ - - '>='
42
46
  - !ruby/object:Gem::Version
43
47
  version: '0'
44
48
  type: :development
45
49
  prerelease: false
46
- version_requirements: *70193477682340
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
47
55
  - !ruby/object:Gem::Dependency
48
56
  name: mocha
49
- requirement: &70193477702100 !ruby/object:Gem::Requirement
50
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
51
58
  requirements:
52
- - - ! '>='
59
+ - - '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
62
  type: :development
56
63
  prerelease: false
57
- version_requirements: *70193477702100
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: sequel
60
- requirement: &70193477701680 !ruby/object:Gem::Requirement
61
- none: false
71
+ requirement: !ruby/object:Gem::Requirement
62
72
  requirements:
63
- - - ! '>='
73
+ - - '>='
64
74
  - !ruby/object:Gem::Version
65
75
  version: '0'
66
76
  type: :development
67
77
  prerelease: false
68
- version_requirements: *70193477701680
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: dm-sqlite-adapter
71
- requirement: &70193477701260 !ruby/object:Gem::Requirement
72
- none: false
85
+ requirement: !ruby/object:Gem::Requirement
73
86
  requirements:
74
- - - ! '>='
87
+ - - '>='
75
88
  - !ruby/object:Gem::Version
76
89
  version: '0'
77
90
  type: :development
78
91
  prerelease: false
79
- version_requirements: *70193477701260
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
80
97
  - !ruby/object:Gem::Dependency
81
98
  name: sqlite3
82
- requirement: &70193477700840 !ruby/object:Gem::Requirement
83
- none: false
99
+ requirement: !ruby/object:Gem::Requirement
84
100
  requirements:
85
- - - ! '>='
101
+ - - '>='
86
102
  - !ruby/object:Gem::Version
87
103
  version: '0'
88
104
  type: :development
89
105
  prerelease: false
90
- version_requirements: *70193477700840
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
91
111
  description: Generates attr_accessors that encrypt and decrypt attributes transparently
92
112
  email: danpal@gmail.com
93
113
  executables: []
@@ -95,7 +115,10 @@ extensions: []
95
115
  extra_rdoc_files: []
96
116
  files:
97
117
  - .gitignore
98
- - .rvmrc
118
+ - .ruby-gemset
119
+ - .ruby-version
120
+ - Gemfile
121
+ - Gemfile.lock
99
122
  - MIT-LICENSE
100
123
  - README.md
101
124
  - Rakefile
@@ -111,8 +134,9 @@ files:
111
134
  - test/debug_order.rb
112
135
  - test/sequel_test.rb
113
136
  - test/test_helper.rb
114
- homepage: http://github.com/danpal/attr_encrypted
137
+ homepage: http://github.com/danpal/attr_encryptor
115
138
  licenses: []
139
+ metadata: {}
116
140
  post_install_message:
117
141
  rdoc_options:
118
142
  - --line-numbers
@@ -122,22 +146,20 @@ rdoc_options:
122
146
  require_paths:
123
147
  - lib
124
148
  required_ruby_version: !ruby/object:Gem::Requirement
125
- none: false
126
149
  requirements:
127
- - - ! '>='
150
+ - - '>='
128
151
  - !ruby/object:Gem::Version
129
152
  version: '0'
130
153
  required_rubygems_version: !ruby/object:Gem::Requirement
131
- none: false
132
154
  requirements:
133
- - - ! '>='
155
+ - - '>='
134
156
  - !ruby/object:Gem::Version
135
157
  version: '0'
136
158
  requirements: []
137
159
  rubyforge_project:
138
- rubygems_version: 1.8.6
160
+ rubygems_version: 2.0.3
139
161
  signing_key:
140
- specification_version: 3
162
+ specification_version: 4
141
163
  summary: Encrypt and decrypt attributes
142
164
  test_files:
143
165
  - test/active_record_test.rb
@@ -146,4 +168,3 @@ test_files:
146
168
  - test/debug_order.rb
147
169
  - test/sequel_test.rb
148
170
  - test/test_helper.rb
149
- has_rdoc: false
data/.rvmrc DELETED
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
- # development environment upon cd'ing into the directory
5
-
6
- # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
- environment_id="ruby-1.9.2-p290@attr_encrypted"
8
-
9
- #
10
- # Uncomment following line if you want options to be set only for given project.
11
- #
12
- # PROJECT_JRUBY_OPTS=( --1.9 )
13
-
14
- #
15
- # First we attempt to load the desired environment directly from the environment
16
- # file. This is very fast and efficient compared to running through the entire
17
- # CLI and selector. If you want feedback on which environment was used then
18
- # insert the word 'use' after --create as this triggers verbose mode.
19
- #
20
- if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
- && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
22
- then
23
- \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
24
-
25
- if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
26
- then
27
- . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
28
- fi
29
- else
30
- # If the environment file has not yet been created, use the RVM CLI to select.
31
- if ! rvm --create "$environment_id"
32
- then
33
- echo "Failed to create RVM environment '${environment_id}'."
34
- exit 1
35
- fi
36
- fi
37
-
38
- #
39
- # If you use an RVM gemset file to install a list of gems (*.gems), you can have
40
- # it be automatically loaded. Uncomment the following and adjust the filename if
41
- # necessary.
42
- #
43
- # filename=".gems"
44
- # if [[ -s "$filename" ]] ; then
45
- # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
46
- # fi
47
-