securely_hashed_attributes 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.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README.md +116 -0
- data/Rakefile +9 -0
- data/init.rb +1 -0
- data/lib/securely_hashed_attributes.rb +72 -0
- data/lib/securely_hashed_attributes/coders.rb +5 -0
- data/lib/securely_hashed_attributes/coders/bcrypt_password_column.rb +30 -0
- data/lib/securely_hashed_attributes/version.rb +4 -0
- data/securely_hashed_attributes.gemspec +26 -0
- data/spec/securely_hashed_attributes/coders/bcrypt_password_column_spec.rb +32 -0
- data/spec/securely_hashed_attributes_spec.rb +96 -0
- data/spec/spec_helper.rb +16 -0
- metadata +126 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
## Overview
|
2
|
+
|
3
|
+
This gem provides a quick and dirty way to add secure hashing to your
|
4
|
+
ActiveRecord models. It relies on the recent refactoring of
|
5
|
+
`ActiveRecord::Base::serialize` thus **Rails 3.1+** is **required**.
|
6
|
+
|
7
|
+
## Motivation
|
8
|
+
|
9
|
+
I wrote this gem in response to Aaron Patterson's request for a
|
10
|
+
`has_secure_password` implementation that uses the newfound flexibility of
|
11
|
+
`ActiveRecord::Base::serialize`. I originally intended to refactor the
|
12
|
+
`has_secure_password` method in Rails 3.1, but that poses a problem that
|
13
|
+
stems from the fact that `has_secure_password` is defined in ActiveModel::SecurePassword,
|
14
|
+
while all of the column serialization jazz is part of `ActiveRecord::Base`.
|
15
|
+
|
16
|
+
Either `SecurePassword` would need to be moved to `ActiveRecord`, or all of
|
17
|
+
the `serialize` jazz would need to be moved to `ActiveModel`. The first
|
18
|
+
approach is the easiest, and at the moment only `ActiveRecord::Base` mixes-in
|
19
|
+
the `ActiveModel::SecurePassword` module, but it still takes away the option
|
20
|
+
of using it in, say, `ActiveResource::Base`. The second approach would be
|
21
|
+
a pretty involved undertaking, and while the work done by `serialize` and the
|
22
|
+
coders does not depend upon `ActiveRecord`, no actual serialization is
|
23
|
+
performed until the model is persisted. As a result, it probably doesn't make
|
24
|
+
much sense to refactor `serialize` into `ActiveModel`.
|
25
|
+
|
26
|
+
In either case, such a refactoring would require some amount of pull amongst
|
27
|
+
the Rails community (both components mentioned were put in place by some
|
28
|
+
important Rails people) and unlike Jackie Treehorn, I don't pull shit in this
|
29
|
+
town. So, I created this gem to illustrate how dead simple the new hotness
|
30
|
+
of `serialize` makes this feature. It should work just fine with
|
31
|
+
`ActiveRecord`, but it was built as more of a proof of concept than anything
|
32
|
+
else.
|
33
|
+
|
34
|
+
### Usage
|
35
|
+
|
36
|
+
Here's an example of how you might use this gem:
|
37
|
+
|
38
|
+
# Schema: users(:password_hash => String, :bollocks => String,
|
39
|
+
# :fancy_pants => String)
|
40
|
+
class User < ActiveRecord::Base
|
41
|
+
securely_hashes :password, :to => :password_hash
|
42
|
+
securely_hashes :bollocks
|
43
|
+
|
44
|
+
class AlternateCoder
|
45
|
+
def self.dump some_value
|
46
|
+
# ...
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.load encoded
|
50
|
+
# ...
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
securely_hashes :fancy_pants, :with => AlternateCoder
|
55
|
+
end
|
56
|
+
|
57
|
+
some_user = User.new
|
58
|
+
some_user.password = 'super secret'
|
59
|
+
some_user.bollocks = 'something else to hash'
|
60
|
+
some_user.fancy_pants = 'you get the idea'
|
61
|
+
some_user.save
|
62
|
+
some_user.reload
|
63
|
+
some_user.password_hash # => $2a$10blahetcetc...
|
64
|
+
some_user.bollocks # => $2a$10yaddayadda...
|
65
|
+
|
66
|
+
When using the `:to => <column name>` option, the gem will create getters and
|
67
|
+
setters for the given attribute name and the setter will pass the value on
|
68
|
+
to the actual column. So, in our example of
|
69
|
+
|
70
|
+
securely_hashes :password, :to => :password_hash
|
71
|
+
|
72
|
+
the gem defined `password` and `password=` methods on our model automatically.
|
73
|
+
This behavior is important to note because it can clobber (or be clobbered) by
|
74
|
+
methods explicitly defined on the model. If the `:to => ...` option is not
|
75
|
+
used, no methods are created.
|
76
|
+
|
77
|
+
### Installing
|
78
|
+
|
79
|
+
You can use this gem in your rails app by adding
|
80
|
+
|
81
|
+
gem 'securely_hashed_attributes'
|
82
|
+
|
83
|
+
to your `Gemfile`. Alternatively, you can install the gem directly:
|
84
|
+
|
85
|
+
gem install securely_hashed_attributes
|
86
|
+
|
87
|
+
or you can clone the git repo:
|
88
|
+
|
89
|
+
git clone git://github.com/iande/securely_hashed_attributes.git
|
90
|
+
|
91
|
+
I want to re-iterate that this gem was written mostly as a proof of concept,
|
92
|
+
and you **must** be running Rails **3.1+** to use it.
|
93
|
+
|
94
|
+
### Further Thoughts
|
95
|
+
|
96
|
+
Hopefully this gem serves its purpose of demonstrating how easy it is to do
|
97
|
+
some pretty cool shit with serialized columns in Rails 3.1. You could easily
|
98
|
+
add a coder that handles encryption to securely persist data in a column and
|
99
|
+
semi-automagically work with the unencrypted data in your app. It also
|
100
|
+
provides opportunities for leveraging features of your database of choice, as
|
101
|
+
Aaron Patterson demonstrated with his HStore coder at RailsConf 2011.
|
102
|
+
Although, you may not want to use `eval` to decode the data.
|
103
|
+
|
104
|
+
|
105
|
+
### License
|
106
|
+
|
107
|
+
Public Domained!
|
108
|
+
|
109
|
+
### Contributing
|
110
|
+
|
111
|
+
I'm pretty open to pull requests, if anyone finds utility in this gem and
|
112
|
+
wants to contribute additional features. All I ask is that you provide
|
113
|
+
adequate documentation and test coverage for any code you contribute. If you
|
114
|
+
find the "public domaining" of this code to be problematic, fork the code
|
115
|
+
and put it under whatever license you like. You're free to do with this code
|
116
|
+
pretty much whatever you like.
|
data/Rakefile
ADDED
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'securely_hashed_attributes'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Kind of necessary for, you know, everything else we do.
|
2
|
+
require 'bcrypt'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
# The primary namespace of this gem
|
6
|
+
module SecurelyHashedAttributes
|
7
|
+
# The default settings constant. Once the library is fully loaded,
|
8
|
+
# +:with+ will still be +nil+, but +:to+ will be set to
|
9
|
+
# {SecurelyHashedAttributes::Coders::BCryptPasswordColumn}
|
10
|
+
DEFAULT_ATTRIBUTE_OPTIONS = {
|
11
|
+
:to => nil,
|
12
|
+
:with => nil
|
13
|
+
}
|
14
|
+
end
|
15
|
+
require 'securely_hashed_attributes/version'
|
16
|
+
require 'securely_hashed_attributes/coders'
|
17
|
+
|
18
|
+
# Adds the singleton method
|
19
|
+
# {ActiveRecord::Base.securely_hashes securely_hashes} to +ActiveRecord::Base+
|
20
|
+
class ActiveRecord::Base
|
21
|
+
class << self
|
22
|
+
# Adds a secure hash serialization to a column with the help of +bcrypt+.
|
23
|
+
# By default, +attrib+ will serve as both the attribute to serialize and
|
24
|
+
# the name of the column that will hold the serialized value. If you want
|
25
|
+
# to serialize the value to a different column, use the +:to+ option.
|
26
|
+
# Hashing of the value assigned to +attrib+ will not occur until the model
|
27
|
+
# is persisted.
|
28
|
+
#
|
29
|
+
# @param [#to_sym] attrib attribute to serialize
|
30
|
+
# @param [Hash] opts additional options
|
31
|
+
# @option opts [#to_sym] :to The column to serialize +attrib+ to. If this
|
32
|
+
# option is specified, a reader attribute will be created for +attrib+
|
33
|
+
# and a +<attrib>=+ method will be create that copies the assigned value
|
34
|
+
# to the specified column.
|
35
|
+
# @option opts [#to_sym] :with (BCryptPasswordColumn)
|
36
|
+
# The coder to use to serialize and deserialize values assigned to +attrib+.
|
37
|
+
# @see SecurelyHashedAttributes::Coders::BCryptPasswordColumn
|
38
|
+
# @example
|
39
|
+
# class User < ActiveRecord::Base
|
40
|
+
# securely_hashes :password, :to => :password_hash
|
41
|
+
# securely_hashes :security_answer
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# new_user = User.new
|
45
|
+
# new_user.password = 'my password'
|
46
|
+
# new_user.security_answer = 'I am a turtle'
|
47
|
+
# new_user.save
|
48
|
+
# new_user.reload
|
49
|
+
# new_user.password_hash # => '$2a$10blahetcetc...'
|
50
|
+
# new_user.security_answer # => '$2a$10yaddayadda...'
|
51
|
+
# new_user.password_hash == 'not my password' # => false
|
52
|
+
# new_user.password_hash == 'my password' # => true
|
53
|
+
# new_user.security_answer == 'I am a duck' # => false
|
54
|
+
# new_user.security_answer == 'I am a turtle' # => true
|
55
|
+
def securely_hashes attrib, opts={}
|
56
|
+
opts = SecurelyHashedAttributes::DEFAULT_ATTRIBUTE_OPTIONS.merge opts
|
57
|
+
attrib = attrib.to_sym
|
58
|
+
if opts[:to]
|
59
|
+
col = opts[:to].to_sym
|
60
|
+
serialize col, opts[:with]
|
61
|
+
|
62
|
+
attr_reader attrib
|
63
|
+
define_method :"#{attrib}=" do |val|
|
64
|
+
instance_variable_set(:"@#{attrib}", val)
|
65
|
+
self[col] = val
|
66
|
+
end
|
67
|
+
else
|
68
|
+
serialize attrib, opts[:with]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This coder serializes strings to +BCrypt::Password+ instances which, as the
|
2
|
+
# name suggests, are suitable handlers for passwords.
|
3
|
+
class SecurelyHashedAttributes::Coders::BCryptPasswordColumn
|
4
|
+
# A list of errors to handle when loading
|
5
|
+
RESCUE_ERRORS = [ArgumentError, BCrypt::Errors::InvalidHash]
|
6
|
+
|
7
|
+
# Wrap the given data in the warm blanket of a +BCrypt::Password+
|
8
|
+
# @param [#to_s] str data to serialize
|
9
|
+
# @return [BCrypt::Password]
|
10
|
+
def self.dump str
|
11
|
+
BCrypt::Password.create str
|
12
|
+
end
|
13
|
+
|
14
|
+
# Takes a String digest generated by +bcrypt+ and wraps it in a new
|
15
|
+
# +BCrypt::Password+ for functionality beyond that of a simple +String+.
|
16
|
+
# If +digest+ is +nil+, an empty string is returned. If +bcrypt+ does not
|
17
|
+
# recognize +digest+ as a valid hash, +digest+ itself is returned.
|
18
|
+
# @param [String] digest a string digest generated by +bcrypt+
|
19
|
+
# @return [BCrypt::Password, String]
|
20
|
+
def self.load digest
|
21
|
+
return '' if digest.nil?
|
22
|
+
begin
|
23
|
+
BCrypt::Password.new digest
|
24
|
+
rescue *RESCUE_ERRORS
|
25
|
+
digest
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
SecurelyHashedAttributes::DEFAULT_ATTRIBUTE_OPTIONS[:with] = self
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "securely_hashed_attributes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "securely_hashed_attributes"
|
7
|
+
s.version = SecurelyHashedAttributes::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ian D. Eccles"]
|
10
|
+
s.email = ["ian.eccles@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Add securely hashed attributes to your models}
|
13
|
+
s.description = %q{Add securely hashed attributes to your models, serialized with BCrypt}
|
14
|
+
|
15
|
+
s.rubyforge_project = "securely_hashed_attributes"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_development_dependency 'rails', '~> 3.1.0.beta1'
|
22
|
+
s.add_development_dependency 'rspec', '~> 2.6.0'
|
23
|
+
s.add_development_dependency 'with_model', '~> 0.1.5'
|
24
|
+
s.add_development_dependency 'sqlite3', '~> 1.3.3'
|
25
|
+
s.add_development_dependency 'simplecov', '~> 0.4.2'
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SecurelyHashedAttributes::Coders::BCryptPasswordColumn do
|
4
|
+
it "should dump a string as a bcrypt password hash" do
|
5
|
+
hashed = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.dump('my stringzy')
|
6
|
+
hashed.should be_a_kind_of(BCrypt::Password)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should dump a non string to bcrypt by converting it to a string" do
|
10
|
+
hashed = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.dump([1, 2, 3])
|
11
|
+
hashed.should be_a_kind_of(BCrypt::Password)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should load a bcrypt hash as a string" do
|
15
|
+
hashed = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.dump('my stringzy')
|
16
|
+
loaded = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.load(hashed)
|
17
|
+
loaded.should be_a_kind_of(BCrypt::Password)
|
18
|
+
loaded.should == 'my stringzy'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should load a nil as an empty string" do
|
22
|
+
loaded = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.load(nil)
|
23
|
+
loaded.should_not be_a_kind_of(BCrypt::Password)
|
24
|
+
loaded.should == ''
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should load a non bcrypt hash as a plain string" do
|
28
|
+
loaded = SecurelyHashedAttributes::Coders::BCryptPasswordColumn.load('sweet lameness')
|
29
|
+
loaded.should_not be_a_kind_of(BCrypt::Password)
|
30
|
+
loaded.should == 'sweet lameness'
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'active_record/connection_adapters/sqlite3_adapter'
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
6
|
+
|
7
|
+
describe ActiveRecord::Base do
|
8
|
+
class AlternateCoder
|
9
|
+
def self.dump(*_); 'encoded'; end
|
10
|
+
def self.load(*_); 'decoded'; end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:new_model) {
|
14
|
+
HashingModel.new
|
15
|
+
}
|
16
|
+
|
17
|
+
with_model :hashing_model do
|
18
|
+
table do |t|
|
19
|
+
t.string :blathering
|
20
|
+
t.string :password_hash
|
21
|
+
t.string :chicken_fist_digest
|
22
|
+
t.string :big_mclargehuge
|
23
|
+
end
|
24
|
+
|
25
|
+
model do
|
26
|
+
attr_reader :stately_dutch, :portly
|
27
|
+
alias :stately_dutch? :stately_dutch
|
28
|
+
alias :portly? :portly
|
29
|
+
|
30
|
+
securely_hashes :blathering, :with => AlternateCoder
|
31
|
+
securely_hashes :password, :to => :password_hash
|
32
|
+
securely_hashes :chicken_fist, :to => :chicken_fist_digest
|
33
|
+
|
34
|
+
def chicken_fist=(bird)
|
35
|
+
@stately_dutch = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def rip_steakface=(beefy)
|
39
|
+
@portly = true
|
40
|
+
end
|
41
|
+
|
42
|
+
securely_hashes :rip_steakface, :to => :big_mclargehuge
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
HashingModel.delete_all
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should create getters and setters for :password" do
|
51
|
+
new_model.should respond_to(:password)
|
52
|
+
new_model.should respond_to(:password=)
|
53
|
+
new_model.password = 'super duper'
|
54
|
+
new_model.password.should == 'super duper'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should serialize :password to :password_digest on save" do
|
58
|
+
new_model.password = 'super duper'
|
59
|
+
new_model.save
|
60
|
+
new_model.reload
|
61
|
+
new_model.password_hash.should_not be_empty
|
62
|
+
new_model.password_hash.should be_a_kind_of(BCrypt::Password)
|
63
|
+
new_model.password_hash.should == 'super duper'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should get clobbered by #chicken_fist=" do
|
67
|
+
new_model.should_not be_stately_dutch
|
68
|
+
new_model.chicken_fist = 'a string to hash'
|
69
|
+
new_model.should be_stately_dutch
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not hash properly because of #chicken_fist=" do
|
73
|
+
new_model.chicken_fist = 'a string to hash'
|
74
|
+
new_model.save
|
75
|
+
new_model.chicken_fist_digest.should be_empty
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should clobber #rip_steakface=" do
|
79
|
+
new_model.should_not be_portly
|
80
|
+
new_model.rip_steakface = 'a string to hash'
|
81
|
+
new_model.should_not be_portly
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should has properly because it overwrote #rip_steakface=" do
|
85
|
+
new_model.rip_steakface = 'a string to hash'
|
86
|
+
new_model.save
|
87
|
+
new_model.big_mclargehuge.should_not be_empty
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should serialize :blathering with an alternate coder" do
|
91
|
+
new_model.blathering = 'fancy pants'
|
92
|
+
new_model.save
|
93
|
+
new_model.reload
|
94
|
+
new_model.blathering.should == 'decoded'
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Dir[File.expand_path('support', File.dirname(__FILE__)) + "/**/*.rb"].each { |f| require f }
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter "/spec/"
|
7
|
+
end
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'securely_hashed_attributes'
|
12
|
+
require 'with_model'
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.extend WithModel
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: securely_hashed_attributes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ian D. Eccles
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-19 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 3.1.0.beta1
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.6.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: with_model
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.1.5
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: sqlite3
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.3.3
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: simplecov
|
61
|
+
prerelease: false
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.4.2
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id005
|
70
|
+
description: Add securely hashed attributes to your models, serialized with BCrypt
|
71
|
+
email:
|
72
|
+
- ian.eccles@gmail.com
|
73
|
+
executables: []
|
74
|
+
|
75
|
+
extensions: []
|
76
|
+
|
77
|
+
extra_rdoc_files: []
|
78
|
+
|
79
|
+
files:
|
80
|
+
- .gitignore
|
81
|
+
- .rspec
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- init.rb
|
87
|
+
- lib/securely_hashed_attributes.rb
|
88
|
+
- lib/securely_hashed_attributes/coders.rb
|
89
|
+
- lib/securely_hashed_attributes/coders/bcrypt_password_column.rb
|
90
|
+
- lib/securely_hashed_attributes/version.rb
|
91
|
+
- securely_hashed_attributes.gemspec
|
92
|
+
- spec/securely_hashed_attributes/coders/bcrypt_password_column_spec.rb
|
93
|
+
- spec/securely_hashed_attributes_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
homepage: ""
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project: securely_hashed_attributes
|
118
|
+
rubygems_version: 1.7.2
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Add securely hashed attributes to your models
|
122
|
+
test_files:
|
123
|
+
- spec/securely_hashed_attributes/coders/bcrypt_password_column_spec.rb
|
124
|
+
- spec/securely_hashed_attributes_spec.rb
|
125
|
+
- spec/spec_helper.rb
|
126
|
+
has_rdoc:
|