Skip to content

Commit 7478d63

Browse files
committed
Add implementation for new IEmailSender<T>.
1 parent edb4bc5 commit 7478d63

File tree

4 files changed

+67
-38
lines changed

4 files changed

+67
-38
lines changed

Server/Components/Account/Pages/ForgotPassword.razor

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
private async Task OnValidSubmitAsync()
4141
{
4242
var user = await UserManager.FindByEmailAsync(Input.Email);
43-
if (user is null || !(await UserManager.IsEmailConfirmedAsync(user)))
43+
// if (user is null || !(await UserManager.IsEmailConfirmedAsync(user)))
44+
// Confirmation is currently disabled by default.
45+
if (user is null)
4446
{
4547
// Don't reveal that the user does not exist or is not confirmed
4648
RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation");

Server/Components/_Imports.razor

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,4 @@
2525
@using Remotely.Server.Components.TreeView
2626
@using Remotely.Server.Auth
2727
@using Remotely.Shared.Entities
28-
@using Remotely.Server.Models
29-
@using Remotely.Server.Enums;
28+
@using Remotely.Server.Models

Server/Program.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1+
using Immense.RemoteControl.Server.Extensions;
2+
using Immense.SimpleMessenger;
13
using Microsoft.AspNetCore.Authorization;
24
using Microsoft.AspNetCore.Components.Authorization;
35
using Microsoft.AspNetCore.Components.Server.Circuits;
46
using Microsoft.AspNetCore.HttpOverrides;
57
using Microsoft.AspNetCore.Identity;
68
using Microsoft.AspNetCore.Identity.UI.Services;
9+
using Microsoft.AspNetCore.RateLimiting;
710
using Microsoft.AspNetCore.StaticFiles;
811
using Microsoft.EntityFrameworkCore;
912
using Microsoft.Extensions.FileProviders;
1013
using Remotely.Server.Auth;
14+
using Remotely.Server.Components;
15+
using Remotely.Server.Components.Account;
1116
using Remotely.Server.Data;
17+
using Remotely.Server.Extensions;
1218
using Remotely.Server.Hubs;
19+
using Remotely.Server.Models;
20+
using Remotely.Server.Options;
1321
using Remotely.Server.Services;
14-
using System.Net;
15-
using Immense.RemoteControl.Server.Extensions;
1622
using Remotely.Server.Services.RcImplementations;
23+
using Remotely.Server.Services.Stores;
24+
using Remotely.Shared.Entities;
1725
using Remotely.Shared.Services;
1826
using Serilog;
19-
using Microsoft.AspNetCore.RateLimiting;
27+
using System.Net;
2028
using RatePolicyNames = Remotely.Server.RateLimiting.PolicyNames;
21-
using Remotely.Shared.Entities;
22-
using Immense.SimpleMessenger;
23-
using Remotely.Server.Services.Stores;
24-
using Remotely.Server.Components.Account;
25-
using Remotely.Server.Components;
26-
using Remotely.Server.Options;
27-
using Remotely.Server.Extensions;
28-
using Remotely.Server.Models;
2929

3030
var builder = WebApplication.CreateBuilder(args);
3131
var configuration = builder.Configuration;
@@ -57,19 +57,22 @@
5757
{
5858
case "sqlite":
5959
services.AddDbContext<AppDb, SqliteDbContext>(
60-
contextLifetime: ServiceLifetime.Transient,
60+
contextLifetime: ServiceLifetime.Transient,
6161
optionsLifetime: ServiceLifetime.Transient);
6262
break;
63+
6364
case "sqlserver":
6465
services.AddDbContext<AppDb, SqlServerDbContext>(
6566
contextLifetime: ServiceLifetime.Transient,
6667
optionsLifetime: ServiceLifetime.Transient);
6768
break;
69+
6870
case "postgresql":
6971
services.AddDbContext<AppDb, PostgreSqlDbContext>(
7072
contextLifetime: ServiceLifetime.Transient,
7173
optionsLifetime: ServiceLifetime.Transient);
7274
break;
75+
7376
default:
7477
throw new InvalidOperationException(
7578
$"Invalid DBProvider: {dbProvider}. Ensure a valid value " +
@@ -112,7 +115,6 @@
112115
.AddSignInManager()
113116
.AddDefaultTokenProviders();
114117

115-
116118
services.AddScoped<IAuthorizationHandler, TwoFactorRequiredHandler>();
117119
services.AddScoped<IAuthorizationHandler, OrganizationAdminRequirementHandler>();
118120
services.AddScoped<IAuthorizationHandler, ServerAdminRequirementHandler>();
@@ -154,7 +156,7 @@
154156

155157
services.AddCors(options =>
156158
{
157-
if (settings.TrustedCorsOrigins is { Count: > 0} trustedOrigins)
159+
if (settings.TrustedCorsOrigins is { Count: > 0 } trustedOrigins)
158160
{
159161
options.AddPolicy("TrustedOriginPolicy", builder => builder
160162
.WithOrigins(trustedOrigins.ToArray())
@@ -165,7 +167,6 @@
165167
}
166168
});
167169

168-
169170
services.Configure<ForwardedHeadersOptions>(options =>
170171
{
171172
options.ForwardedHeaders = ForwardedHeaders.All;
@@ -177,7 +178,7 @@
177178
options.KnownProxies.Add(dockerGatewayIp);
178179
}
179180

180-
if (settings.KnownProxies is { Count: >0 } knownProxies)
181+
if (settings.KnownProxies is { Count: > 0 } knownProxies)
181182
{
182183
foreach (var proxy in knownProxies)
183184
{
@@ -207,7 +208,7 @@
207208
{
208209
clOptions.QueueLimit = int.MaxValue;
209210

210-
clOptions.PermitLimit =
211+
clOptions.PermitLimit =
211212
settings.MaxConcurrentUpdates <= 0 ?
212213
10 :
213214
settings.MaxConcurrentUpdates;
@@ -222,6 +223,7 @@
222223
}
223224
else
224225
{
226+
services.AddScoped<IEmailSender<RemotelyUser>, EmailSenderEx>();
225227
services.AddScoped<IEmailSenderEx, EmailSenderEx>();
226228
}
227229
services.AddSingleton<IAppDbFactory, AppDbFactory>();
@@ -367,13 +369,12 @@ void ConfigureSerilog(WebApplicationBuilder webAppBuilder, SettingsModel setting
367369
{
368370
try
369371
{
370-
371372
var dataRetentionDays = settings.DataRetentionInDays;
372373
if (dataRetentionDays <= 0)
373374
{
374375
dataRetentionDays = 7;
375376
}
376-
377+
377378
var logPath = LogsManager.DefaultLogsDirectory;
378379

379380
void ApplySharedLoggerConfig(LoggerConfiguration loggerConfiguration)

Server/Services/EmailSender.cs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
using MailKit.Net.Smtp;
2-
using MailKit.Security;
2+
using Microsoft.AspNetCore.Identity;
33
using Microsoft.AspNetCore.Identity.UI.Services;
4-
using Microsoft.Build.Framework;
5-
using Microsoft.Extensions.Logging;
6-
using Microsoft.Identity.Client;
74
using MimeKit;
85
using MimeKit.Text;
9-
using NuGet.Configuration;
10-
using System;
11-
using System.Net;
12-
using System.Threading.Tasks;
6+
using Remotely.Shared.Entities;
137

148
namespace Remotely.Server.Services;
159

1610
public interface IEmailSenderEx
1711
{
1812
Task<bool> SendEmailAsync(string email, string replyTo, string subject, string htmlMessage, string? organizationID = null);
13+
1914
Task<bool> SendEmailAsync(string email, string subject, string htmlMessage, string? organizationID = null);
2015
}
2116

@@ -34,7 +29,7 @@ public Task SendEmailAsync(string email, string subject, string htmlMessage)
3429
}
3530
}
3631

37-
public class EmailSenderEx : IEmailSenderEx
32+
public class EmailSenderEx : IEmailSenderEx, IEmailSender<RemotelyUser>
3833
{
3934
private readonly IDataService _dataService;
4035
private readonly ILogger<EmailSenderEx> _logger;
@@ -46,11 +41,22 @@ public EmailSenderEx(
4641
_dataService = dataService;
4742
_logger = logger;
4843
}
44+
45+
public async Task SendConfirmationLinkAsync(RemotelyUser user, string email, string confirmationLink)
46+
{
47+
await SendEmailAsync(
48+
email,
49+
"Remotely Account Confirmation",
50+
"Please confirm your Remotely account by clicking the following link: " +
51+
$"<a href=\"{confirmationLink}\">{confirmationLink}</a>",
52+
user.OrganizationID);
53+
}
54+
4955
public async Task<bool> SendEmailAsync(
50-
string toEmail,
51-
string replyTo,
52-
string subject,
53-
string htmlMessage,
56+
string toEmail,
57+
string replyTo,
58+
string subject,
59+
string htmlMessage,
5460
string? organizationID = null)
5561
{
5662
try
@@ -68,7 +74,7 @@ public async Task<bool> SendEmailAsync(
6874
};
6975

7076
using var client = new SmtpClient();
71-
77+
7278
if (!string.IsNullOrWhiteSpace(settings.SmtpLocalDomain))
7379
{
7480
client.LocalDomain = settings.SmtpLocalDomain;
@@ -103,7 +109,28 @@ public async Task<bool> SendEmailAsync(string email, string subject, string html
103109
var settings = await _dataService.GetSettings();
104110
return await SendEmailAsync(email, settings.SmtpEmail, subject, htmlMessage, organizationID);
105111
}
112+
113+
public async Task SendPasswordResetCodeAsync(RemotelyUser user, string email, string resetCode)
114+
{
115+
await SendEmailAsync(
116+
email,
117+
"Remotely Password Reset",
118+
$"A password reset code has been requested for your account. Reset Code: {resetCode}",
119+
user.OrganizationID);
120+
}
121+
122+
public async Task SendPasswordResetLinkAsync(RemotelyUser user, string email, string resetLink)
123+
{
124+
await SendEmailAsync(
125+
email,
126+
"Remotely Password Reset",
127+
"A password reset has been requested for your account. If this was not requested by you, you can ignore this email.<br/><br/>" +
128+
"Otherwise, please follow this link to reset your password: " +
129+
$"<a href=\"{resetLink}\">{resetLink}</a>",
130+
user.OrganizationID);
131+
}
106132
}
133+
107134
public class EmailSenderFake(ILogger<EmailSenderFake> _logger) : IEmailSenderEx
108135
{
109136
public Task<bool> SendEmailAsync(string email, string replyTo, string subject, string htmlMessage, string? organizationID = null)
@@ -112,8 +139,8 @@ public Task<bool> SendEmailAsync(string email, string replyTo, string subject, s
112139
"Fake EmailSender registered in dev mode. " +
113140
"Email would have been sent to {email}." +
114141
"\n\nSubject: {EmailSubject}. " +
115-
"\n\nMessage: {EmailMessage}",
116-
email,
142+
"\n\nMessage: {EmailMessage}",
143+
email,
117144
subject,
118145
htmlMessage);
119146
return Task.FromResult(true);

0 commit comments

Comments
 (0)