securely_hashed_attributes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|