has_protected_token 0.0.0.pre.beta → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +17 -9
- data/Appraisals +1 -17
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -2
- data/README.md +82 -1
- data/Rakefile +12 -0
- data/gemfiles/AR_4.2.gemfile +7 -5
- data/gemfiles/AR_5.0.gemfile +6 -4
- data/gemfiles/AR_5.1.gemfile +6 -4
- data/gemfiles/AR_5.2.gemfile +6 -4
- data/gemfiles/AR_6.0.gemfile +6 -4
- data/has_protected_token.gemspec +10 -6
- data/lib/has_protected_token.rb +18 -11
- data/spec/features/token_authentication_spec.rb +43 -0
- data/spec/lib/has_protected_token_spec.rb +11 -9
- data/spec/spec_helper.rb +6 -1
- data/spec/support/model.rb +4 -2
- data/spec/support/schema.rb +2 -0
- metadata +41 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eab02b7662c9a1411f7e12d6ba5b847ed6abed6ae0c9320f872d889344647087
|
4
|
+
data.tar.gz: 6c97a89ebc3c9b0b937d074bfbb034c1bb23e8a0df2f4855788b32bdac0e57b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ad8401ee713aacc57e39d64a41088d249b14deedd83cc0b95d368e13f6997a220a41781ec8a34cb7fead5a787c0ef24cfbb77cd388e2058071d06582f219eaa
|
7
|
+
data.tar.gz: 6322d1b090e322b1064c3c3306f737a6e801ca87b9c9a26678f9f2e8d09f5d36aba3bbf8e8dea1ce88b67f3731e0a7ab66775eaacc100350dd562276ee7edce4
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
|
4
|
+
Metrics/LineLength:
|
5
|
+
Exclude:
|
6
|
+
- has_protected_token.gemspec
|
7
|
+
|
8
|
+
Naming/FileName:
|
9
|
+
Exclude:
|
10
|
+
- gemfiles/*
|
11
|
+
|
12
|
+
Metrics/BlockLength:
|
13
|
+
Exclude:
|
14
|
+
- spec/**/*
|
15
|
+
|
16
|
+
Naming/PredicateName:
|
17
|
+
Enabled: false
|
data/.travis.yml
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
3
|
rvm:
|
4
|
-
- 2.2
|
5
4
|
- 2.3
|
6
5
|
- 2.4
|
7
6
|
- 2.5
|
@@ -16,18 +15,27 @@ gemfile:
|
|
16
15
|
|
17
16
|
matrix:
|
18
17
|
exclude:
|
19
|
-
- rvm: 2.2
|
20
|
-
gemfile: gemfiles/AR_5.0.gemfile
|
21
|
-
- rvm: 2.2
|
22
|
-
gemfile: gemfiles/AR_5.1.gemfile
|
23
|
-
- rvm: 2.2
|
24
|
-
gemfile: gemfiles/AR_5.2.gemfile
|
25
|
-
- rvm: 2.2
|
26
|
-
gemfile: gemfiles/AR_6.0.gemfile
|
27
18
|
- rvm: 2.3
|
28
19
|
gemfile: gemfiles/AR_6.0.gemfile
|
29
20
|
- rvm: 2.4
|
30
21
|
gemfile: gemfiles/AR_6.0.gemfile
|
22
|
+
- rvm: 2.6
|
23
|
+
gemfile: gemfiles/AR_4.2.gemfile
|
24
|
+
include:
|
25
|
+
- rvm: 2.6
|
26
|
+
gemfile: Gemfile
|
27
|
+
- stage: linting
|
28
|
+
rvm: 2.3
|
29
|
+
script: rake lint
|
30
|
+
gemfile: gemfiles/AR_4.2.gemfile
|
31
|
+
|
32
|
+
deploy:
|
33
|
+
provider: rubygems
|
34
|
+
gem: has_protected_token
|
35
|
+
api_key:
|
36
|
+
secure: "BJclI6dKunv06hNB1ZkyqKnRnZgAFUuyr2TQinCfPCx47yI62zLWYkxGFEHYcLfjLM60lkTHHABg70qozAPTy+2YObaMOl3oCASDcMToPyhoIZngq3YYrphOGPgHD5vgHC9RZiPrbGorY/bM4lqMfhU2VC438/3BFUONgbgwnmJ2D8y4TC4fj2tAifb89cLHM45fFvu4lxbRWAIA/g1lqBBZYMcbbFKm+cAJqP2piXJizWvpOwHwZF7bs9cThsKGkQi9Ya4oDu/cytzmOybP46edapdWOzBvGcqzog7GaoqlUnMJfL2BWWnuLdcT4L17zfiRdnvpBH4F2/u5CR7Dv2Jy07c2/BTMWC1QNwzfVp84fl0qDi+CGaGtww1qNXvzZlVOR0l3pBCwi0rxksFDj4PpMuqWIGNYSgxatn6WoVeas2sP1emT9VLus7G8UWtyGjSk9QE8g8ZiamELi5hbW9MWT1JyfdDYub+oY9svfJBefxB9SA6mG/8Dbhq+VkA7fd6VNAuG9hDmmQx/hI3ymw+sr6iN7EYZq4s3sWz3/CSmioopy1eV+OoY8YsGxwpck3IqqQxQWdAJ8l0Z7o8HyHSTyp5vB6dJNsatVFgMfP74XRGMTD/r1H9CFA029Ekkpvu6FoNFQ6qX13pSlbRXoNp3Dlag7+c1h5ZPVb8D7UE="
|
37
|
+
on:
|
38
|
+
tags: true
|
31
39
|
|
32
40
|
before_install:
|
33
41
|
- gem install bundler -v 1.17.3
|
data/Appraisals
CHANGED
@@ -1,20 +1,4 @@
|
|
1
|
-
|
2
|
-
gem 'activerecord', '~> 3.0.20'
|
3
|
-
gem 'sqlite3', '~> 1.3.6'
|
4
|
-
gem 'byebug', '~> 10.0.2'
|
5
|
-
end
|
6
|
-
|
7
|
-
appraise 'AR_3.1' do
|
8
|
-
gem 'activerecord', '~> 3.1.12'
|
9
|
-
gem 'sqlite3', '~> 1.3.6'
|
10
|
-
gem 'byebug', '~> 10.0.2'
|
11
|
-
end
|
12
|
-
|
13
|
-
appraise 'AR_3.2' do
|
14
|
-
gem 'activerecord', '~> 3.2.22'
|
15
|
-
gem 'sqlite3', '~> 1.3.6'
|
16
|
-
gem 'byebug', '~> 10.0.2'
|
17
|
-
end
|
1
|
+
# frozen_string_literal: true
|
18
2
|
|
19
3
|
appraise 'AR_4.2' do
|
20
4
|
gem 'activerecord', '~> 4.2.11'
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
has_protected_token (0.
|
4
|
+
has_protected_token (0.1.0)
|
5
5
|
activerecord (>= 4.2)
|
6
6
|
bcrypt (~> 3.1.1)
|
7
7
|
|
@@ -23,6 +23,7 @@ GEM
|
|
23
23
|
bundler
|
24
24
|
rake
|
25
25
|
thor (>= 0.14.0)
|
26
|
+
ast (2.4.0)
|
26
27
|
bcrypt (3.1.13)
|
27
28
|
bump (0.8.0)
|
28
29
|
byebug (11.0.1)
|
@@ -31,7 +32,12 @@ GEM
|
|
31
32
|
diff-lcs (1.3)
|
32
33
|
i18n (1.7.0)
|
33
34
|
concurrent-ruby (~> 1.0)
|
34
|
-
|
35
|
+
jaro_winkler (1.5.3)
|
36
|
+
minitest (5.13.0)
|
37
|
+
parallel (1.18.0)
|
38
|
+
parser (2.6.5.0)
|
39
|
+
ast (~> 2.4.0)
|
40
|
+
rainbow (3.0.0)
|
35
41
|
rake (13.0.0)
|
36
42
|
rspec (3.9.0)
|
37
43
|
rspec-core (~> 3.9.0)
|
@@ -46,11 +52,21 @@ GEM
|
|
46
52
|
diff-lcs (>= 1.2.0, < 2.0)
|
47
53
|
rspec-support (~> 3.9.0)
|
48
54
|
rspec-support (3.9.0)
|
55
|
+
rubocop (0.69.0)
|
56
|
+
jaro_winkler (~> 1.5.1)
|
57
|
+
parallel (~> 1.10)
|
58
|
+
parser (>= 2.6)
|
59
|
+
rainbow (>= 2.2.2, < 4.0)
|
60
|
+
ruby-progressbar (~> 1.7)
|
61
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
62
|
+
ruby-progressbar (1.10.1)
|
49
63
|
sqlite3 (1.4.1)
|
50
64
|
thor (0.20.3)
|
51
65
|
thread_safe (0.3.6)
|
52
66
|
tzinfo (1.2.5)
|
53
67
|
thread_safe (~> 0.1)
|
68
|
+
unicode-display_width (1.6.0)
|
69
|
+
wwtd (1.4.0)
|
54
70
|
zeitwerk (2.2.0)
|
55
71
|
|
56
72
|
PLATFORMS
|
@@ -65,7 +81,9 @@ DEPENDENCIES
|
|
65
81
|
has_protected_token!
|
66
82
|
rake
|
67
83
|
rspec
|
84
|
+
rubocop
|
68
85
|
sqlite3
|
86
|
+
wwtd
|
69
87
|
|
70
88
|
BUNDLED WITH
|
71
89
|
1.17.3
|
data/README.md
CHANGED
@@ -1,3 +1,84 @@
|
|
1
1
|
# has_protected_token
|
2
2
|
|
3
|
-
This gem is
|
3
|
+
Current version: _0.0.0beta_. This gem is currently in pre-release beta and a stable release will be made _real soon now_.
|
4
|
+
|
5
|
+
## What?
|
6
|
+
|
7
|
+
Abstracts away generating, storing and validating user auth tokens. Use it if you need to deal with shared secrets, etc.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Requirements: Ruby >= 2.2, ActiveRecord >= 4.2
|
12
|
+
|
13
|
+
From the command line:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ gem install has_protected_token
|
17
|
+
```
|
18
|
+
|
19
|
+
In your project gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'has_protected_token'
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Adding it to your model
|
28
|
+
|
29
|
+
Add it to your model as you would with `has_secure_password`:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class User < ActiveRecord::Base
|
33
|
+
has_protected_token
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
The gem assumes the existance of a `token` attribute on the model. If you would like to use a different name, you can pass an optional hash:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
has_protected_token column_name: :my_column_name
|
41
|
+
```
|
42
|
+
|
43
|
+
The gem will replace 'token' with 'my_column_name' in all instance methods described below. Thus, `#token` becomes `#my_column_name`, `#regenerate_token` becomes `#regenerate_my_column_name`, etc.
|
44
|
+
|
45
|
+
### Generating and validating tokens
|
46
|
+
|
47
|
+
To automatically generate a new random token and save it to your model, call `#regenerate_token`:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
user = User.new
|
51
|
+
user.regenerate_token
|
52
|
+
# => 'e13d0bbd4a12d2aea673127c7e995a67'
|
53
|
+
user.token
|
54
|
+
# => '$2a$12$5xVuny6Z79bYfgMMU7nyzeaOSjygRnXfsJjeJHzRZ0vUYRGeUjo6u'
|
55
|
+
```
|
56
|
+
|
57
|
+
If you would like to supply your own token:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
user = User.new
|
61
|
+
user.token = 'happiness is a cup of coffee'
|
62
|
+
# => 'happiness is a cup of coffee'
|
63
|
+
user.save!
|
64
|
+
# => true
|
65
|
+
user.token
|
66
|
+
# => '$2a$12$5zWuBy3279hYfgOMU2nyz3aQWjygTnXfsJjeJHzRZ0vUYZGeUgY6W'
|
67
|
+
```
|
68
|
+
|
69
|
+
To validate a token against the hashed value stored in the database:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
user.validate_token('correct value')
|
73
|
+
# => true
|
74
|
+
user.validate_token('incorrect value')
|
75
|
+
# => false
|
76
|
+
```
|
77
|
+
|
78
|
+
### More advanced features
|
79
|
+
|
80
|
+
`has_protected_token` uses BCrypt to hash the token before storage. By default, it uses BCrypt's default cost (currently 12) during hashing. You can lower this value to speed up the hashing process at the cost of lower security, or raise it for the opposite effect. Simply add a `cost` parameter to the options hash when calling `has_protected_token`:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
has_protected_token cost: 16
|
84
|
+
```
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rspec/core/rake_task'
|
2
4
|
require 'bump/tasks'
|
3
5
|
|
@@ -7,4 +9,14 @@ RSpec::Core::RakeTask.new :test do |task|
|
|
7
9
|
task.pattern = Dir.glob('spec/**/*_spec.rb')
|
8
10
|
end
|
9
11
|
|
12
|
+
desc 'Run the whole CI job suite as Travis would'
|
13
|
+
task :ci do
|
14
|
+
sh('bundle exec wwtd')
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run the linter'
|
18
|
+
task :lint do
|
19
|
+
sh('bundle exec rubocop')
|
20
|
+
end
|
21
|
+
|
10
22
|
task default: :test
|
data/gemfiles/AR_4.2.gemfile
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
|
-
source
|
5
|
+
source 'https://rubygems.org'
|
4
6
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
-
gem
|
7
|
+
gem 'activerecord', '~> 4.2.11'
|
8
|
+
gem 'byebug', '~> 10.0.2'
|
9
|
+
gem 'sqlite3', '~> 1.3.6'
|
8
10
|
|
9
|
-
gemspec path:
|
11
|
+
gemspec path: '../'
|
data/gemfiles/AR_5.0.gemfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
|
-
source
|
5
|
+
source 'https://rubygems.org'
|
4
6
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
+
gem 'activerecord', '~> 5.0.7'
|
8
|
+
gem 'sqlite3', '~> 1.3.6'
|
7
9
|
|
8
|
-
gemspec path:
|
10
|
+
gemspec path: '../'
|
data/gemfiles/AR_5.1.gemfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
|
-
source
|
5
|
+
source 'https://rubygems.org'
|
4
6
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
+
gem 'activerecord', '~> 5.1.7'
|
8
|
+
gem 'sqlite3'
|
7
9
|
|
8
|
-
gemspec path:
|
10
|
+
gemspec path: '../'
|
data/gemfiles/AR_5.2.gemfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
|
-
source
|
5
|
+
source 'https://rubygems.org'
|
4
6
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
+
gem 'activerecord', '~> 5.2.3'
|
8
|
+
gem 'sqlite3'
|
7
9
|
|
8
|
-
gemspec path:
|
10
|
+
gemspec path: '../'
|
data/gemfiles/AR_6.0.gemfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
|
-
source
|
5
|
+
source 'https://rubygems.org'
|
4
6
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
+
gem 'activerecord', '~> 6.0.0'
|
8
|
+
gem 'sqlite3'
|
7
9
|
|
8
|
-
gemspec path:
|
10
|
+
gemspec path: '../'
|
data/has_protected_token.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = 'has_protected_token'
|
3
|
-
s.version = '0.
|
5
|
+
s.version = '0.1.0'
|
4
6
|
s.date = '2019-10-06'
|
5
7
|
s.summary = 'Easily generate random tokens for any ActiveRecord model and store them securely in the database.'
|
6
8
|
s.description = 'Generate random tokens (or use your own) for any ActiveRecord model. Hashes and salts the token before storage in the database using the same methodology as has_secure_password.'
|
@@ -9,17 +11,19 @@ Gem::Specification.new do |s|
|
|
9
11
|
s.files = `git ls-files`.split("\n")
|
10
12
|
s.homepage = 'https://github.com/StaphSynth/has_protected_token'
|
11
13
|
s.license = 'MIT'
|
12
|
-
s.required_ruby_version = '>= 2.
|
14
|
+
s.required_ruby_version = '>= 2.3'
|
13
15
|
|
14
16
|
s.add_dependency 'activerecord', '>= 4.2'
|
15
17
|
s.add_dependency 'bcrypt', '~> 3.1.1'
|
16
18
|
|
19
|
+
s.add_development_dependency 'appraisal'
|
20
|
+
s.add_development_dependency 'bump'
|
17
21
|
s.add_development_dependency 'bundler', '~> 1.17.3'
|
22
|
+
s.add_development_dependency 'byebug'
|
23
|
+
s.add_development_dependency 'database_cleaner'
|
18
24
|
s.add_development_dependency 'rake'
|
19
25
|
s.add_development_dependency 'rspec'
|
26
|
+
s.add_development_dependency 'rubocop'
|
20
27
|
s.add_development_dependency 'sqlite3'
|
21
|
-
s.add_development_dependency '
|
22
|
-
s.add_development_dependency 'database_cleaner'
|
23
|
-
s.add_development_dependency 'bump'
|
24
|
-
s.add_development_dependency 'appraisal'
|
28
|
+
s.add_development_dependency 'wwtd'
|
25
29
|
end
|
data/lib/has_protected_token.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
require 'bcrypt'
|
3
5
|
|
4
6
|
module ActiveRecord
|
5
|
-
module ProtectedToken
|
7
|
+
module ProtectedToken # :nodoc:
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
8
|
-
module ClassMethods
|
9
|
-
|
10
|
+
module ClassMethods # :nodoc:
|
11
|
+
##
|
12
|
+
# == .has_protected_token
|
10
13
|
#
|
11
14
|
# Adds methods to set and validate against a token
|
12
15
|
# that has been hashed and salted using BCrypt.
|
@@ -66,31 +69,36 @@ module ActiveRecord
|
|
66
69
|
#
|
67
70
|
# user2.authenticate_token('super_secret_token')
|
68
71
|
# => true
|
72
|
+
|
73
|
+
# TODO: something about the method length
|
74
|
+
# rubocop:disable Metrics/MethodLength
|
69
75
|
def has_protected_token(options = {})
|
70
76
|
attribute = options[:column_name] || :token
|
71
77
|
cost = options[:cost] || BCrypt::Engine::DEFAULT_COST
|
72
78
|
|
73
79
|
define_method("regenerate_#{attribute}") do
|
74
80
|
raw_token = self.class.generate_token
|
75
|
-
hashed_token = hash_token(raw_token, cost)
|
76
81
|
|
77
|
-
|
82
|
+
update_column(attribute, hash_token(raw_token, cost))
|
78
83
|
raw_token
|
79
84
|
end
|
80
85
|
|
81
86
|
define_method("#{attribute}=") do |raw_token|
|
82
87
|
super(hash_token(raw_token, cost))
|
88
|
+
raw_token
|
83
89
|
end
|
84
90
|
|
85
91
|
define_method("authenticate_#{attribute}") do |raw_token|
|
86
92
|
begin
|
87
|
-
BCrypt::Password.new(
|
93
|
+
BCrypt::Password.new(send(attribute)) == raw_token
|
88
94
|
rescue BCrypt::Error
|
89
95
|
false
|
90
96
|
end
|
91
97
|
end
|
92
98
|
end
|
99
|
+
# rubocop:enable Metrics/MethodLength
|
93
100
|
|
101
|
+
##
|
94
102
|
# == .generate_token
|
95
103
|
# Class method to generate random tokens
|
96
104
|
#
|
@@ -99,18 +107,17 @@ module ActiveRecord
|
|
99
107
|
def generate_token(length = 24)
|
100
108
|
n = length.to_i
|
101
109
|
SecureRandom.hex(n / 2) # hex returns n * 2
|
102
|
-
|
103
|
-
|
104
|
-
raise ArgumentError, 'Token length must be an integer'
|
110
|
+
rescue NoMethodError
|
111
|
+
raise ArgumentError, 'Token length must be an integer'
|
105
112
|
end
|
106
113
|
end
|
107
114
|
|
108
115
|
private
|
109
116
|
|
110
117
|
def hash_token(raw_token, cost)
|
111
|
-
BCrypt::Password.create(raw_token, :
|
118
|
+
BCrypt::Password.create(raw_token, cost: cost)
|
112
119
|
end
|
113
120
|
end
|
114
121
|
end
|
115
122
|
|
116
|
-
ActiveRecord::Base.
|
123
|
+
ActiveRecord::Base.include ActiveRecord::ProtectedToken
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'token authentication' do
|
6
|
+
let(:user) { User.create }
|
7
|
+
|
8
|
+
describe 'for locally generated tokens' do
|
9
|
+
describe 'when presented with the correct secret value' do
|
10
|
+
it 'returns true' do
|
11
|
+
secret = user.regenerate_token
|
12
|
+
|
13
|
+
expect(user.authenticate_token(secret)).to eq(true)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'when presented with the incorrect secret value' do
|
18
|
+
it 'returns false' do
|
19
|
+
user.regenerate_token
|
20
|
+
|
21
|
+
expect(user.authenticate_token('derp derp')).to eq(false)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'for user-supplied tokens' do
|
27
|
+
before do
|
28
|
+
user.token = 'trains'
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'when presented with the correct secret value' do
|
32
|
+
it 'returns true' do
|
33
|
+
expect(user.authenticate_token('trains')).to eq(true)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'when presented with the incorrect secret value' do
|
38
|
+
it 'returns false' do
|
39
|
+
expect(user.authenticate_token('buses')).to eq(false)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe ActiveRecord::ProtectedToken do
|
@@ -36,12 +38,12 @@ describe ActiveRecord::ProtectedToken do
|
|
36
38
|
end
|
37
39
|
|
38
40
|
context 'when an integer is provided' do
|
39
|
-
let(:user) {
|
41
|
+
let(:user) { LowCostUser.new }
|
40
42
|
|
41
43
|
it 'accepts that instead' do
|
42
44
|
expect(BCrypt::Password).to receive(:create).with(
|
43
45
|
raw_token,
|
44
|
-
cost:
|
46
|
+
cost: 4
|
45
47
|
)
|
46
48
|
|
47
49
|
user.token = raw_token
|
@@ -59,7 +61,7 @@ describe ActiveRecord::ProtectedToken do
|
|
59
61
|
)
|
60
62
|
end
|
61
63
|
|
62
|
-
describe '#
|
64
|
+
describe '#regenerate_token' do
|
63
65
|
it 'returns a new token' do
|
64
66
|
expect(user.regenerate_token).to eq(raw_token)
|
65
67
|
end
|
@@ -71,12 +73,12 @@ describe ActiveRecord::ProtectedToken do
|
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
|
-
describe '#
|
76
|
+
describe '#authenticate_token' do
|
75
77
|
before do
|
76
78
|
user.regenerate_token
|
77
79
|
end
|
78
80
|
|
79
|
-
context 'when passed
|
81
|
+
context 'when passed a plain text token' do
|
80
82
|
it 'returns true if it matches the stored value' do
|
81
83
|
expect(user.authenticate_token(raw_token)).to eq(true)
|
82
84
|
end
|
@@ -92,12 +94,12 @@ describe ActiveRecord::ProtectedToken do
|
|
92
94
|
end
|
93
95
|
|
94
96
|
it 'returns false' do
|
95
|
-
expect(user.authenticate_token(
|
97
|
+
expect(user.authenticate_token(bad: 'data')).to eq(false)
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
100
|
-
describe '#
|
102
|
+
describe '#token=' do
|
101
103
|
context 'when passed a value' do
|
102
104
|
it 'hashes it and stores the hashed value in the model instance' do
|
103
105
|
user.token = raw_token
|
@@ -125,8 +127,8 @@ describe ActiveRecord::ProtectedToken do
|
|
125
127
|
|
126
128
|
context 'when passing a length' do
|
127
129
|
it 'validates the length is coercable to an integer' do
|
128
|
-
expect{ User.generate_token(12) }.not_to raise_error
|
129
|
-
expect{ User.generate_token(false) }.to raise_error(ArgumentError)
|
130
|
+
expect { User.generate_token(12) }.not_to raise_error
|
131
|
+
expect { User.generate_token(false) }.to raise_error(ArgumentError)
|
130
132
|
end
|
131
133
|
|
132
134
|
it 'returns a token of that length' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'byebug'
|
2
4
|
require 'database_cleaner'
|
3
5
|
require 'has_protected_token'
|
@@ -15,7 +17,10 @@ RSpec.configure do |config|
|
|
15
17
|
end
|
16
18
|
|
17
19
|
config.before :suite do
|
18
|
-
ActiveRecord::Base.establish_connection
|
20
|
+
ActiveRecord::Base.establish_connection(
|
21
|
+
adapter: 'sqlite3',
|
22
|
+
database: ':memory:'
|
23
|
+
)
|
19
24
|
ActiveRecord::Migration.suppress_messages do
|
20
25
|
load 'support/schema.rb'
|
21
26
|
end
|
data/spec/support/model.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Model < ActiveRecord::Base; end
|
2
4
|
|
3
5
|
class User < Model
|
@@ -8,6 +10,6 @@ class SpecialUser < Model
|
|
8
10
|
has_protected_token column_name: :shared_secret
|
9
11
|
end
|
10
12
|
|
11
|
-
class
|
12
|
-
has_protected_token cost:
|
13
|
+
class LowCostUser < Model
|
14
|
+
has_protected_token cost: 4
|
13
15
|
end
|
data/spec/support/schema.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_protected_token
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Allen
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 3.1.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: appraisal
|
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: bump
|
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'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,7 +81,7 @@ dependencies:
|
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: 1.17.3
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
84
|
+
name: byebug
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - ">="
|
@@ -67,7 +95,7 @@ dependencies:
|
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
98
|
+
name: database_cleaner
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
72
100
|
requirements:
|
73
101
|
- - ">="
|
@@ -81,7 +109,7 @@ dependencies:
|
|
81
109
|
- !ruby/object:Gem::Version
|
82
110
|
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
112
|
+
name: rake
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
115
|
- - ">="
|
@@ -95,7 +123,7 @@ dependencies:
|
|
95
123
|
- !ruby/object:Gem::Version
|
96
124
|
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
126
|
+
name: rspec
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
100
128
|
requirements:
|
101
129
|
- - ">="
|
@@ -109,7 +137,7 @@ dependencies:
|
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '0'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
140
|
+
name: rubocop
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
114
142
|
requirements:
|
115
143
|
- - ">="
|
@@ -123,7 +151,7 @@ dependencies:
|
|
123
151
|
- !ruby/object:Gem::Version
|
124
152
|
version: '0'
|
125
153
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
154
|
+
name: sqlite3
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
128
156
|
requirements:
|
129
157
|
- - ">="
|
@@ -137,7 +165,7 @@ dependencies:
|
|
137
165
|
- !ruby/object:Gem::Version
|
138
166
|
version: '0'
|
139
167
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
168
|
+
name: wwtd
|
141
169
|
requirement: !ruby/object:Gem::Requirement
|
142
170
|
requirements:
|
143
171
|
- - ">="
|
@@ -160,6 +188,7 @@ extra_rdoc_files: []
|
|
160
188
|
files:
|
161
189
|
- ".gitignore"
|
162
190
|
- ".rspec"
|
191
|
+
- ".rubocop.yml"
|
163
192
|
- ".ruby-version"
|
164
193
|
- ".travis.yml"
|
165
194
|
- Appraisals
|
@@ -176,6 +205,7 @@ files:
|
|
176
205
|
- gemfiles/AR_6.0.gemfile
|
177
206
|
- has_protected_token.gemspec
|
178
207
|
- lib/has_protected_token.rb
|
208
|
+
- spec/features/token_authentication_spec.rb
|
179
209
|
- spec/lib/has_protected_token_spec.rb
|
180
210
|
- spec/spec_helper.rb
|
181
211
|
- spec/support/model.rb
|
@@ -192,12 +222,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
192
222
|
requirements:
|
193
223
|
- - ">="
|
194
224
|
- !ruby/object:Gem::Version
|
195
|
-
version: '2.
|
225
|
+
version: '2.3'
|
196
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
227
|
requirements:
|
198
|
-
- - "
|
228
|
+
- - ">="
|
199
229
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
230
|
+
version: '0'
|
201
231
|
requirements: []
|
202
232
|
rubygems_version: 3.0.3
|
203
233
|
signing_key:
|