jump_in 0.0.1 → 0.0.2
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/Rakefile +0 -6
- data/lib/generators/jump_in/config_initializer.rb +13 -0
- data/lib/generators/jump_in/install_generator.rb +14 -0
- data/lib/generators/templates/jump_in_initializer.rb +25 -0
- data/lib/jump_in/authentication/cookies.rb +35 -0
- data/lib/jump_in/authentication/session.rb +32 -0
- data/lib/jump_in/authentication.rb +54 -55
- data/lib/jump_in/password_reset.rb +15 -15
- data/lib/jump_in/persistence.rb +2 -0
- data/lib/jump_in/strategies/base.rb +36 -0
- data/lib/jump_in/strategies/by_password.rb +13 -0
- data/lib/jump_in/strategies.rb +2 -0
- data/lib/jump_in/tokenator.rb +25 -0
- data/lib/jump_in/version.rb +1 -1
- data/lib/jump_in.rb +46 -2
- data/spec/dummy/app/models/user_with_secure_password.rb +3 -0
- data/spec/dummy/db/migrate/20150908085412_rename_users_to_user_with_secure_passwords.rb +5 -0
- data/spec/dummy/db/schema.rb +2 -2
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +5280 -0
- data/spec/dummy/spec/classes/configuration_spec.rb +34 -0
- data/spec/dummy/spec/factories.rb +1 -1
- data/spec/dummy/spec/modules/authentication_spec.rb +59 -52
- data/spec/dummy/spec/modules/password_reset_spec.rb +60 -77
- data/spec/dummy/spec/modules/strategies_spec.rb +71 -0
- data/spec/dummy/spec/modules/tokenator_spec.rb +46 -0
- data/spec/dummy/spec/rails_helper.rb +1 -0
- data/spec/dummy/spec/support/common_methods.rb +9 -9
- metadata +29 -42
- data/lib/jump_in/authentication/by_password.rb +0 -13
- data/lib/jump_in/authentication/strategy.rb +0 -16
- data/lib/jump_in/tokenizer.rb +0 -21
- data/spec/dummy/README.rdoc +0 -28
- data/spec/dummy/app/controllers/password_resets_controller.rb +0 -34
- data/spec/dummy/app/controllers/sessions_controller.rb +0 -16
- data/spec/dummy/app/controllers/users_controller.rb +0 -32
- data/spec/dummy/app/mailers/system_mailer.rb +0 -8
- data/spec/dummy/app/models/user.rb +0 -3
- data/spec/dummy/app/views/layouts/application.html.erb +0 -18
- data/spec/dummy/app/views/password_resets/edit.html.erb +0 -9
- data/spec/dummy/app/views/password_resets/new.html.erb +0 -7
- data/spec/dummy/app/views/sessions/new.html.erb +0 -7
- data/spec/dummy/app/views/system_mailer/password_reset.html.erb +0 -2
- data/spec/dummy/app/views/users/show.html.erb +0 -1
- data/spec/dummy/spec/controllers/password_resets_controller_spec.rb +0 -53
- data/spec/dummy/spec/controllers/sessions_controller_spec.rb +0 -36
- data/spec/dummy/spec/controllers/users_controller_spec.rb +0 -20
- data/spec/dummy/spec/integration/logging_spec.rb +0 -18
- data/spec/dummy/spec/integration/reset_password_spec.rb +0 -39
- data/spec/dummy/spec/modules/tokenizer_spec.rb +0 -19
- /data/{README.rdoc → spec/dummy/log/development.log} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57658a9f021f93df365961389568711509f87ade
|
4
|
+
data.tar.gz: 8403fd961358c66d60087d4fb1710eafa0e7ce33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00b6cdeb5a579770178b9b5126571d725baf82927a331d8bd29981bc6fc481b6e95edf8781631b8156e53a1a7f784ea2d57f23120c50e6b8d48c70fa5548e289
|
7
|
+
data.tar.gz: fad2351ffa003c311d4fc0b1cf408bf199ba3967f283b7b7b7b782d3c25a8efd6392836d858a1d56be65bd7fe88c9c5520df17136188afa51e9e53ef952d66d8
|
data/Rakefile
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
module JumpIn
|
2
|
+
module Generators
|
3
|
+
class ConfigInitializerGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../../templates", __FILE__)
|
5
|
+
desc "Creates JumpIn initializer for your application"
|
6
|
+
|
7
|
+
def prepare_initializer
|
8
|
+
template "jump_in_initializer.rb", "config/initializers/jump_in.rb"
|
9
|
+
puts "Install complete. You can now customize JumpIn defaults in your config/initializers/jump_in.rb."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module JumpIn
|
2
|
+
module Generators
|
3
|
+
class ConfigInitializerGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../../templates', __FILE__)
|
5
|
+
desc 'Creates JumpIn initializer for your application'
|
6
|
+
|
7
|
+
def prepare_initializer
|
8
|
+
template 'jump_in_initializer.rb', 'config/initializers/jump_in.rb'
|
9
|
+
puts 'Install complete. You can now customize JumpIn defaults in your
|
10
|
+
config/initializers/jump_in.rb.'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
JumpIn.configure do |config|
|
2
|
+
# AUTHENTICATION
|
3
|
+
|
4
|
+
# for `permanent` set to
|
5
|
+
# - true - login method sets cookies,
|
6
|
+
# - false - login method sets session.
|
7
|
+
|
8
|
+
config.permanent = true
|
9
|
+
|
10
|
+
# `expires` is used by login method only when `permanent` is set to true
|
11
|
+
# It defines expiration time for cookies.
|
12
|
+
# Default value is set to 20 years - as in cookies.permanent.
|
13
|
+
# You can uncomment the line below and change it.
|
14
|
+
|
15
|
+
# config.expires = 20.years
|
16
|
+
|
17
|
+
# PASSWORD RESET
|
18
|
+
|
19
|
+
# `expiration_time` is used by PasswordReset#password_reset_valid?
|
20
|
+
# to verify whether password_reset_token is still valid.
|
21
|
+
# Default value is set to 2 hours.
|
22
|
+
# You can uncomment the line below and change it.
|
23
|
+
|
24
|
+
# config.expiration_time = 2.hours
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'jump_in/authentication'
|
2
|
+
|
3
|
+
module JumpIn
|
4
|
+
module Authentication
|
5
|
+
module Persistence
|
6
|
+
module Cookies
|
7
|
+
def self.included(klass)
|
8
|
+
klass.jumpin_callback :on_login, :set_user_cookies
|
9
|
+
klass.jumpin_callback :on_logout, :remove_user_cookies
|
10
|
+
klass.jumpin_callback :get_current_user, :current_user_from_cookies
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_user_cookies(user:)
|
14
|
+
return nil unless JumpIn.conf.permanent
|
15
|
+
expires = (JumpIn.conf.expires || 20.years).from_now
|
16
|
+
cookies.signed[:jump_in_class] = { value: user.class.to_s,
|
17
|
+
expires: expires }
|
18
|
+
cookies.signed[:jump_in_id] = { value: user.id, expires: expires }
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove_user_cookies
|
22
|
+
cookies.delete :jump_in_class
|
23
|
+
cookies.delete :jump_in_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_user_from_cookies
|
27
|
+
return nil unless cookies.signed[:jump_in_id] &&
|
28
|
+
cookies.signed[:jump_in_class]
|
29
|
+
klass = cookies.signed[:jump_in_class].constantize
|
30
|
+
klass.find_by(id: cookies.signed[:jump_in_id])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'jump_in/authentication'
|
2
|
+
|
3
|
+
module JumpIn
|
4
|
+
module Authentication
|
5
|
+
module Persistence
|
6
|
+
module Session
|
7
|
+
def self.included(klass)
|
8
|
+
klass.jumpin_callback :on_login, :set_user_session
|
9
|
+
klass.jumpin_callback :on_logout, :remove_user_session
|
10
|
+
klass.jumpin_callback :get_current_user, :current_user_from_session
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_user_session(user:)
|
14
|
+
return nil if JumpIn.conf.permanent
|
15
|
+
session[:jump_in_class] = user.class.to_s
|
16
|
+
session[:jump_in_id] = user.id
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove_user_session
|
20
|
+
session.delete :jump_in_class
|
21
|
+
session.delete :jump_in_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_user_from_session
|
25
|
+
return nil unless session[:jump_in_id] && session[:jump_in_class]
|
26
|
+
klass = session[:jump_in_class].constantize
|
27
|
+
klass.find_by(id: session[:jump_in_id])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,96 +1,95 @@
|
|
1
|
-
require 'jump_in/
|
2
|
-
require 'jump_in/
|
1
|
+
require 'jump_in/strategies'
|
2
|
+
require 'jump_in/persistence'
|
3
3
|
|
4
4
|
module JumpIn
|
5
5
|
module Authentication
|
6
|
-
|
7
|
-
STRATEGIES = [ByPassword]
|
8
|
-
|
9
6
|
def self.included(base)
|
10
|
-
base.
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
base.send :helper_method, :current_user, :logged_in? if
|
9
|
+
base.respond_to? :helper_method
|
11
10
|
end
|
12
11
|
|
13
|
-
# LOGGING IN
|
14
|
-
def jump_in(user:,
|
15
|
-
|
16
|
-
|
17
|
-
login(user: user
|
12
|
+
# LOGGING IN
|
13
|
+
def jump_in(user:, **auth_params)
|
14
|
+
if !logged_in? && authenticate_by_strategy(user: user,
|
15
|
+
auth_params: auth_params)
|
16
|
+
login(user: user)
|
18
17
|
else
|
19
18
|
return false
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
def authenticate_by_strategy(user:,
|
24
|
-
if strategy = detected_strategy(user: user,
|
22
|
+
def authenticate_by_strategy(user:, auth_params:)
|
23
|
+
if strategy = detected_strategy(user: user, auth_params: auth_params)
|
25
24
|
strategy.authenticate_user
|
26
25
|
else
|
27
26
|
false
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def login(user
|
32
|
-
|
33
|
-
|
34
|
-
else
|
35
|
-
set_session(user: user)
|
30
|
+
def login(user:)
|
31
|
+
self.class::ON_LOGIN.each do |on_login|
|
32
|
+
send(on_login, user: user)
|
36
33
|
end
|
37
34
|
true
|
38
35
|
end
|
39
36
|
|
40
|
-
|
41
|
-
expires = (expires || 20.years).from_now
|
42
|
-
cookies.signed[:jump_in_class] = { value: user.class.to_s, expires: expires }
|
43
|
-
cookies.signed[:jump_in_id] = { value: user.id, expires: expires }
|
44
|
-
end
|
45
|
-
|
46
|
-
def set_session(user:)
|
47
|
-
session[:jump_in_class] = user.class.to_s
|
48
|
-
session[:jump_in_id] = user.id
|
49
|
-
end
|
37
|
+
# LOGGING OUT
|
50
38
|
|
51
|
-
# LOGGING OUT
|
52
39
|
def jump_out
|
53
|
-
|
54
|
-
delete_session
|
55
|
-
elsif cookies[:jump_in_id] && cookies[:jump_in_class]
|
56
|
-
delete_cookies
|
57
|
-
end
|
40
|
+
self.class::ON_LOGOUT.each { |on_logout| send(on_logout) }
|
58
41
|
true
|
59
42
|
end
|
60
43
|
|
61
|
-
|
62
|
-
cookies.delete :jump_in_class
|
63
|
-
cookies.delete :jump_in_id
|
64
|
-
end
|
65
|
-
|
66
|
-
def delete_session
|
67
|
-
session.delete :jump_in_class
|
68
|
-
session.delete :jump_in_id
|
69
|
-
end
|
44
|
+
# HELPER METHODS
|
70
45
|
|
71
|
-
# HELPER METHODS
|
72
46
|
def current_user
|
73
|
-
return
|
74
|
-
|
75
|
-
id = (session[:jump_in_id] || cookies.signed[:jump_in_id])
|
76
|
-
@current_user ||= klass.find_by_id(id)
|
47
|
+
return @current_user if defined?(@current_user)
|
48
|
+
@current_user = get_current_user
|
77
49
|
end
|
78
50
|
|
79
51
|
def logged_in?
|
80
52
|
!!current_user
|
81
53
|
end
|
82
54
|
|
55
|
+
# CLASS METHODS
|
56
|
+
|
57
|
+
module ClassMethods
|
58
|
+
def jumpin_callback(callback, method_to_be_called)
|
59
|
+
jumpin_constant = callback.upcase
|
60
|
+
unless constants.include?(jumpin_constant)
|
61
|
+
const_set(jumpin_constant, [])
|
62
|
+
end
|
63
|
+
const_get(jumpin_constant) << method_to_be_called
|
64
|
+
end
|
65
|
+
|
66
|
+
def jumpin_use(persistence:)
|
67
|
+
persistence.each do |symbol|
|
68
|
+
include(JumpIn::Authentication::Persistence
|
69
|
+
.const_get(symbol.capitalize))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# PRIVATE
|
75
|
+
|
83
76
|
private
|
84
|
-
|
85
|
-
|
86
|
-
|
77
|
+
|
78
|
+
def get_current_user
|
79
|
+
current_user = nil
|
80
|
+
self.class::GET_CURRENT_USER.each do |current_user_finder|
|
81
|
+
current_user = send(current_user_finder)
|
82
|
+
break if current_user
|
83
|
+
end
|
84
|
+
current_user
|
87
85
|
end
|
88
86
|
|
89
|
-
def detected_strategy(user
|
90
|
-
if
|
91
|
-
|
87
|
+
def detected_strategy(user:, auth_params:)
|
88
|
+
if the_strategy = JumpIn::Strategies::Base::STRATEGIES
|
89
|
+
.detect { |strategy| strategy.detected?(auth_params) }
|
90
|
+
the_strategy.new(user: user, auth_params: auth_params)
|
92
91
|
else
|
93
|
-
|
92
|
+
fail JumpIn::AuthenticationStrategyError
|
94
93
|
end
|
95
94
|
end
|
96
95
|
end
|
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'jump_in/tokenator'
|
2
|
+
|
1
3
|
module JumpIn
|
2
4
|
module PasswordReset
|
5
|
+
include JumpIn::Tokenator
|
3
6
|
|
4
|
-
# CREATING TOKEN
|
7
|
+
# CREATING TOKEN
|
5
8
|
def set_password_reset_for(user:, token: nil)
|
6
9
|
if token_uniq_or_empty?(user: user, token: token)
|
7
10
|
set_token(user: user, token: token)
|
@@ -10,7 +13,7 @@ module JumpIn
|
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
13
|
-
def set_token(user:, token:)
|
16
|
+
def set_token(user:, token: nil)
|
14
17
|
token ||= generate_unique_token_for(user: user)
|
15
18
|
user.update_attribute(:password_reset_token, token)
|
16
19
|
end
|
@@ -22,10 +25,6 @@ module JumpIn
|
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
|
-
def generate_token
|
26
|
-
JumpIn::Tokenizer.generate_token
|
27
|
-
end
|
28
|
-
|
29
28
|
def token_uniq_or_empty?(user:, token:)
|
30
29
|
(token && token_uniq?(user: user, token: token)) || token.nil?
|
31
30
|
end
|
@@ -34,17 +33,18 @@ module JumpIn
|
|
34
33
|
!user.class.where(password_reset_token: token).exists?
|
35
34
|
end
|
36
35
|
|
37
|
-
# RECEIVING TOKEN
|
38
|
-
def password_reset_valid?(password_reset_token
|
39
|
-
|
36
|
+
# RECEIVING TOKEN
|
37
|
+
def password_reset_valid?(password_reset_token:)
|
38
|
+
decode_time(password_reset_token) > Time.now - JumpIn.conf.expiration_time
|
40
39
|
end
|
41
40
|
|
42
|
-
def update_password_for(user:, password:, password_confirmation:,
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
def update_password_for(user:, password:, password_confirmation:,
|
42
|
+
password_reset_token:)
|
43
|
+
return false unless token_correct?(user_token: user.password_reset_token,
|
44
|
+
received_token: password_reset_token)
|
45
|
+
user.update_attributes(password: password,
|
46
|
+
password_confirmation: password_confirmation,
|
47
|
+
password_reset_token: nil)
|
48
48
|
end
|
49
49
|
|
50
50
|
def token_correct?(user_token:, received_token:)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'jump_in/strategies'
|
2
|
+
|
3
|
+
module JumpIn
|
4
|
+
module Strategies
|
5
|
+
class Base
|
6
|
+
STRATEGIES = []
|
7
|
+
DETECTABLE_ATTRIBUTES = {}
|
8
|
+
|
9
|
+
def self.inherited(subclass)
|
10
|
+
STRATEGIES << subclass
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.has_unique_attributes(unique_attributes)
|
14
|
+
unique_attributes.sort!
|
15
|
+
if DETECTABLE_ATTRIBUTES.values.include?(unique_attributes)
|
16
|
+
STRATEGIES.delete(name.constantize)
|
17
|
+
fail JumpIn::AttributesNotUnique
|
18
|
+
end
|
19
|
+
DETECTABLE_ATTRIBUTES[name.constantize] = unique_attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.detected?(auth_params)
|
23
|
+
auth_params.keys.sort == DETECTABLE_ATTRIBUTES[name.constantize]
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(user:, auth_params:)
|
27
|
+
@user = user
|
28
|
+
@auth_params = auth_params
|
29
|
+
end
|
30
|
+
|
31
|
+
def authenticate_user
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module JumpIn
|
4
|
+
module Tokenator
|
5
|
+
DELIMITER = '.'.freeze
|
6
|
+
|
7
|
+
def generate_token
|
8
|
+
Base64.urlsafe_encode64 [SecureRandom.hex(12), Time.now.xmlschema]
|
9
|
+
.join(DELIMITER)
|
10
|
+
end
|
11
|
+
|
12
|
+
def decode_and_split_token(token)
|
13
|
+
Base64.urlsafe_decode64(token).split(DELIMITER)
|
14
|
+
rescue
|
15
|
+
raise JumpIn::InvalidTokenError
|
16
|
+
end
|
17
|
+
|
18
|
+
def decode_time(token)
|
19
|
+
token_time = decode_and_split_token(token)[1]
|
20
|
+
Time.parse(token_time)
|
21
|
+
rescue
|
22
|
+
raise JumpIn::InvalidTokenError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/jump_in/version.rb
CHANGED
data/lib/jump_in.rb
CHANGED
@@ -1,8 +1,52 @@
|
|
1
|
-
require
|
1
|
+
require 'jump_in/version'
|
2
2
|
require 'jump_in/authentication'
|
3
|
+
require 'jump_in/authentication/session'
|
4
|
+
require 'jump_in/authentication/cookies'
|
5
|
+
require 'jump_in/strategies'
|
3
6
|
require 'jump_in/password_reset'
|
4
|
-
require 'jump_in/
|
7
|
+
require 'jump_in/tokenator'
|
5
8
|
|
9
|
+
# JumpIn top-level module
|
6
10
|
module JumpIn
|
11
|
+
class Error < StandardError
|
12
|
+
def initialize
|
13
|
+
super(message)
|
14
|
+
end
|
15
|
+
end
|
7
16
|
|
17
|
+
class InvalidTokenError < Error
|
18
|
+
def message
|
19
|
+
'Invalid token passed.'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class AuthenticationStrategyError < Error
|
24
|
+
def message
|
25
|
+
'No authentication strategy detected.'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class AttributesNotUnique < Error
|
30
|
+
def message
|
31
|
+
'Custom authentication strategy attribute is not unique.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.configure(&block)
|
36
|
+
yield(conf)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.conf
|
40
|
+
@configuration ||= Configuration.new
|
41
|
+
end
|
42
|
+
|
43
|
+
class Configuration
|
44
|
+
attr_accessor :permanent, :expires, :expiration_time
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@permanent = false
|
48
|
+
@expires = 20.years
|
49
|
+
@expiration_time = 2.hours
|
50
|
+
end
|
51
|
+
end
|
8
52
|
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -11,9 +11,9 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
14
|
+
ActiveRecord::Schema.define(version: 20150908085412) do
|
15
15
|
|
16
|
-
create_table "
|
16
|
+
create_table "user_with_secure_passwords", force: :cascade do |t|
|
17
17
|
t.string "email"
|
18
18
|
t.string "password_digest"
|
19
19
|
t.string "name"
|
Binary file
|