Password reset implemented partialy
This commit is contained in:
parent
45defd7903
commit
5b019bc953
8 changed files with 187 additions and 11 deletions
|
@ -18,5 +18,6 @@ public enum AuditLogType
|
|||
DisableTotp,
|
||||
AddDomainRecord,
|
||||
UpdateDomainRecord,
|
||||
DeleteDomainRecord
|
||||
DeleteDomainRecord,
|
||||
PasswordReset
|
||||
}
|
|
@ -52,12 +52,14 @@ public class MailService
|
|||
try
|
||||
{
|
||||
using var client = new SmtpClient();
|
||||
|
||||
|
||||
client.Host = Server;
|
||||
client.Port = Port;
|
||||
client.EnableSsl = true;
|
||||
client.EnableSsl = false;
|
||||
client.Credentials = new NetworkCredential(Email, Password);
|
||||
|
||||
Logger.Debug("Sending");
|
||||
|
||||
await client.SendMailAsync(new MailMessage()
|
||||
{
|
||||
From = new MailAddress(Email),
|
||||
|
@ -75,6 +77,8 @@ public class MailService
|
|||
Logger.Warn("Error sending mail");
|
||||
Logger.Warn(e);
|
||||
}
|
||||
|
||||
Logger.Debug("Mail send task stopped");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using JWT.Builder;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Exceptions;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Services.LogServices;
|
||||
|
@ -142,20 +143,27 @@ public class UserService
|
|||
}
|
||||
}
|
||||
|
||||
public async Task ChangePassword(User user, string password)
|
||||
public async Task ChangePassword(User user, string password, bool isSystemAction = false)
|
||||
{
|
||||
user.Password = BCrypt.Net.BCrypt.HashPassword(password);
|
||||
user.TokenValidTime = DateTime.Now;
|
||||
UserRepository.Update(user);
|
||||
|
||||
await MailService.SendMail(user!, "passwordChange", values =>
|
||||
if (isSystemAction)
|
||||
{
|
||||
values.Add("Ip", IdentityService.GetIp());
|
||||
values.Add("Device", IdentityService.GetDevice());
|
||||
values.Add("Location", "In your walls");
|
||||
});
|
||||
await AuditLogService.LogSystem(AuditLogType.ChangePassword, user.Email);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MailService.SendMail(user!, "passwordChange", values =>
|
||||
{
|
||||
values.Add("Ip", IdentityService.GetIp());
|
||||
values.Add("Device", IdentityService.GetDevice());
|
||||
values.Add("Location", "In your walls");
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.ChangePassword, user.Email);
|
||||
await AuditLogService.Log(AuditLogType.ChangePassword, user.Email);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<User> SftpLogin(int id, string password)
|
||||
|
@ -197,4 +205,29 @@ public class UserService
|
|||
|
||||
return token;
|
||||
}
|
||||
|
||||
public async Task ResetPassword(string email)
|
||||
{
|
||||
email = email.ToLower();
|
||||
|
||||
var user = UserRepository
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Email == email);
|
||||
|
||||
if (user == null)
|
||||
throw new DisplayException("A user with this email can not be found");
|
||||
|
||||
var newPassword = StringHelper.GenerateString(16);
|
||||
await ChangePassword(user, newPassword, true);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.PasswordReset);
|
||||
|
||||
await MailService.SendMail(user, "passwordReset", values =>
|
||||
{
|
||||
values.Add("Ip", IdentityService.GetIp());
|
||||
values.Add("Device", IdentityService.GetDevice());
|
||||
values.Add("Location", "In your walls");
|
||||
values.Add("Password", newPassword);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -72,7 +72,7 @@
|
|||
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
|
||||
<div></div>
|
||||
|
||||
<a href="/reset-password" class="link-primary">
|
||||
<a href="/passwordreset" class="link-primary">
|
||||
<TL>Forgot password?</TL>
|
||||
</a>
|
||||
</div>
|
||||
|
|
73
Moonlight/Shared/Components/Auth/PasswordReset.razor
Normal file
73
Moonlight/Shared/Components/Auth/PasswordReset.razor
Normal file
|
@ -0,0 +1,73 @@
|
|||
@page "/passwordreset"
|
||||
@using Moonlight.App.Services
|
||||
|
||||
@* This is just a "virtual" route/page. The handling for that is
|
||||
@* MainLayout doing for us. We need to put that here so the router
|
||||
@* does not return the 404 page
|
||||
*@
|
||||
|
||||
@inject UserService UserService
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
|
||||
<div class="d-flex flex-center">
|
||||
<div class="card rounded-3 w-md-550px">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-center flex-column-fluid pb-15 pb-lg-20">
|
||||
@if (Send)
|
||||
{
|
||||
<div class="text-center mb-11">
|
||||
<h1 class="text-dark fw-bolder mb-3">
|
||||
<TL>Passwort reset successfull. Check your mail</TL>
|
||||
</h1>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="form w-100 fv-plugins-bootstrap5 fv-plugins-framework" novalidate="novalidate">
|
||||
<div class="text-center mb-11">
|
||||
<h1 class="text-dark fw-bolder mb-3">
|
||||
<TL>Password reset</TL>
|
||||
</h1>
|
||||
<div class="text-gray-500 fw-semibold fs-6">
|
||||
<TL>Reset the password of your account</TL>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fv-row mb-8 fv-plugins-icon-container">
|
||||
<input @bind="Email" type="email" placeholder="@(SmartTranslateService.Translate("Email"))" name="email" class="form-control bg-transparent">
|
||||
</div>
|
||||
|
||||
<div class="d-grid mb-10">
|
||||
<WButton Text="@(SmartTranslateService.Translate("Reset password"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Working"))"
|
||||
CssClasses="btn-primary"
|
||||
OnClick="Submit">
|
||||
</WButton>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-500 text-center fw-semibold fs-6">
|
||||
<TL>Wrong here?</TL>
|
||||
|
||||
<a href="/login" class="link-primary">
|
||||
<TL>Sign in</TL>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private string Email = "";
|
||||
private bool Send = false;
|
||||
|
||||
private async Task Submit()
|
||||
{
|
||||
await UserService.ResetPassword(Email);
|
||||
Send = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
|
@ -62,6 +62,7 @@
|
|||
<PageErrorBoundary>
|
||||
<SoftErrorBoundary>
|
||||
@if (uri.LocalPath != "/login" &&
|
||||
uri.LocalPath != "/passwordreset" &&
|
||||
uri.LocalPath != "/register")
|
||||
{
|
||||
if (User == null)
|
||||
|
@ -94,6 +95,10 @@
|
|||
{
|
||||
<Register></Register>
|
||||
}
|
||||
else if (uri.LocalPath == "/passwordreset")
|
||||
{
|
||||
<PasswordReset></PasswordReset>
|
||||
}
|
||||
}
|
||||
</SoftErrorBoundary>
|
||||
</PageErrorBoundary>
|
||||
|
|
|
@ -323,3 +323,9 @@ None;None
|
|||
No user with this id found;No user with this id found
|
||||
Back to list;Back to list
|
||||
New domain;New domain
|
||||
Reset password;Reset password
|
||||
Password reset;Password reset
|
||||
Reset the password of your account;Reset the password of your account
|
||||
Wrong here?;Wrong here?
|
||||
A user with this email can not be found;A user with this email can not be found
|
||||
Passwort reset successfull. Check your mail;Passwort reset successfull. Check your mail
|
||||
|
|
54
Moonlight/resources/mail/passwordReset.html
Normal file
54
Moonlight/resources/mail/passwordReset.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Moonlight password reset</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="background-color:#ffffff; padding: 45px 0 34px 0; border-radius: 24px; margin:40px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" height="auto"
|
||||
style="border-collapse:collapse">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="center" style="text-align:center; padding-bottom: 10px">
|
||||
<div style="text-align:center; margin:0 15px 34px 15px">
|
||||
<div style="margin-bottom: 10px">
|
||||
<a href="https://endelon-hosting.de" rel="noopener" target="_blank">
|
||||
<img alt="Logo" src="https://moonlight.endelon-hosting.de/assets/media/logo/MoonFullText.png" style="height: 35px">
|
||||
</a>
|
||||
</div>
|
||||
<div style="font-size: 14px; font-weight: 500; margin-bottom: 27px; font-family:Arial,Helvetica,sans-serif;">
|
||||
<p style="margin-bottom:9px; color:#181C32; font-size: 22px; font-weight:700">Hey {{FirstName}}, your password has been resetted</p>
|
||||
<p style="margin-bottom:2px; color:#7E8299">Your new password is: <b>{{Password}}</b></p>
|
||||
<p style="margin-bottom:2px; color:#7E8299">If this was not you please contact us. Also here is the data we collected.</p>
|
||||
<p style="margin-bottom:2px; color:#7E8299">IP: {{Ip}}</p>
|
||||
<p style="margin-bottom:2px; color:#7E8299">Device: {{Device}}</p>
|
||||
<p style="margin-bottom:2px; color:#7E8299">Location: {{Location}}</p>
|
||||
</div>
|
||||
<a href="https://moonlight.endelon-hosting.de" target="_blank"
|
||||
style="background-color:#50cd89; border-radius:6px;display:inline-block; padding:11px 19px; color: #FFFFFF; font-size: 14px; font-weight:500;">Open Moonlight
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="center"
|
||||
style="font-size: 13px; text-align:center; padding: 0 10px 10px 10px; font-weight: 500; color: #A1A5B7; font-family:Arial,Helvetica,sans-serif">
|
||||
<p style="color:#181C32; font-size: 16px; font-weight: 600; margin-bottom:9px">You need help?</p>
|
||||
<p style="margin-bottom:2px">We are happy to help!</p>
|
||||
<p style="margin-bottom:4px">More information at
|
||||
<a href="https://endelon.link/support" rel="noopener" target="_blank" style="font-weight: 600">endelon.link/support</a>.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="center"
|
||||
style="font-size: 13px; padding:0 15px; text-align:center; font-weight: 500; color: #A1A5B7;font-family:Arial,Helvetica,sans-serif">
|
||||
<p>Copyright 2022 Endelon Hosting </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue