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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -6
  3. data/lib/generators/jump_in/config_initializer.rb +13 -0
  4. data/lib/generators/jump_in/install_generator.rb +14 -0
  5. data/lib/generators/templates/jump_in_initializer.rb +25 -0
  6. data/lib/jump_in/authentication/cookies.rb +35 -0
  7. data/lib/jump_in/authentication/session.rb +32 -0
  8. data/lib/jump_in/authentication.rb +54 -55
  9. data/lib/jump_in/password_reset.rb +15 -15
  10. data/lib/jump_in/persistence.rb +2 -0
  11. data/lib/jump_in/strategies/base.rb +36 -0
  12. data/lib/jump_in/strategies/by_password.rb +13 -0
  13. data/lib/jump_in/strategies.rb +2 -0
  14. data/lib/jump_in/tokenator.rb +25 -0
  15. data/lib/jump_in/version.rb +1 -1
  16. data/lib/jump_in.rb +46 -2
  17. data/spec/dummy/app/models/user_with_secure_password.rb +3 -0
  18. data/spec/dummy/db/migrate/20150908085412_rename_users_to_user_with_secure_passwords.rb +5 -0
  19. data/spec/dummy/db/schema.rb +2 -2
  20. data/spec/dummy/db/test.sqlite3 +0 -0
  21. data/spec/dummy/log/test.log +5280 -0
  22. data/spec/dummy/spec/classes/configuration_spec.rb +34 -0
  23. data/spec/dummy/spec/factories.rb +1 -1
  24. data/spec/dummy/spec/modules/authentication_spec.rb +59 -52
  25. data/spec/dummy/spec/modules/password_reset_spec.rb +60 -77
  26. data/spec/dummy/spec/modules/strategies_spec.rb +71 -0
  27. data/spec/dummy/spec/modules/tokenator_spec.rb +46 -0
  28. data/spec/dummy/spec/rails_helper.rb +1 -0
  29. data/spec/dummy/spec/support/common_methods.rb +9 -9
  30. metadata +29 -42
  31. data/lib/jump_in/authentication/by_password.rb +0 -13
  32. data/lib/jump_in/authentication/strategy.rb +0 -16
  33. data/lib/jump_in/tokenizer.rb +0 -21
  34. data/spec/dummy/README.rdoc +0 -28
  35. data/spec/dummy/app/controllers/password_resets_controller.rb +0 -34
  36. data/spec/dummy/app/controllers/sessions_controller.rb +0 -16
  37. data/spec/dummy/app/controllers/users_controller.rb +0 -32
  38. data/spec/dummy/app/mailers/system_mailer.rb +0 -8
  39. data/spec/dummy/app/models/user.rb +0 -3
  40. data/spec/dummy/app/views/layouts/application.html.erb +0 -18
  41. data/spec/dummy/app/views/password_resets/edit.html.erb +0 -9
  42. data/spec/dummy/app/views/password_resets/new.html.erb +0 -7
  43. data/spec/dummy/app/views/sessions/new.html.erb +0 -7
  44. data/spec/dummy/app/views/system_mailer/password_reset.html.erb +0 -2
  45. data/spec/dummy/app/views/users/show.html.erb +0 -1
  46. data/spec/dummy/spec/controllers/password_resets_controller_spec.rb +0 -53
  47. data/spec/dummy/spec/controllers/sessions_controller_spec.rb +0 -36
  48. data/spec/dummy/spec/controllers/users_controller_spec.rb +0 -20
  49. data/spec/dummy/spec/integration/logging_spec.rb +0 -18
  50. data/spec/dummy/spec/integration/reset_password_spec.rb +0 -39
  51. data/spec/dummy/spec/modules/tokenizer_spec.rb +0 -19
  52. /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: 318fdf2dd172c63b434927189856adf7faebc4f4
4
- data.tar.gz: 32a22b706b0948f5da995cdf6f85b3f9746d0dc7
3
+ metadata.gz: 57658a9f021f93df365961389568711509f87ade
4
+ data.tar.gz: 8403fd961358c66d60087d4fb1710eafa0e7ce33
5
5
  SHA512:
6
- metadata.gz: a8ff65b78df304466eaa27caf64c18fc61bd08af9898ece2c73eb2935f90c91ccb4eaeb1f581a8bc710b77a45e02de42f871d7c7deaf7daa57cff2cc3baa94fb
7
- data.tar.gz: be6c454eda28bd44567a53e04b9f58dcb532bcc262e336125d356786754898217b10a25a248ad24cf2fc2549dc8348ae0302ae9f37c0bbb72d1319c0c73d46af
6
+ metadata.gz: 00b6cdeb5a579770178b9b5126571d725baf82927a331d8bd29981bc6fc481b6e95edf8781631b8156e53a1a7f784ea2d57f23120c50e6b8d48c70fa5548e289
7
+ data.tar.gz: fad2351ffa003c311d4fc0b1cf408bf199ba3967f283b7b7b7b782d3c25a8efd6392836d858a1d56be65bd7fe88c9c5520df17136188afa51e9e53ef952d66d8
data/Rakefile CHANGED
@@ -14,10 +14,4 @@ RDoc::Task.new(:rdoc) do |rdoc|
14
14
  rdoc.rdoc_files.include('lib/**/*.rb')
15
15
  end
16
16
 
17
-
18
-
19
-
20
-
21
-
22
17
  Bundler::GemHelper.install_tasks
23
-
@@ -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/authentication/strategy'
2
- require 'jump_in/authentication/by_password'
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.send :helper_method, :current_user, :logged_in? if base.respond_to? :helper_method
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:, permanent: false, expires: nil, **params)
15
- return false if logged_in?
16
- if authenticate_by_strategy(user: user, params: params)
17
- login(user: user, permanent: permanent, expires: expires)
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:, params:)
24
- if strategy = detected_strategy(user: user, params: params)
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:, permanent: false, expires: nil)
32
- if permanent
33
- set_cookies(user: user, expires: expires)
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
- def set_cookies(user:, expires:)
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
- if session[:jump_in_id] && session[:jump_in_class]
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
- def delete_cookies
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 nil unless session_or_cookies_set?
74
- klass = (session[:jump_in_class] || cookies.signed[:jump_in_class]).constantize
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
- def session_or_cookies_set?
85
- (session[:jump_in_id] && session[:jump_in_class]) ||
86
- (cookies.signed[:jump_in_id] && cookies.signed[:jump_in_class])
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: user, params: params)
90
- if strategy = STRATEGIES.detect { |strategy| strategy.detected?(params) }
91
- strategy.new(user: user, params: params)
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
- false
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:, expiration_time: 2.hours)
39
- JumpIn::Tokenizer.decode_time(password_reset_token) > Time.now - expiration_time
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:, password_reset_token:)
43
- if token_correct?(user_token: user.password_reset_token, received_token: password_reset_token)
44
- user.update_attributes(password: password, password_confirmation: password_confirmation, password_reset_token: nil)
45
- else
46
- false
47
- end
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,2 @@
1
+ require 'jump_in/authentication/session'
2
+ require 'jump_in/authentication/cookies'
@@ -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,13 @@
1
+ require 'jump_in/strategies'
2
+
3
+ module JumpIn
4
+ module Strategies
5
+ class ByPassword < Base
6
+ has_unique_attributes [:password]
7
+
8
+ def authenticate_user
9
+ @user.authenticate(@auth_params[:password]) ? true : false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ require 'jump_in/strategies/base'
2
+ require 'jump_in/strategies/by_password'
@@ -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
@@ -1,3 +1,3 @@
1
1
  module JumpIn
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/jump_in.rb CHANGED
@@ -1,8 +1,52 @@
1
- require "jump_in/version"
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/tokenizer'
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
@@ -0,0 +1,3 @@
1
+ class UserWithSecurePassword < ActiveRecord::Base
2
+ has_secure_password
3
+ end
@@ -0,0 +1,5 @@
1
+ class RenameUsersToUserWithSecurePasswords < ActiveRecord::Migration
2
+ def change
3
+ rename_table :users, :user_with_secure_passwords
4
+ end
5
+ end
@@ -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: 20150717123339) do
14
+ ActiveRecord::Schema.define(version: 20150908085412) do
15
15
 
16
- create_table "users", force: :cascade do |t|
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