has_secure_attribute 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/active_model/secure_attribute/has_secure_attribute.rb +7 -7
- data/lib/has_secure_attribute/version.rb +1 -1
- data/spec/factories/test_model_with_attributes.rb +9 -0
- data/spec/models/has_secure_attribute_spec.rb +8 -0
- data/spec/models/test_model_with_attribute_with_case_sensitive.rb +8 -0
- data/spec/spec_helper.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21d52ef0208b3210f48d7968e7f28b608039353f
|
4
|
+
data.tar.gz: 283b78f054f1610670abebc05b7a280a42c693bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 427ce061b78c731ade3192481bde53975f5fffd3f88d0dac299ae99e4de2fc6d409c5aa5faafd82392055369c6b7cee693d8cffe73f532f2070d1b11eb820fce
|
7
|
+
data.tar.gz: 687b7590e7250bad4ca8214c42834073e21703249625f41279bd90c9cafec56f36e9ec4b98a27a3d9cc5d0276093382a5df0859cd407868e5ecfebe394b90ea8
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
`has_secure_attribute`
|
2
2
|
======================
|
3
3
|
|
4
|
-
Why have `has_secure_password` and not any attribute that you want
|
4
|
+
Why have `has_secure_password` and not any attribute that you want? I believe that, quite often, we want to one-way encrypt one attribute and authenticate against its value, and this is not only the `password` case.
|
5
5
|
|
6
6
|
Requires
|
7
7
|
--------
|
@@ -36,6 +36,8 @@ In the above example:
|
|
36
36
|
* It raises an exception if `security_answer_digest` is empty on create.
|
37
37
|
* It defines the method `authenticate_security_answer(answer_to_authenticate)` which returns `false` if the answer given does not correspond to the saved digest, or returns the object instance itself if it does.
|
38
38
|
|
39
|
+
__Case Insensitive Values__: you can pass `case_insensitive => false` if you want to handle values that match even if they differ on case. Then, `answer` will match `Answer`, for example.
|
40
|
+
|
39
41
|
Do you want to test it?
|
40
42
|
------------------------
|
41
43
|
|
@@ -21,7 +21,7 @@ module ActiveModel
|
|
21
21
|
def has_secure_attribute(meth, *args, &block)
|
22
22
|
attribute_sym = meth.to_sym
|
23
23
|
attr_reader attribute_sym # setter is defined later on
|
24
|
-
options = {:
|
24
|
+
options = {validations: true, protect_setter_for_digest: false, case_sensitive: true}
|
25
25
|
options.merge! args[0] unless args.blank?
|
26
26
|
if options[:validations]
|
27
27
|
validates attribute_sym, confirmation: true, if: lambda { |m| m.send(attribute_sym).present? }
|
@@ -30,18 +30,18 @@ module ActiveModel
|
|
30
30
|
before_create { raise "#{attribute_sym}_digest missing on new record" if send("#{attribute_sym}_digest").blank? }
|
31
31
|
end
|
32
32
|
|
33
|
-
define_setter(attribute_sym)
|
33
|
+
define_setter(attribute_sym, options)
|
34
34
|
protect_setter_for_digest(attribute_sym) if options[:protect_setter_for_digest]
|
35
35
|
|
36
|
-
define_authenticate_method(attribute_sym)
|
36
|
+
define_authenticate_method(attribute_sym, options)
|
37
37
|
end
|
38
38
|
|
39
|
-
def define_setter(attribute_sym)
|
39
|
+
def define_setter(attribute_sym, options)
|
40
40
|
define_method "#{attribute_sym.to_s}=" do |unencrypted_value|
|
41
41
|
unless unencrypted_value.blank?
|
42
42
|
instance_variable_set("@#{attribute_sym.to_s}".to_sym, unencrypted_value)
|
43
43
|
cost = ActiveModel::SecureAttribute.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST
|
44
|
-
send("#{attribute_sym.to_s}_digest=".to_sym, BCrypt::Password.create(unencrypted_value, cost: cost))
|
44
|
+
send("#{attribute_sym.to_s}_digest=".to_sym, BCrypt::Password.create(options[:case_sensitive] ? unencrypted_value : unencrypted_value.downcase, cost: cost))
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -53,9 +53,9 @@ module ActiveModel
|
|
53
53
|
protected "#{attribute_sym}_digest=".to_sym
|
54
54
|
end
|
55
55
|
|
56
|
-
def define_authenticate_method(attribute_sym)
|
56
|
+
def define_authenticate_method(attribute_sym, options)
|
57
57
|
define_method "authenticate_#{attribute_sym}" do |value|
|
58
|
-
BCrypt::Password.new(send("#{attribute_sym}_digest")) == value && self
|
58
|
+
BCrypt::Password.new(send("#{attribute_sym}_digest")) == (options[:case_sensitive] ? value : value.downcase) && self
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -24,4 +24,13 @@ FactoryGirl.define do
|
|
24
24
|
security_answer 'answer'
|
25
25
|
security_answer_confirmation 'answer'
|
26
26
|
end
|
27
|
+
|
28
|
+
factory :test_model_with_attribute_with_case_sensitive do
|
29
|
+
username 'username_protect'
|
30
|
+
password 'password'
|
31
|
+
password_confirmation 'password'
|
32
|
+
security_question 'question'
|
33
|
+
security_answer 'answer'
|
34
|
+
security_answer_confirmation 'answer'
|
35
|
+
end
|
27
36
|
end
|
@@ -163,3 +163,11 @@ describe TestModelWithAttributeProtectSetterForDigest do
|
|
163
163
|
end.should raise_error NoMethodError
|
164
164
|
end
|
165
165
|
end
|
166
|
+
|
167
|
+
describe TestModelWithAttributeWithCaseSensitive do
|
168
|
+
it 'should authenticate even if answer is of different case' do
|
169
|
+
t = FactoryGirl.create :test_model_with_attribute_with_case_sensitive, security_answer: 'Answer', security_answer_confirmation: 'Answer'
|
170
|
+
|
171
|
+
t.authenticate_security_answer('answer').should eq t
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class TestModelWithAttributeWithCaseSensitive < ActiveRecord::Base
|
2
|
+
self.table_name = "test_model_with_attributes"
|
3
|
+
has_secure_password
|
4
|
+
has_secure_security_answer :case_sensitive => false
|
5
|
+
|
6
|
+
validates :username, :presence => true, :uniqueness => {:case_sensitive => false}
|
7
|
+
validates :security_question, :presence => true
|
8
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,7 @@ require File.expand_path("../../lib/active_model/secure_attribute/has_secure_att
|
|
7
7
|
require File.expand_path("../models/test_model_with_attribute", __FILE__)
|
8
8
|
require File.expand_path("../models/test_model_with_attribute_no_validation", __FILE__)
|
9
9
|
require File.expand_path("../models/test_model_with_attribute_protect_setter_for_digest", __FILE__)
|
10
|
+
require File.expand_path("../models/test_model_with_attribute_with_case_sensitive", __FILE__)
|
10
11
|
|
11
12
|
require 'factory_girl'
|
12
13
|
FactoryGirl.find_definitions
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_secure_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Panayotis Matsinopoulos
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- spec/models/test_model_with_attribute_no_validation.rb
|
127
127
|
- spec/models/test_model_with_attribute_protect_setter_for_digest.rb
|
128
128
|
- spec/models/test_model_with_attribute.rb
|
129
|
+
- spec/models/test_model_with_attribute_with_case_sensitive.rb
|
129
130
|
- spec/db/migrate/db_helper.rb
|
130
131
|
- spec/db/migrate/create_test_model_with_attributes.rb
|
131
132
|
- README.md
|