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 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 base64 encode/decode when encrypting/decrypting.
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
 
@@ -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 base64 encoded as well as encrypted. This is useful if you're
30
- # planning on storing the encrypted attributes in a database. Defaults to false unless you're using
31
- # it with ActiveRecord.
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 self.new.respond_to?(encrypted_attribute_name)
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('m*') if options[:encode]
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('m*').to_s if options[:encode]
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 = write_attribute(attribute, self.class.send("decrypt_#{attribute}".to_sym, encrypted_value)) if value.nil? && !encrypted_value.nil?
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
@@ -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
@@ -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.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