attr_encrypted 1.0.9 → 1.1.0
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/README.rdoc +308 -0
- data/Rakefile +1 -1
- data/lib/attr_encrypted.rb +192 -196
- data/lib/attr_encrypted/adapters/active_record.rb +55 -0
- data/lib/attr_encrypted/adapters/data_mapper.rb +21 -0
- data/lib/attr_encrypted/adapters/sequel.rb +13 -0
- data/test/active_record_test.rb +1 -1
- data/test/attr_encrypted_test.rb +12 -5
- data/test/data_mapper_test.rb +1 -1
- data/test/sequel_test.rb +1 -1
- data/test/test_helper.rb +0 -6
- metadata +14 -10
- data/CHANGELOG +0 -45
- data/README.markdown +0 -299
- data/lib/huberry/attr_encrypted/adapters/active_record.rb +0 -57
- data/lib/huberry/attr_encrypted/adapters/data_mapper.rb +0 -23
- data/lib/huberry/attr_encrypted/adapters/sequel.rb +0 -15
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
if defined?(ActiveRecord)
|
|
2
|
+
module AttrEncrypted
|
|
3
|
+
module Adapters
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
def self.extended(base)
|
|
6
|
+
base.attr_encrypted_options[:encode] = true
|
|
7
|
+
base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# Ensures the attribute methods for db fields have been defined before calling the original
|
|
13
|
+
# <tt>attr_encrypted</tt> method
|
|
14
|
+
def attr_encrypted(*attrs)
|
|
15
|
+
define_attribute_methods rescue nil
|
|
16
|
+
super
|
|
17
|
+
attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
|
|
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
|
+
|
|
54
|
+
ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
|
|
55
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
if defined?(DataMapper)
|
|
2
|
+
module AttrEncrypted
|
|
3
|
+
module Adapters
|
|
4
|
+
module DataMapper
|
|
5
|
+
def self.extended(base)
|
|
6
|
+
base.eigenclass_eval do
|
|
7
|
+
alias_method :included_without_attr_encrypted, :included
|
|
8
|
+
alias_method :included, :included_with_attr_encrypted
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def included_with_attr_encrypted(base)
|
|
13
|
+
included_without_attr_encrypted(base)
|
|
14
|
+
base.attr_encrypted_options[:encode] = true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
DataMapper::Resource.extend AttrEncrypted::Adapters::DataMapper
|
|
21
|
+
end
|
data/test/active_record_test.rb
CHANGED
|
@@ -20,7 +20,7 @@ create_people_table
|
|
|
20
20
|
|
|
21
21
|
class Person < ActiveRecord::Base
|
|
22
22
|
attr_encrypted :email, :key => 'a secret key'
|
|
23
|
-
attr_encrypted :credentials, :key => Proc.new { |user|
|
|
23
|
+
attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
|
|
24
24
|
|
|
25
25
|
def after_initialize
|
|
26
26
|
self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
|
data/test/attr_encrypted_test.rb
CHANGED
|
@@ -24,6 +24,9 @@ class User
|
|
|
24
24
|
attr_encrypted :with_false_if, :key => 'secret key', :if => false
|
|
25
25
|
attr_encrypted :with_true_unless, :key => 'secret key', :unless => true
|
|
26
26
|
attr_encrypted :with_false_unless, :key => 'secret key', :unless => false
|
|
27
|
+
|
|
28
|
+
attr_encryptor :aliased, :key => 'secret_key'
|
|
29
|
+
|
|
27
30
|
attr_accessor :salt
|
|
28
31
|
|
|
29
32
|
def initialize
|
|
@@ -157,7 +160,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
157
160
|
assert_nil @user.ssn_encrypted
|
|
158
161
|
@user.ssn = 'testing'
|
|
159
162
|
assert_not_nil @user.ssn_encrypted
|
|
160
|
-
assert_equal
|
|
163
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt), @user.ssn_encrypted
|
|
161
164
|
end
|
|
162
165
|
|
|
163
166
|
def test_should_evaluate_a_key_passed_as_a_proc
|
|
@@ -165,7 +168,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
165
168
|
assert_nil @user.crypted_password_test
|
|
166
169
|
@user.password = 'testing'
|
|
167
170
|
assert_not_nil @user.crypted_password_test
|
|
168
|
-
assert_equal
|
|
171
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
|
|
169
172
|
end
|
|
170
173
|
|
|
171
174
|
def test_should_use_options_found_in_the_attr_encrypted_options_attribute
|
|
@@ -173,7 +176,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
173
176
|
assert_nil @user.crypted_password_test
|
|
174
177
|
@user.password = 'testing'
|
|
175
178
|
assert_not_nil @user.crypted_password_test
|
|
176
|
-
assert_equal
|
|
179
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
|
|
177
180
|
end
|
|
178
181
|
|
|
179
182
|
def test_should_inherit_encrypted_attributes
|
|
@@ -215,7 +218,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
215
218
|
assert_nil @user.encrypted_with_true_if
|
|
216
219
|
@user.with_true_if = 'testing'
|
|
217
220
|
assert_not_nil @user.encrypted_with_true_if
|
|
218
|
-
assert_equal
|
|
221
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_true_if
|
|
219
222
|
end
|
|
220
223
|
|
|
221
224
|
def test_should_not_encrypt_with_false_if
|
|
@@ -231,7 +234,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
231
234
|
assert_nil @user.encrypted_with_false_unless
|
|
232
235
|
@user.with_false_unless = 'testing'
|
|
233
236
|
assert_not_nil @user.encrypted_with_false_unless
|
|
234
|
-
assert_equal
|
|
237
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_false_unless
|
|
235
238
|
end
|
|
236
239
|
|
|
237
240
|
def test_should_not_encrypt_with_true_unless
|
|
@@ -242,4 +245,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
|
242
245
|
assert_equal 'testing', @user.encrypted_with_true_unless
|
|
243
246
|
end
|
|
244
247
|
|
|
248
|
+
def test_should_work_with_aliased_attr_encryptor
|
|
249
|
+
assert User.encrypted_attributes.include?('aliased')
|
|
250
|
+
end
|
|
251
|
+
|
|
245
252
|
end
|
data/test/data_mapper_test.rb
CHANGED
|
@@ -11,7 +11,7 @@ class Client
|
|
|
11
11
|
property :salt, String
|
|
12
12
|
|
|
13
13
|
attr_encrypted :email, :key => 'a secret key'
|
|
14
|
-
attr_encrypted :credentials, :key => Proc.new { |client|
|
|
14
|
+
attr_encrypted :credentials, :key => Proc.new { |client| Encryptor.encrypt(:value => client.salt, :key => 'some private key') }, :marshal => true
|
|
15
15
|
|
|
16
16
|
def initialize(attrs = {})
|
|
17
17
|
super attrs
|
data/test/sequel_test.rb
CHANGED
|
@@ -12,7 +12,7 @@ end
|
|
|
12
12
|
|
|
13
13
|
class Human < Sequel::Model(:humans)
|
|
14
14
|
attr_encrypted :email, :key => 'a secret key'
|
|
15
|
-
attr_encrypted :credentials, :key => Proc.new { |human|
|
|
15
|
+
attr_encrypted :credentials, :key => Proc.new { |human| Encryptor.encrypt(:value => human.salt, :key => 'some private key') }, :marshal => true
|
|
16
16
|
|
|
17
17
|
def after_initialize(attrs = {})
|
|
18
18
|
self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: attr_encrypted
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
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:
|
|
12
|
+
date: 2010-01-28 00:00:00 -08:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -20,7 +20,7 @@ dependencies:
|
|
|
20
20
|
requirements:
|
|
21
21
|
- - ">="
|
|
22
22
|
- !ruby/object:Gem::Version
|
|
23
|
-
version: 1.
|
|
23
|
+
version: 1.1.1
|
|
24
24
|
version:
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: encryptor
|
|
@@ -30,7 +30,7 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 1.
|
|
33
|
+
version: 1.1.0
|
|
34
34
|
version:
|
|
35
35
|
description: Generates attr_accessors that encrypt and decrypt attributes transparently
|
|
36
36
|
email: shuber@huberry.com
|
|
@@ -41,14 +41,17 @@ extensions: []
|
|
|
41
41
|
extra_rdoc_files: []
|
|
42
42
|
|
|
43
43
|
files:
|
|
44
|
-
- CHANGELOG
|
|
45
44
|
- lib/attr_encrypted.rb
|
|
46
|
-
- lib/
|
|
47
|
-
- lib/
|
|
48
|
-
- lib/
|
|
45
|
+
- lib/attr_encrypted/adapters/active_record.rb
|
|
46
|
+
- lib/attr_encrypted/adapters/data_mapper.rb
|
|
47
|
+
- lib/attr_encrypted/adapters/sequel.rb
|
|
49
48
|
- MIT-LICENSE
|
|
50
49
|
- Rakefile
|
|
51
|
-
- README.
|
|
50
|
+
- README.rdoc
|
|
51
|
+
- test/active_record_test.rb
|
|
52
|
+
- test/attr_encrypted_test.rb
|
|
53
|
+
- test/data_mapper_test.rb
|
|
54
|
+
- test/sequel_test.rb
|
|
52
55
|
- test/test_helper.rb
|
|
53
56
|
has_rdoc: true
|
|
54
57
|
homepage: http://github.com/shuber/attr_encrypted
|
|
@@ -59,7 +62,7 @@ rdoc_options:
|
|
|
59
62
|
- --line-numbers
|
|
60
63
|
- --inline-source
|
|
61
64
|
- --main
|
|
62
|
-
- README.
|
|
65
|
+
- README.rdoc
|
|
63
66
|
require_paths:
|
|
64
67
|
- lib
|
|
65
68
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
@@ -86,3 +89,4 @@ test_files:
|
|
|
86
89
|
- test/attr_encrypted_test.rb
|
|
87
90
|
- test/data_mapper_test.rb
|
|
88
91
|
- test/sequel_test.rb
|
|
92
|
+
- test/test_helper.rb
|
data/CHANGELOG
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
2009-05-20 - Sean Huber (shuber@huberry.com)
|
|
2
|
-
* Update ActiveRecord tests
|
|
3
|
-
|
|
4
|
-
2009-01-18 - Sean Huber (shuber@huberry.com)
|
|
5
|
-
* Don't attempt to encrypt/decrypt empty strings
|
|
6
|
-
|
|
7
|
-
2009-01-14 - Sean Huber (shuber@huberry.com)
|
|
8
|
-
* Move Class logic into Object
|
|
9
|
-
|
|
10
|
-
2009-01-13 - Sean Huber (shuber@huberry.com)
|
|
11
|
-
* :marshal no longer defaults to true in ORM adapters
|
|
12
|
-
* Load gem dependencies
|
|
13
|
-
|
|
14
|
-
2009-01-12 - Sean Huber (shuber@huberry.com)
|
|
15
|
-
* Remove read_attribute and write_attribute methods - unnecessary
|
|
16
|
-
* ActiveRecord and DataMapper extensions are now "adapters"
|
|
17
|
-
* Check for existing reader and writer methods separately before creating default ones for encrypted attributes
|
|
18
|
-
* Typo: should send(encrypted_attribute_name.to_sym) instead of send(encrypted_attribute_name.to_s)
|
|
19
|
-
* Add Sequel adapter
|
|
20
|
-
* Update DataMapper tests
|
|
21
|
-
* Update README
|
|
22
|
-
* Set attr_encrypted_options instead of overwriting the attr_encrypted method in adapters
|
|
23
|
-
|
|
24
|
-
2009-01-11 - Sean Huber (shuber@huberry.com)
|
|
25
|
-
* Update README
|
|
26
|
-
|
|
27
|
-
2009-01-10 - Sean Huber (shuber@huberry.com)
|
|
28
|
-
* Update README
|
|
29
|
-
|
|
30
|
-
2009-01-08 - Sean Huber (shuber@huberry.com)
|
|
31
|
-
* Update comments and documentation
|
|
32
|
-
* Update README
|
|
33
|
-
* Add gemspec
|
|
34
|
-
* Add support for data mapper
|
|
35
|
-
* Attribute methods are now defined before calling attr_encrypted when using active record
|
|
36
|
-
* Add ability to specify your own encoding directives
|
|
37
|
-
* Update logic that evaluates symbol and proc options
|
|
38
|
-
* Add support for :if and :unless options
|
|
39
|
-
* Add AttrEncrypted namespace
|
|
40
|
-
|
|
41
|
-
2009-01-07 - Sean Huber (shuber@huberry.com)
|
|
42
|
-
* Initial commit
|
|
43
|
-
* Add comments/documentation to the active record related logic
|
|
44
|
-
* Add more attr_encrypted tests
|
|
45
|
-
* Update tests and comments
|
data/README.markdown
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
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 attr_encrypted --source http://gemcutter.org
|
|
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`). So, if you're storing the encrypted attribute in the database, you need to make sure the `encrypted_#{attribute}` field exists in your table. You have a couple of options if you want to name your attribute something else.
|
|
47
|
-
|
|
48
|
-
#### The `:attribute` option ####
|
|
49
|
-
|
|
50
|
-
You can simply pass the name of the encrypted attribute as the `:attribute` option:
|
|
51
|
-
|
|
52
|
-
class User
|
|
53
|
-
attr_encrypted :email, :key => 'a secret key', :attribute => 'email_encrypted'
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
This would generate an attribute named `email_encrypted`
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
#### The `:prefix` and `:suffix` options ####
|
|
60
|
-
|
|
61
|
-
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:
|
|
62
|
-
|
|
63
|
-
class User
|
|
64
|
-
attr_encrypted :email, :credit_card, :ssn, :key => 'a secret key', :prefix => 'secret_', :suffix => '_crypted'
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
This would generate the following attributes: `secret_email_crypted`, `secret_credit_card_crypted`, and `secret_ssn_crypted`.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
### Encryption keys ###
|
|
71
|
-
|
|
72
|
-
Although a `:key` option may not be required (see custom encryptor below), it has a few special features
|
|
73
|
-
|
|
74
|
-
#### Unique keys for each attribute ####
|
|
75
|
-
|
|
76
|
-
You can specify unique keys for each attribute if you'd like:
|
|
77
|
-
|
|
78
|
-
class User
|
|
79
|
-
attr_encrypted :email, :key => 'a secret key'
|
|
80
|
-
attr_encrypted :ssn, :key => 'a different secret key'
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
#### Symbols representing instance methods as keys ####
|
|
85
|
-
|
|
86
|
-
If your class has an instance method that determines the encryption key to use, simply pass a symbol representing it like so:
|
|
87
|
-
|
|
88
|
-
class User
|
|
89
|
-
attr_encrypted :email, :key => :encryption_key
|
|
90
|
-
|
|
91
|
-
def encryption_key
|
|
92
|
-
# does some fancy logic and returns an encryption key
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
#### Procs as keys ####
|
|
98
|
-
|
|
99
|
-
You can pass a proc/lambda object as the `:key` option as well:
|
|
100
|
-
|
|
101
|
-
class User
|
|
102
|
-
attr_encrypted :email, :key => proc { |user| ... }
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
### Conditional encrypting ###
|
|
107
|
-
|
|
108
|
-
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
|
|
109
|
-
attributes when you're in development mode. You can specify conditions like this:
|
|
110
|
-
|
|
111
|
-
class User < ActiveRecord::Base
|
|
112
|
-
attr_encrypted :email, :key => 'a secret key', :unless => Rails.env.development?
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
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.
|
|
116
|
-
Any objects that respond to `:call` are evaluated as well.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
### Custom encryptor ###
|
|
120
|
-
|
|
121
|
-
The [Huberry::Encryptor](http://github.com/shuber/encryptor) class is used by default. You may use your own custom encryptor by specifying
|
|
122
|
-
the `:encryptor`, `:encrypt_method`, and `:decrypt_method` options
|
|
123
|
-
|
|
124
|
-
Lets suppose you'd like to use this custom encryptor class:
|
|
125
|
-
|
|
126
|
-
class SillyEncryptor
|
|
127
|
-
def self.silly_encrypt(options)
|
|
128
|
-
(options[:value] + options[:secret_key]).reverse
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def self.silly_decrypt(options)
|
|
132
|
-
options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
Simply set up your class like so:
|
|
137
|
-
|
|
138
|
-
class User
|
|
139
|
-
attr_encrypted :email, :secret_key => 'a secret key', :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
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.
|
|
143
|
-
Notice it uses `:secret_key` instead of `:key`.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
### Custom algorithms ###
|
|
147
|
-
|
|
148
|
-
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
|
|
149
|
-
modify this by passing the `:algorithm` option to the `attr_encrypted` call like so:
|
|
150
|
-
|
|
151
|
-
class User
|
|
152
|
-
attr_encrypted :email, :key => 'a secret key', :algorithm => 'bf'
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
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.
|
|
156
|
-
|
|
157
|
-
aes-128-cbc
|
|
158
|
-
aes-128-ecb
|
|
159
|
-
aes-192-cbc
|
|
160
|
-
aes-192-ecb
|
|
161
|
-
aes-256-cbc
|
|
162
|
-
aes-256-ecb
|
|
163
|
-
base64
|
|
164
|
-
bf
|
|
165
|
-
bf-cbc
|
|
166
|
-
bf-cfb
|
|
167
|
-
bf-ecb
|
|
168
|
-
bf-ofb
|
|
169
|
-
cast
|
|
170
|
-
cast-cbc
|
|
171
|
-
cast5-cbc
|
|
172
|
-
cast5-cfb
|
|
173
|
-
cast5-ecb
|
|
174
|
-
cast5-ofb
|
|
175
|
-
des
|
|
176
|
-
des-cbc
|
|
177
|
-
des-cfb
|
|
178
|
-
des-ecb
|
|
179
|
-
des-ede
|
|
180
|
-
des-ede-cbc
|
|
181
|
-
des-ede-cfb
|
|
182
|
-
des-ede-ofb
|
|
183
|
-
des-ede3
|
|
184
|
-
des-ede3-cbc
|
|
185
|
-
des-ede3-cfb
|
|
186
|
-
des-ede3-ofb
|
|
187
|
-
des-ofb
|
|
188
|
-
des3
|
|
189
|
-
desx
|
|
190
|
-
idea
|
|
191
|
-
idea-cbc
|
|
192
|
-
idea-cfb
|
|
193
|
-
idea-ecb
|
|
194
|
-
idea-ofb
|
|
195
|
-
rc2
|
|
196
|
-
rc2-40-cbc
|
|
197
|
-
rc2-64-cbc
|
|
198
|
-
rc2-cbc
|
|
199
|
-
rc2-cfb
|
|
200
|
-
rc2-ecb
|
|
201
|
-
rc2-ofb
|
|
202
|
-
rc4
|
|
203
|
-
rc4-40
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
### Default options ###
|
|
207
|
-
|
|
208
|
-
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.
|
|
209
|
-
Instead of having to define your class like this:
|
|
210
|
-
|
|
211
|
-
class User
|
|
212
|
-
attr_encrypted :email, :key => 'a secret key', :prefix => '', :suffix => '_crypted'
|
|
213
|
-
attr_encrypted :ssn, :key => 'a different secret key', :prefix => '', :suffix => '_crypted'
|
|
214
|
-
attr_encrypted :credit_card, :key => 'another secret key', :prefix => '', :suffix => '_crypted'
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
You can simply define some default options like so:
|
|
218
|
-
|
|
219
|
-
class User
|
|
220
|
-
attr_encrypted_options.merge!(:prefix => '', :suffix => '_crypted')
|
|
221
|
-
attr_encrypted :email, :key => 'a secret key'
|
|
222
|
-
attr_encrypted :ssn, :key => 'a different secret key'
|
|
223
|
-
attr_encrypted :credit_card, :key => 'another secret key'
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
This should help keep your classes clean and DRY.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
### Encoding ###
|
|
230
|
-
|
|
231
|
-
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
|
|
232
|
-
encrypted string. I've had this problem myself using MySQL. You can simply pass the `:encode` option to automatically encode/decode when encrypting/decrypting.
|
|
233
|
-
|
|
234
|
-
class User
|
|
235
|
-
attr_encrypted :email, :key => 'some secret key', :encode => true
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
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.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
### Marshaling ###
|
|
242
|
-
|
|
243
|
-
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
|
|
244
|
-
when encrypting/decrypting.
|
|
245
|
-
|
|
246
|
-
class User
|
|
247
|
-
attr_encrypted :credentials, :key => 'some secret key', :marshal => true
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
### Encrypt/decrypt attribute methods ###
|
|
252
|
-
|
|
253
|
-
If you use the same key to encrypt every record (per attribute) like this:
|
|
254
|
-
|
|
255
|
-
class User
|
|
256
|
-
attr_encrypted :email, :key => 'a secret key'
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
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
|
|
260
|
-
be useful when you're using ActiveRecord (see below).
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
### ActiveRecord ###
|
|
264
|
-
|
|
265
|
-
If you're using this gem with ActiveRecord, you get a few extra features:
|
|
266
|
-
|
|
267
|
-
#### Default options ####
|
|
268
|
-
|
|
269
|
-
For your convenience, the `:encode` option is set to true by default since you'll be storing everything in a database.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
#### Dynamic find\_by\_ and scoped\_by\_ methods ####
|
|
273
|
-
|
|
274
|
-
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:
|
|
275
|
-
|
|
276
|
-
class User < ActiveRecord::Base
|
|
277
|
-
attr_encrypted :email, :key => 'a secret key'
|
|
278
|
-
attr_encrypted :password, :key => 'some other secret key'
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
You can now lookup and login users like so:
|
|
282
|
-
|
|
283
|
-
User.find_by_email_and_password('test@example.com', 'testing')
|
|
284
|
-
|
|
285
|
-
The call to `find_by_email_and_password` is intercepted and modified to `find_by_encrypted_email_and_encrypted_password('ENCRYPTED EMAIL', 'ENCRYPTED PASSWORD')`.
|
|
286
|
-
The dynamic scope methods like `scoped_by_email_and_password` work the same way.
|
|
287
|
-
|
|
288
|
-
NOTE: This only works if all records are encrypted with the same encryption key (per attribute).
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
### DataMapper and Sequel ###
|
|
292
|
-
|
|
293
|
-
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.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
Contact
|
|
297
|
-
-------
|
|
298
|
-
|
|
299
|
-
Problems, comments, and suggestions all welcome: [shuber@huberry.com](mailto:shuber@huberry.com)
|