jobshop 0.0.41 → 0.0.53
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/app/controllers/concerns/email_token_validation.rb +59 -0
- data/app/controllers/concerns/registration_token_validation.rb +34 -18
- data/app/controllers/jobshop/application_controller.rb +1 -54
- data/app/controllers/jobshop/sessions_controller.rb +6 -0
- data/app/controllers/jobshop/teams/lookups_controller.rb +1 -2
- data/app/controllers/jobshop/teams/registrations_controller.rb +2 -2
- data/app/mailers/jobshop/teams_mailer.rb +3 -3
- data/app/models/jobshop/user.rb +5 -1
- data/app/views/devise/sessions/new.html.haml +1 -0
- data/app/views/jobshop/dashboards/show.html.haml +1 -1
- data/app/views/jobshop/teams/lookups/show.html.haml +1 -0
- data/app/views/jobshop/teams_mailer/found_teams.html.haml +11 -0
- data/app/views/jobshop/teams_mailer/found_teams.text.erb +2 -1
- data/app/views/layouts/jobshop/unauthenticated.html.haml +1 -1
- data/config/initializers/devise.rb +1 -1
- data/config/routes.rb +9 -1
- data/lib/jobshop/templates/secrets.yml.erb +7 -2
- data/lib/jobshop/version.rb +1 -1
- data/lib/jobshop.rb +6 -2
- metadata +11 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8a2d1798548ecae570f0b45babfa2e513b82395c
|
|
4
|
+
data.tar.gz: bc7448f4acea0f1582843a1a47ff9b98a1c4aae6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 649182157861589f953e47725d6947e86f3245e81e2c90c8d1b36127865fdacd74a4498303dd6bd99b9f837752353dfcd211733ad43c9963d88a5d83346bf3ae
|
|
7
|
+
data.tar.gz: e7b646ec641cceae9c9e699a5f4afb9e5d725fcd1f0a066e7974af05cf1127ba4af99e484b1966dee8b71972aba0a4faf24d20a489a0f5e26484ee6dd46eca39
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class EmailTokenValidation
|
|
2
|
+
def self.before(controller)
|
|
3
|
+
@token = EmailToken.new(
|
|
4
|
+
controller.params.fetch(:user_email, nil),
|
|
5
|
+
controller.params.fetch(:email_authentication_token, nil)
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
if @token.valid?
|
|
9
|
+
sign_out_current_scope
|
|
10
|
+
sign_in token.user
|
|
11
|
+
token.destroy
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class EmailToken
|
|
16
|
+
attr_reader :token
|
|
17
|
+
|
|
18
|
+
def initialize(email, token)
|
|
19
|
+
@email, @token = email, token
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def valid?
|
|
23
|
+
present? && user && token && !expired? && secure_compare
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
def present?
|
|
28
|
+
@email.present? && @token.present?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def user
|
|
32
|
+
@user ||= Jobshop::User.where(email: @email)
|
|
33
|
+
.where.not(email_authentication_token_sent_at: nil).first
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def destroy
|
|
37
|
+
user.update({
|
|
38
|
+
email_authentication_token: nil,
|
|
39
|
+
email_authentication_token_sent_at: nil
|
|
40
|
+
})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def secure_compare
|
|
44
|
+
# Notice how we use Devise.secure_compare to compare the token in the
|
|
45
|
+
# database with the token given in the params, mitigating timing
|
|
46
|
+
# attacks.
|
|
47
|
+
Devise.secure_compare(user.email_authentication_token, token)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def expired?
|
|
51
|
+
@expired ||= Time.now >= expires_on
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def expires_on
|
|
55
|
+
# TODO: Make token expiration configurable in initializers/jobshop.rb.
|
|
56
|
+
@expires_on ||= user.email_authentication_token_sent_at + 6.hours
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,25 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
class RegistrationTokenValidation
|
|
2
|
+
def self.before(controller)
|
|
3
|
+
new(controller.dup)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def initialize(controller)
|
|
7
|
+
@controller = controller.dup
|
|
8
|
+
@token = @controller.params.fetch(:registration_token, nil)
|
|
9
|
+
@team_id = @controller.params.fetch(:team_id, nil)
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
@
|
|
11
|
+
if @token
|
|
12
|
+
@controller.redirect_to(@controller.new_user_session_path) unless valid?
|
|
11
13
|
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def valid?
|
|
17
|
+
!expired? && !owned? && resolves?
|
|
18
|
+
end
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
private
|
|
21
|
+
def team
|
|
22
|
+
@team ||= Jobshop::Team.where(id: @team_id).first
|
|
23
|
+
end
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
def resolves?
|
|
26
|
+
encrypted_token = Devise.token_generator.digest(
|
|
27
|
+
Jobshop::Team, :registration_token, @token)
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
# Notice how we use Devise.secure_compare to compare the token in the
|
|
30
|
+
# database with the token given in the params, mitigating timing attacks.
|
|
31
|
+
Devise.secure_compare(team.registration_token, encrypted_token)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def expired?
|
|
35
|
+
@expired ||= !team.registration_token_period_valid?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def owned?
|
|
39
|
+
@owned ||= team.owner.present?
|
|
24
40
|
end
|
|
25
41
|
end
|
|
@@ -10,7 +10,7 @@ module Jobshop
|
|
|
10
10
|
|
|
11
11
|
protect_from_forgery
|
|
12
12
|
|
|
13
|
-
before_action
|
|
13
|
+
before_action EmailTokenValidation
|
|
14
14
|
before_action :authenticate_user!
|
|
15
15
|
|
|
16
16
|
# after_action :verify_authorized, except: :index
|
|
@@ -18,67 +18,14 @@ module Jobshop
|
|
|
18
18
|
|
|
19
19
|
private
|
|
20
20
|
|
|
21
|
-
def authenticate_user_from_email!
|
|
22
|
-
token = EmailAuthenticationToken.new(
|
|
23
|
-
params.fetch(:user_email, nil),
|
|
24
|
-
params.fetch(:email_authentication_token, nil)
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
if token.valid?
|
|
28
|
-
sign_in token.user
|
|
29
|
-
token.destroy
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
21
|
def layout_for_application
|
|
34
22
|
if devise_controller? && controller_name == "sessions" ||
|
|
35
23
|
controller_path == "jobshop/teams/lookups"
|
|
36
24
|
"jobshop/unauthenticated"
|
|
37
25
|
else
|
|
38
|
-
|
|
39
26
|
"jobshop/application"
|
|
40
27
|
end
|
|
41
28
|
end
|
|
42
29
|
|
|
43
|
-
class EmailAuthenticationToken
|
|
44
|
-
attr_reader :token
|
|
45
|
-
|
|
46
|
-
def initialize(email, token)
|
|
47
|
-
@email = email
|
|
48
|
-
@token = token
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def valid?
|
|
52
|
-
user && token && !expired? && secure_compare
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def user
|
|
56
|
-
@user ||= Jobshop::User.where(email: @email)
|
|
57
|
-
.where.not(email_authentication_token_sent_at: nil).first
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def destroy
|
|
61
|
-
user.update({
|
|
62
|
-
email_authentication_token: nil,
|
|
63
|
-
email_authentication_token_sent_at: nil
|
|
64
|
-
})
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def secure_compare
|
|
68
|
-
# Notice how we use Devise.secure_compare to compare the token in the
|
|
69
|
-
# database with the token given in the params, mitigating timing
|
|
70
|
-
# attacks.
|
|
71
|
-
Devise.secure_compare(user.email_authentication_token, token)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def expired?
|
|
75
|
-
@expired ||= Time.now >= expires_on
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def expires_on
|
|
79
|
-
# TODO: Make token expiration configurable in initializers/jobshop.rb.
|
|
80
|
-
@expires_on ||= user.email_authentication_token_sent_at + 6.hours
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
30
|
end
|
|
84
31
|
end
|
|
@@ -10,12 +10,11 @@ module Jobshop
|
|
|
10
10
|
|
|
11
11
|
def create
|
|
12
12
|
emails = params[:user][:email].split(",").map(&:strip).take(5)
|
|
13
|
-
|
|
14
13
|
Jobshop::Team.grouped_by_email(emails).each_pair do |email, teams|
|
|
15
14
|
Jobshop::TeamsMailer.found_teams(email, teams).deliver_later
|
|
16
15
|
end
|
|
17
16
|
|
|
18
|
-
redirect_to
|
|
17
|
+
redirect_to teams_lookup_path
|
|
19
18
|
end
|
|
20
19
|
end
|
|
21
20
|
end
|
|
@@ -2,10 +2,10 @@ require_dependency "jobshop/application_controller"
|
|
|
2
2
|
|
|
3
3
|
module Jobshop
|
|
4
4
|
class Teams::RegistrationsController < ApplicationController
|
|
5
|
-
before_action RegistrationTokenValidation
|
|
6
|
-
|
|
7
5
|
skip_before_action :authenticate_user!
|
|
8
6
|
|
|
7
|
+
before_action RegistrationTokenValidation
|
|
8
|
+
|
|
9
9
|
layout "jobshop/unauthenticated"
|
|
10
10
|
|
|
11
11
|
def new
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Jobshop
|
|
2
2
|
class TeamsMailer < ApplicationMailer
|
|
3
|
-
def found_teams(
|
|
4
|
-
@user =
|
|
3
|
+
def found_teams(email, teams)
|
|
4
|
+
@user = Jobshop::User.where(email: email).first
|
|
5
5
|
@teams = teams
|
|
6
6
|
|
|
7
|
-
mail(to:
|
|
7
|
+
mail(to: email, subject: "We found your Jobshop Teams!")
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
data/app/models/jobshop/user.rb
CHANGED
|
@@ -16,8 +16,12 @@ module Jobshop
|
|
|
16
16
|
presence: { if: :password_required? },
|
|
17
17
|
confirmation: { if: :password_required? }
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
def self.find_for_authentication(warden_conditions)
|
|
20
|
+
where(email: warden_conditions[:email],
|
|
21
|
+
team_id: warden_conditions[:team_id]).first
|
|
22
|
+
end
|
|
20
23
|
|
|
24
|
+
private
|
|
21
25
|
def generate_email_authentication_token
|
|
22
26
|
loop do
|
|
23
27
|
token = Devise.friendly_token
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
%span(class="visuallyhidden") User Actions
|
|
28
28
|
%ul(class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="accbtn")
|
|
29
29
|
%li(class="mdl-menu__item")
|
|
30
|
-
%a(href="#{destroy_user_session_path}" data-method="delete") Sign out
|
|
30
|
+
%a(href="#{destroy_user_session_path(team_id: current_user.team_id)}" data-method="delete") Sign out
|
|
31
31
|
%nav(class="demo-navigation mdl-navigation mdl-color--blue-grey-800")
|
|
32
32
|
%a(class="mdl-navigation__link" href="")
|
|
33
33
|
%i(class="mdl-color-text--blue-grey-400 material-icons" role="presentation") home
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
%nav.mdl-navigation
|
|
9
9
|
%a.mdl-navigation__link{ href: jobshop.about_path }
|
|
10
10
|
About
|
|
11
|
-
%a.mdl-navigation__link.mdl-color-text--pink{ href: jobshop.
|
|
11
|
+
%a.mdl-navigation__link.mdl-color-text--pink{ href: jobshop.teams_lookup_path }
|
|
12
12
|
Sign In
|
|
13
13
|
|
|
14
14
|
= yield
|
|
@@ -36,7 +36,7 @@ Devise.setup do |config|
|
|
|
36
36
|
# filter. You can also supply a hash where the value is a boolean determining
|
|
37
37
|
# whether or not authentication should be aborted when the value is not
|
|
38
38
|
# present.
|
|
39
|
-
|
|
39
|
+
config.authentication_keys = [ :email, :team_id ]
|
|
40
40
|
|
|
41
41
|
# Configure parameters from the request object used for authentication. Each
|
|
42
42
|
# entry given should be a request method and it will automatically be passed
|
data/config/routes.rb
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
Jobshop::Engine.routes.draw do
|
|
2
|
-
|
|
2
|
+
default_url_options(Jobshop.configuration.default_url_options)
|
|
3
|
+
|
|
4
|
+
devise_for(:users, class_name: "Jobshop::User", module: "devise", skip: [ :sessions ])
|
|
5
|
+
|
|
6
|
+
devise_scope :user do
|
|
7
|
+
get "teams/:team_id/sign_in" => "sessions#new", as: :new_user_session
|
|
8
|
+
post "teams/:team_id/sign_in" => "sessions#create", as: :user_session
|
|
9
|
+
delete "teams/:team_id/sign_out" => "sessions#destroy", as: :destroy_user_session
|
|
10
|
+
end
|
|
3
11
|
|
|
4
12
|
resources :teams, only: [ ] do
|
|
5
13
|
collection do
|
|
@@ -10,13 +10,18 @@
|
|
|
10
10
|
# Make sure the secrets in this file are kept private
|
|
11
11
|
# if you're sharing your code publicly.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
defaults: &defaults
|
|
14
|
+
canonical_name: "localhost"
|
|
14
15
|
secret_key_base: <%= SecureRandom.hex(64) %>
|
|
15
16
|
|
|
17
|
+
development:
|
|
18
|
+
<<: *defaults
|
|
19
|
+
|
|
16
20
|
test:
|
|
17
|
-
|
|
21
|
+
<<: *defaults
|
|
18
22
|
|
|
19
23
|
# Do not keep production secrets in the repository,
|
|
20
24
|
# instead read values from the environment.
|
|
21
25
|
production:
|
|
26
|
+
canonical_name: <%%= ENV["CANONICAL_NAME"] %>
|
|
22
27
|
secret_key_base: <%%= ENV["SECRET_KEY_BASE"] %>
|
data/lib/jobshop/version.rb
CHANGED
data/lib/jobshop.rb
CHANGED
|
@@ -14,10 +14,14 @@ module Jobshop
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class Configuration
|
|
17
|
-
attr_writer :
|
|
17
|
+
attr_writer :canonical_name
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
@canonical_name = "localhost:3000"
|
|
21
|
+
end
|
|
18
22
|
|
|
19
23
|
def default_url_options
|
|
20
|
-
{}
|
|
24
|
+
{ host: @canonical_name }
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jobshop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.53
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Frank J. Mattia
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-09-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: coffee-rails
|
|
@@ -58,28 +58,28 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 4.
|
|
61
|
+
version: 4.2.0
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 4.
|
|
68
|
+
version: 4.2.0
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: material_design_lite-sass
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: 1.
|
|
75
|
+
version: 1.2.0
|
|
76
76
|
type: :runtime
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: 1.
|
|
82
|
+
version: 1.2.0
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: pundit
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,14 +142,14 @@ dependencies:
|
|
|
142
142
|
requirements:
|
|
143
143
|
- - "~>"
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: 3.
|
|
145
|
+
version: 3.3.0
|
|
146
146
|
type: :runtime
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
150
|
- - "~>"
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
|
-
version: 3.
|
|
152
|
+
version: 3.3.0
|
|
153
153
|
- !ruby/object:Gem::Dependency
|
|
154
154
|
name: turbolinks
|
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -321,9 +321,11 @@ files:
|
|
|
321
321
|
- app/assets/stylesheets/jobshop/application.scss
|
|
322
322
|
- app/assets/stylesheets/jobshop/breakpoints.scss
|
|
323
323
|
- app/assets/stylesheets/jobshop/static.scss
|
|
324
|
+
- app/controllers/concerns/email_token_validation.rb
|
|
324
325
|
- app/controllers/concerns/registration_token_validation.rb
|
|
325
326
|
- app/controllers/jobshop/application_controller.rb
|
|
326
327
|
- app/controllers/jobshop/dashboards_controller.rb
|
|
328
|
+
- app/controllers/jobshop/sessions_controller.rb
|
|
327
329
|
- app/controllers/jobshop/setups_controller.rb
|
|
328
330
|
- app/controllers/jobshop/teams/lookups_controller.rb
|
|
329
331
|
- app/controllers/jobshop/teams/registrations_controller.rb
|
|
@@ -355,6 +357,7 @@ files:
|
|
|
355
357
|
- app/views/jobshop/setups/show.html.haml
|
|
356
358
|
- app/views/jobshop/teams/lookups/show.html.haml
|
|
357
359
|
- app/views/jobshop/teams/registrations/new.html.haml
|
|
360
|
+
- app/views/jobshop/teams_mailer/found_teams.html.haml
|
|
358
361
|
- app/views/jobshop/teams_mailer/found_teams.text.erb
|
|
359
362
|
- app/views/layouts/jobshop/application.html.haml
|
|
360
363
|
- app/views/layouts/jobshop/mailer.text.erb
|