sevenwire-attr_encrypted 1.0.8

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 ADDED
@@ -0,0 +1,42 @@
1
+ 2009-01-18 - Sean Huber (shuber@huberry.com)
2
+ * Don't attempt to encrypt/decrypt empty strings
3
+
4
+ 2009-01-14 - Sean Huber (shuber@huberry.com)
5
+ * Move Class logic into Object
6
+
7
+ 2009-01-13 - Sean Huber (shuber@huberry.com)
8
+ * :marshal no longer defaults to true in ORM adapters
9
+ * Load gem dependencies
10
+
11
+ 2009-01-12 - Sean Huber (shuber@huberry.com)
12
+ * Remove read_attribute and write_attribute methods - unnecessary
13
+ * ActiveRecord and DataMapper extensions are now "adapters"
14
+ * Check for existing reader and writer methods separately before creating default ones for encrypted attributes
15
+ * Typo: should send(encrypted_attribute_name.to_sym) instead of send(encrypted_attribute_name.to_s)
16
+ * Add Sequel adapter
17
+ * Update DataMapper tests
18
+ * Update README
19
+ * Set attr_encrypted_options instead of overwriting the attr_encrypted method in adapters
20
+
21
+ 2009-01-11 - Sean Huber (shuber@huberry.com)
22
+ * Update README
23
+
24
+ 2009-01-10 - Sean Huber (shuber@huberry.com)
25
+ * Update README
26
+
27
+ 2009-01-08 - Sean Huber (shuber@huberry.com)
28
+ * Update comments and documentation
29
+ * Update README
30
+ * Add gemspec
31
+ * Add support for data mapper
32
+ * Attribute methods are now defined before calling attr_encrypted when using active record
33
+ * Add ability to specify your own encoding directives
34
+ * Update logic that evaluates symbol and proc options
35
+ * Add support for :if and :unless options
36
+ * Add AttrEncrypted namespace
37
+
38
+ 2009-01-07 - Sean Huber (shuber@huberry.com)
39
+ * Initial commit
40
+ * Add comments/documentation to the active record related logic
41
+ * Add more attr_encrypted tests
42
+ * Update tests and comments
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Sean Huber - shuber@huberry.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,300 @@
1
+ attr\_encrypted
2
+ ===============
3
+
4
+ Generates attr\_accessors that encrypt and decrypt attributes transparently
5
+
6
+ It works with ANY class, however, you get a few extra features when you're using it with ActiveRecord, DataMapper, or Sequel
7
+
8
+
9
+ Installation
10
+ ------------
11
+
12
+ gem install shuber-attr_encrypted --source http://gems.github.com
13
+
14
+
15
+ Usage
16
+ -----
17
+
18
+ ### Basic ###
19
+
20
+ Encrypting attributes has never been easier:
21
+
22
+ class User
23
+ attr_accessor :name
24
+ attr_encrypted :ssn, :key => 'a secret key'
25
+
26
+ def load
27
+ # loads the stored data
28
+ end
29
+
30
+ def save
31
+ # saves the :name and :encrypted_ssn attributes somewhere (e.g. filesystem, database, etc)
32
+ end
33
+ end
34
+
35
+ @user = User.new
36
+ @user.ssn = '123-45-6789'
37
+ @user.encrypted_ssn # returns the encrypted version of :ssn
38
+ @user.save
39
+
40
+ @user = User.load
41
+ @user.ssn # decrypts :encrypted_ssn and returns '123-45-6789'
42
+
43
+
44
+ ### Specifying the encrypted attribute name ###
45
+
46
+ By default, the encrypted attribute name is `encrypted_#{attribute}` (e.g. `attr_encrypted :email` would create an attribute named `encrypted_email`).
47
+ You have a couple of options if you want to name your attribute something else.
48
+
49
+ #### The `:attribute` option ####
50
+
51
+ You can simply pass the name of the encrypted attribute as the `:attribute` option:
52
+
53
+ class User
54
+ attr_encrypted :email, :key => 'a secret key', :attribute => 'email_encrypted'
55
+ end
56
+
57
+ This would generate an attribute named `email_encrypted`
58
+
59
+
60
+ #### The `:prefix` and `:suffix` options ####
61
+
62
+ If you're planning on encrypting a few different attributes and you don't like the `encrypted_#{attribute}` naming convention then you can specify your own:
63
+
64
+ class User
65
+ attr_encrypted :email, :credit_card, :ssn, :key => 'a secret key', :prefix => 'secret_', :suffix => '_crypted'
66
+ end
67
+
68
+ This would generate the following attributes: `secret_email_crypted`, `secret_credit_card_crypted`, and `secret_ssn_crypted`.
69
+
70
+
71
+ ### Encryption keys ###
72
+
73
+ Although a `:key` option may not be required (see custom encryptor below), it has a few special features
74
+
75
+ #### Unique keys for each attribute ####
76
+
77
+ You can specify unique keys for each attribute if you'd like:
78
+
79
+ class User
80
+ attr_encrypted :email, :key => 'a secret key'
81
+ attr_encrypted :ssn, :key => 'a different secret key'
82
+ end
83
+
84
+
85
+ #### Symbols representing instance methods as keys ####
86
+
87
+ If your class has an instance method that determines the encryption key to use, simply pass a symbol representing it like so:
88
+
89
+ class User
90
+ attr_encrypted :email, :key => :encryption_key
91
+
92
+ def encryption_key
93
+ # does some fancy logic and returns an encryption key
94
+ end
95
+ end
96
+
97
+
98
+ #### Procs as keys ####
99
+
100
+ You can pass a proc/lambda object as the `:key` option as well:
101
+
102
+ class User
103
+ attr_encrypted :email, :key => proc { |user| ... }
104
+ end
105
+
106
+
107
+ ### Conditional encrypting ###
108
+
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
+ attributes when you're in development mode. You can specify conditions like this:
111
+
112
+ class User < ActiveRecord::Base
113
+ attr_encrypted :email, :key => 'a secret key', :unless => Rails.env.development?
114
+ end
115
+
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 `:call` are evaluated as well.
118
+
119
+
120
+ ### Custom encryptor ###
121
+
122
+ The [Huberry::Encryptor](http://github.com/shuber/encryptor) class is used by default. You may use your own custom encryptor by specifying
123
+ the `:encryptor`, `:encrypt_method`, and `:decrypt_method` options
124
+
125
+ Lets suppose you'd like to use this custom encryptor class:
126
+
127
+ class SillyEncryptor
128
+ def self.silly_encrypt(options)
129
+ (options[:value] + options[:secret_key]).reverse
130
+ end
131
+
132
+ def self.silly_decrypt(options)
133
+ options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
134
+ end
135
+ end
136
+
137
+ Simply set up your class like so:
138
+
139
+ class User
140
+ attr_encrypted :email, :secret_key => 'a secret key', :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt
141
+ end
142
+
143
+ Any options that you pass to `attr_encrypted` will be passed to the encryptor along with the `:value` option which contains the string to encrypt/decrypt.
144
+ Notice it uses `:secret_key` instead of `:key`.
145
+
146
+
147
+ ### Custom algorithms ###
148
+
149
+ The default [Huberry::Encryptor](http://github.com/shuber/encryptor) uses the standard ruby OpenSSL library. It's default algorithm is `aes-256-cbc`. You can
150
+ modify this by passing the `:algorithm` option to the `attr_encrypted` call like so:
151
+
152
+ class User
153
+ attr_encrypted :email, :key => 'a secret key', :algorithm => 'bf'
154
+ end
155
+
156
+ Run `openssl list-cipher-commands` to view a list of algorithms supported on your platform. See [http://github.com/shuber/encryptor](http://github.com/shuber/encryptor) for more information.
157
+
158
+ aes-128-cbc
159
+ aes-128-ecb
160
+ aes-192-cbc
161
+ aes-192-ecb
162
+ aes-256-cbc
163
+ aes-256-ecb
164
+ base64
165
+ bf
166
+ bf-cbc
167
+ bf-cfb
168
+ bf-ecb
169
+ bf-ofb
170
+ cast
171
+ cast-cbc
172
+ cast5-cbc
173
+ cast5-cfb
174
+ cast5-ecb
175
+ cast5-ofb
176
+ des
177
+ des-cbc
178
+ des-cfb
179
+ des-ecb
180
+ des-ede
181
+ des-ede-cbc
182
+ des-ede-cfb
183
+ des-ede-ofb
184
+ des-ede3
185
+ des-ede3-cbc
186
+ des-ede3-cfb
187
+ des-ede3-ofb
188
+ des-ofb
189
+ des3
190
+ desx
191
+ idea
192
+ idea-cbc
193
+ idea-cfb
194
+ idea-ecb
195
+ idea-ofb
196
+ rc2
197
+ rc2-40-cbc
198
+ rc2-64-cbc
199
+ rc2-cbc
200
+ rc2-cfb
201
+ rc2-ecb
202
+ rc2-ofb
203
+ rc4
204
+ rc4-40
205
+
206
+
207
+ ### Default options ###
208
+
209
+ Let's imagine that you have a few attributes that you want to encrypt with different keys, but you don't like the `encrypted_#{attribute}` naming convention.
210
+ Instead of having to define your class like this:
211
+
212
+ class User
213
+ attr_encrypted :email, :key => 'a secret key', :prefix => '', :suffix => '_crypted'
214
+ attr_encrypted :ssn, :key => 'a different secret key', :prefix => '', :suffix => '_crypted'
215
+ attr_encrypted :credit_card, :key => 'another secret key', :prefix => '', :suffix => '_crypted'
216
+ end
217
+
218
+ You can simply define some default options like so:
219
+
220
+ class User
221
+ attr_encrypted_options.merge!(:prefix => '', :suffix => '_crypted')
222
+ attr_encrypted :email, :key => 'a secret key'
223
+ attr_encrypted :ssn, :key => 'a different secret key'
224
+ attr_encrypted :credit_card, :key => 'another secret key'
225
+ end
226
+
227
+ This should help keep your classes clean and DRY.
228
+
229
+
230
+ ### Encoding ###
231
+
232
+ 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
233
+ encrypted string. I've had this problem myself using MySQL. You can simply pass the `:encode` option to automatically encode/decode when encrypting/decrypting.
234
+
235
+ class User
236
+ attr_encrypted :email, :key => 'some secret key', :encode => true
237
+ end
238
+
239
+ 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.
240
+
241
+
242
+ ### Marshaling ###
243
+
244
+ You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). If this is the case, simply pass the `:marshal` option to automatically marshal
245
+ when encrypting/decrypting.
246
+
247
+ class User
248
+ attr_encrypted :credentials, :key => 'some secret key', :marshal => true
249
+ end
250
+
251
+
252
+ ### Encrypt/decrypt attribute methods ###
253
+
254
+ If you use the same key to encrypt every record (per attribute) like this:
255
+
256
+ class User
257
+ attr_encrypted :email, :key => 'a secret key'
258
+ end
259
+
260
+ Then you'll have these two class methods available for each attribute: `User.encrypt_email(email_to_encrypt)` and `User.decrypt_email(email_to_decrypt)`. This can
261
+ be useful when you're using ActiveRecord (see below).
262
+
263
+
264
+ ### ActiveRecord ###
265
+
266
+ If you're using this gem with ActiveRecord, you get a few extra features:
267
+
268
+ #### Default options ####
269
+
270
+ For your convenience, the `:encode` option is set to true by default since you'll be storing everything in a database.
271
+
272
+
273
+ #### Dynamic find\_by\_ and scoped\_by\_ methods ####
274
+
275
+ Let's say you'd like to encrypt your user's email addresses, but you also need a way for them to login. Simply set up your class like so:
276
+
277
+ class User < ActiveRecord::Base
278
+ attr_encrypted :email, :key => 'a secret key'
279
+ attr_encrypted :password, :key => 'some other secret key'
280
+ end
281
+
282
+ You can now lookup and login users like so:
283
+
284
+ User.find_by_email_and_password('test@example.com', 'testing')
285
+
286
+ The call to `find_by_email_and_password` is intercepted and modified to `find_by_encrypted_email_and_encrypted_password('ENCRYPTED EMAIL', 'ENCRYPTED PASSWORD')`.
287
+ The dynamic scope methods like `scoped_by_email_and_password` work the same way.
288
+
289
+ NOTE: This only works if all records are encrypted with the same encryption key (per attribute).
290
+
291
+
292
+ ### DataMapper and Sequel ###
293
+
294
+ Just like the default options for ActiveRecord, the `:encode` option is set to true by default since you'll be storing everything in a database.
295
+
296
+
297
+ Contact
298
+ -------
299
+
300
+ Problems, comments, and suggestions all welcome: [shuber@huberry.com](mailto:shuber@huberry.com)
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the attr_encrypted gem.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the attr_encrypted gem.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'attr_encrypted'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README.markdown')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
@@ -0,0 +1,226 @@
1
+ gem 'shuber-eigenclass', '>= 1.0.1'
2
+ require 'eigenclass'
3
+
4
+ gem 'shuber-encryptor'
5
+ require 'encryptor'
6
+
7
+ module Huberry
8
+ module AttrEncrypted
9
+ def self.extended(base)
10
+ base.attr_encrypted_options = {}
11
+ base.instance_variable_set('@encrypted_attributes', {})
12
+ end
13
+
14
+ # Default options to use with calls to <tt>attr_encrypted</tt>.
15
+ #
16
+ # It will inherit existing options from its parent class
17
+ def attr_encrypted_options
18
+ @attr_encrypted_options ||= superclass.attr_encrypted_options.nil? ? {} : superclass.attr_encrypted_options.dup
19
+ end
20
+
21
+ # Sets default options to use with calls to <tt>attr_encrypted</tt>.
22
+ def attr_encrypted_options=(options)
23
+ @attr_encrypted_options = options
24
+ end
25
+
26
+ # Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute
27
+ # names as values
28
+ #
29
+ # Example
30
+ #
31
+ # class User
32
+ # attr_encrypted :email
33
+ # end
34
+ #
35
+ # User.encrypted_attributes # { 'email' => 'encrypted_email' }
36
+ def encrypted_attributes
37
+ @encrypted_attributes ||= superclass.encrypted_attributes.nil? ? {} : superclass.encrypted_attributes.dup
38
+ end
39
+
40
+ # Checks if an attribute has been configured to be encrypted
41
+ #
42
+ # Example
43
+ #
44
+ # class User
45
+ # attr_accessor :name
46
+ # attr_encrypted :email
47
+ # end
48
+ #
49
+ # User.attr_encrypted?(:name) # false
50
+ # User.attr_encrypted?(:email) # true
51
+ def attr_encrypted?(attribute)
52
+ encrypted_attributes.keys.include?(attribute.to_s)
53
+ end
54
+
55
+ protected
56
+
57
+ # Generates attr_accessors that encrypt and decrypt attributes transparently
58
+ #
59
+ # Options (any other options you specify are passed to the encryptor's encrypt and decrypt methods)
60
+ #
61
+ # :attribute => The name of the referenced encrypted attribute. For example
62
+ # <tt>attr_accessor :email, :attribute => :ee</tt> would generate an
63
+ # attribute named 'ee' to store the encrypted email. This is useful when defining
64
+ # one attribute to encrypt at a time or when the :prefix and :suffix options
65
+ # aren't enough. Defaults to nil.
66
+ #
67
+ # :prefix => A prefix used to generate the name of the referenced encrypted attributes.
68
+ # For example <tt>attr_accessor :email, :password, :prefix => 'crypted_'</tt> would
69
+ # generate attributes named 'crypted_email' and 'crypted_password' to store the
70
+ # encrypted email and password. Defaults to 'encrypted_'.
71
+ #
72
+ # :suffix => A suffix used to generate the name of the referenced encrypted attributes.
73
+ # For example <tt>attr_accessor :email, :password, :prefix => '', :suffix => '_encrypted'</tt>
74
+ # would generate attributes named 'email_encrypted' and 'password_encrypted' to store the
75
+ # encrypted email. Defaults to ''.
76
+ #
77
+ # :key => The encryption key. This option may not be required if you're using a custom encryptor. If you pass
78
+ # a symbol representing an instance method then the :key option will be replaced with the result of the
79
+ # method before being passed to the encryptor. Objects that respond to :call are evaluated as well (including procs).
80
+ # Any other key types will be passed directly to the encryptor.
81
+ #
82
+ # :encode => If set to true, attributes will be encoded as well as encrypted. This is useful if you're
83
+ # planning on storing the encrypted attributes in a database. The default encoding is 'm*' (base64),
84
+ # however this can be overwritten by setting the :encode option to some other encoding string instead of
85
+ # just 'true'. See http://www.ruby-doc.org/core/classes/Array.html#M002245 for more encoding directives.
86
+ # Defaults to false unless you're using it with ActiveRecord or DataMapper.
87
+ #
88
+ # :marshal => If set to true, attributes will be marshaled as well as encrypted. This is useful if you're planning
89
+ # on encrypting something other than a string. Defaults to false unless you're using it with ActiveRecord
90
+ # or DataMapper.
91
+ #
92
+ # :encryptor => The object to use for encrypting. Defaults to Huberry::Encryptor.
93
+ #
94
+ # :encrypt_method => The encrypt method name to call on the <tt>:encryptor</tt> object. Defaults to :encrypt.
95
+ #
96
+ # :decrypt_method => The decrypt method name to call on the <tt>:encryptor</tt> object. Defaults to :decrypt.
97
+ #
98
+ # :if => Attributes are only encrypted if this option evaluates to true. If you pass a symbol representing an instance
99
+ # method then the result of the method will be evaluated. Any objects that respond to :call are evaluated as well.
100
+ # Defaults to true.
101
+ #
102
+ # :unless => Attributes are only encrypted if this option evaluates to false. If you pass a symbol representing an instance
103
+ # method then the result of the method will be evaluated. Any objects that respond to :call are evaluated as well.
104
+ # Defaults to false.
105
+ #
106
+ # You can specify your own default options
107
+ #
108
+ # class User
109
+ # # now all attributes will be encoded and marshaled by default
110
+ # attr_encrypted_options.merge!(:encode => true, :marshal => true, :some_other_option => true)
111
+ # attr_encrypted :configuration
112
+ # end
113
+ #
114
+ #
115
+ # Example
116
+ #
117
+ # class User
118
+ # attr_encrypted :email, :credit_card, :key => 'some secret key'
119
+ # attr_encrypted :configuration, :key => 'some other secret key', :marshal => true
120
+ # end
121
+ #
122
+ # @user = User.new
123
+ # @user.encrypted_email # returns nil
124
+ # @user.email = 'test@example.com'
125
+ # @user.encrypted_email # returns the encrypted version of 'test@example.com'
126
+ #
127
+ # @user.configuration = { :time_zone => 'UTC' }
128
+ # @user.encrypted_configuration # returns the encrypted version of configuration
129
+ #
130
+ # See README for more examples
131
+ def attr_encrypted(*attrs)
132
+ options = {
133
+ :prefix => 'encrypted_',
134
+ :suffix => '',
135
+ :encryptor => Huberry::Encryptor,
136
+ :encrypt_method => :encrypt,
137
+ :decrypt_method => :decrypt,
138
+ :encode => false,
139
+ :marshal => false,
140
+ :if => true,
141
+ :unless => false
142
+ }.merge(attr_encrypted_options).merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
143
+ options[:encode] = 'm*' if options[:encode] == true
144
+
145
+ attrs.each do |attribute|
146
+ encrypted_attribute_name = options[:attribute].nil? ? options[:prefix].to_s + attribute.to_s + options[:suffix].to_s : options[:attribute].to_s
147
+
148
+ encrypted_attributes[attribute.to_s] = encrypted_attribute_name
149
+
150
+ attr_reader encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
151
+ attr_writer encrypted_attribute_name.to_sym unless instance_methods.include?("#{encrypted_attribute_name}=")
152
+
153
+ define_class_method "encrypt_#{attribute}" do |value|
154
+ if options[:if] && !options[:unless]
155
+ if value.nil? || (value.is_a?(String) && value.empty?)
156
+ encrypted_value = value
157
+ else
158
+ value = Marshal.dump(value) if options[:marshal]
159
+ encrypted_value = options[:encryptor].send options[:encrypt_method], options.merge(:value => value)
160
+ encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
161
+ end
162
+ encrypted_value
163
+ else
164
+ value
165
+ end
166
+ end
167
+
168
+ define_class_method "decrypt_#{attribute}" do |encrypted_value|
169
+ if options[:if] && !options[:unless]
170
+ if encrypted_value.nil? || (encrypted_value.is_a?(String) && encrypted_value.empty?)
171
+ decrypted_value = encrypted_value
172
+ else
173
+ encrypted_value = encrypted_value.unpack(options[:encode]).to_s if options[:encode]
174
+ decrypted_value = options[:encryptor].send(options[:decrypt_method], options.merge(:value => encrypted_value))
175
+ decrypted_value = Marshal.load(decrypted_value) if options[:marshal]
176
+ end
177
+ decrypted_value
178
+ else
179
+ encrypted_value
180
+ end
181
+ end
182
+
183
+ define_method "#{attribute}" do
184
+ value = instance_variable_get("@#{attribute}")
185
+ encrypted_value = send(encrypted_attribute_name.to_sym)
186
+ original_options = [:key, :if, :unless].inject({}) do |hash, option|
187
+ hash[option] = options[option]
188
+ options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
189
+ hash
190
+ end
191
+ value = instance_variable_set("@#{attribute}", self.class.send("decrypt_#{attribute}".to_sym, encrypted_value)) if value.nil? && !encrypted_value.nil?
192
+ options.merge!(original_options)
193
+ value
194
+ end
195
+
196
+ define_method "#{attribute}=" do |value|
197
+ original_options = [:key, :if, :unless].inject({}) do |hash, option|
198
+ hash[option] = options[option]
199
+ options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
200
+ hash
201
+ end
202
+ send("#{encrypted_attribute_name}=".to_sym, self.class.send("encrypt_#{attribute}".to_sym, value))
203
+ options.merge!(original_options)
204
+ instance_variable_set("@#{attribute}", value)
205
+ end
206
+ end
207
+ end
208
+
209
+ # Evaluates an option specified as a symbol representing an instance method or a proc
210
+ #
211
+ # If the option is not a symbol or proc then the original option is returned
212
+ def evaluate_attr_encrypted_option(option, object)
213
+ if option.is_a?(Symbol) && object.respond_to?(option)
214
+ object.send(option)
215
+ elsif option.respond_to?(:call)
216
+ option.call(object)
217
+ else
218
+ option
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ Object.extend Huberry::AttrEncrypted
225
+
226
+ Dir[File.join(File.dirname(__FILE__), 'huberry', 'attr_encrypted', 'adapters', '*.rb')].each { |file| require file }
@@ -0,0 +1,56 @@
1
+ if defined?(ActiveRecord)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module ActiveRecord
6
+ def self.extended(base)
7
+ base.attr_encrypted_options[:encode] = true
8
+ base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
9
+ end
10
+
11
+ protected
12
+
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
17
+ super
18
+ end
19
+
20
+ # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
21
+ # encrypted attributes
22
+ #
23
+ # NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
24
+ #
25
+ # This is useful for encrypting fields like email addresses. Your user's email addresses
26
+ # are encrypted in the database, but you can still look up a user by email for logging in
27
+ #
28
+ # Example
29
+ #
30
+ # class User < ActiveRecord::Base
31
+ # attr_encrypted :email, :key => 'secret key'
32
+ # end
33
+ #
34
+ # User.find_by_email_and_password('test@example.com', 'testing')
35
+ # # results in a call to
36
+ # User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
37
+ def method_missing_with_attr_encrypted(method, *args, &block)
38
+ if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
39
+ attribute_names = match.captures.last.split('_and_')
40
+ attribute_names.each_with_index do |attribute, index|
41
+ if attr_encrypted?(attribute)
42
+ args[index] = send("encrypt_#{attribute}", args[index])
43
+ attribute_names[index] = encrypted_attributes[attribute]
44
+ end
45
+ end
46
+ method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
47
+ end
48
+ method_missing_without_attr_encrypted(method, *args, &block)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ ActiveRecord::Base.extend Huberry::AttrEncrypted::Adapters::ActiveRecord
56
+ end
@@ -0,0 +1,15 @@
1
+ if defined?(ActiveResource)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module ActiveResource
6
+ def self.extended(base)
7
+ base.attr_encrypted_options[:encode] = true
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ ActiveResource::Base.extend Huberry::AttrEncrypted::Adapters::ActiveResource
15
+ end
@@ -0,0 +1,23 @@
1
+ if defined?(DataMapper)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module DataMapper
6
+ def self.extended(base)
7
+ base.eigenclass_eval do
8
+ alias_method :included_without_attr_encrypted, :included
9
+ alias_method :included, :included_with_attr_encrypted
10
+ end
11
+ end
12
+
13
+ def included_with_attr_encrypted(base)
14
+ included_without_attr_encrypted(base)
15
+ base.attr_encrypted_options[:encode] = true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ DataMapper::Resource.extend Huberry::AttrEncrypted::Adapters::DataMapper
23
+ end
@@ -0,0 +1,15 @@
1
+ if defined?(Sequel)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module Sequel
6
+ def self.extended(base)
7
+ base.attr_encrypted_options[:encode] = true
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ Sequel::Model.extend Huberry::AttrEncrypted::Adapters::Sequel
15
+ end
@@ -0,0 +1,78 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
4
+
5
+ def create_people_table
6
+ silence_stream(STDOUT) do
7
+ ActiveRecord::Schema.define(:version => 1) do
8
+ create_table :people do |t|
9
+ t.string :encrypted_email
10
+ t.string :password
11
+ t.string :encrypted_credentials
12
+ t.string :salt
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # The table needs to exist before defining the class
19
+ create_people_table
20
+
21
+ class Person < ActiveRecord::Base
22
+ attr_encrypted :email, :key => 'a secret key'
23
+ attr_encrypted :credentials, :key => Proc.new { |user| Huberry::Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
24
+
25
+ def after_initialize
26
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
27
+ self.credentials ||= { :username => 'example', :password => 'test' }
28
+ end
29
+ end
30
+
31
+ class ActiveRecordTest < Test::Unit::TestCase
32
+
33
+ def setup
34
+ ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
35
+ create_people_table
36
+ end
37
+
38
+ def test_should_encrypt_email
39
+ @person = Person.create :email => 'test@example.com'
40
+ assert_not_nil @person.encrypted_email
41
+ assert_not_equal @person.email, @person.encrypted_email
42
+ assert_equal @person.email, Person.find(:first).email
43
+ end
44
+
45
+ def test_should_marshal_and_encrypt_credentials
46
+ @person = Person.create
47
+ assert_not_nil @person.encrypted_credentials
48
+ assert_not_equal @person.credentials, @person.encrypted_credentials
49
+ assert_equal @person.credentials, Person.find(:first).credentials
50
+ end
51
+
52
+ def test_should_find_by_email
53
+ @person = Person.create(:email => 'test@example.com')
54
+ assert_equal @person, Person.find_by_email('test@example.com')
55
+ end
56
+
57
+ def test_should_find_by_email_and_password
58
+ Person.create(:email => 'test@example.com', :password => 'invalid')
59
+ @person = Person.create(:email => 'test@example.com', :password => 'test')
60
+ assert_equal @person, Person.find_by_email_and_password('test@example.com', 'test')
61
+ end
62
+
63
+ def test_should_scope_by_email
64
+ @person = Person.create(:email => 'test@example.com')
65
+ assert_equal @person, Person.scoped_by_email('test@example.com').find(:first) rescue NoMethodError
66
+ end
67
+
68
+ def test_should_scope_by_email_and_password
69
+ Person.create(:email => 'test@example.com', :password => 'invalid')
70
+ @person = Person.create(:email => 'test@example.com', :password => 'test')
71
+ assert_equal @person, Person.scoped_by_email_and_password('test@example.com', 'test').find(:first) rescue NoMethodError
72
+ end
73
+
74
+ def test_should_encode_by_default
75
+ assert Person.attr_encrypted_options[:encode]
76
+ end
77
+
78
+ end
@@ -0,0 +1,245 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class SillyEncryptor
4
+ def self.silly_encrypt(options)
5
+ (options[:value] + options[:some_arg]).reverse
6
+ end
7
+
8
+ def self.silly_decrypt(options)
9
+ options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
10
+ end
11
+ end
12
+
13
+ class User
14
+ self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
15
+
16
+ attr_encrypted :email, :without_encoding, :key => 'secret key'
17
+ attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
18
+ attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
19
+ 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_accessor :salt
28
+
29
+ def initialize
30
+ self.salt = Time.now.to_i.to_s
31
+ end
32
+ end
33
+
34
+ class Admin < User
35
+ attr_encrypted :testing
36
+ end
37
+
38
+ class SomeOtherClass
39
+ def self.call(object)
40
+ object.class
41
+ end
42
+ end
43
+
44
+ class AttrEncryptedTest < Test::Unit::TestCase
45
+
46
+ def test_should_store_email_in_encrypted_attributes
47
+ assert User.encrypted_attributes.include?('email')
48
+ end
49
+
50
+ def test_should_not_store_salt_in_encrypted_attributes
51
+ assert !User.encrypted_attributes.include?('salt')
52
+ end
53
+
54
+ def test_attr_encrypted_should_return_true_for_email
55
+ assert User.attr_encrypted?('email')
56
+ end
57
+
58
+ def test_attr_encrypted_should_return_false_for_salt
59
+ assert !User.attr_encrypted?('salt')
60
+ end
61
+
62
+ def test_should_generate_an_encrypted_attribute
63
+ assert User.new.respond_to?(:encrypted_email)
64
+ end
65
+
66
+ def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
67
+ assert User.new.respond_to?(:crypted_password_test)
68
+ end
69
+
70
+ def test_should_generate_an_encrypted_attribute_with_the_attribute_option
71
+ assert User.new.respond_to?(:ssn_encrypted)
72
+ end
73
+
74
+ def test_should_not_encrypt_nil_value
75
+ assert_nil User.encrypt_email(nil)
76
+ end
77
+
78
+ def test_should_not_encrypt_empty_string
79
+ assert_equal '', User.encrypt_email('')
80
+ end
81
+
82
+ def test_should_encrypt_email
83
+ assert_not_nil User.encrypt_email('test@example.com')
84
+ assert_not_equal 'test@example.com', User.encrypt_email('test@example.com')
85
+ end
86
+
87
+ def test_should_encrypt_email_when_modifying_the_attr_writer
88
+ @user = User.new
89
+ assert_nil @user.encrypted_email
90
+ @user.email = 'test@example.com'
91
+ assert_not_nil @user.encrypted_email
92
+ assert_equal User.encrypt_email('test@example.com'), @user.encrypted_email
93
+ end
94
+
95
+ def test_should_not_decrypt_nil_value
96
+ assert_nil User.decrypt_email(nil)
97
+ end
98
+
99
+ def test_should_not_decrypt_empty_string
100
+ assert_equal '', User.decrypt_email('')
101
+ end
102
+
103
+ def test_should_decrypt_email
104
+ encrypted_email = User.encrypt_email('test@example.com')
105
+ assert_not_equal 'test@test.com', encrypted_email
106
+ assert_equal 'test@example.com', User.decrypt_email(encrypted_email)
107
+ end
108
+
109
+ def test_should_decrypt_email_when_reading
110
+ @user = User.new
111
+ assert_nil @user.email
112
+ @user.encrypted_email = User.encrypt_email('test@example.com')
113
+ assert_equal 'test@example.com', @user.email
114
+ end
115
+
116
+ def test_should_encrypt_with_encoding
117
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m*')
118
+ end
119
+
120
+ def test_should_decrypt_with_encoding
121
+ encrypted = User.encrypt_with_encoding('test')
122
+ assert_equal 'test', User.decrypt_with_encoding(encrypted)
123
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m*').to_s)
124
+ end
125
+
126
+ def test_should_encrypt_with_custom_encoding
127
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
128
+ end
129
+
130
+ def test_should_decrypt_with_custom_encoding
131
+ encrypted = User.encrypt_with_encoding('test')
132
+ assert_equal 'test', User.decrypt_with_encoding(encrypted)
133
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').to_s)
134
+ end
135
+
136
+ def test_should_encrypt_with_marshaling
137
+ @user = User.new
138
+ @user.with_marshaling = [1, 2, 3]
139
+ assert_not_nil @user.encrypted_with_marshaling
140
+ assert_equal User.encrypt_with_marshaling([1, 2, 3]), @user.encrypted_with_marshaling
141
+ end
142
+
143
+ def test_should_decrypt_with_marshaling
144
+ encrypted = User.encrypt_with_marshaling([1, 2, 3])
145
+ @user = User.new
146
+ assert_nil @user.with_marshaling
147
+ @user.encrypted_with_marshaling = encrypted
148
+ assert_equal [1, 2, 3], @user.with_marshaling
149
+ end
150
+
151
+ def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
152
+ assert_equal SillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), User.encrypt_credit_card('testing')
153
+ end
154
+
155
+ def test_should_evaluate_a_key_passed_as_a_symbol
156
+ @user = User.new
157
+ assert_nil @user.ssn_encrypted
158
+ @user.ssn = 'testing'
159
+ assert_not_nil @user.ssn_encrypted
160
+ assert_equal Huberry::Encryptor.encrypt(:value => 'testing', :key => @user.salt), @user.ssn_encrypted
161
+ end
162
+
163
+ def test_should_evaluate_a_key_passed_as_a_proc
164
+ @user = User.new
165
+ assert_nil @user.crypted_password_test
166
+ @user.password = 'testing'
167
+ assert_not_nil @user.crypted_password_test
168
+ assert_equal Huberry::Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
169
+ end
170
+
171
+ def test_should_use_options_found_in_the_attr_encrypted_options_attribute
172
+ @user = User.new
173
+ assert_nil @user.crypted_password_test
174
+ @user.password = 'testing'
175
+ assert_not_nil @user.crypted_password_test
176
+ assert_equal Huberry::Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
177
+ end
178
+
179
+ def test_should_inherit_encrypted_attributes
180
+ assert_equal User.encrypted_attributes.merge('testing' => 'encrypted_testing'), Admin.encrypted_attributes
181
+ end
182
+
183
+ def test_should_inherit_attr_encrypted_options
184
+ assert !User.attr_encrypted_options.empty?
185
+ assert_equal User.attr_encrypted_options, Admin.attr_encrypted_options
186
+ end
187
+
188
+ def test_should_not_inherit_unrelated_attributes
189
+ assert SomeOtherClass.attr_encrypted_options.empty?
190
+ assert SomeOtherClass.encrypted_attributes.empty?
191
+ end
192
+
193
+ def test_should_evaluate_a_symbol_option
194
+ assert_equal Object, Object.send(:evaluate_attr_encrypted_option, :class, Object.new)
195
+ end
196
+
197
+ def test_should_evaluate_a_proc_option
198
+ assert_equal Object, Object.send(:evaluate_attr_encrypted_option, proc { |object| object.class }, Object.new)
199
+ end
200
+
201
+ def test_should_evaluate_a_lambda_option
202
+ assert_equal Object, Object.send(:evaluate_attr_encrypted_option, lambda { |object| object.class }, Object.new)
203
+ end
204
+
205
+ def test_should_evaluate_a_method_option
206
+ assert_equal Object, Object.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call), Object.new)
207
+ end
208
+
209
+ def test_should_return_a_string_option
210
+ assert_equal 'Object', Object.send(:evaluate_attr_encrypted_option, 'Object', Object.new)
211
+ end
212
+
213
+ def test_should_encrypt_with_true_if
214
+ @user = User.new
215
+ assert_nil @user.encrypted_with_true_if
216
+ @user.with_true_if = 'testing'
217
+ assert_not_nil @user.encrypted_with_true_if
218
+ assert_equal Huberry::Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_true_if
219
+ end
220
+
221
+ def test_should_not_encrypt_with_false_if
222
+ @user = User.new
223
+ assert_nil @user.encrypted_with_false_if
224
+ @user.with_false_if = 'testing'
225
+ assert_not_nil @user.encrypted_with_false_if
226
+ assert_equal 'testing', @user.encrypted_with_false_if
227
+ end
228
+
229
+ def test_should_encrypt_with_false_unless
230
+ @user = User.new
231
+ assert_nil @user.encrypted_with_false_unless
232
+ @user.with_false_unless = 'testing'
233
+ assert_not_nil @user.encrypted_with_false_unless
234
+ assert_equal Huberry::Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_false_unless
235
+ end
236
+
237
+ def test_should_not_encrypt_with_true_unless
238
+ @user = User.new
239
+ assert_nil @user.encrypted_with_true_unless
240
+ @user.with_true_unless = 'testing'
241
+ assert_not_nil @user.encrypted_with_true_unless
242
+ assert_equal 'testing', @user.encrypted_with_true_unless
243
+ end
244
+
245
+ end
@@ -0,0 +1,52 @@
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') }, :marshal => true
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
+ @client = Client.new :email => 'test@example.com'
33
+ assert @client.save
34
+ assert_not_nil @client.encrypted_email
35
+ assert_not_equal @client.email, @client.encrypted_email
36
+ assert_equal @client.email, Client.first.email
37
+ end
38
+
39
+ def test_should_marshal_and_encrypt_credentials
40
+ @client = Client.new
41
+ assert @client.save
42
+ assert_not_nil @client.encrypted_credentials
43
+ assert_not_equal @client.credentials, @client.encrypted_credentials
44
+ assert_equal @client.credentials, Client.first.credentials
45
+ assert Client.first.credentials.is_a?(Hash)
46
+ end
47
+
48
+ def test_should_encode_by_default
49
+ assert Client.attr_encrypted_options[:encode]
50
+ end
51
+
52
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ DB = Sequel.sqlite
4
+
5
+ DB.create_table :humans do
6
+ primary_key :id
7
+ column :encrypted_email, :string
8
+ column :password, :string
9
+ column :encrypted_credentials, :string
10
+ column :salt, :string
11
+ end
12
+
13
+ class Human < Sequel::Model(:humans)
14
+ attr_encrypted :email, :key => 'a secret key'
15
+ attr_encrypted :credentials, :key => Proc.new { |human| Huberry::Encryptor.encrypt(:value => human.salt, :key => 'some private key') }, :marshal => true
16
+
17
+ def after_initialize(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
+ class SequelTest < Test::Unit::TestCase
24
+
25
+ def setup
26
+ Human.all.each(&:destroy)
27
+ end
28
+
29
+ def test_should_encrypt_email
30
+ @human = Human.new :email => 'test@example.com'
31
+ assert @human.save
32
+ assert_not_nil @human.encrypted_email
33
+ assert_not_equal @human.email, @human.encrypted_email
34
+ assert_equal @human.email, Human.first.email
35
+ end
36
+
37
+ def test_should_marshal_and_encrypt_credentials
38
+ @human = Human.new
39
+ assert @human.save
40
+ assert_not_nil @human.encrypted_credentials
41
+ assert_not_equal @human.credentials, @human.encrypted_credentials
42
+ assert_equal @human.credentials, Human.first.credentials
43
+ assert Human.first.credentials.is_a?(Hash)
44
+ end
45
+
46
+ def test_should_encode_by_default
47
+ assert Human.attr_encrypted_options[:encode]
48
+ end
49
+
50
+ end
@@ -0,0 +1,16 @@
1
+ require 'test/unit'
2
+ require 'digest/sha2'
3
+
4
+ require 'rubygems'
5
+
6
+ gem 'activerecord'
7
+ gem 'datamapper'
8
+ gem 'sequel'
9
+
10
+ require 'eigenclass'
11
+ require 'encryptor'
12
+ require 'active_record'
13
+ require 'datamapper'
14
+ require 'sequel'
15
+
16
+ require File.dirname(__FILE__) + '/../lib/attr_encrypted'
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sevenwire-attr_encrypted
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.8
5
+ platform: ruby
6
+ authors:
7
+ - Sean Huber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-13 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: shuber-eigenclass
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: shuber-encryptor
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ version:
35
+ description: Generates attr_accessors that encrypt and decrypt attributes transparently
36
+ email: shuber@huberry.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - CHANGELOG
45
+ - lib/attr_encrypted.rb
46
+ - lib/huberry/attr_encrypted/adapters/active_record.rb
47
+ - lib/huberry/attr_encrypted/adapters/active_resource.rb
48
+ - lib/huberry/attr_encrypted/adapters/data_mapper.rb
49
+ - lib/huberry/attr_encrypted/adapters/sequel.rb
50
+ - MIT-LICENSE
51
+ - Rakefile
52
+ - README.markdown
53
+ - test/test_helper.rb
54
+ has_rdoc: false
55
+ homepage: http://github.com/shuber/attr_encrypted
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --line-numbers
59
+ - --inline-source
60
+ - --main
61
+ - README.markdown
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.2.0
80
+ signing_key:
81
+ specification_version: 2
82
+ summary: Generates attr_accessors that encrypt and decrypt attributes transparently
83
+ test_files:
84
+ - test/active_record_test.rb
85
+ - test/attr_encrypted_test.rb
86
+ - test/data_mapper_test.rb
87
+ - test/sequel_test.rb