lesli_shield 1.1.5 → 1.1.7
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 +3 -0
- data/app/assets/stylesheets/lesli_shield/application.css +140 -1
- data/app/assets/stylesheets/lesli_shield/confirmations.css +917 -18
- data/app/assets/stylesheets/lesli_shield/confirmations.tailwind.css +918 -0
- data/app/assets/stylesheets/lesli_shield/passwords.css +872 -18
- data/app/assets/stylesheets/lesli_shield/passwords.tailwind.css +873 -0
- data/app/assets/stylesheets/lesli_shield/registrations.css +904 -770
- data/app/assets/stylesheets/lesli_shield/registrations.tailwind.css +908 -0
- data/app/assets/stylesheets/lesli_shield/sessions.css +984 -32
- data/app/assets/stylesheets/lesli_shield/sessions.tailwind.css +983 -1
- data/app/controllers/lesli_shield/profile/passwords_controller.rb +119 -0
- data/app/controllers/lesli_shield/profiles_controller.rb +63 -0
- data/app/controllers/lesli_shield/sessions_controller.rb +1 -2
- data/app/controllers/lesli_shield/users_controller.rb +3 -7
- data/app/controllers/users/confirmations_controller.rb +162 -49
- data/app/controllers/users/passwords_controller.rb +211 -28
- data/app/controllers/users/registrations_controller.rb +108 -83
- data/app/controllers/users/sessions_controller.rb +122 -84
- data/app/interfaces/lesli_shield/authentication_interface.rb +3 -3
- data/app/interfaces/lesli_shield/authorization_interface.rb +2 -2
- data/app/mailers/lesli_shield/devise_mailer.rb +73 -17
- data/app/models/concerns/lesli_shield/user_authentication.rb +54 -0
- data/app/models/lesli_shield/account.rb +4 -1
- data/app/models/lesli_shield/invite.rb +1 -1
- data/app/models/lesli_shield/user/role.rb +1 -1
- data/app/models/lesli_shield/user.rb +5 -2
- data/app/services/lesli_shield/profile/password_service.rb +47 -0
- data/app/services/lesli_shield/profile_service.rb +24 -0
- data/app/services/lesli_shield/user_registration_service.rb +41 -74
- data/app/services/lesli_shield/user_session_service.rb +1 -1
- data/app/services/lesli_shield/user_validator_service.rb +35 -39
- data/app/views/devise/confirmations/new.html.erb +58 -12
- data/app/views/devise/confirmations/show.html.erb +27 -60
- data/app/views/devise/passwords/edit.html.erb +59 -25
- data/app/views/devise/passwords/new.html.erb +61 -26
- data/app/views/devise/registrations/new.html.erb +80 -53
- data/app/views/devise/sessions/new.html.erb +53 -36
- data/app/views/devise/shared/_application-devise-simple.erb +18 -19
- data/app/views/devise/shared/_demo.html.erb +8 -6
- data/app/views/devise/shared/_error_messages.html.erb +45 -10
- data/app/views/devise/shared/_links.html.erb +6 -13
- data/app/views/lesli_shield/invites/_form.html.erb +1 -1
- data/app/views/lesli_shield/invites/index.html.erb +3 -2
- data/app/views/lesli_shield/profiles/_password-form.html.erb +68 -0
- data/app/views/lesli_shield/profiles/show.html.erb +29 -0
- data/app/views/lesli_shield/users/_information-card.html.erb +35 -45
- data/app/views/lesli_shield/users/_information-form.html.erb +9 -1
- data/config/initializers/devise.rb +52 -328
- data/config/locales/translations.en.yml +65 -2
- data/config/locales/translations.es.yml +65 -2
- data/config/routes.rb +4 -0
- data/lib/lesli_shield/engine.rb +44 -4
- data/lib/lesli_shield/router.rb +52 -18
- data/lib/lesli_shield/version.rb +2 -2
- data/readme.md +6 -4
- metadata +30 -5
- data/app/assets/config/lesli_shield_manifest.js +0 -48
- data/app/assets/stylesheets/lesli_shield/application.tailwind.css +0 -0
|
@@ -33,96 +33,63 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module LesliShield
|
|
34
34
|
class UserRegistrationService < Lesli::ApplicationLesliService
|
|
35
35
|
|
|
36
|
-
def initialize(
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
def initialize(user)
|
|
37
|
+
super(user)
|
|
38
|
+
self.resource = user
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# force token deletion so we are sure nobody
|
|
48
|
-
# will be able to use the token again
|
|
49
|
-
current_user.update(confirmation_token: nil)
|
|
50
|
-
|
|
51
|
-
# Minimum security settings required
|
|
52
|
-
#self.settings.create_with(:value => false).find_or_create_by(:name => "mfa_enabled")
|
|
53
|
-
#self.settings.create_with(:value => :email).find_or_create_by(:name => "mfa_method")
|
|
41
|
+
# Devise owns confirmation. This service performs only the Lesli account
|
|
42
|
+
# provisioning that must happen after Devise accepts the token.
|
|
43
|
+
def provision_account!
|
|
44
|
+
assign_account! if resource.account.blank?
|
|
45
|
+
assign_initial_role! unless resource.user_roles.exists?
|
|
46
|
+
synchronize_role_privileges!
|
|
54
47
|
|
|
48
|
+
resource
|
|
55
49
|
end
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
add_account() if resource.account.blank?
|
|
60
|
-
add_role() if resource.user_roles.empty?
|
|
51
|
+
private
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
def assign_account!
|
|
54
|
+
account = if multiaccount?
|
|
55
|
+
create_owned_account!
|
|
56
|
+
else
|
|
57
|
+
Lesli::Account.first!
|
|
65
58
|
end
|
|
66
59
|
|
|
67
|
-
|
|
68
|
-
resource.save
|
|
69
|
-
|
|
70
|
-
# # initialize user dependencies
|
|
71
|
-
# def after_account_assignation
|
|
72
|
-
# return unless self.account
|
|
73
|
-
|
|
74
|
-
# #Courier::One::Firebase::User.sync_user(self)
|
|
75
|
-
# # Lesli::Courier.new(:lesli_calendar).from(:calendar_service, self).create({
|
|
76
|
-
# # name: "Personal Calendar",
|
|
77
|
-
# # default: true
|
|
78
|
-
# # })
|
|
79
|
-
# end
|
|
80
|
-
|
|
60
|
+
resource.update!(account: account)
|
|
81
61
|
end
|
|
82
62
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# proprietary instance (only one company is using the platform)
|
|
92
|
-
# Another scenario where it is not needed to create a new account for the
|
|
93
|
-
# user is when the user is confirming the account through an invitation
|
|
94
|
-
def add_account
|
|
95
|
-
|
|
96
|
-
if ALLOW_MULTI_ACCOUNT === true
|
|
97
|
-
# create new account for the new user only if multi-account is allowed
|
|
98
|
-
account = Lesli::Account.create!({
|
|
99
|
-
user: resource, # set user as owner of his just created account
|
|
100
|
-
name: "Lesli", # temporary company name
|
|
101
|
-
email: resource.email,
|
|
102
|
-
status: :active # account is active due user already confirmed his email
|
|
103
|
-
})
|
|
104
|
-
else
|
|
105
|
-
# if multi-account is not allowed user belongs to the first account in instance
|
|
106
|
-
account = Lesli::Account.first
|
|
107
|
-
end
|
|
63
|
+
def create_owned_account!
|
|
64
|
+
Lesli::Account.create!(
|
|
65
|
+
user: resource,
|
|
66
|
+
name: "Lesli",
|
|
67
|
+
email: resource.email,
|
|
68
|
+
status: :active
|
|
69
|
+
)
|
|
70
|
+
end
|
|
108
71
|
|
|
109
|
-
|
|
110
|
-
resource.account
|
|
72
|
+
def assign_initial_role!
|
|
73
|
+
role = resource.account.roles.find_by!(name: initial_role_name)
|
|
74
|
+
resource.user_roles.create!(role: role)
|
|
111
75
|
end
|
|
112
76
|
|
|
113
|
-
def
|
|
114
|
-
|
|
115
|
-
# add owner role to user only if multi-account is allowed
|
|
116
|
-
resource.user_roles.create({ role: account.roles.find_by(name: "owner") })
|
|
117
|
-
else
|
|
118
|
-
# Assigning default role if defined in account settings
|
|
119
|
-
# Otherwise, the default role is "limited"
|
|
120
|
-
default_role_name = Lesli.config.shield.dig(:default_role) || "guest"
|
|
77
|
+
def initial_role_name
|
|
78
|
+
return "owner" if multiaccount?
|
|
121
79
|
|
|
122
|
-
|
|
80
|
+
Lesli.config.shield.dig(:default_role).presence || "guest"
|
|
81
|
+
end
|
|
123
82
|
|
|
124
|
-
|
|
83
|
+
def synchronize_role_privileges!
|
|
84
|
+
resource.roles.find_each do |role|
|
|
85
|
+
LesliShield::RolePrivilegeService.new(nil).synchronize(role)
|
|
125
86
|
end
|
|
126
87
|
end
|
|
88
|
+
|
|
89
|
+
# Read the setting at execution time. Applications and tests can change
|
|
90
|
+
# Lesli configuration after this service class has been loaded.
|
|
91
|
+
def multiaccount?
|
|
92
|
+
Lesli.config.security.dig(:allow_multiaccount) == true
|
|
93
|
+
end
|
|
127
94
|
end
|
|
128
95
|
end
|
|
@@ -55,7 +55,7 @@ module LesliShield
|
|
|
55
55
|
def create(remote_ip, user_agent=nil, session_source="devise_standard_session")
|
|
56
56
|
|
|
57
57
|
# register a new unique session
|
|
58
|
-
current_session = current_user.sessions.create({
|
|
58
|
+
current_session = current_user.sessions.create!({
|
|
59
59
|
:remote => remote_ip,
|
|
60
60
|
|
|
61
61
|
:agent_os => user_agent&.dig(:os) || "unknown",
|
|
@@ -33,11 +33,17 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module LesliShield
|
|
34
34
|
class UserValidatorService < Lesli::ApplicationLesliService
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def initialize(user)
|
|
37
|
+
raise ArgumentError, "user is required" unless user
|
|
38
|
+
|
|
39
|
+
super(user)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def validate
|
|
43
|
+
account_present?()
|
|
37
44
|
active?()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
active_roles?()
|
|
45
|
+
active_roles?() unless roles_empty?()
|
|
46
|
+
self
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
|
|
@@ -69,10 +75,10 @@ module LesliShield
|
|
|
69
75
|
password_settings = []
|
|
70
76
|
|
|
71
77
|
# get password settings from the database
|
|
72
|
-
if
|
|
78
|
+
if current_user.account
|
|
73
79
|
|
|
74
80
|
# if user is already registered
|
|
75
|
-
password_settings =
|
|
81
|
+
password_settings = current_user.account.settings.where(password_values.join(" or "))
|
|
76
82
|
|
|
77
83
|
elseif Account.first
|
|
78
84
|
|
|
@@ -85,7 +91,7 @@ module LesliShield
|
|
|
85
91
|
|
|
86
92
|
# exit validations if password complexity is not enabled
|
|
87
93
|
if settings[:name] == 'password_enforce_complexity' && settings[:value] != "1"
|
|
88
|
-
failures
|
|
94
|
+
failures.clear
|
|
89
95
|
break
|
|
90
96
|
end
|
|
91
97
|
|
|
@@ -147,53 +153,42 @@ module LesliShield
|
|
|
147
153
|
|
|
148
154
|
private
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
#
|
|
152
|
-
def
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
# save a locked log for the requested user
|
|
157
|
-
@resource.logs.create({
|
|
158
|
-
title: "session_creation_failed",
|
|
159
|
-
description: "user_locked"
|
|
160
|
-
})
|
|
156
|
+
# Devise owns password, confirmation, and failed-attempt locking. This
|
|
157
|
+
# service contains only the additional access rules defined by Shield.
|
|
158
|
+
def account_present?
|
|
159
|
+
unless current_user.account.present?
|
|
160
|
+
log_failure("user_has_no_account")
|
|
161
161
|
|
|
162
162
|
return false
|
|
163
|
-
|
|
164
163
|
end
|
|
165
164
|
|
|
166
|
-
|
|
165
|
+
true
|
|
167
166
|
end
|
|
168
167
|
|
|
169
|
-
def confirmed?
|
|
170
168
|
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
# check if user is able to create a new session
|
|
170
|
+
def active?
|
|
171
|
+
temporarily_locked = current_user.locked_until.present? &&
|
|
172
|
+
current_user.locked_until > Time.current
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
})
|
|
174
|
+
unless current_user.active? && !temporarily_locked
|
|
175
|
+
|
|
176
|
+
# save a locked log for the requested user
|
|
177
|
+
log_failure("user_locked")
|
|
179
178
|
|
|
180
179
|
return false
|
|
181
180
|
|
|
182
181
|
end
|
|
183
182
|
|
|
184
183
|
return true
|
|
185
|
-
|
|
186
184
|
end
|
|
187
185
|
|
|
188
186
|
def roles_empty?
|
|
189
187
|
|
|
190
188
|
# check if user has roles assigned
|
|
191
|
-
|
|
189
|
+
unless current_user.roles.exists?
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
title: "session_creation_failed",
|
|
195
|
-
description: "user_has_no_assigned_role"
|
|
196
|
-
})
|
|
191
|
+
log_failure("user_has_no_assigned_role")
|
|
197
192
|
|
|
198
193
|
return true
|
|
199
194
|
|
|
@@ -206,16 +201,17 @@ module LesliShield
|
|
|
206
201
|
def active_roles?
|
|
207
202
|
|
|
208
203
|
# check user has at least one active role before authorize the sign-in request
|
|
209
|
-
unless
|
|
210
|
-
|
|
211
|
-
title: "session_creation_failed",
|
|
212
|
-
description: "user_has_no_active_role"
|
|
213
|
-
})
|
|
204
|
+
unless current_user.roles.exists?(active: true)
|
|
205
|
+
log_failure("user_has_no_active_role")
|
|
214
206
|
|
|
215
207
|
return false
|
|
216
208
|
end
|
|
217
209
|
|
|
218
210
|
return true
|
|
219
211
|
end
|
|
212
|
+
|
|
213
|
+
def log_failure(description)
|
|
214
|
+
failures.push(description) unless failures.include?(description)
|
|
215
|
+
end
|
|
220
216
|
end
|
|
221
217
|
end
|
|
@@ -1,16 +1,62 @@
|
|
|
1
|
-
|
|
1
|
+
<%= render(
|
|
2
|
+
"devise/shared/application-devise-simple",
|
|
3
|
+
title: I18n.t("lesli_shield.devise/confirmations.view_title")
|
|
4
|
+
) do %>
|
|
2
5
|
|
|
3
|
-
<%= form_for(
|
|
4
|
-
|
|
6
|
+
<%= form_for(
|
|
7
|
+
resource,
|
|
8
|
+
as: resource_name,
|
|
9
|
+
url: user_confirmation_path,
|
|
10
|
+
html: { method: :post, class: "text-left" },
|
|
11
|
+
builder: LesliView::Forms::Builder
|
|
12
|
+
) do |form| %>
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
<p class="mb-6 text-center text-sm leading-6 text-slate-600">
|
|
15
|
+
<%= I18n.t(
|
|
16
|
+
"lesli_shield.devise/confirmations.view_description"
|
|
17
|
+
) %>
|
|
18
|
+
</p>
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
21
|
+
|
|
22
|
+
<%= form.field_control_email(
|
|
23
|
+
:email,
|
|
24
|
+
icon: "mail",
|
|
25
|
+
label: I18n.t(
|
|
26
|
+
"lesli_shield.devise/confirmations.field_email"
|
|
27
|
+
),
|
|
28
|
+
message: resource.errors[:email].to_sentence.presence,
|
|
29
|
+
category: resource.errors[:email].any? ? :danger : nil,
|
|
30
|
+
value: resource.pending_reconfirmation? ?
|
|
31
|
+
resource.unconfirmed_email : resource.email,
|
|
32
|
+
required: true,
|
|
33
|
+
autofocus: true,
|
|
34
|
+
autocomplete: "email",
|
|
35
|
+
autocapitalize: "none",
|
|
36
|
+
spellcheck: false
|
|
37
|
+
) %>
|
|
15
38
|
|
|
16
|
-
<%=
|
|
39
|
+
<%= form.field_control_button(
|
|
40
|
+
I18n.t(
|
|
41
|
+
"lesli_shield.devise/confirmations.button_send_instructions"
|
|
42
|
+
),
|
|
43
|
+
{
|
|
44
|
+
class: "w-full",
|
|
45
|
+
data: {
|
|
46
|
+
turbo_submits_with: I18n.t(
|
|
47
|
+
"lesli_shield.devise/confirmations.button_sending"
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
icon: "mark_email_unread"
|
|
52
|
+
) %>
|
|
53
|
+
<% end %>
|
|
54
|
+
|
|
55
|
+
<%= render(
|
|
56
|
+
"devise/shared/links",
|
|
57
|
+
login: true,
|
|
58
|
+
password_reset: false,
|
|
59
|
+
magic_link: false,
|
|
60
|
+
otp: false
|
|
61
|
+
) %>
|
|
62
|
+
<% end %>
|
|
@@ -1,61 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
29
|
-
|
|
30
|
-
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
31
|
-
// ·
|
|
32
|
-
=end
|
|
33
|
-
%>
|
|
34
|
-
|
|
35
|
-
<% content_for :application_custom_assets do %>
|
|
36
|
-
<script>
|
|
37
|
-
//setTimeout(() => { window.location.href = "/"; }, 10000)
|
|
38
|
-
</script>
|
|
39
|
-
<% end %>
|
|
40
|
-
|
|
41
|
-
<%= render("devise/shared/application-devise-simple", title:"Account confirmation") do %>
|
|
42
|
-
|
|
43
|
-
<% if flash[:danger] %>
|
|
44
|
-
<% flash.each do |type, msg| %>
|
|
45
|
-
<div class="notification is-<%= type %>">
|
|
46
|
-
<%= msg %>
|
|
47
|
-
</div>
|
|
48
|
-
<% end %>
|
|
49
|
-
<% end %>
|
|
50
|
-
|
|
51
|
-
<% if flash[:success] %>
|
|
52
|
-
<div class="confirmation-message">
|
|
53
|
-
<p>Your account has been successfully verified</p>
|
|
54
|
-
</div>
|
|
55
|
-
<% end %>
|
|
56
|
-
|
|
57
|
-
<%= render("devise/shared/links", login:true) %>
|
|
58
|
-
|
|
1
|
+
<%= render(
|
|
2
|
+
"devise/shared/application-devise-simple",
|
|
3
|
+
title: I18n.t("lesli_shield.devise/confirmations.view_success_title")
|
|
4
|
+
) do %>
|
|
5
|
+
<section
|
|
6
|
+
class="my-8 w-full max-w-lg rounded-xl border border-emerald-200 bg-white p-8 text-center shadow-sm"
|
|
7
|
+
role="status"
|
|
8
|
+
>
|
|
9
|
+
<span
|
|
10
|
+
class="material-symbols-outlined text-5xl text-emerald-600"
|
|
11
|
+
aria-hidden="true"
|
|
12
|
+
>
|
|
13
|
+
verified
|
|
14
|
+
</span>
|
|
15
|
+
|
|
16
|
+
<p class="mt-4 text-sm leading-6 text-slate-600">
|
|
17
|
+
<%= I18n.t(
|
|
18
|
+
"lesli_shield.devise/confirmations.view_success_description"
|
|
19
|
+
) %>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<%= link_to(
|
|
23
|
+
I18n.t("lesli_shield.devise/shared.button_login"),
|
|
24
|
+
new_user_session_path,
|
|
25
|
+
class: "mt-6 inline-flex min-h-11 items-center justify-center rounded-lg bg-[var(--lesli-color-primary)] px-5 py-2.5 text-sm font-semibold text-white transition-opacity hover:opacity-90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--lesli-color-primary)]"
|
|
26
|
+
) %>
|
|
27
|
+
</section>
|
|
59
28
|
<% end %>
|
|
60
|
-
|
|
61
|
-
|
|
@@ -1,36 +1,70 @@
|
|
|
1
|
-
<%= render(
|
|
1
|
+
<%= render(
|
|
2
|
+
"devise/shared/application-devise-simple",
|
|
3
|
+
title: I18n.t("lesli_shield.devise/passwords.view_update_title")
|
|
4
|
+
) do %>
|
|
2
5
|
|
|
3
6
|
<%= form_for(
|
|
4
|
-
resource,
|
|
5
|
-
as: resource_name,
|
|
6
|
-
url: user_password_path
|
|
7
|
-
html: { class: "
|
|
7
|
+
resource,
|
|
8
|
+
as: resource_name,
|
|
9
|
+
url: user_password_path,
|
|
10
|
+
html: { class: "text-left", method: :put },
|
|
8
11
|
builder: LesliView::Forms::Builder
|
|
9
|
-
|
|
12
|
+
) do |form| %>
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
<p class="mb-6 text-center text-sm leading-6 text-slate-600">
|
|
15
|
+
<%= I18n.t("lesli_shield.devise/passwords.view_update_description") %>
|
|
16
|
+
</p>
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
label_html:form.label(:password),
|
|
15
|
-
control_html:form.password_field(:password, autocomplete: "current-password", placeholder: "* * * * * *"),
|
|
16
|
-
message_text: flash.first&.second,
|
|
17
|
-
category: flash.first&.first,
|
|
18
|
-
icon: "key"
|
|
19
|
-
) %>
|
|
18
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
label_html:form.label(:password_confirmation),
|
|
23
|
-
control_html:form.password_field(:password_confirmation, autocomplete: "current-password", placeholder: "* * * * * *"),
|
|
24
|
-
message_text: flash.first&.second,
|
|
25
|
-
category: flash.first&.first,
|
|
26
|
-
icon: "key"
|
|
27
|
-
) %>
|
|
20
|
+
<%= form.hidden_field :reset_password_token %>
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
<%= form.field_control_password(
|
|
23
|
+
:password,
|
|
24
|
+
icon: "key",
|
|
25
|
+
label: I18n.t("lesli_shield.devise/passwords.field_password"),
|
|
26
|
+
message: I18n.t(
|
|
27
|
+
"lesli_shield.devise/passwords.field_password_hint",
|
|
28
|
+
count: @minimum_password_length
|
|
29
|
+
),
|
|
30
|
+
required: true,
|
|
31
|
+
autofocus: true,
|
|
32
|
+
autocomplete: "new-password",
|
|
33
|
+
minlength: @minimum_password_length,
|
|
34
|
+
value: ""
|
|
35
|
+
) %>
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
<%= form.field_control_password(
|
|
38
|
+
:password_confirmation,
|
|
39
|
+
icon: "key",
|
|
40
|
+
label: I18n.t(
|
|
41
|
+
"lesli_shield.devise/passwords.field_password_confirmation"
|
|
42
|
+
),
|
|
43
|
+
required: true,
|
|
44
|
+
autocomplete: "new-password",
|
|
45
|
+
minlength: @minimum_password_length,
|
|
46
|
+
value: ""
|
|
47
|
+
) %>
|
|
32
48
|
|
|
33
|
-
|
|
49
|
+
<%= form.field_control_button(
|
|
50
|
+
I18n.t("lesli_shield.devise/passwords.button_update_password"),
|
|
51
|
+
{
|
|
52
|
+
class: "is-fullwidth",
|
|
53
|
+
data: {
|
|
54
|
+
turbo_submits_with: I18n.t(
|
|
55
|
+
"lesli_shield.devise/passwords.button_updating"
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
icon: "key"
|
|
60
|
+
) %>
|
|
61
|
+
<% end %>
|
|
34
62
|
|
|
35
|
-
<%= render(
|
|
63
|
+
<%= render(
|
|
64
|
+
"devise/shared/links",
|
|
65
|
+
login: true,
|
|
66
|
+
password_reset: false,
|
|
67
|
+
magic_link: false,
|
|
68
|
+
otp: false
|
|
69
|
+
) %>
|
|
36
70
|
<% end %>
|
|
@@ -1,33 +1,68 @@
|
|
|
1
1
|
|
|
2
|
-
<%= render(
|
|
2
|
+
<%= render(
|
|
3
|
+
"devise/shared/application-devise-simple",
|
|
4
|
+
title: I18n.t("lesli_shield.devise/passwords.view_request_title")
|
|
5
|
+
) do %>
|
|
3
6
|
|
|
4
7
|
<%= form_for(
|
|
5
|
-
resource,
|
|
6
|
-
as: resource_name,
|
|
7
|
-
url: user_password_path
|
|
8
|
-
html: { class: "
|
|
8
|
+
resource,
|
|
9
|
+
as: resource_name,
|
|
10
|
+
url: user_password_path,
|
|
11
|
+
html: { class: "text-left" },
|
|
9
12
|
builder: LesliView::Forms::Builder
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
13
|
+
) do |form| %>
|
|
14
|
+
|
|
15
|
+
<p class="mb-6 text-center text-sm leading-6 text-slate-600">
|
|
16
|
+
<%= I18n.t("lesli_shield.devise/passwords.view_request_description") %>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
20
|
+
|
|
21
|
+
<%= form.field_control_email(
|
|
22
|
+
:email,
|
|
23
|
+
icon: "mail",
|
|
24
|
+
label: I18n.t("lesli_shield.devise/passwords.field_email"),
|
|
25
|
+
required: true,
|
|
26
|
+
autofocus: true,
|
|
27
|
+
autocomplete: "email",
|
|
28
|
+
autocapitalize: "none",
|
|
29
|
+
spellcheck: false
|
|
30
|
+
) %>
|
|
31
|
+
|
|
32
|
+
<%= form.field_control_button(
|
|
33
|
+
I18n.t("lesli_shield.devise/passwords.button_send_instructions"),
|
|
34
|
+
{
|
|
35
|
+
class: "is-fullwidth",
|
|
36
|
+
data: {
|
|
37
|
+
turbo_submits_with: I18n.t(
|
|
38
|
+
"lesli_shield.devise/passwords.button_sending"
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
icon: "mail"
|
|
43
|
+
) %>
|
|
44
|
+
|
|
45
|
+
<% if Lesli.config.security.dig(:allow_registration) %>
|
|
46
|
+
<p class="mt-6 text-center text-sm text-slate-600">
|
|
47
|
+
<%= I18n.t(
|
|
48
|
+
"lesli_shield.devise/sessions.view_still_not_registered"
|
|
49
|
+
) %>
|
|
50
|
+
<%= link_to(
|
|
51
|
+
I18n.t(
|
|
52
|
+
"lesli_shield.devise/registrations.button_create_account"
|
|
53
|
+
),
|
|
54
|
+
new_user_registration_path,
|
|
55
|
+
class: "font-semibold text-[var(--lesli-color-primary)] underline underline-offset-2 hover:opacity-80 focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--lesli-color-primary)]"
|
|
56
|
+
) %>
|
|
57
|
+
</p>
|
|
30
58
|
<% end %>
|
|
59
|
+
<% end %>
|
|
31
60
|
|
|
32
|
-
<%= render(
|
|
61
|
+
<%= render(
|
|
62
|
+
"devise/shared/links",
|
|
63
|
+
login: true,
|
|
64
|
+
password_reset: false,
|
|
65
|
+
magic_link: false,
|
|
66
|
+
otp: false
|
|
67
|
+
) %>
|
|
33
68
|
<% end %>
|