shuber-attr_encrypted 1.0.0 → 1.0.1
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.
- data/CHANGELOG +3 -0
- data/README.markdown +5 -1
- data/lib/attr_encrypted.rb +5 -0
- data/lib/huberry/active_record.rb +1 -0
- data/lib/huberry/class.rb +12 -8
- data/lib/huberry/data_mapper.rb +21 -0
- data/lib/huberry/object.rb +0 -4
- data/test/attr_encrypted_test.rb +11 -0
- data/test/data_mapper_test.rb +48 -0
- data/test/test_helper.rb +2 -0
- metadata +3 -1
data/CHANGELOG
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
* Update comments and documentation
|
3
3
|
* Update README
|
4
4
|
* Add gemspec
|
5
|
+
* Add support for data mapper
|
6
|
+
* Attribute methods are now defined before calling attr_encrypted when using active record
|
7
|
+
* Add ability to specify your own encoding directives
|
5
8
|
|
6
9
|
2009-01-07 - Sean Huber (shuber@huberry.com)
|
7
10
|
* Initial commit
|
data/README.markdown
CHANGED
@@ -3,6 +3,8 @@ attr\_encrypted
|
|
3
3
|
|
4
4
|
Generates attr\_accessors that encrypt and decrypt attributes transparently
|
5
5
|
|
6
|
+
Works with any class including ActiveRecord and DataMapper
|
7
|
+
|
6
8
|
|
7
9
|
Installation
|
8
10
|
------------
|
@@ -215,12 +217,14 @@ This should help keep your classes clean and DRY.
|
|
215
217
|
### Encoding ###
|
216
218
|
|
217
219
|
You're probably going to be storing your encrypted attributes somehow (e.g. filesystem, database, etc) and may run into some issues trying to store a weird
|
218
|
-
encrypted string. I've had this problem myself using MySQL. You can simply pass the `:encode` option to automatically
|
220
|
+
encrypted string. I've had this problem myself using MySQL. You can simply pass the `:encode` option to automatically encode/decode when encrypting/decrypting.
|
219
221
|
|
220
222
|
class User
|
221
223
|
attr_encrypted :email, :key => 'some secret key', :encode => true
|
222
224
|
end
|
223
225
|
|
226
|
+
The default encoding is `m*` (base64). You can change this by setting `:encode => 'some encoding'`. See [Array#pack](http://www.ruby-doc.org/core/classes/Array.html#M002245) for more encoding options.
|
227
|
+
|
224
228
|
|
225
229
|
### Marshaling ###
|
226
230
|
|
data/lib/attr_encrypted.rb
CHANGED
@@ -7,4 +7,9 @@ Object.send :include, Huberry::Object
|
|
7
7
|
if defined?(ActiveRecord)
|
8
8
|
require 'huberry/active_record'
|
9
9
|
ActiveRecord::Base.extend Huberry::ActiveRecord
|
10
|
+
end
|
11
|
+
|
12
|
+
if defined?(DataMapper)
|
13
|
+
require 'huberry/data_mapper'
|
14
|
+
DataMapper::Resource.send :include, Huberry::DataMapper
|
10
15
|
end
|
@@ -9,6 +9,7 @@ module Huberry
|
|
9
9
|
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
10
10
|
# unless they've already been specified
|
11
11
|
def attr_encrypted(*attrs)
|
12
|
+
define_attribute_methods
|
12
13
|
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
13
14
|
super *(attrs << options)
|
14
15
|
end
|
data/lib/huberry/class.rb
CHANGED
@@ -26,12 +26,15 @@ module Huberry
|
|
26
26
|
# method before being passed to the encryptor. Proc objects are evaluated as well. Any other key types
|
27
27
|
# will be passed directly to the encryptor.
|
28
28
|
#
|
29
|
-
# :encode => If set to true, attributes will be
|
30
|
-
# planning on storing the encrypted attributes in a database.
|
31
|
-
#
|
29
|
+
# :encode => If set to true, attributes will be encoded as well as encrypted. This is useful if you're
|
30
|
+
# planning on storing the encrypted attributes in a database. The default encoding is 'm*' (base64),
|
31
|
+
# however this can be overwritten by setting the :encode option to some other encoding string instead of
|
32
|
+
# just 'true'. See http://www.ruby-doc.org/core/classes/Array.html#M002245 for more encoding directives.
|
33
|
+
# Defaults to false unless you're using it with ActiveRecord or DataMapper.
|
32
34
|
#
|
33
35
|
# :marshal => If set to true, attributes will be marshaled as well as encrypted. This is useful if you're planning
|
34
|
-
# on encrypting something other than a string. Defaults to false unless you're using it with ActiveRecord
|
36
|
+
# on encrypting something other than a string. Defaults to false unless you're using it with ActiveRecord
|
37
|
+
# or DataMapper.
|
35
38
|
#
|
36
39
|
# :encryptor => The object to use for encrypting. Defaults to Huberry::Encryptor.
|
37
40
|
#
|
@@ -75,13 +78,14 @@ module Huberry
|
|
75
78
|
:encode => false,
|
76
79
|
:marshal => false
|
77
80
|
}.merge(attr_encrypted_options).merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
81
|
+
options[:encode] = 'm*' if options[:encode] == true
|
78
82
|
|
79
83
|
attrs.each do |attribute|
|
80
84
|
encrypted_attribute_name = options[:attribute].nil? ? options[:prefix].to_s + attribute.to_s + options[:suffix].to_s : options[:attribute].to_s
|
81
85
|
|
82
86
|
encrypted_attributes[attribute.to_s] = encrypted_attribute_name
|
83
87
|
|
84
|
-
attr_accessor encrypted_attribute_name.to_sym unless
|
88
|
+
attr_accessor encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
|
85
89
|
|
86
90
|
define_class_method "encrypt_#{attribute}" do |value|
|
87
91
|
if value.nil?
|
@@ -89,7 +93,7 @@ module Huberry
|
|
89
93
|
else
|
90
94
|
value = Marshal.dump(value) if options[:marshal]
|
91
95
|
encrypted_value = options[:encryptor].send options[:encrypt_method], options.merge(:value => value)
|
92
|
-
encrypted_value = [encrypted_value].pack(
|
96
|
+
encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
|
93
97
|
end
|
94
98
|
encrypted_value
|
95
99
|
end
|
@@ -98,7 +102,7 @@ module Huberry
|
|
98
102
|
if encrypted_value.nil?
|
99
103
|
decrypted_value = nil
|
100
104
|
else
|
101
|
-
encrypted_value = encrypted_value.unpack(
|
105
|
+
encrypted_value = encrypted_value.unpack(options[:encode]).to_s if options[:encode]
|
102
106
|
decrypted_value = options[:encryptor].send(options[:decrypt_method], options.merge(:value => encrypted_value))
|
103
107
|
decrypted_value = Marshal.load(decrypted_value) if options[:marshal]
|
104
108
|
end
|
@@ -110,7 +114,7 @@ module Huberry
|
|
110
114
|
encrypted_value = read_attribute(encrypted_attribute_name)
|
111
115
|
original_key = options[:key]
|
112
116
|
options[:key] = self.class.send :evaluate_attr_encrypted_key, options[:key], self
|
113
|
-
value =
|
117
|
+
value = instance_variable_set("@#{attribute}", self.class.send("decrypt_#{attribute}".to_sym, encrypted_value)) if value.nil? && !encrypted_value.nil?
|
114
118
|
options[:key] = original_key
|
115
119
|
value
|
116
120
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Huberry
|
2
|
+
module DataMapper
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
extend ClassMethods
|
6
|
+
alias_method :read_attribute, :attribute_get
|
7
|
+
alias_method :write_attribute, :attribute_set
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
protected
|
13
|
+
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
14
|
+
# unless they've already been specified
|
15
|
+
def attr_encrypted(*attrs)
|
16
|
+
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
17
|
+
super *(attrs << options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/huberry/object.rb
CHANGED
@@ -10,15 +10,11 @@ module Huberry
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Wraps instance_variable_get
|
13
|
-
#
|
14
|
-
# ActiveRecord overwrites this (if you're using it)
|
15
13
|
def read_attribute(attribute)
|
16
14
|
instance_variable_get("@#{attribute}")
|
17
15
|
end
|
18
16
|
|
19
17
|
# Wraps instance_variable_set
|
20
|
-
#
|
21
|
-
# ActiveRecord overwrites this (if you're using it)
|
22
18
|
def write_attribute(attribute, value)
|
23
19
|
instance_variable_set("@#{attribute}", value)
|
24
20
|
end
|
data/test/attr_encrypted_test.rb
CHANGED
@@ -18,6 +18,7 @@ class User
|
|
18
18
|
attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
|
19
19
|
attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
|
20
20
|
attr_encrypted :with_encoding, :key => 'secret key', :encode => true
|
21
|
+
attr_encrypted :with_custom_encoding, :key => 'secret key', :encode => 'm'
|
21
22
|
attr_encrypted :with_marshaling, :key => 'secret key', :marshal => true
|
22
23
|
attr_accessor :salt
|
23
24
|
|
@@ -107,6 +108,16 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
107
108
|
assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m*').to_s)
|
108
109
|
end
|
109
110
|
|
111
|
+
def test_should_encrypt_with_custom_encoding
|
112
|
+
assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_should_decrypt_with_custom_encoding
|
116
|
+
encrypted = User.encrypt_with_encoding('test')
|
117
|
+
assert_equal 'test', User.decrypt_with_encoding(encrypted)
|
118
|
+
assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').to_s)
|
119
|
+
end
|
120
|
+
|
110
121
|
def test_should_encrypt_with_marshaling
|
111
122
|
@user = User.new
|
112
123
|
@user.with_marshaling = [1, 2, 3]
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
4
|
+
|
5
|
+
class Client
|
6
|
+
include DataMapper::Resource
|
7
|
+
|
8
|
+
property :id, Serial
|
9
|
+
property :encrypted_email, String
|
10
|
+
property :encrypted_credentials, Text
|
11
|
+
property :salt, String
|
12
|
+
|
13
|
+
attr_encrypted :email, :key => 'a secret key'
|
14
|
+
attr_encrypted :credentials, :key => Proc.new { |client| Huberry::Encryptor.encrypt(:value => client.salt, :key => 'some private key') }
|
15
|
+
|
16
|
+
def initialize(attrs = {})
|
17
|
+
super attrs
|
18
|
+
self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
|
19
|
+
self.credentials ||= { :username => 'example', :password => 'test' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
DataMapper.auto_migrate!
|
24
|
+
|
25
|
+
class DataMapperTest < Test::Unit::TestCase
|
26
|
+
|
27
|
+
def setup
|
28
|
+
Client.all.each(&:destroy)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_encrypt_email
|
32
|
+
@person = Client.new :email => 'test@example.com'
|
33
|
+
assert @person.save
|
34
|
+
assert_not_nil @person.encrypted_email
|
35
|
+
assert_not_equal @person.email, @person.encrypted_email
|
36
|
+
assert_equal @person.email, Client.first.email
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_marshal_and_encrypt_credentials
|
40
|
+
@person = Client.new
|
41
|
+
assert @person.save
|
42
|
+
assert_not_nil @person.encrypted_credentials
|
43
|
+
assert_not_equal @person.credentials, @person.encrypted_credentials
|
44
|
+
assert_equal @person.credentials, Client.first.credentials
|
45
|
+
assert Client.first.credentials.is_a?(Hash)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -5,9 +5,11 @@ require 'rubygems'
|
|
5
5
|
gem 'shuber-eigenclass', '>= 1.0.1'
|
6
6
|
gem 'shuber-encryptor'
|
7
7
|
gem 'activerecord'
|
8
|
+
gem 'datamapper'
|
8
9
|
|
9
10
|
require 'eigenclass'
|
10
11
|
require 'encryptor'
|
11
12
|
require 'active_record'
|
13
|
+
require 'datamapper'
|
12
14
|
|
13
15
|
require File.dirname(__FILE__) + '/../lib/attr_encrypted'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shuber-attr_encrypted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Huber
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/attr_encrypted.rb
|
44
44
|
- lib/huberry/active_record.rb
|
45
45
|
- lib/huberry/class.rb
|
46
|
+
- lib/huberry/data_mapper.rb
|
46
47
|
- lib/huberry/object.rb
|
47
48
|
- MIT-LICENSE
|
48
49
|
- Rakefile
|
@@ -80,3 +81,4 @@ summary: Generates attr_accessors that encrypt and decrypt attributes transparen
|
|
80
81
|
test_files:
|
81
82
|
- test/active_record_test.rb
|
82
83
|
- test/attr_encrypted_test.rb
|
84
|
+
- test/data_mapper_test.rb
|