bullet_train 1.0.6 → 1.0.10
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/account/invitations_controller.rb +1 -1
- data/app/controllers/account/two_factors_controller.rb +18 -0
- data/app/controllers/concerns/account/controllers/base.rb +118 -0
- data/app/controllers/concerns/account/users/controller_base.rb +1 -1
- data/app/controllers/concerns/controllers/base.rb +119 -0
- data/app/controllers/concerns/devise_current_attributes.rb +13 -0
- data/app/controllers/concerns/registrations/controller_base.rb +1 -1
- data/app/controllers/concerns/sessions/controller_base.rb +1 -1
- data/app/models/concerns/records/base.rb +60 -0
- data/app/views/account/two_factors/create.js.erb +1 -0
- data/app/views/account/two_factors/destroy.js.erb +1 -0
- data/app/views/layouts/account.html.erb +1 -0
- data/app/views/layouts/devise.html.erb +1 -0
- data/lib/bullet_train/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a460b28ddcaa9b63e0b3d86ff22bd1f55947bb98e76abe6febde2be804253732
|
4
|
+
data.tar.gz: efe38f3559f947a23bbb33a87bf199e692c4595d886b01911c2756945576a750
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c46781c9c2a4f4fc3c6e31326610fa87839c73d0f96b802c344a2048683f73c7842720fcd2d059b7adb11630767490d9bbc6fadda839a624fe80a6ff28766db8
|
7
|
+
data.tar.gz: cead3f1bc71f9d70ea51fa211252770370f07526dbc9879073f1326fd9fe2fd9b52ebbd6f9a8922b998b848b2da2add9bc9ad991928c088348bd33a1e8fc35e7
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Account::TwoFactorsController < Account::ApplicationController
|
2
|
+
before_action :authenticate_user!
|
3
|
+
|
4
|
+
def create
|
5
|
+
@backup_codes = current_user.generate_otp_backup_codes!
|
6
|
+
@user = current_user
|
7
|
+
|
8
|
+
current_user.update(
|
9
|
+
otp_secret: User.generate_otp_secret,
|
10
|
+
otp_required_for_login: true
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def destroy
|
15
|
+
@user = current_user
|
16
|
+
current_user.update(otp_required_for_login: false)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Account::Controllers::Base
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
include LoadsAndAuthorizesResource
|
6
|
+
include Fields::ControllerSupport
|
7
|
+
|
8
|
+
before_action :set_last_seen_at, if: proc {
|
9
|
+
user_signed_in? && (current_user.last_seen_at.nil? || current_user.last_seen_at < 1.minute.ago)
|
10
|
+
}
|
11
|
+
|
12
|
+
layout "account"
|
13
|
+
|
14
|
+
before_action :authenticate_user!
|
15
|
+
before_action :set_paper_trail_whodunnit
|
16
|
+
before_action :ensure_onboarding_is_complete_and_set_next_step
|
17
|
+
end
|
18
|
+
|
19
|
+
class_methods do
|
20
|
+
# this is a template method called by LoadsAndAuthorizesResource.
|
21
|
+
# it allows that module to understand what namespaces of a controller
|
22
|
+
# are organizing the controllers, and which are organizing the models.
|
23
|
+
def regex_to_remove_controller_namespace
|
24
|
+
/^Account::/
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def adding_user_email?
|
29
|
+
is_a?(Account::Onboarding::UserEmailController)
|
30
|
+
end
|
31
|
+
|
32
|
+
def adding_user_details?
|
33
|
+
is_a?(Account::Onboarding::UserDetailsController)
|
34
|
+
end
|
35
|
+
|
36
|
+
def adding_team?
|
37
|
+
return true if request.get? && request.path == new_account_team_path
|
38
|
+
return true if request.post? && request.path == account_teams_path
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def switching_teams?
|
43
|
+
return true if request.get? && request.path == account_teams_path
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def managing_account?
|
48
|
+
is_a?(Account::UsersController) || self.class.module_parents.include?(Oauth)
|
49
|
+
end
|
50
|
+
|
51
|
+
def accepting_invitation?
|
52
|
+
(params[:controller] == "account/invitations") && (params[:action] == "show" || params[:action] == "accept")
|
53
|
+
end
|
54
|
+
|
55
|
+
def ensure_onboarding_is_complete_and_set_next_step
|
56
|
+
unless ensure_onboarding_is_complete
|
57
|
+
session[:after_onboarding_url] ||= request.url
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ensure_onboarding_is_complete
|
62
|
+
# This is temporary, but if we've gotten this far and `@team` is loaded, we need to ensure current_team is
|
63
|
+
# updated for the checks below. This entire concept of `current_team` is going away soon.
|
64
|
+
current_user.update(current_team: @team) if @team&.persisted?
|
65
|
+
|
66
|
+
# since the onboarding controllers are child classes of this class,
|
67
|
+
# we actually have to check to make sure we're not currently on that
|
68
|
+
# step otherwise we'll end up in an endless redirection loop.
|
69
|
+
if current_user.email_is_oauth_placeholder?
|
70
|
+
if adding_user_email?
|
71
|
+
return true
|
72
|
+
else
|
73
|
+
redirect_to edit_account_onboarding_user_email_path(current_user)
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# some team-related onboarding steps need to be skipped if we're in the process
|
79
|
+
# of creating a new team.
|
80
|
+
unless adding_team? || accepting_invitation?
|
81
|
+
|
82
|
+
# USER ONBOARDING STUFF
|
83
|
+
# first we make sure the user is properly onboarded.
|
84
|
+
unless current_team.present?
|
85
|
+
|
86
|
+
# don't force the user to create a team if they've already got one.
|
87
|
+
if current_user.teams.any?
|
88
|
+
current_user.update(current_team: current_user.teams.first)
|
89
|
+
else
|
90
|
+
redirect_to new_account_team_path
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# TEAM ONBOARDING STUFF.
|
96
|
+
# then make sure the team is properly onboarded.
|
97
|
+
|
98
|
+
# since the onboarding controllers are child classes of this class,
|
99
|
+
# we actually have to check to make sure we're not currently on that
|
100
|
+
# step otherwise we'll end up in an endless redirection loop.
|
101
|
+
unless current_user.details_provided?
|
102
|
+
if adding_user_details?
|
103
|
+
return true
|
104
|
+
else
|
105
|
+
redirect_to edit_account_onboarding_user_detail_path(current_user)
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_last_seen_at
|
116
|
+
current_user.update_attribute(:last_seen_at, Time.current)
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Controllers::Base
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
# these are common for authentication workflows.
|
6
|
+
include InvitationOnlyHelper
|
7
|
+
include InvitationsHelper
|
8
|
+
|
9
|
+
include DeviseCurrentAttributes
|
10
|
+
|
11
|
+
around_action :set_locale
|
12
|
+
layout :layout_by_resource
|
13
|
+
|
14
|
+
before_action { @updating = request.headers["X-Cable-Ready"] == "update" }
|
15
|
+
|
16
|
+
# TODO Extract this into an optional `bullet_train-sentry` package.
|
17
|
+
before_action :set_sentry_context
|
18
|
+
|
19
|
+
skip_before_action :verify_authenticity_token, if: -> { controller_name == "sessions" && action_name == "create" }
|
20
|
+
|
21
|
+
rescue_from CanCan::AccessDenied do |exception|
|
22
|
+
if current_user.nil?
|
23
|
+
respond_to do |format|
|
24
|
+
format.html do
|
25
|
+
session["user_return_to"] = request.path
|
26
|
+
redirect_to [:new, :user, :session], alert: exception.message
|
27
|
+
end
|
28
|
+
end
|
29
|
+
elsif current_user.teams.none?
|
30
|
+
respond_to do |format|
|
31
|
+
format.html { redirect_to [:new, :account, :team], alert: exception.message }
|
32
|
+
end
|
33
|
+
else
|
34
|
+
respond_to do |format|
|
35
|
+
# TODO we do this for now because it ensures `current_team` doesn't remain set in an invalid state.
|
36
|
+
format.html { redirect_to [:account, current_user.teams.first], alert: exception.message }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# this is an ugly hack, but it's what is recommended at
|
43
|
+
# https://github.com/plataformatec/devise/wiki/How-To:-Create-custom-layouts
|
44
|
+
def layout_by_resource
|
45
|
+
if devise_controller?
|
46
|
+
"devise"
|
47
|
+
else
|
48
|
+
"public"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_sign_in_path_for(resource_or_scope)
|
53
|
+
resource = resource_or_scope.class.name.downcase
|
54
|
+
stored_location_for(resource) || account_dashboard_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def after_sign_up_path_for(resource_or_scope)
|
58
|
+
resource = resource_or_scope.class.name.downcase
|
59
|
+
stored_location_for(resource) || account_dashboard_path
|
60
|
+
end
|
61
|
+
|
62
|
+
def current_team
|
63
|
+
helpers.current_team
|
64
|
+
end
|
65
|
+
|
66
|
+
def current_membership
|
67
|
+
helpers.current_membership
|
68
|
+
end
|
69
|
+
|
70
|
+
def current_locale
|
71
|
+
helpers.current_locale
|
72
|
+
end
|
73
|
+
|
74
|
+
def enforce_invitation_only
|
75
|
+
if invitation_only?
|
76
|
+
unless helpers.invited?
|
77
|
+
redirect_to [:account, :teams], notice: t("teams.notifications.invitation_only")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_locale
|
83
|
+
I18n.locale = [
|
84
|
+
current_user&.locale,
|
85
|
+
current_user&.current_team&.locale,
|
86
|
+
http_accept_language.compatible_language_from(I18n.available_locales),
|
87
|
+
I18n.default_locale.to_s
|
88
|
+
].compact.find { |potential_locale| I18n.available_locales.include?(potential_locale.to_sym) }
|
89
|
+
yield
|
90
|
+
I18n.locale = I18n.default_locale
|
91
|
+
end
|
92
|
+
|
93
|
+
# Whitelist the account namespace and prevent JavaScript
|
94
|
+
# embedding when passing paths as parameters in links.
|
95
|
+
def only_allow_path(path)
|
96
|
+
return if path.nil?
|
97
|
+
account_namespace_regexp = /^\/account\/*+/
|
98
|
+
scheme = URI.parse(path).scheme
|
99
|
+
return nil unless path.match?(account_namespace_regexp) && scheme != "javascript"
|
100
|
+
path
|
101
|
+
end
|
102
|
+
|
103
|
+
# TODO Extract this into an optional `bullet_train-sentry` package.
|
104
|
+
def set_sentry_context
|
105
|
+
return unless ENV["SENTRY_DSN"]
|
106
|
+
|
107
|
+
Sentry.configure_scope do |scope|
|
108
|
+
scope.set_user(id: current_user.id, email: current_user.email) if current_user
|
109
|
+
|
110
|
+
scope.set_context(
|
111
|
+
"request",
|
112
|
+
{
|
113
|
+
url: request.url,
|
114
|
+
params: params.to_unsafe_h
|
115
|
+
}
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Records::Base
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
if defined?(Webhooks::Outgoing::IssuingModel)
|
6
|
+
include Webhooks::Outgoing::IssuingModel
|
7
|
+
end
|
8
|
+
|
9
|
+
if defined?(ObfuscatesId)
|
10
|
+
include ObfuscatesId
|
11
|
+
end
|
12
|
+
|
13
|
+
if defined?(QuestionMethodsFromScopes)
|
14
|
+
include QuestionMethodsFromScopes
|
15
|
+
end
|
16
|
+
|
17
|
+
include CableReady::Updatable
|
18
|
+
enable_updates
|
19
|
+
|
20
|
+
extend ActiveHash::Associations::ActiveRecordExtensions
|
21
|
+
|
22
|
+
# 🏚 i'd like to deprecate these. they're not descriptive enough.
|
23
|
+
scope :newest, -> { order("created_at DESC") }
|
24
|
+
scope :oldest, -> { order("created_at ASC") }
|
25
|
+
|
26
|
+
scope :newest_created, -> { order("created_at DESC") }
|
27
|
+
scope :oldest_created, -> { order("created_at ASC") }
|
28
|
+
scope :newest_updated, -> { order("updated_at DESC") }
|
29
|
+
scope :oldest_updated, -> { order("updated_at ASC") }
|
30
|
+
|
31
|
+
# Microscope adds useful scopes targeting ActiveRecord `boolean`, `date` and `datetime` attributes.
|
32
|
+
# https://github.com/mirego/microscope
|
33
|
+
acts_as_microscope
|
34
|
+
end
|
35
|
+
|
36
|
+
class_methods do
|
37
|
+
# by default we represent methods by their first string attribute.
|
38
|
+
def label_attribute
|
39
|
+
columns_hash.values.find { |column| column.sql_type_metadata.type == :string }&.name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# this is a template method you can override in activerecord models if we shouldn't just use their first string to
|
44
|
+
# identify them.
|
45
|
+
def label_string
|
46
|
+
if (label_attribute = self.class.label_attribute)
|
47
|
+
send("#{label_attribute}_was")
|
48
|
+
else
|
49
|
+
self.class.name.underscore.split("/").last.titleize
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parent_collection
|
54
|
+
# TODO Try to suggest what the entire method definition should actually be
|
55
|
+
# using parent_key below to do so.
|
56
|
+
model_name = self.class
|
57
|
+
# parent_key = model_name.reflect_on_all_associations(:belongs_to).first.name
|
58
|
+
raise "You're trying to use a feature that requires #{model_name} to have a `collection` method defined that returns the Active Record association that this model belongs to within its parent object."
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
$("#two-factor").html("<%= j render partial: "devise/registrations/two_factor"%>");
|
@@ -0,0 +1 @@
|
|
1
|
+
$("#two-factor").html("<%= j render partial: "devise/registrations/two_factor"%>");
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render "themes/#{current_theme}/layouts/account" %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render "themes/#{current_theme}/layouts/devise" %>
|
data/lib/bullet_train/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -40,13 +40,17 @@ files:
|
|
40
40
|
- app/controllers/account/onboarding/user_details_controller.rb
|
41
41
|
- app/controllers/account/onboarding/user_email_controller.rb
|
42
42
|
- app/controllers/account/teams_controller.rb
|
43
|
+
- app/controllers/account/two_factors_controller.rb
|
43
44
|
- app/controllers/account/users_controller.rb
|
45
|
+
- app/controllers/concerns/account/controllers/base.rb
|
44
46
|
- app/controllers/concerns/account/invitations/controller_base.rb
|
45
47
|
- app/controllers/concerns/account/memberships/controller_base.rb
|
46
48
|
- app/controllers/concerns/account/onboarding/user_details/controller_base.rb
|
47
49
|
- app/controllers/concerns/account/onboarding/user_email/controller_base.rb
|
48
50
|
- app/controllers/concerns/account/teams/controller_base.rb
|
49
51
|
- app/controllers/concerns/account/users/controller_base.rb
|
52
|
+
- app/controllers/concerns/controllers/base.rb
|
53
|
+
- app/controllers/concerns/devise_current_attributes.rb
|
50
54
|
- app/controllers/concerns/registrations/controller_base.rb
|
51
55
|
- app/controllers/concerns/sessions/controller_base.rb
|
52
56
|
- app/controllers/registrations_controller.rb
|
@@ -71,6 +75,7 @@ files:
|
|
71
75
|
- app/mailers/user_mailer.rb
|
72
76
|
- app/models/concerns/invitations/base.rb
|
73
77
|
- app/models/concerns/memberships/base.rb
|
78
|
+
- app/models/concerns/records/base.rb
|
74
79
|
- app/models/concerns/teams/base.rb
|
75
80
|
- app/models/concerns/users/base.rb
|
76
81
|
- app/models/invitation.rb
|
@@ -109,6 +114,8 @@ files:
|
|
109
114
|
- app/views/account/teams/new.html.erb
|
110
115
|
- app/views/account/teams/show.html.erb
|
111
116
|
- app/views/account/teams/show.json.jbuilder
|
117
|
+
- app/views/account/two_factors/create.js.erb
|
118
|
+
- app/views/account/two_factors/destroy.js.erb
|
112
119
|
- app/views/account/users/_breadcrumbs.html.erb
|
113
120
|
- app/views/account/users/_form.html.erb
|
114
121
|
- app/views/account/users/edit.html.erb
|
@@ -128,6 +135,8 @@ files:
|
|
128
135
|
- app/views/devise/shared/_links.html.erb
|
129
136
|
- app/views/devise/shared/_oauth.html.erb
|
130
137
|
- app/views/devise/unlocks/new.html.erb
|
138
|
+
- app/views/layouts/account.html.erb
|
139
|
+
- app/views/layouts/devise.html.erb
|
131
140
|
- config/locales/en/devise.en.yml
|
132
141
|
- config/locales/en/invitations.en.yml
|
133
142
|
- config/locales/en/memberships.en.yml
|