userbin 1.5.0 → 1.6.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 +4 -4
- data/README.md +39 -30
- data/lib/userbin.rb +3 -2
- data/lib/userbin/client.rb +37 -77
- data/lib/userbin/models/account.rb +11 -0
- data/lib/userbin/models/context.rb +1 -1
- data/lib/userbin/models/pairing.rb +3 -0
- data/lib/userbin/session_token.rb +8 -8
- data/lib/userbin/support/cookie_store.rb +8 -1
- data/lib/userbin/support/padrino.rb +1 -2
- data/lib/userbin/support/rails.rb +1 -1
- data/lib/userbin/support/sinatra.rb +1 -2
- data/lib/userbin/token_store.rb +30 -0
- data/lib/userbin/version.rb +1 -1
- data/spec/models/user_spec.rb +0 -12
- data/spec/spec_helper.rb +12 -1
- data/spec/utils_spec.rb +11 -7
- metadata +18 -3
- data/lib/userbin/trusted_token_store.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a838f3a5b083d7baf4689189e9937242ee900f35
|
4
|
+
data.tar.gz: 43613aa2135886c221fd39fc2753cd9aed44e8fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64882804d2c11cc349d85e92fcbde230106bdb40e75099f94cf33b67ad47904ec587094dc98b18b656b326230e981c535248ed7256f1c1af10c903911efd7e0e
|
7
|
+
data.tar.gz: 89dcec756ea9f6856894071b1eae52f8017e48db7e6efb8484115d76cdf6bcd5e9eb0a12873137710a34e0fef44f242de67b702a4e0cfbf1cc760d1fb6029c31
|
data/README.md
CHANGED
@@ -3,14 +3,16 @@
|
|
3
3
|
[](https://travis-ci.org/userbin/userbin-ruby)
|
4
4
|
[](http://badge.fury.io/rb/userbin)
|
5
5
|
[](https://gemnasium.com/userbin/userbin-ruby)
|
6
|
+
[](https://coveralls.io/r/userbin/userbin-ruby)
|
6
7
|
|
8
|
+
**[Userbin](https://userbin.com) adds an additional security layer to your application by providing account takeover protection and two-factor authentication in a white-label package**
|
7
9
|
|
8
|
-
|
10
|
+
Your users **do not** need to be signed up or registered for Userbin before using the service and there's no need for them to download any proprietary apps. Also, Userbin requires **no modification of your current database schema** as it uses your local user IDs.
|
9
11
|
|
10
12
|
## Table of Contents
|
11
13
|
|
14
|
+
- [Installation](#installation)
|
12
15
|
- [Getting Started](#getting-started)
|
13
|
-
- [Setup User Monitoring](#setup-user-monitoring)
|
14
16
|
- [Active Sessions](#active-sessions)
|
15
17
|
- [Security Events](#security-events)
|
16
18
|
- [Two-factor Authentication](#two-factor-authentication)
|
@@ -22,7 +24,7 @@
|
|
22
24
|
- [Backup Codes](#backup-codes)
|
23
25
|
- [List Pairings](#list-pairings)
|
24
26
|
|
25
|
-
##
|
27
|
+
## Installation
|
26
28
|
|
27
29
|
Add the `userbin` gem to your `Gemfile`
|
28
30
|
|
@@ -30,22 +32,17 @@ Add the `userbin` gem to your `Gemfile`
|
|
30
32
|
gem "userbin"
|
31
33
|
```
|
32
34
|
|
33
|
-
Install the gem
|
34
|
-
|
35
|
-
```bash
|
36
|
-
bundle install
|
37
|
-
```
|
38
|
-
|
39
35
|
Load and configure the library with your Userbin API secret in an initializer or similar.
|
40
36
|
|
41
37
|
```ruby
|
42
|
-
require 'userbin'
|
43
38
|
Userbin.api_secret = "YOUR_API_SECRET"
|
44
39
|
```
|
45
40
|
|
46
|
-
##
|
41
|
+
## Getting started
|
47
42
|
|
48
|
-
|
43
|
+
### 1. Logging in and out
|
44
|
+
|
45
|
+
You should call `login` as soon as the user has logged in to your application to start the Userbin session. Pass a unique user identifier, and an *optional* hash of user properties which are used when searching for users in your dashboard.
|
49
46
|
|
50
47
|
```ruby
|
51
48
|
def your_after_login_hook
|
@@ -53,9 +50,7 @@ def your_after_login_hook
|
|
53
50
|
end
|
54
51
|
```
|
55
52
|
|
56
|
-
|
57
|
-
|
58
|
-
When a user logs out from within your application, call `logout` to remove the session from the user's [active sessions](#active-sessions).
|
53
|
+
When a user logs out from within your application, call `logout` to tell Userbin to remove the session from the user's [active sessions](#active-sessions).
|
59
54
|
|
60
55
|
```ruby
|
61
56
|
def your_after_logout_hook
|
@@ -63,32 +58,46 @@ def your_after_logout_hook
|
|
63
58
|
end
|
64
59
|
```
|
65
60
|
|
66
|
-
|
61
|
+
**Check that it works** by logging in to your application and watch your user appear in the [Userbin dashboard](https://dashboard.userbin.com).
|
67
62
|
|
68
|
-
|
63
|
+
### 2. Protecting routes
|
69
64
|
|
70
|
-
|
71
|
-
class AccountController < ApplicationController
|
72
|
-
before_filter :authenticate_user! # from e.g. Devise
|
73
|
-
before_filter { userbin.authorize! }
|
74
|
-
# ...
|
75
|
-
end
|
76
|
-
```
|
65
|
+
Call `authorize!` just before your `current_user` is being initialized. Usually you'll want to override your normal authentication filter, e.g. `authenticate_user!` if you're using Devise.
|
77
66
|
|
78
|
-
|
67
|
+
- `UserUnauthorizedError` will be raised if `login` has not yet been called, or if the session is no longer valid.
|
68
|
+
- `ChallengeRequiredError` will be raised when the user has enabled two-factor authentication and is logging in from an untrusted device.
|
79
69
|
|
80
70
|
```ruby
|
81
71
|
class ApplicationController < ActionController::Base
|
82
|
-
rescue_from Userbin::UserUnauthorizedError
|
83
|
-
|
84
|
-
|
72
|
+
rescue_from Userbin::UserUnauthorizedError, with: :user_unauthorized
|
73
|
+
rescue_from Userbin::ChallengeRequiredError, with: :challenge_required
|
74
|
+
|
75
|
+
# IMPLEMENT: Override the authentication method from your framework
|
76
|
+
def authenticate_user!
|
77
|
+
userbin.authorize!
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
# IMPLEMENT: Log out your user locally
|
82
|
+
def user_unauthorized
|
83
|
+
sign_out
|
84
|
+
redirect_to root_path
|
85
|
+
end
|
86
|
+
|
87
|
+
# IMPLEMENT: Redirect to two-factor authentication login
|
88
|
+
def challenge_required
|
89
|
+
redirect_to show_challenge_path
|
85
90
|
end
|
86
91
|
end
|
87
92
|
```
|
88
93
|
|
94
|
+
Then use the overridden filter in your protected routes as you normally would, and all your critical flows will be protected from account takeover.
|
89
95
|
|
90
|
-
|
91
|
-
|
96
|
+
```ruby
|
97
|
+
class AccountController < ApplicationController
|
98
|
+
before_filter :authenticate_user!
|
99
|
+
end
|
100
|
+
```
|
92
101
|
|
93
102
|
## Active Sessions
|
94
103
|
|
data/lib/userbin.rb
CHANGED
@@ -12,13 +12,13 @@ require 'userbin/version'
|
|
12
12
|
require 'userbin/configuration'
|
13
13
|
require 'userbin/client'
|
14
14
|
require 'userbin/errors'
|
15
|
-
require 'userbin/
|
16
|
-
require 'userbin/trusted_token_store'
|
15
|
+
require 'userbin/token_store'
|
17
16
|
require 'userbin/jwt'
|
18
17
|
require 'userbin/utils'
|
19
18
|
require 'userbin/request'
|
20
19
|
require 'userbin/session_token'
|
21
20
|
|
21
|
+
require 'userbin/support/cookie_store'
|
22
22
|
require 'userbin/support/rails' if defined?(Rails::Railtie)
|
23
23
|
if defined?(Sinatra::Base)
|
24
24
|
if defined?(Padrino)
|
@@ -34,6 +34,7 @@ end
|
|
34
34
|
|
35
35
|
# These need to be required after setting up Her
|
36
36
|
require 'userbin/models/model'
|
37
|
+
require 'userbin/models/account'
|
37
38
|
require 'userbin/models/event'
|
38
39
|
require 'userbin/models/challenge'
|
39
40
|
require 'userbin/models/context'
|
data/lib/userbin/client.rb
CHANGED
@@ -17,21 +17,13 @@ module Userbin
|
|
17
17
|
:backup_codes, :generate_backup_codes, :trusted_devices,
|
18
18
|
:enable_mfa!, :disable_mfa!
|
19
19
|
|
20
|
-
def initialize(request,
|
20
|
+
def initialize(request, response, opts = {})
|
21
21
|
# Save a reference in the per-request store so that the request
|
22
22
|
# middleware in request.rb can access it
|
23
23
|
RequestStore.store[:userbin] = self
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
# use any store, such as Redis or Memcached to store your Userbin tokens.
|
28
|
-
if opts[:session_store]
|
29
|
-
@session_store = opts[:session_store]
|
30
|
-
else
|
31
|
-
@session_store = Userbin::SessionStore::Rack.new(request.session)
|
32
|
-
end
|
33
|
-
|
34
|
-
@trusted_token_store = Userbin::TrustedTokenStore::Rack.new(cookies)
|
25
|
+
cookies = Userbin::CookieStore.new(request, response)
|
26
|
+
@store = Userbin::TokenStore.new(cookies)
|
35
27
|
|
36
28
|
@request_context = {
|
37
29
|
ip: request.ip,
|
@@ -39,58 +31,23 @@ module Userbin
|
|
39
31
|
}
|
40
32
|
end
|
41
33
|
|
42
|
-
def session_token=(value)
|
43
|
-
if value && value != @session_store.read
|
44
|
-
@session_store.write(value)
|
45
|
-
elsif !value
|
46
|
-
@session_store.destroy
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
34
|
def session_token
|
51
|
-
|
52
|
-
Userbin::SessionToken.new(token) if token
|
53
|
-
end
|
54
|
-
|
55
|
-
def trusted_device_token=(value)
|
56
|
-
if value && value != @trusted_token_store.read
|
57
|
-
@trusted_token_store.write(value)
|
58
|
-
elsif !value
|
59
|
-
@trusted_token_store.destroy
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def trusted_device_token
|
64
|
-
@trusted_token_store.read
|
35
|
+
@store.session_token
|
65
36
|
end
|
66
37
|
|
67
|
-
def
|
68
|
-
|
69
|
-
user_id = URI.encode(user_id.to_s)
|
70
|
-
|
71
|
-
@session_store.user_id = user_id
|
72
|
-
@trusted_token_store.user_id = user_id
|
73
|
-
end
|
74
|
-
|
75
|
-
def authorize
|
76
|
-
return unless session_token
|
77
|
-
|
78
|
-
if session_token.expired?
|
79
|
-
Userbin::Monitoring.heartbeat
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def authorized?
|
84
|
-
!!session_token
|
38
|
+
def session_token=(session_token)
|
39
|
+
@store.session_token = session_token
|
85
40
|
end
|
86
41
|
|
87
42
|
def authorize!
|
88
|
-
unless session_token
|
43
|
+
unless @store.session_token
|
89
44
|
raise Userbin::UserUnauthorizedError,
|
90
45
|
'Need to call login before authorize'
|
91
46
|
end
|
92
47
|
|
93
|
-
|
48
|
+
if @store.session_token.expired?
|
49
|
+
Userbin::Monitoring.heartbeat
|
50
|
+
end
|
94
51
|
|
95
52
|
if mfa_in_progress?
|
96
53
|
logout
|
@@ -103,63 +60,66 @@ module Userbin
|
|
103
60
|
end
|
104
61
|
end
|
105
62
|
|
63
|
+
def authorized?
|
64
|
+
!!@store.session_token
|
65
|
+
end
|
66
|
+
|
106
67
|
def login(user_id, user_attrs = {})
|
107
68
|
# Clear the session token if any
|
108
|
-
|
109
|
-
|
110
|
-
identify(user_id)
|
69
|
+
@store.session_token = nil
|
111
70
|
|
112
|
-
user = Userbin::User.new(
|
71
|
+
user = Userbin::User.new(user_id.to_s)
|
113
72
|
session = user.sessions.create(
|
114
|
-
user: user_attrs, trusted_device_token:
|
73
|
+
user: user_attrs, trusted_device_token: @store.trusted_device_token)
|
115
74
|
|
116
75
|
# Set the session token for use in all subsequent requests
|
117
|
-
|
76
|
+
@store.session_token = session.token
|
118
77
|
|
119
78
|
session
|
120
79
|
end
|
121
80
|
|
122
|
-
def trust_device(attrs = {})
|
123
|
-
trusted_device = trusted_devices.create(attrs)
|
124
|
-
|
125
|
-
# Set the session token for use in all subsequent requests
|
126
|
-
self.trusted_device_token = trusted_device.token
|
127
|
-
end
|
128
|
-
|
129
|
-
# This method ends the current monitoring session. It should be called
|
130
|
-
# whenever the user logs out from your system.
|
131
|
-
#
|
132
81
|
def logout
|
133
|
-
return unless session_token
|
82
|
+
return unless @store.session_token
|
134
83
|
|
135
84
|
# Destroy the current session specified in the session token
|
136
85
|
begin
|
137
86
|
sessions.destroy('$current')
|
138
|
-
rescue Userbin::
|
87
|
+
rescue Userbin::ApiError # ignored
|
139
88
|
end
|
140
89
|
|
141
90
|
# Clear the session token
|
142
|
-
|
91
|
+
@store.session_token = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def trust_device(attrs = {})
|
95
|
+
unless @store.session_token
|
96
|
+
raise Userbin::UserUnauthorizedError,
|
97
|
+
'Need to call login before trusting device'
|
98
|
+
end
|
99
|
+
trusted_device = trusted_devices.create(attrs)
|
100
|
+
|
101
|
+
# Set the session token for use in all subsequent requests
|
102
|
+
@store.trusted_device_token = trusted_device.token
|
143
103
|
end
|
144
104
|
|
145
105
|
def mfa_enabled?
|
146
|
-
session_token ? session_token.mfa_enabled? : false
|
106
|
+
@store.session_token ? @store.session_token.mfa_enabled? : false
|
147
107
|
end
|
148
108
|
|
149
109
|
def device_trusted?
|
150
|
-
session_token ? session_token.device_trusted? : false
|
110
|
+
@store.session_token ? @store.session_token.device_trusted? : false
|
151
111
|
end
|
152
112
|
|
153
113
|
def mfa_in_progress?
|
154
|
-
session_token ? session_token.
|
114
|
+
@store.session_token ? @store.session_token.mfa_in_progress? : false
|
155
115
|
end
|
156
116
|
|
157
117
|
def mfa_required?
|
158
|
-
session_token ? session_token.
|
118
|
+
@store.session_token ? @store.session_token.mfa_required? : false
|
159
119
|
end
|
160
120
|
|
161
121
|
def has_default_pairing?
|
162
|
-
session_token ? session_token.has_default_pairing? : false
|
122
|
+
@store.session_token ? @store.session_token.has_default_pairing? : false
|
163
123
|
end
|
164
124
|
end
|
165
125
|
end
|
@@ -16,24 +16,24 @@ module Userbin
|
|
16
16
|
@jwt.expired?
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
@jwt.payload['
|
19
|
+
def device_trusted?
|
20
|
+
@jwt.payload['tru'] == 1
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
@jwt.payload['
|
23
|
+
def has_default_pairing?
|
24
|
+
@jwt.payload['dpr'] > 0
|
25
25
|
end
|
26
26
|
|
27
27
|
def mfa_enabled?
|
28
28
|
@jwt.payload['mfa'] == 1
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
@jwt.payload['
|
31
|
+
def mfa_in_progress?
|
32
|
+
@jwt.payload['chg'] == 1
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
@jwt.payload['
|
35
|
+
def mfa_required?
|
36
|
+
@jwt.payload['vfy'] > 0
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -10,7 +10,14 @@ module Userbin
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def []=(key, value)
|
13
|
-
@
|
13
|
+
@request.cookies[key] = value
|
14
|
+
if value
|
15
|
+
@response.set_cookie(key, value: value,
|
16
|
+
expires: Time.now + (365 * 24 * 60 * 60),
|
17
|
+
path: '/')
|
18
|
+
else
|
19
|
+
@response.delete_cookie(key)
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
16
23
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Userbin
|
2
|
+
class TokenStore
|
3
|
+
def initialize(cookies)
|
4
|
+
@cookies = cookies
|
5
|
+
end
|
6
|
+
|
7
|
+
def session_token
|
8
|
+
token = @cookies['_ubs']
|
9
|
+
Userbin::SessionToken.new(token) if token
|
10
|
+
end
|
11
|
+
|
12
|
+
def session_token=(value)
|
13
|
+
@cookies['_ubs'] = value
|
14
|
+
|
15
|
+
if value && value != @cookies['_ubs']
|
16
|
+
@cookies['_ubs']
|
17
|
+
elsif !value
|
18
|
+
@cookies['_ubs'] = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def trusted_device_token
|
23
|
+
@cookies['_ubt']
|
24
|
+
end
|
25
|
+
|
26
|
+
def trusted_device_token=(value)
|
27
|
+
@cookies['_ubt'] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/userbin/version.rb
CHANGED
data/spec/models/user_spec.rb
CHANGED
@@ -28,16 +28,4 @@ describe 'Userbin::User' do
|
|
28
28
|
user.save
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
32
|
-
it 'imports users' do
|
33
|
-
VCR.use_cassette('user_import') do
|
34
|
-
users = Userbin::User.import(
|
35
|
-
users: [
|
36
|
-
{ email: '10@example.com', username: '10' },
|
37
|
-
{ email: '20@example.com', username: '20' }
|
38
|
-
]
|
39
|
-
)
|
40
|
-
users.count.should == 2
|
41
|
-
end
|
42
|
-
end
|
43
31
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
3
|
require 'rack'
|
4
|
-
require 'userbin'
|
5
4
|
require 'vcr'
|
6
5
|
require 'webmock/rspec'
|
6
|
+
require 'simplecov'
|
7
|
+
require 'coveralls'
|
8
|
+
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
11
|
+
Coveralls::SimpleCov::Formatter
|
12
|
+
]
|
13
|
+
SimpleCov.start do
|
14
|
+
add_filter 'spec'
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'userbin'
|
7
18
|
|
8
19
|
VCR.configure do |config|
|
9
20
|
config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
data/spec/utils_spec.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class MemoryStore < Userbin::
|
3
|
+
class MemoryStore < Userbin::TokenStore
|
4
4
|
def initialize
|
5
5
|
@value = nil
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
@value
|
8
|
+
def session_token
|
9
|
+
@value['_ubs']
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
@value = value
|
12
|
+
def session_token=(value)
|
13
|
+
@value['_ubs'] = value
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
@value
|
16
|
+
def trusted_device_token
|
17
|
+
@value['_ubt']
|
18
|
+
end
|
19
|
+
|
20
|
+
def trusted_device_token=(value)
|
21
|
+
@value['_ubt'] = value
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: userbin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: her
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: coveralls
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.7.2
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 0.7.2
|
167
181
|
description: Secure your application with multi-factor authentication, user activity
|
168
182
|
monitoring, and real-time threat protection.
|
169
183
|
email: johan@userbin.com
|
@@ -178,6 +192,7 @@ files:
|
|
178
192
|
- lib/userbin/errors.rb
|
179
193
|
- lib/userbin/ext/her.rb
|
180
194
|
- lib/userbin/jwt.rb
|
195
|
+
- lib/userbin/models/account.rb
|
181
196
|
- lib/userbin/models/backup_codes.rb
|
182
197
|
- lib/userbin/models/challenge.rb
|
183
198
|
- lib/userbin/models/context.rb
|
@@ -195,7 +210,7 @@ files:
|
|
195
210
|
- lib/userbin/support/padrino.rb
|
196
211
|
- lib/userbin/support/rails.rb
|
197
212
|
- lib/userbin/support/sinatra.rb
|
198
|
-
- lib/userbin/
|
213
|
+
- lib/userbin/token_store.rb
|
199
214
|
- lib/userbin/utils.rb
|
200
215
|
- lib/userbin/version.rb
|
201
216
|
- spec/fixtures/vcr_cassettes/challenge_create.yml
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Userbin
|
2
|
-
class TrustedTokenStore
|
3
|
-
class Rack < TrustedTokenStore
|
4
|
-
def initialize(cookies)
|
5
|
-
@cookies = cookies
|
6
|
-
end
|
7
|
-
|
8
|
-
def user_id
|
9
|
-
@cookies['userbin.user_id']
|
10
|
-
end
|
11
|
-
|
12
|
-
def user_id=(value)
|
13
|
-
@cookies['userbin.user_id'] = value
|
14
|
-
end
|
15
|
-
|
16
|
-
def read
|
17
|
-
@cookies[key]
|
18
|
-
end
|
19
|
-
|
20
|
-
def write(value)
|
21
|
-
@cookies[key] = value
|
22
|
-
end
|
23
|
-
|
24
|
-
def destroy
|
25
|
-
@cookies.delete(key)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def key
|
31
|
-
"userbin.trusted_device_token.#{user_id}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|