has_secure_attribute 0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +23 -0
- data/README.md +2 -0
- data/lib/active_model/secure_attribute/has_secure_attribute.rb +71 -0
- data/lib/has_secure_attribute/version.rb +3 -0
- data/lib/has_secure_attribute.rb +1 -0
- data/spec/config/database.yml +33 -0
- data/spec/db/migrate/create_test_model_with_attributes.rb +24 -0
- data/spec/db/migrate/db_helper.rb +15 -0
- data/spec/factories/test_model_with_attributes.rb +27 -0
- data/spec/models/has_secure_attribute_spec.rb +165 -0
- data/spec/models/test_model_with_attribute.rb +7 -0
- data/spec/models/test_model_with_attribute_no_validation.rb +8 -0
- data/spec/models/test_model_with_attribute_protect_setter_for_digest.rb +8 -0
- data/spec/spec_helper.rb +35 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 791d8b4c2ad53a2ab79fe663e7e6e7e19b355e90
|
4
|
+
data.tar.gz: ecebf104e0f461d50c064d86d9441581f6950b9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 758ae145496f31c48766909bffd81d03dd316a458e3bea9d6027061de6bf2b6437d94e58fb6f57db087d9579e003a98b2b70f8760cc74fd9ab37f28eee32e7b1
|
7
|
+
data.tar.gz: 42305c94aede34da459b9f0611ca57a157808c5556027c3225628651485adc5107a9d53893de1d950cf50a46c2daad708120fd88dda4e48ddb6e9ff3f2b45771
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2013 Panayotis Matsinopoulos
|
2
|
+
|
3
|
+
Contact: panayotis@matsinopoulos.gr
|
4
|
+
Site: http://www.matsinopoulos.gr
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module SecureAttribute
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :min_cost
|
9
|
+
end
|
10
|
+
self.min_cost = false
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def method_missing(meth, *args, &block)
|
14
|
+
if meth.to_s =~ /^has_secure_(.+)$/
|
15
|
+
has_secure_attribute($1, *args, &block)
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_secure_attribute(meth, *args, &block)
|
22
|
+
attribute_sym = meth.to_sym
|
23
|
+
attr_reader attribute_sym # setter is defined later on
|
24
|
+
options = {:validations => true, :protect_setter_for_digest => false}
|
25
|
+
options.merge! args[0] unless args.blank?
|
26
|
+
if options[:validations]
|
27
|
+
validates attribute_sym, confirmation: true, if: lambda { |m| m.send(attribute_sym).present? }
|
28
|
+
validates attribute_sym, presence: true, on: :create
|
29
|
+
validates "#{attribute_sym}_confirmation".to_sym, presence: true, if: lambda { |m| m.send(attribute_sym).present? }
|
30
|
+
before_create { raise "#{attribute_sym}_digest missing on new record" if send("#{attribute_sym}_digest").blank? }
|
31
|
+
end
|
32
|
+
|
33
|
+
define_setter(attribute_sym)
|
34
|
+
protect_setter_for_digest(attribute_sym) if options[:protect_setter_for_digest]
|
35
|
+
|
36
|
+
define_authenticate_method(attribute_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_setter(attribute_sym)
|
40
|
+
define_method "#{attribute_sym.to_s}=" do |unencrypted_value|
|
41
|
+
unless unencrypted_value.blank?
|
42
|
+
instance_variable_set("@#{attribute_sym.to_s}".to_sym, unencrypted_value)
|
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))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def protect_setter_for_digest(attribute_sym)
|
50
|
+
define_method "#{attribute_sym}_digest=" do |value|
|
51
|
+
write_attribute "#{attribute_sym}_digest".to_sym, value
|
52
|
+
end
|
53
|
+
protected "#{attribute_sym}_digest=".to_sym
|
54
|
+
end
|
55
|
+
|
56
|
+
def define_authenticate_method(attribute_sym)
|
57
|
+
define_method "authenticate_#{attribute_sym}" do |value|
|
58
|
+
BCrypt::Password.new(send("#{attribute_sym}_digest")) == value && self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
protected :has_secure_attribute
|
63
|
+
protected :define_setter
|
64
|
+
protected :protect_setter_for_digest
|
65
|
+
protected :define_authenticate_method
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
ActiveRecord::Base.send :include, ActiveModel::SecureAttribute
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_model/secure_attribute/has_secure_attribute'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
development:
|
2
|
+
adapter: mysql2
|
3
|
+
encoding: utf8
|
4
|
+
reconnect: false
|
5
|
+
database: has_secure_attribute_development
|
6
|
+
pool: 5
|
7
|
+
username: root
|
8
|
+
password:
|
9
|
+
socket: /var/run/mysqld/mysqld.sock
|
10
|
+
|
11
|
+
# Warning: The database defined as "test" will be erased and
|
12
|
+
# re-generated from your development database when you run "rake".
|
13
|
+
# Do not set this db to the same as development or production.
|
14
|
+
test:
|
15
|
+
adapter: mysql2
|
16
|
+
encoding: utf8
|
17
|
+
reconnect: false
|
18
|
+
database: has_secure_attribute_test
|
19
|
+
pool: 5
|
20
|
+
username: root
|
21
|
+
password:
|
22
|
+
socket: /var/run/mysqld/mysqld.sock
|
23
|
+
|
24
|
+
production:
|
25
|
+
adapter: mysql2
|
26
|
+
encoding: utf8
|
27
|
+
reconnect: false
|
28
|
+
database: has_secure_attribute_production
|
29
|
+
pool: 5
|
30
|
+
username: root
|
31
|
+
password:
|
32
|
+
socket: /var/run/mysqld/mysqld.sock
|
33
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateTestModelWithAttributes < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
HasSecureAttribute::DbHelper.new.connect_to_database
|
4
|
+
return if ActiveRecord::Base.connection.table_exists? :test_model_with_attributes
|
5
|
+
create_table :test_model_with_attributes do |t|
|
6
|
+
t.string :username, :null => false
|
7
|
+
t.string :password_digest, :null => false
|
8
|
+
t.string :security_question, :null => false
|
9
|
+
t.string :security_answer_digest, :null => false
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :test_model_with_attributes, [:username], :unique => true, :name => 'test_model_with_attributes_username_uidx'
|
15
|
+
end
|
16
|
+
|
17
|
+
def down
|
18
|
+
HasSecureAttribute::DbHelper.new.connect_to_database
|
19
|
+
return unless ActiveRecord::Base.connection.table_exists? :test_model_with_attributes
|
20
|
+
drop_table :test_model_with_attributes
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module HasSecureAttribute
|
2
|
+
class DbHelper
|
3
|
+
def connect_to_database
|
4
|
+
filename = File.expand_path("../../../config/database.yml", __FILE__)
|
5
|
+
database_settings = YAML.load_file(filename)
|
6
|
+
ActiveRecord::Base.establish_connection database_settings['test']
|
7
|
+
end
|
8
|
+
|
9
|
+
def connect_to_server
|
10
|
+
filename = File.expand_path("../../../config/database.yml", __FILE__)
|
11
|
+
database_settings = YAML.load_file(filename)
|
12
|
+
ActiveRecord::Base.establish_connection database_settings['test'].delete_if{|k,v| 'database' == k}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :test_model_with_attribute do
|
3
|
+
username 'username'
|
4
|
+
password 'password'
|
5
|
+
password_confirmation 'password'
|
6
|
+
security_question 'question'
|
7
|
+
security_answer 'answer'
|
8
|
+
security_answer_confirmation 'answer'
|
9
|
+
end
|
10
|
+
|
11
|
+
factory :test_model_with_attribute_no_validation do
|
12
|
+
username 'username_no_validation'
|
13
|
+
password 'password'
|
14
|
+
password_confirmation 'password'
|
15
|
+
security_question 'question'
|
16
|
+
security_answer 'answer'
|
17
|
+
end
|
18
|
+
|
19
|
+
factory :test_model_with_attribute_protect_setter_for_digest do
|
20
|
+
username 'username_protect'
|
21
|
+
password 'password'
|
22
|
+
password_confirmation 'password'
|
23
|
+
security_question 'question'
|
24
|
+
security_answer 'answer'
|
25
|
+
security_answer_confirmation 'answer'
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TestModelWithAttribute do
|
4
|
+
it { should respond_to(:security_answer) }
|
5
|
+
it { should respond_to(:security_answer=) }
|
6
|
+
it { should respond_to(:security_answer_confirmation) }
|
7
|
+
it { should respond_to(:security_answer_confirmation=) }
|
8
|
+
it { should respond_to(:authenticate_security_answer) }
|
9
|
+
|
10
|
+
it 'should confirm security answer' do
|
11
|
+
subject.security_answer = 'hello there'
|
12
|
+
subject.security_answer_confirmation = 'there hello'
|
13
|
+
subject.valid?
|
14
|
+
subject.errors[:security_answer_confirmation].should include("doesn't match Security answer")
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should not confirm security answer if not given' do
|
18
|
+
subject.security_answer = nil
|
19
|
+
subject.security_answer_confirmation = 'there hello'
|
20
|
+
subject.valid?
|
21
|
+
subject.errors[:security_answer_confirmation].should be_blank
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should require security answer on create' do
|
25
|
+
subject.should be_new_record
|
26
|
+
subject.security_answer = nil
|
27
|
+
subject.valid?
|
28
|
+
subject.errors[:security_answer].should include("can't be blank")
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should require security answer confirmation if security answer given ' do
|
32
|
+
subject.security_answer = 'hello there'
|
33
|
+
subject.valid?
|
34
|
+
subject.errors[:security_answer_confirmation].should include "can't be blank"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not require security answer confirmation if security answer is not given' do
|
38
|
+
subject.security_answer = ''
|
39
|
+
subject.valid?
|
40
|
+
subject.errors[:security_answer_confirmation].should be_blank
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should require security answer digest on create' do
|
44
|
+
subject = FactoryGirl.build :test_model_with_attribute
|
45
|
+
subject.should be_new_record
|
46
|
+
|
47
|
+
# change the security_answer_digest to verify the test
|
48
|
+
subject.security_answer_digest = ''
|
49
|
+
lambda do
|
50
|
+
begin
|
51
|
+
subject.save!
|
52
|
+
rescue Exception => ex
|
53
|
+
ex.message.should include("security_answer_digest missing on new record")
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
end.should raise_error RuntimeError
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should not require security answer digest on update' do
|
60
|
+
subject = FactoryGirl.build :test_model_with_attribute
|
61
|
+
subject.should be_new_record
|
62
|
+
|
63
|
+
subject.save!
|
64
|
+
|
65
|
+
# change the security_answer_digest to verify the test
|
66
|
+
subject.security_answer_digest = ''
|
67
|
+
|
68
|
+
subject.save!
|
69
|
+
|
70
|
+
subject.reload
|
71
|
+
subject.security_answer_digest.should be_blank
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should allow to call security answer digest directly if protect setter for digest is not given as option' do
|
75
|
+
lambda do
|
76
|
+
subject.security_answer_digest = 'hello'
|
77
|
+
end.should_not raise_error
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#security_answer=" do
|
81
|
+
it 'should set the security answer and save it encrypted' do
|
82
|
+
tmwa = FactoryGirl.create :test_model_with_attribute, security_answer: 'old answer', security_answer_confirmation: 'old answer'
|
83
|
+
tmwa.security_answer_digest.should_not be_blank
|
84
|
+
old_security_answer_digest = tmwa.security_answer_digest
|
85
|
+
|
86
|
+
tmwa.security_answer = 'new answer'
|
87
|
+
tmwa.security_answer_confirmation = 'new answer'
|
88
|
+
tmwa.instance_variable_get(:@security_answer).should == 'new answer'
|
89
|
+
tmwa.save!
|
90
|
+
tmwa.security_answer_digest.should_not be_blank
|
91
|
+
tmwa.security_answer_digest.should_not == old_security_answer_digest
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#authenticate_security_answer' do
|
96
|
+
it 'should return subject if security answer given matches the one stored' do
|
97
|
+
tmwa = FactoryGirl.create :test_model_with_attribute, security_answer: 'some answer', security_answer_confirmation: 'some answer'
|
98
|
+
tmwa.authenticate_security_answer('some answer').should eq tmwa
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should return false if security answer given does not match the one stored' do
|
102
|
+
tmwa = FactoryGirl.create :test_model_with_attribute, security_answer: 'some answer', security_answer_confirmation: 'some answer'
|
103
|
+
tmwa.authenticate_security_answer('some other answer').should be_false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe TestModelWithAttributeNoValidation do
|
109
|
+
it { should respond_to(:security_answer) }
|
110
|
+
it { should respond_to(:security_answer=) }
|
111
|
+
it { should_not respond_to(:security_answer_confirmation) }
|
112
|
+
it { should_not respond_to(:security_answer_confirmation=) }
|
113
|
+
it { should respond_to(:authenticate_security_answer) }
|
114
|
+
|
115
|
+
it 'should not require security answer on create' do
|
116
|
+
subject.should be_new_record
|
117
|
+
subject.security_answer = nil
|
118
|
+
subject.valid?
|
119
|
+
subject.errors[:security_answer].should be_blank
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should not require security answer confirmation if security answer given ' do
|
123
|
+
subject.security_answer = 'hello there'
|
124
|
+
subject.valid?
|
125
|
+
subject.errors[:security_answer_confirmation].should be_blank
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should not require security answer confirmation if security answer is not given' do
|
129
|
+
subject.security_answer = ''
|
130
|
+
subject.valid?
|
131
|
+
subject.errors[:security_answer_confirmation].should be_blank
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should not require security answer digest on create' do
|
135
|
+
subject = FactoryGirl.build :test_model_with_attribute_no_validation
|
136
|
+
subject.should be_new_record
|
137
|
+
|
138
|
+
# change the security_answer_digest to verify the test
|
139
|
+
subject.security_answer_digest = ''
|
140
|
+
subject.save!
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should not require security answer digest on update' do
|
144
|
+
subject = FactoryGirl.build :test_model_with_attribute_no_validation
|
145
|
+
subject.should be_new_record
|
146
|
+
|
147
|
+
subject.save!
|
148
|
+
|
149
|
+
# change the security_answer_digest to verify the test
|
150
|
+
subject.send :security_answer_digest=, ''
|
151
|
+
|
152
|
+
subject.save!
|
153
|
+
|
154
|
+
subject.reload
|
155
|
+
subject.security_answer_digest.should be_blank
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe TestModelWithAttributeProtectSetterForDigest do
|
160
|
+
it 'should not allow to call security answer digest directly' do
|
161
|
+
lambda do
|
162
|
+
subject.security_answer_digest = 'hello'
|
163
|
+
end.should raise_error NoMethodError
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class TestModelWithAttributeNoValidation < ActiveRecord::Base
|
2
|
+
self.table_name = "test_model_with_attributes"
|
3
|
+
has_secure_password
|
4
|
+
has_secure_security_answer :validations => false
|
5
|
+
|
6
|
+
validates :username, :presence => true, :uniqueness => {:case_sensitive => false}
|
7
|
+
validates :security_question, :presence => true
|
8
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class TestModelWithAttributeProtectSetterForDigest < ActiveRecord::Base
|
2
|
+
self.table_name = "test_model_with_attributes"
|
3
|
+
has_secure_password
|
4
|
+
has_secure_security_answer :protect_setter_for_digest => true
|
5
|
+
|
6
|
+
validates :username, :presence => true, :uniqueness => {:case_sensitive => false}
|
7
|
+
validates :security_question, :presence => true
|
8
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
require File.expand_path("../db/migrate/db_helper", __FILE__)
|
4
|
+
HasSecureAttribute::DbHelper.new.connect_to_database
|
5
|
+
|
6
|
+
require File.expand_path("../../lib/active_model/secure_attribute/has_secure_attribute", __FILE__)
|
7
|
+
require File.expand_path("../models/test_model_with_attribute", __FILE__)
|
8
|
+
require File.expand_path("../models/test_model_with_attribute_no_validation", __FILE__)
|
9
|
+
require File.expand_path("../models/test_model_with_attribute_protect_setter_for_digest", __FILE__)
|
10
|
+
|
11
|
+
require 'factory_girl'
|
12
|
+
FactoryGirl.find_definitions
|
13
|
+
require 'database_cleaner'
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
|
17
|
+
# Run specs in random order to surface order dependencies. If you find an
|
18
|
+
# order dependency and want to debug it, you can fix the order by providing
|
19
|
+
# the seed, which is printed after each run.
|
20
|
+
# --seed 1234
|
21
|
+
config.order = "random"
|
22
|
+
|
23
|
+
config.before(:suite) do
|
24
|
+
DatabaseCleaner.strategy = :transaction
|
25
|
+
DatabaseCleaner.clean_with(:truncation)
|
26
|
+
end
|
27
|
+
|
28
|
+
config.before(:each) do
|
29
|
+
DatabaseCleaner[:active_record].start
|
30
|
+
end
|
31
|
+
|
32
|
+
config.after(:each) do
|
33
|
+
DatabaseCleaner.clean
|
34
|
+
end
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_secure_attribute
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Panayotis Matsinopoulos
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bcrypt-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mysql2
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: factory_girl
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: database_cleaner
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Does what `has_secure_password` does, but for any attribute that you
|
112
|
+
want. It does not have to be a `password` attribute. It may be for example `security_answer`
|
113
|
+
email:
|
114
|
+
- panayotis@matsinopoulos.gr
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- lib/active_model/secure_attribute/has_secure_attribute.rb
|
120
|
+
- lib/has_secure_attribute.rb
|
121
|
+
- lib/has_secure_attribute/version.rb
|
122
|
+
- spec/spec_helper.rb
|
123
|
+
- spec/factories/test_model_with_attributes.rb
|
124
|
+
- spec/config/database.yml
|
125
|
+
- spec/models/has_secure_attribute_spec.rb
|
126
|
+
- spec/models/test_model_with_attribute_no_validation.rb
|
127
|
+
- spec/models/test_model_with_attribute_protect_setter_for_digest.rb
|
128
|
+
- spec/models/test_model_with_attribute.rb
|
129
|
+
- spec/db/migrate/db_helper.rb
|
130
|
+
- spec/db/migrate/create_test_model_with_attributes.rb
|
131
|
+
- README.md
|
132
|
+
- MIT-LICENSE
|
133
|
+
homepage: https://github.com/pmatsinopoulos/has_secure_attribute
|
134
|
+
licenses: []
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.0.3
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Allows an ActiveRecord::Base class to declare an attribute that will be saved
|
156
|
+
one-way encrypted and not clear text
|
157
|
+
test_files: []
|