shuber-attr_encrypted 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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