shuber-attr_encrypted 1.0.3 → 1.0.4
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 +11 -0
- data/README.markdown +4 -4
- data/lib/attr_encrypted.rb +2 -10
- data/lib/huberry/attr_encrypted/adapters/active_record.rb +58 -0
- data/lib/huberry/attr_encrypted/adapters/data_mapper.rb +25 -0
- data/lib/huberry/attr_encrypted/class.rb +12 -11
- data/lib/huberry/attr_encrypted/object.rb +40 -36
- metadata +4 -4
- data/lib/huberry/attr_encrypted/active_record.rb +0 -50
- data/lib/huberry/attr_encrypted/data_mapper.rb +0 -23
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
2009-01-12 - Sean Huber (shuber@huberry.com)
|
2
|
+
* Remove read_attribute and write_attribute methods - unnecessary
|
3
|
+
* ActiveRecord and DataMapper extensions are now "adapters"
|
4
|
+
* Check for existing reader and writer methods separately before creating default ones for encrypted attributes
|
5
|
+
|
6
|
+
2009-01-11 - Sean Huber (shuber@huberry.com)
|
7
|
+
* Update README
|
8
|
+
|
9
|
+
2009-01-10 - Sean Huber (shuber@huberry.com)
|
10
|
+
* Update README
|
11
|
+
|
1
12
|
2009-01-08 - Sean Huber (shuber@huberry.com)
|
2
13
|
* Update comments and documentation
|
3
14
|
* Update README
|
data/README.markdown
CHANGED
@@ -3,7 +3,7 @@ attr\_encrypted
|
|
3
3
|
|
4
4
|
Generates attr\_accessors that encrypt and decrypt attributes transparently
|
5
5
|
|
6
|
-
Works with
|
6
|
+
Works with ANY class including ActiveRecord and DataMapper
|
7
7
|
|
8
8
|
|
9
9
|
Installation
|
@@ -97,7 +97,7 @@ If your class has an instance method that determines the encryption key to use,
|
|
97
97
|
|
98
98
|
#### Procs as keys ####
|
99
99
|
|
100
|
-
You can pass a proc object as the `:key` option as well:
|
100
|
+
You can pass a proc/lambda object as the `:key` option as well:
|
101
101
|
|
102
102
|
class User
|
103
103
|
attr_encrypted :email, :key => proc { |user| ... }
|
@@ -109,12 +109,12 @@ You can pass a proc object as the `:key` option as well:
|
|
109
109
|
There may be times that you want to only encrypt when certain conditions are met. For example maybe you're using rails and you don't want to encrypt
|
110
110
|
attributes when you're in development mode. You can specify conditions like this:
|
111
111
|
|
112
|
-
class User
|
112
|
+
class User < ActiveRecord::Base
|
113
113
|
attr_encrypted :email, :key => 'a secret key', :unless => Rails.env.development?
|
114
114
|
end
|
115
115
|
|
116
116
|
You can specify both `:if` and `:unless` options. If you pass a symbol representing an instance method then the result of the method will be evaluated.
|
117
|
-
Any objects that respond to
|
117
|
+
Any objects that respond to `:call` are evaluated as well.
|
118
118
|
|
119
119
|
|
120
120
|
### Custom encryptor ###
|
data/lib/attr_encrypted.rb
CHANGED
@@ -2,14 +2,6 @@ require 'huberry/attr_encrypted/class'
|
|
2
2
|
Class.send :include, Huberry::AttrEncrypted::Class
|
3
3
|
|
4
4
|
require 'huberry/attr_encrypted/object'
|
5
|
-
Object.
|
5
|
+
Object.extend Huberry::AttrEncrypted::Object
|
6
6
|
|
7
|
-
|
8
|
-
require 'huberry/attr_encrypted/active_record'
|
9
|
-
ActiveRecord::Base.extend Huberry::AttrEncrypted::ActiveRecord
|
10
|
-
end
|
11
|
-
|
12
|
-
if defined?(DataMapper)
|
13
|
-
require 'huberry/attr_encrypted/data_mapper'
|
14
|
-
DataMapper::Resource.send :include, Huberry::AttrEncrypted::DataMapper
|
15
|
-
end
|
7
|
+
Dir[File.join(File.dirname(__FILE__), 'huberry', 'attr_encrypted', 'adapters', '*.rb')].each { |file| require file }
|
@@ -0,0 +1,58 @@
|
|
1
|
+
if defined?(ActiveRecord)
|
2
|
+
module Huberry
|
3
|
+
module AttrEncrypted
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
def self.extended(base)
|
7
|
+
base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
13
|
+
# unless they've already been specified
|
14
|
+
#
|
15
|
+
# Also defines the attribute methods for db fields if they don't exist yet
|
16
|
+
def attr_encrypted(*attrs)
|
17
|
+
define_attribute_methods
|
18
|
+
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
19
|
+
super *(attrs << options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
|
23
|
+
# encrypted attributes
|
24
|
+
#
|
25
|
+
# NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
|
26
|
+
#
|
27
|
+
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
28
|
+
# are encrypted in the database, but you can still look up a user by email for logging in
|
29
|
+
#
|
30
|
+
# Example
|
31
|
+
#
|
32
|
+
# class User < ActiveRecord::Base
|
33
|
+
# attr_encrypted :email, :key => 'secret key'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# User.find_by_email_and_password('test@example.com', 'testing')
|
37
|
+
# # results in a call to
|
38
|
+
# User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
|
39
|
+
def method_missing_with_attr_encrypted(method, *args, &block)
|
40
|
+
if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
|
41
|
+
attribute_names = match.captures.last.split('_and_')
|
42
|
+
attribute_names.each_with_index do |attribute, index|
|
43
|
+
if attr_encrypted?(attribute)
|
44
|
+
args[index] = send("encrypt_#{attribute}", args[index])
|
45
|
+
attribute_names[index] = encrypted_attributes[attribute]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
|
49
|
+
end
|
50
|
+
method_missing_without_attr_encrypted(method, *args, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ActiveRecord::Base.extend Huberry::AttrEncrypted::Adapters::ActiveRecord
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
if defined?(DataMapper)
|
2
|
+
module Huberry
|
3
|
+
module AttrEncrypted
|
4
|
+
module Adapters
|
5
|
+
module DataMapper
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
protected
|
12
|
+
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
13
|
+
# unless they've already been specified
|
14
|
+
def attr_encrypted(*attrs)
|
15
|
+
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
16
|
+
super *(attrs << options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
DataMapper::Resource.send :include, Huberry::AttrEncrypted::Adapters::DataMapper
|
25
|
+
end
|
@@ -89,14 +89,15 @@ module Huberry
|
|
89
89
|
:unless => false
|
90
90
|
}.merge(attr_encrypted_options).merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
91
91
|
options[:encode] = 'm*' if options[:encode] == true
|
92
|
-
|
92
|
+
|
93
93
|
attrs.each do |attribute|
|
94
94
|
encrypted_attribute_name = options[:attribute].nil? ? options[:prefix].to_s + attribute.to_s + options[:suffix].to_s : options[:attribute].to_s
|
95
|
-
|
95
|
+
|
96
96
|
encrypted_attributes[attribute.to_s] = encrypted_attribute_name
|
97
|
-
|
98
|
-
|
99
|
-
|
97
|
+
|
98
|
+
attr_reader encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
|
99
|
+
attr_writer encrypted_attribute_name.to_sym unless instance_methods.include?("#{encrypted_attribute_name}=")
|
100
|
+
|
100
101
|
define_class_method "encrypt_#{attribute}" do |value|
|
101
102
|
if options[:if] && !options[:unless]
|
102
103
|
if value.nil?
|
@@ -111,7 +112,7 @@ module Huberry
|
|
111
112
|
value
|
112
113
|
end
|
113
114
|
end
|
114
|
-
|
115
|
+
|
115
116
|
define_class_method "decrypt_#{attribute}" do |encrypted_value|
|
116
117
|
if options[:if] && !options[:unless]
|
117
118
|
if encrypted_value.nil?
|
@@ -126,10 +127,10 @@ module Huberry
|
|
126
127
|
encrypted_value
|
127
128
|
end
|
128
129
|
end
|
129
|
-
|
130
|
+
|
130
131
|
define_method "#{attribute}" do
|
131
132
|
value = instance_variable_get("@#{attribute}")
|
132
|
-
encrypted_value =
|
133
|
+
encrypted_value = send(encrypted_attribute_name.to_s)
|
133
134
|
original_options = [:key, :if, :unless].inject({}) do |hash, option|
|
134
135
|
hash[option] = options[option]
|
135
136
|
options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
|
@@ -139,20 +140,20 @@ module Huberry
|
|
139
140
|
options.merge!(original_options)
|
140
141
|
value
|
141
142
|
end
|
142
|
-
|
143
|
+
|
143
144
|
define_method "#{attribute}=" do |value|
|
144
145
|
original_options = [:key, :if, :unless].inject({}) do |hash, option|
|
145
146
|
hash[option] = options[option]
|
146
147
|
options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
|
147
148
|
hash
|
148
149
|
end
|
149
|
-
|
150
|
+
send("#{encrypted_attribute_name}=".to_sym, self.class.send("encrypt_#{attribute}".to_sym, value))
|
150
151
|
options.merge!(original_options)
|
151
152
|
instance_variable_set("@#{attribute}", value)
|
152
153
|
end
|
153
154
|
end
|
154
155
|
end
|
155
|
-
|
156
|
+
|
156
157
|
# Evaluates an option specified as a symbol representing an instance method or a proc
|
157
158
|
# If the option is not a symbol or proc then the original option is returned
|
158
159
|
def evaluate_attr_encrypted_option(option, object)
|
@@ -1,46 +1,50 @@
|
|
1
1
|
module Huberry
|
2
2
|
module AttrEncrypted
|
3
3
|
module Object
|
4
|
-
def self.
|
5
|
-
base.
|
6
|
-
|
7
|
-
eattr_accessor :attr_encrypted_options, :encrypted_attributes
|
8
|
-
attr_encrypted_options = {}
|
9
|
-
encrypted_attributes = {}
|
10
|
-
end
|
4
|
+
def self.extended(base)
|
5
|
+
base.attr_encrypted_options = {}
|
6
|
+
base.instance_variable_set('@encrypted_attributes', {})
|
11
7
|
end
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
8
|
+
|
9
|
+
# Default options to use with calls to <tt>attr_encrypted</tt>.
|
10
|
+
#
|
11
|
+
# It will inherit existing options from its parent class
|
12
|
+
def attr_encrypted_options
|
13
|
+
@attr_encrypted_options ||= superclass.attr_encrypted_options.nil? ? {} : superclass.attr_encrypted_options.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
# Sets default options to use with calls to <tt>attr_encrypted</tt>.
|
17
|
+
def attr_encrypted_options=(options)
|
18
|
+
@attr_encrypted_options = options
|
16
19
|
end
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
-
|
20
|
+
|
21
|
+
# Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute
|
22
|
+
# names as values
|
23
|
+
#
|
24
|
+
# Example
|
25
|
+
#
|
26
|
+
# class User
|
27
|
+
# attr_encrypted :email
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# User.encrypted_attributes # { 'email' => 'encrypted_email' }
|
31
|
+
def encrypted_attributes
|
32
|
+
@encrypted_attributes ||= superclass.encrypted_attributes.nil? ? {} : superclass.encrypted_attributes.dup
|
21
33
|
end
|
22
|
-
|
23
|
-
module ClassMethods
|
24
|
-
# Checks if an attribute has been configured to be encrypted
|
25
|
-
#
|
26
|
-
# Example
|
27
|
-
#
|
28
|
-
# class User
|
29
|
-
# attr_accessor :name
|
30
|
-
# attr_encrypted :email
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# User.attr_encrypted?(:name) # false
|
34
|
-
# User.attr_encrypted?(:email) # true
|
35
|
-
def attr_encrypted?(attribute)
|
36
|
-
encrypted_attributes.keys.include?(attribute.to_s)
|
37
|
-
end
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
# Checks if an attribute has been configured to be encrypted
|
36
|
+
#
|
37
|
+
# Example
|
38
|
+
#
|
39
|
+
# class User
|
40
|
+
# attr_accessor :name
|
41
|
+
# attr_encrypted :email
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# User.attr_encrypted?(:name) # false
|
45
|
+
# User.attr_encrypted?(:email) # true
|
46
|
+
def attr_encrypted?(attribute)
|
47
|
+
encrypted_attributes.keys.include?(attribute.to_s)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Huber
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -41,9 +41,9 @@ extra_rdoc_files: []
|
|
41
41
|
files:
|
42
42
|
- CHANGELOG
|
43
43
|
- lib/attr_encrypted.rb
|
44
|
-
- lib/huberry/attr_encrypted/active_record.rb
|
44
|
+
- lib/huberry/attr_encrypted/adapters/active_record.rb
|
45
|
+
- lib/huberry/attr_encrypted/adapters/data_mapper.rb
|
45
46
|
- lib/huberry/attr_encrypted/class.rb
|
46
|
-
- lib/huberry/attr_encrypted/data_mapper.rb
|
47
47
|
- lib/huberry/attr_encrypted/object.rb
|
48
48
|
- MIT-LICENSE
|
49
49
|
- Rakefile
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Huberry
|
2
|
-
module AttrEncrypted
|
3
|
-
module ActiveRecord
|
4
|
-
def self.extended(base)
|
5
|
-
base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
|
6
|
-
end
|
7
|
-
|
8
|
-
protected
|
9
|
-
|
10
|
-
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
11
|
-
# unless they've already been specified
|
12
|
-
def attr_encrypted(*attrs)
|
13
|
-
define_attribute_methods
|
14
|
-
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
15
|
-
super *(attrs << options)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
|
19
|
-
# encrypted attributes
|
20
|
-
#
|
21
|
-
# NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
|
22
|
-
#
|
23
|
-
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
24
|
-
# are encrypted in the database, but you can still look up a user by email for logging in
|
25
|
-
#
|
26
|
-
# Example
|
27
|
-
#
|
28
|
-
# class User < ActiveRecord::Base
|
29
|
-
# attr_encrypted :email, :key => 'secret key'
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# User.find_by_email_and_password('test@example.com', 'testing')
|
33
|
-
# # results in a call to
|
34
|
-
# User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
|
35
|
-
def method_missing_with_attr_encrypted(method, *args, &block)
|
36
|
-
if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
|
37
|
-
attribute_names = match.captures.last.split('_and_')
|
38
|
-
attribute_names.each_with_index do |attribute, index|
|
39
|
-
if attr_encrypted?(attribute)
|
40
|
-
args[index] = send("encrypt_#{attribute}", args[index])
|
41
|
-
attribute_names[index] = encrypted_attributes[attribute]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
|
45
|
-
end
|
46
|
-
method_missing_without_attr_encrypted(method, *args, &block)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Huberry
|
2
|
-
module AttrEncrypted
|
3
|
-
module DataMapper
|
4
|
-
def self.included(base)
|
5
|
-
base.class_eval do
|
6
|
-
extend ClassMethods
|
7
|
-
alias_method :read_attribute, :attribute_get
|
8
|
-
alias_method :write_attribute, :attribute_set
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
protected
|
14
|
-
# Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
|
15
|
-
# unless they've already been specified
|
16
|
-
def attr_encrypted(*attrs)
|
17
|
-
options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
|
18
|
-
super *(attrs << options)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|