lesli_shield 1.0.3 → 1.0.4
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/assets/stylesheets/lesli_shield/confirmations.css +18732 -0
- data/app/assets/stylesheets/lesli_shield/passwords.css +2 -238
- data/app/assets/stylesheets/lesli_shield/registrations.css +2 -238
- data/app/assets/stylesheets/lesli_shield/sessions.css +2 -238
- data/app/controllers/lesli_shield/dashboards_controller.rb +1 -8
- data/app/controllers/lesli_shield/invites_controller.rb +80 -0
- data/app/controllers/lesli_shield/role/actions_controller.rb +32 -20
- data/app/controllers/lesli_shield/roles_controller.rb +16 -8
- data/app/controllers/lesli_shield/sessions_controller.rb +5 -8
- data/app/controllers/lesli_shield/user/roles_controller.rb +62 -0
- data/app/controllers/lesli_shield/users_controller.rb +57 -20
- data/app/controllers/users/confirmations_controller.rb +42 -8
- data/app/controllers/users/passwords_controller.rb +52 -37
- data/app/controllers/users/registrations_controller.rb +2 -8
- data/app/controllers/users/sessions_controller.rb +57 -50
- data/app/helpers/lesli_shield/invites_helper.rb +4 -0
- data/app/helpers/lesli_shield/user/roles_helper.rb +4 -0
- data/app/interfaces/lesli_shield/authorization_interface.rb +8 -2
- data/app/mailers/lesli_shield/devise_mailer.rb +98 -0
- data/app/mailers/lesli_shield/invitation.html.erb +23 -0
- data/app/models/concerns/lesli_shield/user_security.rb +222 -0
- data/app/models/lesli_shield/account.rb +1 -1
- data/app/models/lesli_shield/dashboard.rb +1 -4
- data/app/models/lesli_shield/invite.rb +24 -0
- data/{lib/vue/confirmations.js → app/models/lesli_shield/role/action.rb} +17 -10
- data/{db/migrate/v1/0801003010_create_lesli_shield_dashboards.rb → app/models/lesli_shield/role/privilege.rb} +5 -4
- data/app/models/lesli_shield/user/role.rb +8 -0
- data/app/models/lesli_shield/user/session.rb +80 -0
- data/app/services/lesli_shield/invite_service.rb +43 -0
- data/app/services/lesli_shield/role_action_service.rb +118 -0
- data/app/services/lesli_shield/role_privilege_service.rb +112 -0
- data/app/{operators/lesli_shield/user_registration_operator.rb → services/lesli_shield/user_registration_service.rb} +26 -29
- data/app/services/lesli_shield/user_session_service.rb +78 -0
- data/app/services/lesli_shield/user_validator_service.rb +221 -0
- data/app/views/devise/confirmations/show.html.erb +4 -6
- data/app/views/devise/passwords/edit.html.erb +1 -2
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/new.html.erb +5 -4
- data/app/views/devise/sessions/new.html.erb +3 -2
- data/app/views/devise/shared/_application-devise-simple.erb +59 -0
- data/app/views/devise/shared/_application-devise.html.erb +76 -0
- data/app/views/lesli_shield/dashboards/_component-calendar.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-chart-bar.html.erb +6 -0
- data/app/views/lesli_shield/dashboards/_component-chart-line.html.erb +8 -0
- data/app/views/lesli_shield/dashboards/_component-count.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-date.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-weather.html.erb +1 -0
- data/app/views/lesli_shield/invites/_form.html.erb +10 -0
- data/app/views/lesli_shield/invites/_invite.html.erb +2 -0
- data/app/views/lesli_shield/invites/edit.html.erb +12 -0
- data/app/views/lesli_shield/invites/index.html.erb +66 -0
- data/{db/migrate/v1/0801001710_create_lesli_shield_settings.rb → app/views/lesli_shield/invites/new.html.erb} +9 -10
- data/{lib/vue/apps/dashboards/components/engine-version.vue → app/views/lesli_shield/invites/show.html.erb} +26 -43
- data/app/views/lesli_shield/partials/_navigation.html.erb +2 -4
- data/app/views/lesli_shield/{roles/_form-privileges.html.erb → role/actions/_form.html.erb} +5 -30
- data/app/views/lesli_shield/role/actions/index.html.erb +14 -0
- data/app/views/lesli_shield/roles/index.html.erb +2 -6
- data/app/views/lesli_shield/roles/new.html.erb +0 -11
- data/app/views/lesli_shield/roles/show.html.erb +5 -8
- data/app/views/lesli_shield/user/roles/_form.html.erb +17 -0
- data/app/views/lesli_shield/user/roles/_role.html.erb +2 -0
- data/app/views/lesli_shield/user/roles/edit.html.erb +12 -0
- data/app/views/lesli_shield/user/roles/index.html.erb +16 -0
- data/app/views/lesli_shield/user/roles/new.html.erb +11 -0
- data/app/views/lesli_shield/user/roles/show.html.erb +10 -0
- data/app/views/lesli_shield/users/{_viewer-activities.html.erb → _activities-viewer.html.erb} +2 -4
- data/app/views/lesli_shield/users/_information-card.html.erb +3 -3
- data/app/views/lesli_shield/users/_management-privileges.html.erb +74 -0
- data/app/views/lesli_shield/users/_management-security.html.erb +5 -0
- data/app/views/lesli_shield/users/index.html.erb +3 -7
- data/app/views/lesli_shield/users/new.html.erb +5 -11
- data/app/views/lesli_shield/users/show.html.erb +7 -5
- data/config/initializers/devise.rb +305 -304
- data/config/locales/translations.en.yml +4 -1
- data/config/locales/translations.es.yml +4 -1
- data/config/locales/translations.it.yml +4 -1
- data/config/routes.rb +7 -8
- data/db/migrate/v1/0801100210_create_lesli_shield_role_actions.rb +48 -0
- data/db/migrate/v1/0801100410_create_lesli_shield_role_privileges.rb +45 -0
- data/db/migrate/v1/0801110110_create_lesli_shield_user_roles.rb +43 -0
- data/db/migrate/v1/0801111210_create_lesli_shield_user_sessions.rb +56 -0
- data/db/migrate/v1/0801120110_create_lesli_shield_invites.rb +49 -0
- data/lib/lesli_shield/router.rb +21 -0
- data/lib/lesli_shield/version.rb +2 -2
- data/lib/lesli_shield.rb +1 -1
- data/lib/scss/confirmations.scss +24 -24
- data/lib/tasks/lesli_shield_tasks.rake +1 -1
- data/readme.md +59 -20
- metadata +57 -33
- data/app/controllers/lesli_shield/dashboard/components_controller.rb +0 -60
- data/app/models/lesli_shield/dashboard/component.rb +0 -18
- data/app/views/lesli_shield/dashboards/edit.html.erb +0 -1
- data/app/views/lesli_shield/dashboards/index.html.erb +0 -9
- data/app/views/lesli_shield/dashboards/new.html.erb +0 -1
- data/app/views/lesli_shield/dashboards/show.html.erb +0 -1
- data/app/views/lesli_shield/roles/_session.html.erb +0 -2
- data/app/views/lesli_shield/roles/edit.html.erb +0 -12
- data/app/views/lesli_shield/roles/update.turbo_stream.erb +0 -3
- data/app/views/lesli_shield/users/update.turbo_stream.erb +0 -3
- data/lib/lesli_shield/routing.rb +0 -23
- data/lib/vue/application.js +0 -83
- data/lib/vue/apps/sessions/index.vue +0 -50
- data/lib/vue/passwords.js +0 -137
- data/lib/vue/registrations.js +0 -144
- data/lib/vue/sessions.js +0 -148
- data/lib/vue/stores/sessions.js +0 -43
- data/lib/vue/stores/translations.json +0 -162
- /data/app/views/lesli_shield/roles/{_form-information.html.erb → _form.html.erb} +0 -0
- /data/db/migrate/v1/{0801120310_create_lesli_shield_user_shortcuts.rb → 0801111010_create_lesli_shield_user_shortcuts.rb} +0 -0
- /data/db/migrate/v1/{0801120410_create_lesli_shield_user_tokens.rb → 0801111110_create_lesli_shield_user_tokens.rb} +0 -0
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
Lesli
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
8
|
+
|
|
9
|
+
This program is free software: you can redistribute it and/or modify
|
|
10
|
+
it under the terms of the GNU General Public License as published by
|
|
11
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
(at your option) any later version.
|
|
13
|
+
|
|
14
|
+
This program is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
GNU General Public License for more details.
|
|
18
|
+
|
|
19
|
+
You should have received a copy of the GNU General Public License
|
|
20
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
21
|
+
|
|
22
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
23
|
+
|
|
24
|
+
Made with ♥ by LesliTech
|
|
25
|
+
Building a better future, one line of code at a time.
|
|
26
|
+
|
|
27
|
+
@contact hello@lesli.tech
|
|
28
|
+
@website https://www.lesli.tech
|
|
29
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
30
|
+
|
|
31
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
32
|
+
// ·
|
|
33
|
+
=end
|
|
2
34
|
class Users::ConfirmationsController < Devise::ConfirmationsController
|
|
3
35
|
|
|
4
36
|
def show
|
|
@@ -23,22 +55,24 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
|
|
|
23
55
|
end
|
|
24
56
|
|
|
25
57
|
# register a log with a validation atempt for the user
|
|
26
|
-
|
|
58
|
+
log = user.log(engine: LesliShield, source: self.class.name, action: action_name, operation: "user_confirmation", description: "Confirmation process started")
|
|
27
59
|
|
|
28
|
-
|
|
29
|
-
|
|
60
|
+
# create a new instance of the registration service
|
|
61
|
+
registration_service = LesliShield::UserRegistrationService.new(user)
|
|
30
62
|
|
|
31
63
|
# confirm the user
|
|
32
|
-
|
|
64
|
+
registration_service.confirm
|
|
65
|
+
|
|
66
|
+
# send a welcome email to user as is confirmed
|
|
67
|
+
LesliShield::DeviseMailer.with(user: resource).welcome.deliver_later
|
|
33
68
|
|
|
34
69
|
# let the user knows that the confirmation is done
|
|
35
70
|
flash[:success] = I18n.t("core.users/confirmations.messages_success_email_updated")
|
|
36
71
|
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
registration_operator.create_account if user.account.blank?
|
|
40
|
-
#Thread.new { registration_operator.create_account } if user.account.blank?
|
|
72
|
+
# setup the new account
|
|
73
|
+
registration_service.create_account if user.account.blank?
|
|
41
74
|
|
|
75
|
+
log.update(description: 'User confirmed successfully') if defined?(LesliAudit)
|
|
42
76
|
end
|
|
43
77
|
|
|
44
78
|
|
|
@@ -1,66 +1,81 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
=begin
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
def create
|
|
7
|
-
begin
|
|
5
|
+
Lesli
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
#Account::Activity.log("core", "/password/create", "password_creation_failed", "no_valid_email")
|
|
11
|
-
raise(I18n.t("core.shared.messages_warning_user_not_found"))
|
|
12
|
-
end
|
|
7
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
This program is free software: you can redistribute it and/or modify
|
|
10
|
+
it under the terms of the GNU General Public License as published by
|
|
11
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
(at your option) any later version.
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
This program is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
GNU General Public License for more details.
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# email: (params[:user][:email] || "")
|
|
24
|
-
# })
|
|
25
|
-
raise(I18n.t("core.shared.messages_warning_user_not_found"))
|
|
26
|
-
end
|
|
19
|
+
You should have received a copy of the GNU General Public License
|
|
20
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
23
|
+
|
|
24
|
+
Made with ♥ by LesliTech
|
|
25
|
+
Building a better future, one line of code at a time.
|
|
26
|
+
|
|
27
|
+
@contact hello@lesli.tech
|
|
28
|
+
@website https://www.lesli.tech
|
|
29
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
30
|
+
|
|
31
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
32
|
+
// ·
|
|
33
|
+
=end
|
|
34
|
+
|
|
35
|
+
class Users::PasswordsController < Devise::PasswordsController
|
|
36
|
+
|
|
37
|
+
# Sends an email with a token, so the user can reset their password
|
|
38
|
+
def create
|
|
39
|
+
self.resource = resource_class.send_reset_password_instructions(resource_params)
|
|
40
|
+
|
|
41
|
+
user = self.resource
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
if successfully_sent?(resource)
|
|
35
44
|
|
|
36
|
-
user.
|
|
45
|
+
user.log(
|
|
46
|
+
:engine => LesliShield,
|
|
47
|
+
:source => self.class.name,
|
|
48
|
+
:action => action_name,
|
|
49
|
+
:operation => 'password_reset',
|
|
50
|
+
:description => 'Reset password instructions sent'
|
|
51
|
+
)
|
|
37
52
|
|
|
38
|
-
Lesli::DeviseMailer.reset_password_instructions(user, token).deliver_now
|
|
39
53
|
success(I18n.t("core.users/passwords.messages_success"))
|
|
40
54
|
redirect_to(new_user_password_path)
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
danger(
|
|
55
|
+
else
|
|
56
|
+
#respond_with(resource)
|
|
57
|
+
danger("Error sending reset password instructions")
|
|
44
58
|
redirect_to(new_user_password_path)
|
|
45
59
|
end
|
|
46
60
|
end
|
|
47
61
|
|
|
48
62
|
def update
|
|
49
|
-
super do |
|
|
63
|
+
super do |user|
|
|
50
64
|
|
|
51
|
-
logs =
|
|
65
|
+
logs = user.log(engine: LesliShield, source: self.class.name, action: action_name, operation: 'password_update', description:"Password update attempt")
|
|
52
66
|
|
|
53
67
|
# check if password update was ok
|
|
54
|
-
if
|
|
68
|
+
if user.errors.empty?
|
|
55
69
|
|
|
56
70
|
# reset password expiration due the user just updated his password
|
|
57
|
-
if
|
|
58
|
-
|
|
71
|
+
if user.has_expired_password?
|
|
72
|
+
user.update(password_expiration_at: nil)
|
|
59
73
|
end
|
|
60
74
|
|
|
61
|
-
logs
|
|
75
|
+
logs&.update(description: "Password update successful")
|
|
62
76
|
else
|
|
63
|
-
|
|
77
|
+
danger(user.errors.full_messages.to_sentence)
|
|
78
|
+
logs&.update(description: resource.errors.full_messages.to_sentence)
|
|
64
79
|
end
|
|
65
80
|
end
|
|
66
81
|
end
|
|
@@ -43,6 +43,7 @@ class Users::RegistrationsController < Devise::RegistrationsController
|
|
|
43
43
|
|
|
44
44
|
def create
|
|
45
45
|
begin
|
|
46
|
+
|
|
46
47
|
# Check if instance allow multi-account
|
|
47
48
|
if !Lesli.config.security.dig(:allow_registration)
|
|
48
49
|
raise(I18n.t("core.users/registrations.messages_error_registration_not_allowed"))
|
|
@@ -51,16 +52,9 @@ class Users::RegistrationsController < Devise::RegistrationsController
|
|
|
51
52
|
# build new user
|
|
52
53
|
user = build_resource(sign_up_params)
|
|
53
54
|
|
|
54
|
-
# run password complexity validations
|
|
55
|
-
#user_validator = UsersValidator.new(user).password_complexity(sign_up_params[:password])
|
|
56
|
-
|
|
57
|
-
# return if there are errors with the complexity validations
|
|
58
|
-
# unless user_validator.valid?
|
|
59
|
-
# return respond_with_error("password_complexity_error", password_complexity.failures)
|
|
60
|
-
# end
|
|
61
|
-
|
|
62
55
|
# persist new user
|
|
63
56
|
if user.save
|
|
57
|
+
user.log(engine: LesliShield, source: self.class.name, action: action_name, operation: 'user_creation', description: 'User creation successfully')
|
|
64
58
|
success("Account created, check your email")
|
|
65
59
|
else
|
|
66
60
|
raise(user.errors.full_messages.to_sentence)
|
|
@@ -30,85 +30,92 @@ Building a better future, one line of code at a time.
|
|
|
30
30
|
// ·
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
|
-
#require "uri"
|
|
34
|
-
|
|
35
33
|
class Users::SessionsController < Devise::SessionsController
|
|
36
34
|
|
|
37
|
-
# Creates a new session for the user and allows them access to the platform
|
|
35
|
+
# Creates a new session for the user and allows them access to the platform.
|
|
36
|
+
#
|
|
37
|
+
# Devise provides extension points such as Warden hooks and a custom FailureApp
|
|
38
|
+
# to modify the authentication flow. However, in this case we need full and
|
|
39
|
+
# explicit control over each step of the login process, including validation,
|
|
40
|
+
# logging, session creation, and redirection.
|
|
41
|
+
#
|
|
42
|
+
# For that reason, the default Devise session logic is intentionally overridden
|
|
43
|
+
# and reimplemented here. While this approach is less conventional and may
|
|
44
|
+
# introduce compatibility risks with future Devise releases, it provides a
|
|
45
|
+
# predictable and fully controlled authentication pipeline, which is important
|
|
46
|
+
# for the needs of this framework.
|
|
47
|
+
#
|
|
48
|
+
# This trade-off is accepted as part of the framework’s lifecycle: any
|
|
49
|
+
# incompatibilities introduced by Devise updates will be addressed and
|
|
50
|
+
# maintained as needed.
|
|
38
51
|
def create
|
|
39
52
|
|
|
40
|
-
#
|
|
41
|
-
|
|
53
|
+
# Use guarden to check if the users credetials are valid
|
|
54
|
+
self.resource = warden.authenticate(auth_options)
|
|
42
55
|
|
|
43
|
-
# respond with a no valid credentials generic error if
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
# respond with a no valid credentials generic error if warden
|
|
57
|
+
# cannot validate the user
|
|
58
|
+
unless resource
|
|
59
|
+
danger(I18n.t("lesli_shield.devise/sessions.message_not_valid_credentials"))
|
|
60
|
+
redirect_to user_session_path(r: sign_in_params[:redirect]) and return
|
|
47
61
|
end
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
activity = user.activities.new({ title: "session_create", description:"atempt" })
|
|
63
|
+
user = resource
|
|
51
64
|
|
|
52
|
-
# check
|
|
53
|
-
unless user.
|
|
65
|
+
# check if user has a valid account
|
|
66
|
+
unless user.account
|
|
67
|
+
danger(I18n.t("lesli_shield.devise/sessions.message_not_confirmed_account"))
|
|
68
|
+
redirect_to user_session_path(r: sign_in_params[:redirect]) and return
|
|
69
|
+
end
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
activity.update(description: "invalid_credentials")
|
|
71
|
+
log = nil
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
# Save a log for the current login attempt
|
|
74
|
+
log = user.log(
|
|
75
|
+
engine: LesliShield,
|
|
76
|
+
source: self.class.name,
|
|
77
|
+
action: action_name,
|
|
78
|
+
operation: 'session_new',
|
|
79
|
+
description: 'Session creation attempt'
|
|
80
|
+
) if defined?(LesliAudit)
|
|
62
81
|
|
|
63
82
|
# check if user meet requirements to create a new session
|
|
64
|
-
|
|
83
|
+
LesliShield::UserValidatorService.new(user).valid? do |valid, failures|
|
|
65
84
|
|
|
66
85
|
# if user do not meet requirements to login
|
|
67
86
|
unless valid
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
redirect_to user_session_path(:
|
|
88
|
+
failures_string = failures.join(", ")
|
|
89
|
+
danger(failures_string)
|
|
90
|
+
log.update(description: failures_string) if log
|
|
91
|
+
redirect_to user_session_path(r: sign_in_params[:redirect]) and return
|
|
73
92
|
end
|
|
74
93
|
end
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
# remember the user (not enabled by default)
|
|
78
|
-
# remember_me(user) if sign_in_params[:remember_me] == '1'
|
|
79
|
-
|
|
80
|
-
|
|
81
95
|
# create a new session for the user
|
|
82
|
-
current_session =
|
|
83
|
-
.create(get_user_agent(false)
|
|
96
|
+
current_session = LesliShield::UserSessionService.new(user)
|
|
97
|
+
.create(request.remote_ip, (get_user_agent(false) if log))
|
|
84
98
|
.result
|
|
85
99
|
|
|
86
100
|
# make session id globally available
|
|
87
101
|
session[:user_session_id] = current_session[:id]
|
|
88
102
|
|
|
89
|
-
# create a new multi factor authentication service instance for the current user
|
|
90
|
-
#mfa_service = User::MfaService.new(user, log)
|
|
91
|
-
|
|
92
|
-
# generate a new mfa for the current session (if enabled)
|
|
93
|
-
#mfa_service.generate do |success|
|
|
94
|
-
# mfa was successfully generated, return the user to the mfa page
|
|
95
|
-
# return respond_with_successful({ default_path: "mfa" }) if success
|
|
96
|
-
#end
|
|
97
|
-
|
|
98
103
|
# do a user login
|
|
99
|
-
sign_in(
|
|
104
|
+
sign_in(resource_name, user)
|
|
100
105
|
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
})
|
|
106
|
+
# update logs with a successful login
|
|
107
|
+
log.update(
|
|
108
|
+
description: "Session creation successful",
|
|
109
|
+
session_id: current_session[:id]
|
|
110
|
+
) if log
|
|
107
111
|
|
|
108
112
|
# respond successful and send the path user should go
|
|
109
|
-
#respond_with_successful({ default_path: user.has_role_with_default_path?() })
|
|
110
|
-
#respond_with_successful({ default_path: Lesli.config.path_after_login || "/" })
|
|
111
|
-
redirect_to
|
|
113
|
+
# respond_with_successful({ default_path: user.has_role_with_default_path?() })
|
|
114
|
+
# respond_with_successful({ default_path: Lesli.config.path_after_login || "/" })
|
|
115
|
+
redirect_to safe_redirect_path(sign_in_params[:redirect])
|
|
116
|
+
|
|
117
|
+
# Save the user_agent for every new session
|
|
118
|
+
log_devices if log
|
|
112
119
|
end
|
|
113
120
|
|
|
114
121
|
private
|
|
@@ -27,12 +27,18 @@ module LesliShield
|
|
|
27
27
|
|
|
28
28
|
# privilege for object not found
|
|
29
29
|
if granted.blank?
|
|
30
|
-
|
|
30
|
+
log(
|
|
31
|
+
:operation => :authorize_request,
|
|
32
|
+
:description => "Privilege not found for: #{request.path}"
|
|
33
|
+
)
|
|
31
34
|
return respond_with_unauthorized({ controller: params[:controller], action: params[:action] })
|
|
32
35
|
end
|
|
33
36
|
|
|
34
37
|
unless granted
|
|
35
|
-
|
|
38
|
+
log(
|
|
39
|
+
:operation => :authorize_request,
|
|
40
|
+
:description => "Privilege not granted for: #{request.path}"
|
|
41
|
+
)
|
|
36
42
|
return respond_with_unauthorized({ controller: params[:controller], action: params[:action] })
|
|
37
43
|
end
|
|
38
44
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
|
|
3
|
+
Lesli
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
19
|
+
|
|
20
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
|
+
|
|
22
|
+
Made with ♥ by LesliTech
|
|
23
|
+
Building a better future, one line of code at a time.
|
|
24
|
+
|
|
25
|
+
@contact hello@lesli.tech
|
|
26
|
+
@website https://www.lesli.tech
|
|
27
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
28
|
+
|
|
29
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
|
+
// ·
|
|
31
|
+
=end
|
|
32
|
+
module LesliShield
|
|
33
|
+
class DeviseMailer < Lesli::ApplicationLesliMailer
|
|
34
|
+
|
|
35
|
+
# Sends an email with instructions to allow the user reset the password
|
|
36
|
+
def reset_password_instructions(user, token, opts = {})
|
|
37
|
+
|
|
38
|
+
# defaults for new accounts/users
|
|
39
|
+
email_template = "devise/reset_password_instructions"
|
|
40
|
+
email_subject = I18n.t("core.users/confirmations.mailer_email_verification")
|
|
41
|
+
|
|
42
|
+
# email parameters
|
|
43
|
+
params = {
|
|
44
|
+
url: build_url("/password/edit", { reset_password_token: token}),
|
|
45
|
+
full_name: user.full_name
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# send email
|
|
49
|
+
email(
|
|
50
|
+
params,
|
|
51
|
+
to: user.email,
|
|
52
|
+
subject: email_subject,
|
|
53
|
+
template_name: email_template
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Sends an email to allow the user confirm the email address
|
|
58
|
+
def confirmation_instructions(user, token, opts = {})
|
|
59
|
+
|
|
60
|
+
# defaults for new accounts/users
|
|
61
|
+
email_template = "devise/confirmation_instructions"
|
|
62
|
+
email_subject = I18n.t("core.users/confirmations.mailer_email_verification")
|
|
63
|
+
|
|
64
|
+
# # custom email and subject if user is changin his email address
|
|
65
|
+
# if !record.unconfirmed_email.blank?
|
|
66
|
+
# email_template = "update_email_confirmation_instructions"
|
|
67
|
+
# email_subject = I18n.t("core.users/confirmations.mailer_confirmation_instructions_subject")
|
|
68
|
+
# end
|
|
69
|
+
|
|
70
|
+
# Depending on wheter there is a new user or they are changing their email,
|
|
71
|
+
# one or another field will be used
|
|
72
|
+
email_recipient = user.unconfirmed_email || user.email
|
|
73
|
+
|
|
74
|
+
# email parameters
|
|
75
|
+
params = {
|
|
76
|
+
url: build_url("/confirmation", { confirmation_token: token})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# send email
|
|
80
|
+
email(
|
|
81
|
+
params,
|
|
82
|
+
to: email_recipient,
|
|
83
|
+
subject: email_subject,
|
|
84
|
+
template_name: email_template
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def welcome(user)
|
|
89
|
+
email_recipient = user.unconfirmed_email || user.email
|
|
90
|
+
email(
|
|
91
|
+
{ :user => user },
|
|
92
|
+
to: email_recipient,
|
|
93
|
+
subject: "test",
|
|
94
|
+
template_name: "devise/welcome"
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!doctype html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"><head><title></title><!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]--><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style type="text/css">#outlook a { padding:0; }
|
|
2
|
+
body { margin:0;padding:0;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%; }
|
|
3
|
+
table, td { border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt; }
|
|
4
|
+
img { border:0;height:auto;line-height:100%; outline:none;text-decoration:none;-ms-interpolation-mode:bicubic; }
|
|
5
|
+
p { display:block;margin:13px 0; }</style><!--[if mso]>
|
|
6
|
+
<noscript>
|
|
7
|
+
<xml>
|
|
8
|
+
<o:OfficeDocumentSettings>
|
|
9
|
+
<o:AllowPNG/>
|
|
10
|
+
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
11
|
+
</o:OfficeDocumentSettings>
|
|
12
|
+
</xml>
|
|
13
|
+
</noscript>
|
|
14
|
+
<![endif]--><!--[if lte mso 11]>
|
|
15
|
+
<style type="text/css">
|
|
16
|
+
.mj-outlook-group-fix { width:100% !important; }
|
|
17
|
+
</style>
|
|
18
|
+
<![endif]--><!--[if !mso]><!--><link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css"><style type="text/css">@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);</style><!--<![endif]--><style type="text/css">@media only screen and (min-width:480px) {
|
|
19
|
+
.mj-column-per-100 { width:100% !important; max-width: 100%; }
|
|
20
|
+
}</style><style media="screen and (min-width:480px)">.moz-text-html .mj-column-per-100 { width:100% !important; max-width: 100%; }</style><style type="text/css">@media only screen and (max-width:479px) {
|
|
21
|
+
table.mj-full-width-mobile { width: 100% !important; }
|
|
22
|
+
td.mj-full-width-mobile { width: auto !important; }
|
|
23
|
+
}</style><style type="text/css"></style></head><body style="word-spacing:normal;background-color:#ebecf0;"><div style="background-color:#ebecf0;"><!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="margin:0px auto;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="center" style="font-size:0px;padding:0px;padding-top:60px;padding-bottom:0px;padding-left:5px;word-break:break-word;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;"><tbody><tr><td style="width:125px;"><img src="https://cdn.lesli.tech/leslicloud/brand/app-logo.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="125" height="auto"></td></tr></tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--><div style="height:5px;line-height:5px;"> </div><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#4a5056;"><h1>Welcome to The Lesli Family!</h1></div><!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" bgcolor="#ffffff" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="background:#ffffff;background-color:#ffffff;margin:0px auto;border-radius:15px;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;border-radius:15px;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:40px;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:520px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="center" style="font-size:0px;padding:0px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#4a5056;"><h2><raw><% name = @data.dig(:user, :full_name) %></raw><raw><%= !name.blank? ? "Hi #{name.strip}." : nil %></raw></h2></div></td></tr><tr><td style="background:#95a3ab;font-size:0px;word-break:break-word;"><div style="height:2px;line-height:2px;"> </div></td></tr><tr><td style="font-size:0px;word-break:break-word;"><div style="height:5px;line-height:5px;"> </div></td></tr><tr><td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:18px;line-height:1.4;text-align:center;color:#4a5056;"><p>You have been invitated to Lesli, please confirm your email address by clicking the button below:</p></div></td></tr><tr><td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;"><tbody><tr><td align="center" bgcolor="#eef6fc" role="presentation" style="border:1px solid #209cee;border-radius:5px;cursor:auto;mso-padding-alt:10px;background:#eef6fc;" valign="middle"><a href="<%= url_for(@app[:host] + @data[:url]) %>" style="display:inline-block;background:#eef6fc;color:#209cee;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:17px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px;mso-padding-alt:0px;border-radius:5px;" target="_blank">Confirm my account</a></td></tr></tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--><div style="height:30px;line-height:30px;"> </div><!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="margin:0px auto;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:18px;font-weight:600;line-height:1;text-align:center;color:#444444;">¡Siguenos!</div></td></tr><tr><td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"><table cellpadding="0" cellspacing="0" width="300" border="0" style="color:#000000;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:22px;table-layout:auto;width:300px;border:none;"><tr><td align="center"><img width="45px" alt="Facebook" src="https://cdn.lesli.tech/leslicloud/emails/social-facebook.png"></td><td align="center"><img width="45px" alt="Twitter" src="https://cdn.lesli.tech/leslicloud/emails/social-twitter.png"></td><td align="center"><img width="45px" alt="Instagram" src="https://cdn.lesli.tech/leslicloud/emails/social-instagram.png"></td><td align="center"><img width="45px" alt="Linkedin" src="https://cdn.lesli.tech/leslicloud/emails/social-linkedin.png"></td></tr></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="margin:0px auto;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:18px;font-weight:600;line-height:1;text-align:center;color:#444444;">Download our app</div></td></tr><tr><td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"><table cellpadding="0" cellspacing="0" width="100%" border="0" style="color:#000000;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:22px;table-layout:auto;width:100%;border:none;"><tr><td style="text-align: right; padding: 5px;"><a target="blank" href="https://apps.apple.com/us/app/lesli/id1595893730"><img width="130px" alt="Appstore badge" src="https://cdn.lesli.tech/leslicloud/emails/appstore.png"></a></td><td style="text-align: left; padding: 5px;"><a target="blank" href="https://apps.apple.com/us/app/lesli/id1595893730"><img width="130px" alt="Playstore badge" src="https://cdn.lesli.tech/leslicloud/emails/playstore.png"></a></td></tr></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--><div style="height:10px;line-height:10px;"> </div><!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" role="presentation" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style="margin:0px auto;max-width:600px;"><table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"><tbody><tr><td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;"><!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]--><div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"><table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"><tbody><tr><td align="center" style="font-size:0px;padding:4px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#666666;">Copyright © <%= Time.new.year %> LesliTech</div></td></tr><tr><td align="center" style="font-size:0px;padding:4px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#666666;">Ciudad de Guatemala, Guatemala.</div></td></tr><tr><td align="center" style="font-size:0px;padding:4px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#666666;">All rights reserved.</div></td></tr><tr><td align="center" style="font-size:0px;padding:4px;padding-top:20px;word-break:break-word;"><div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:center;color:#666666;">The Lesli Team</div></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></div></body></html>
|