From badf91fc0f43eec83a6bc5ae18c24c87b4ab4dec Mon Sep 17 00:00:00 2001 From: Paul Scharnofske Date: Fri, 3 Apr 2020 17:03:38 +0200 Subject: [PATCH 01/16] Add flow for forgot password --- .DS_Store | Bin 0 -> 8194 bytes docs/.DS_Store | Bin 0 -> 6147 bytes docs/defaults/.DS_Store | Bin 0 -> 6147 bytes docs/defaults/src/.DS_Store | Bin 0 -> 6147 bytes docs/defaults/src/WebApp/.DS_Store | Bin 0 -> 6147 bytes src/.DS_Store | Bin 0 -> 8192 bytes src/Domain/Entities/EmailSettings.cs | 12 +++ .../Common/Interfaces/IEmailSender.cs | 10 +++ src/Infrastructure/DependencyInjection.cs | 7 +- src/Infrastructure/Infrastructure.csproj | 16 ++-- src/Infrastructure/Services/EmailSender.cs | 55 ++++++++++++ src/WebApp/.DS_Store | Bin 0 -> 8195 bytes .../Pages/Account/Forgot-Password.cshtml | 30 +++++++ .../Pages/Account/Forgot-Password.cshtml.cs | 53 ++++++++++++ src/WebApp/Pages/Account/Login.cshtml | 1 + .../Pages/Account/Reset-Password.cshtml | 34 ++++++++ .../Pages/Account/Reset-Password.cshtml.cs | 81 ++++++++++++++++++ 17 files changed, 291 insertions(+), 8 deletions(-) create mode 100644 .DS_Store create mode 100644 docs/.DS_Store create mode 100644 docs/defaults/.DS_Store create mode 100644 docs/defaults/src/.DS_Store create mode 100644 docs/defaults/src/WebApp/.DS_Store create mode 100644 src/.DS_Store create mode 100644 src/Domain/Entities/EmailSettings.cs create mode 100644 src/Infrastructure/Common/Interfaces/IEmailSender.cs create mode 100644 src/Infrastructure/Services/EmailSender.cs create mode 100644 src/WebApp/.DS_Store create mode 100644 src/WebApp/Pages/Account/Forgot-Password.cshtml create mode 100644 src/WebApp/Pages/Account/Forgot-Password.cshtml.cs create mode 100644 src/WebApp/Pages/Account/Reset-Password.cshtml create mode 100644 src/WebApp/Pages/Account/Reset-Password.cshtml.cs diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3463b2e5b308b9d3581f6c3cbfdd22ae39937ec8 GIT binary patch literal 8194 zcmeHMO=}ZT6upzCb`pyQv9wr_*(feTNr_rP3Tc`yy6^*2R8VO%NoWQpGa;EYXiUk% z{s(p8PSC#~2;$CP;I@Jb_wLp6J~Dloq{Wq}eXqmKr8S!D1di1E9N2Z zePPwLRzNFoEEQnqgN2J>PGVmmKRQtH6aW}UH!o=Oul_)bbpUe``vTE}VhAcwPz{-4 z7&3D(1ReIA^zRE4bTatN7)Q=*$PC4hiHBivcQSGUb*&Z93XCeia`!kb&^9>~MDq9R zuwDAe3n!i$_)&=h{58R`sf|{ZS`qHs2sasW9n9sC4|a8!W6VZ4Q{e1Si^}k>jCk)I z?d@(a7R!FU!BVBahf2}a5U%mVB?A*tdabA_*@M_f5*)nX>d0OS`cChvm z_7Gqz|VuVMJ{;}O}=9!H3o5v=7Sg2o5kw6606Y9?z9?mm!Is0 z>$HMQ=Ccu-h)r!Og<{s{7x|_1?^V8)O^71ZkK|ZE!!Ku?}qJ?eb=dWHdAL; zeJ?0EUbV@|PNfQ$hxZ(>;&<|X+pDzrI7MMF&4iiQOwDz>+3c0HmCa^)X{)=mlu28c zvsZh)ggJX*ad~~K{`g7vX>a!hlMhF`JnHGRxDV@>XodS5j&t2rZEA$STuaaFi3o?> zx_=PcarWV;?z07i+?`_6bA4|ceQcd4=qBBw4O&Ok*M?(A>{(D_lb}1ahR;HQZU7gk zPL*K>e-c#21U?&0Do4E76EMc>KaIH5K#g~7X89X5kQO!CUw3QsGTNc_Al9Q+HPW$* zA28@()JU8s#c78+@&p>}NmZkvc&clr>HBZssaVx@zutI1IERKj4%R;2LtQ^j?_&a8 zv;s#eFd?jSEc;(O{MY{@$IwQtfL7q&R=|iCiiJG(F!;I^-44sNEnHi;SYdvBft-Sh pC*we#j03}e7ou&!m2q+s`vTE}^2dJ$uraBr-~U{ET^(BmegSja$5;RW literal 0 HcmV?d00001 diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bbc3b61b95454786757fd86d969eda5923d803e6 GIT binary patch literal 6147 zcmeHK&2AGh5FV!ioFG9CNc89n5{C$-TA&A1X%)($H>5>y0MzcXfv&V&N7+py2toTA z@CG~zPr&2AH@2x#rCe!+W~A{q_RQGvw~l{^NR8+D4$**!G?cN^LvewypLIhzp`{B{ zu8%pD)KGm;+IJh#(r^_S;BTiXrwP5Ml-9mqR@w|cUKmfH_kTHobwPZ#sHY+RM>Z{s zx*3grs?JvT+VvY+_jSMjHaWJ7q)D53Jx*t@x%ND5jz?i%4z`!eD0(zBQ8Zc&&2o2lG&B#R$E#IO z-@Ui9cW`v_@ze72>dRL*6H-{WPHqSM1K(h5@N$~Ws?t^;;N!eoj<-{ASCXYEoxrNF z{vW`~`9HA6;djKZbBL;lFdz&F1DC}>*!uL%%lZK_t}q}BTv-Nqe=tzSIAH71Z5=4w z3joNsNGGuQ#>hD)U>vaZ2oFU0RG?2);f0}mI@(Q$ivzYEeLAV|_E2GD6&@(cjgJ0} z3nvwOlu{TF2F^3E<*Nfe|DXN+`F}o1YQlgp@Lw^Yy8Frg7*h&o>&E2xtToUhC=186 m9?w!>xT6@cd=zg(ouJ*Y0gMB-9?=4ki-4m+3Sr=%GVmK*zHiO| literal 0 HcmV?d00001 diff --git a/docs/defaults/.DS_Store b/docs/defaults/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..16c8f7af9ca7aecef92a210d5524ff6825e2c5f0 GIT binary patch literal 6147 zcmeHKPiqrF6rX9fb`lE)5n4RWMeq=0!>T=qu*USzo3Nq>m3B89nuX0y$Zi@mrtHD9 zc&!J|`V~BS^Aq@O)c0my(}bs)y*Gb;!_Mq5#&~BEw;5|P#sny$(}3a} zK|g9m)~IC@kn27ai&=j!RlO*!MB4_-fMwucV*tP14R(hev7GhT()X((@ZhoV0QB}R zEnrom)5CVqQ^S$=vGwcKh@t9sqg3}NHa~s+`R?YoN9RSwe-SkrERW{mpf#BJnDxx5 zvzYZ4@GQ@oqM~U&qPcvJMro24uKR)oHv>tgFx`{CZf@b#P7+xhVcE)ot{IAOJ1BRqwVV9@GT_rm#b z=2_l@_n#MgKzT!T#(mYh%DKdGDeov4XQ|2#q2+XT=(Tbw7@#c^S1-kE?IbM&mVt|8 z0M7>ris%!T2KCVag?<45I?${IZ2V`y97*UCmIlEC!c8imN#*py;3gf~CB^xKr9qR< zIK4eMjm+tR!u9CTztrK3`vz@k8L$kjGEg(sCf@(Me}4Y2CfS;0z%uY(F~FT}(CxsI z=x(hn4)0nCdH{-oaiu|>0tH>i+Q6%L8&nJUBpQG|VQCOrKO()N*wY$q{?VPe9CXmDHpmAd+3$==ZtWm^ANQyG zji=it&4W1Yk8E-r^&#ZrZk$GD+BK6j8ryz+*Pv8Q)%F{!vsq_jqp3UX*1V}_o13ks ze$jb3pV!p0wf5_sgW=~dv*Y>KQ@aWw;d{06gzyH=z$mRTIcocdW|+Bv>dCL|L(}UK z2P!`Qe)aA7#nxg>^w*edaCaPy!_bpvZdm0RDjklfEXtDRB(CyD%gbgSZATw&F$MHw+ZJ0JVShZ&c;*f z!XA{EH$i^M>z_jP3+LPKaFSUy@#B0?CV5uX{r(TtT5I3Adr#}G?snfqCw3OqaXqa@ zad|**dvSe|`1qBz`9&Njud{S^6g+%ki#pDVv}AHNPBGY3r7zv!9y_IAH#o(!KZ79IU)WAJ?U_`~Vh{L|v|7ghii{{Gn>cwE9) z46fDZV^kKoE$Dx;Xb(a9*U nad<(&fRAF#rK5Nqoek>^1&E=?#v#_A$%g>TAcZLKM-})9?=EtQ literal 0 HcmV?d00001 diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..05723999d7596de1c247510db5a12640544a15e8 GIT binary patch literal 8192 zcmeI1&u-H|5XNWQ5S$c24oJ;$FGw76NM)c0gk(ZEJyQJF12?6^Oq*qW#4Ff zX66QzA)Y9va|)<{iVbf&VF_3QmVhN-30MOE0|C6VWplQ?_w}l^mVhPDNCNWtz|p08 zMoX>g(E+1M0B8%-s$q;eK*eyQp3zdP3dK2f^}tLhGbIMo;aKO=9qJh^wd!zUI-Hof zGBXtlQ&&eESMJ0-t=3usmcS+fS-T(5W18WURO^n4#F34 zv^eeEej?H$h|?%j!SOVL%d3+(or=Xs%+qPE&g1I^$LTno(_VkMblv*{?z+R(fG>}a zhXa1keXv?}oWnauk0xiA?>{U*u0DNH`4BUY7P_U6*Y@l7Y~T4=nuzo*JY;m6#@P9| z#2!dYb$;Kl{wKeR?~YQdvAZ&MM_FE( zbB%4APAH;K-`6#kpKB~DzB|gUl4Fe(aM)%EG>pK$&bKdX|EJsc{u@TcrfUf_ivVkl z{qYDn|Nik?PhZyA9Q_PkHtAPtRUt5{6o;x(9J>Cq5MvHk8RHo(wPFVCpKk)FI>)~M K6?|(NOW+r7Ct#%j literal 0 HcmV?d00001 diff --git a/src/Domain/Entities/EmailSettings.cs b/src/Domain/Entities/EmailSettings.cs new file mode 100644 index 0000000..5562b49 --- /dev/null +++ b/src/Domain/Entities/EmailSettings.cs @@ -0,0 +1,12 @@ +namespace Codidact.Authentication.Domain.Entities +{ + public class EmailSettings + { + public string Host { get; set; } + public int Port { get; set; } + public string SenderName { get; set; } + public string Sender { get; set; } + public string Password { get; set; } + public bool EnableSsl { get; set; } + } +} diff --git a/src/Infrastructure/Common/Interfaces/IEmailSender.cs b/src/Infrastructure/Common/Interfaces/IEmailSender.cs new file mode 100644 index 0000000..73d6b6a --- /dev/null +++ b/src/Infrastructure/Common/Interfaces/IEmailSender.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Codidact.Authentication.Infrastructure.Common.Interfaces +{ + public interface IEmailSender + { + Task SendEmailAsync(string email, string subject, string message); + Task SendResetPassword(string email, string token, string returnUrl); + } +} diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs index ce8467b..d5b9f39 100644 --- a/src/Infrastructure/DependencyInjection.cs +++ b/src/Infrastructure/DependencyInjection.cs @@ -45,7 +45,8 @@ public static IServiceCollection AddInfrastructure( options.Password.RequireUppercase = false; }) .AddEntityFrameworkStores() - .AddSignInManager(); + .AddSignInManager() + .AddDefaultTokenProviders(); var identityServerBuilder = services.AddIdentityServer() .AddInMemoryClients(configuration.GetSection("IdentityServer:Clients")) @@ -56,6 +57,10 @@ public static IServiceCollection AddInfrastructure( { identityServerBuilder.AddDeveloperSigningCredential(); } + services.AddSingleton(configuration + .GetSection("EmailConfiguration") + .Get()); + services.AddScoped, EmailSender>(); services.AddAuthentication() .AddIdentityCookies(); diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj index 24477fd..35edfc7 100644 --- a/src/Infrastructure/Infrastructure.csproj +++ b/src/Infrastructure/Infrastructure.csproj @@ -5,13 +5,15 @@ Codidact.Authentication.Infrastructure - - - - - - - + + + + + + + + + diff --git a/src/Infrastructure/Services/EmailSender.cs b/src/Infrastructure/Services/EmailSender.cs new file mode 100644 index 0000000..534a298 --- /dev/null +++ b/src/Infrastructure/Services/EmailSender.cs @@ -0,0 +1,55 @@ +using MailKit.Net.Smtp; +using MimeKit; +using MimeKit.Text; +using System.Threading.Tasks; +using System.Web; +using System; + +using Codidact.Authentication.Infrastructure.Common.Interfaces; +using Codidact.Authentication.Domain.Entities; +using Microsoft.Extensions.DependencyInjection; + +namespace Codidact.Authentication.Infrastructure.Services +{ + public class EmailSender : IEmailSender + { + private EmailSettings _emailConfiguration; + private IServiceProvider _secretsService; + public EmailSender(EmailSettings emailConfiguration, IServiceProvider secretsService) + { + _emailConfiguration = emailConfiguration; + _secretsService = secretsService; + } + public async Task SendEmailAsync(string email, string subject, string textMessage) + { + var message = new MimeMessage(); + message.From.Add(new MailboxAddress(_emailConfiguration.SenderName, _emailConfiguration.Sender)); + message.To.Add(new MailboxAddress("Username", email)); + message.Subject = subject; + + message.Body = new TextPart(TextFormat.Html) + { + Text = textMessage + }; + var secrets = _secretsService.GetService(); + //Be careful that the SmtpClient class is the one from Mailkit not the framework! + using (var emailClient = new SmtpClient()) + { + emailClient.Connect(_emailConfiguration.Host, _emailConfiguration.Port, _emailConfiguration.EnableSsl); + + emailClient.AuthenticationMechanisms.Remove("XOAUTH2"); + + emailClient.Authenticate(_emailConfiguration.Sender, secrets.Get("EmailConfiguration:SenderEmailPassword").GetAwaiter().GetResult()); + + await emailClient.SendAsync(message); + + emailClient.Disconnect(true); + } + + } + public async Task SendResetPassword(string email, string token, string returnUrl) + { + await SendEmailAsync(email, "Reset your Password", $"Click here to reset your password Test"); + } + } +} diff --git a/src/WebApp/.DS_Store b/src/WebApp/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c18c2bf4c689489584183c2cca9d9c3cf8fcfa93 GIT binary patch literal 8195 zcmeHMJ8u&~5T3OYa&d%60g6R+O(cpaiWNeTP$b7O66qot5s8PAyV!CJ_MPzqD>z0j zNKXlfl7@;J1PvX(AfiB`;|I`D0N*}r-=5D26(X=}?auo4o89kb=5}vvB4U|lK1Gxy zA`6wv=_xc3g^%+(RATDNEF^v(1;WOatxP6K_7X5(6Nv1dhfFKkl~Sq`lj_9O%1mV_Osoz)Tfm8>r8KRvfU&@^1$geBpn2r&C29oo z_w};BE{GUmq&?_+f5rCd5s{>I@U#fz`%?JlB@q{dg>ShA;!RqcA#W zu~)^x)up?-CD}oUtwL!$V=Mc@Rzg3>@Z8N$@xCS1=z!bssKzSx1(VV^ZIFYgC{R7b z>>Eadkq|&??C2V27Z?pPd~?{hp@tZ+j7DfomAbNW` zRoq`q#Qo5Havf$Jr{lKjRTaM<-D;^L)FXVRLPO|7hNSN0yZ_dAcCarffh)ImyT zKYly@J{ru$h+upM>0z2^daahgw@--oH&Ih@gSN6Rk`0;y8P!1k; zgrA#Kjf@YzZw2FH3K|8(QkCvO?m?$Ub#nA4fuN;D$Z6UH+ND+KsdXTEY=)n1z83}8 zo1m8XaI8-aeI2nE9D&yTlKhOhL-Pea^7Zojo=1jI17D0r>0U@%x+l0V2- zNB{hPGH=eXHWn}z_$>>tv1~4z0kro<5Z2 +
+

Forgot Password

+

Sometimes we forget our password but thats okay, we can help you out. Don't have an account? Sign up instead.

+
+ +
+ @if (Model.Sent == false) + { +
+
+ + +
+
+ + } + else + { +
+

Email has been sent to the provided email.

+
+ } +
+ diff --git a/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs b/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs new file mode 100644 index 0000000..e6e3121 --- /dev/null +++ b/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; + +using Codidact.Authentication.Domain.Entities; +using Codidact.Authentication.Infrastructure.Common.Interfaces; + +namespace Codidact.Authentication.WebApp.Pages.Account +{ + [BindProperties] + public class ForgotPasswordModel : PageModel + { + private readonly UserManager _userManager; + private readonly IEmailSender _emailService; + + public ForgotPasswordModel( + UserManager userManager, + IEmailSender emailService + ) + { + _userManager = userManager; + _emailService = emailService; + } + + [Required(ErrorMessage = "E-Mail Address is required")] + [DataType(DataType.EmailAddress)] + public string Email { get; set; } + + public bool Sent { get; set; } + + public async Task OnPostAsync() + { + if (ModelState.IsValid) + { + var user = await _userManager.FindByEmailAsync(Email); + if (user != null) + { + var token = await _userManager.GeneratePasswordResetTokenAsync(user); + await _emailService.SendResetPassword(Email, token, "http://localhost:8001/"); + Sent = true; + } + else + { + ModelState.AddModelError("Email", "No user found with this email"); + } + } + + return Page(); + } + } +} diff --git a/src/WebApp/Pages/Account/Login.cshtml b/src/WebApp/Pages/Account/Login.cshtml index 268a05b..a3f7ba8 100644 --- a/src/WebApp/Pages/Account/Login.cshtml +++ b/src/WebApp/Pages/Account/Login.cshtml @@ -5,6 +5,7 @@

Sign in

Welcome to Codidact! You can login to your account here. Don't have an account? Sign up instead.

+

Forgot your password? Click here to recover it.

diff --git a/src/WebApp/Pages/Account/Reset-Password.cshtml b/src/WebApp/Pages/Account/Reset-Password.cshtml new file mode 100644 index 0000000..8af7198 --- /dev/null +++ b/src/WebApp/Pages/Account/Reset-Password.cshtml @@ -0,0 +1,34 @@ +@page +@model ResetPasswordModel + +
+
+

Reset your password

+
+ + + + + + +
+
+
+
+ + +

Choose a strong one. At least 8 characters are recommended. Don't choose common words or names.

+
+ +
+ + +

We want to make sure, that you don't accidentally misspell your password.

+
+
+ +
+
+ diff --git a/src/WebApp/Pages/Account/Reset-Password.cshtml.cs b/src/WebApp/Pages/Account/Reset-Password.cshtml.cs new file mode 100644 index 0000000..49d84ad --- /dev/null +++ b/src/WebApp/Pages/Account/Reset-Password.cshtml.cs @@ -0,0 +1,81 @@ +using System.Web; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Codidact.Authentication.Domain.Entities; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace Codidact.Authentication.WebApp.Pages.Account +{ + + [BindProperties] + public class ResetPasswordModel : PageModel + { + + private readonly UserManager _userManager; + + public ResetPasswordModel( + UserManager userManager + ) + { + _userManager = userManager; + } + + [Required(ErrorMessage = "Password is required")] + [DataType(DataType.Password)] + public string Password { get; set; } + + [Required(ErrorMessage = "Password Confirmaton is required")] + [DataType(DataType.Password)] + public string ConfirmPassword { get; set; } + + [Required] + public string ReturnUrl { get; set; } = "/index"; + + [Required(ErrorMessage = "Invalid reset password form")] + public string Token { get; set; } + + [Required(ErrorMessage = "Invalid reset password form")] + public string Email { get; set; } + + public void OnGet([FromQuery] string token, [FromQuery]string returnUrl, [FromQuery]string email) + { + Token = token; + ReturnUrl = returnUrl; + Email = email; + } + + public async Task OnPostAsync() + { + if (!Password.Equals(ConfirmPassword, System.StringComparison.InvariantCulture)) + { + ModelState.AddModelError("ConfirmPassword", "Password and Password Confirmation must match"); + } + if (ModelState.IsValid) + { + var user = await _userManager.FindByEmailAsync(Email); + if (user == null) + { + ModelState.AddModelError("Email", "Email not found"); + } + else + { + var result = await _userManager.ResetPasswordAsync(user, HttpUtility.UrlDecode(Token), Password); + if (!result.Succeeded) + { + foreach (var error in result.Errors) + { + ModelState.AddModelError(error.Code, error.Description); + } + } + else + { + return RedirectToPage("Login"); + } + } + } + return Page(); + } + } +} From c91696228483b93e62909e2384711e7c97f7b853 Mon Sep 17 00:00:00 2001 From: weegee Date: Thu, 2 Apr 2020 23:37:17 +0530 Subject: [PATCH 02/16] Update gitignore --- .gitignore | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.gitignore b/.gitignore index 4d5aa7b..96cec59 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,31 @@ obj/ /.vs/ /.vscode/ *.user + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk From 0fd889a16c1e307a2498de9175252f5ab8a86240 Mon Sep 17 00:00:00 2001 From: weegee Date: Thu, 2 Apr 2020 23:38:40 +0530 Subject: [PATCH 03/16] Fix untracked files --- .DS_Store | Bin 8194 -> 0 bytes docs/.DS_Store | Bin 6147 -> 0 bytes docs/defaults/.DS_Store | Bin 6147 -> 0 bytes docs/defaults/src/.DS_Store | Bin 6147 -> 0 bytes docs/defaults/src/WebApp/.DS_Store | Bin 6147 -> 0 bytes src/.DS_Store | Bin 8192 -> 0 bytes src/WebApp/.DS_Store | Bin 8195 -> 0 bytes 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 docs/.DS_Store delete mode 100644 docs/defaults/.DS_Store delete mode 100644 docs/defaults/src/.DS_Store delete mode 100644 docs/defaults/src/WebApp/.DS_Store delete mode 100644 src/.DS_Store delete mode 100644 src/WebApp/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 3463b2e5b308b9d3581f6c3cbfdd22ae39937ec8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8194 zcmeHMO=}ZT6upzCb`pyQv9wr_*(feTNr_rP3Tc`yy6^*2R8VO%NoWQpGa;EYXiUk% z{s(p8PSC#~2;$CP;I@Jb_wLp6J~Dloq{Wq}eXqmKr8S!D1di1E9N2Z zePPwLRzNFoEEQnqgN2J>PGVmmKRQtH6aW}UH!o=Oul_)bbpUe``vTE}VhAcwPz{-4 z7&3D(1ReIA^zRE4bTatN7)Q=*$PC4hiHBivcQSGUb*&Z93XCeia`!kb&^9>~MDq9R zuwDAe3n!i$_)&=h{58R`sf|{ZS`qHs2sasW9n9sC4|a8!W6VZ4Q{e1Si^}k>jCk)I z?d@(a7R!FU!BVBahf2}a5U%mVB?A*tdabA_*@M_f5*)nX>d0OS`cChvm z_7Gqz|VuVMJ{;}O}=9!H3o5v=7Sg2o5kw6606Y9?z9?mm!Is0 z>$HMQ=Ccu-h)r!Og<{s{7x|_1?^V8)O^71ZkK|ZE!!Ku?}qJ?eb=dWHdAL; zeJ?0EUbV@|PNfQ$hxZ(>;&<|X+pDzrI7MMF&4iiQOwDz>+3c0HmCa^)X{)=mlu28c zvsZh)ggJX*ad~~K{`g7vX>a!hlMhF`JnHGRxDV@>XodS5j&t2rZEA$STuaaFi3o?> zx_=PcarWV;?z07i+?`_6bA4|ceQcd4=qBBw4O&Ok*M?(A>{(D_lb}1ahR;HQZU7gk zPL*K>e-c#21U?&0Do4E76EMc>KaIH5K#g~7X89X5kQO!CUw3QsGTNc_Al9Q+HPW$* zA28@()JU8s#c78+@&p>}NmZkvc&clr>HBZssaVx@zutI1IERKj4%R;2LtQ^j?_&a8 zv;s#eFd?jSEc;(O{MY{@$IwQtfL7q&R=|iCiiJG(F!;I^-44sNEnHi;SYdvBft-Sh pC*we#j03}e7ou&!m2q+s`vTE}^2dJ$uraBr-~U{ET^(BmegSja$5;RW diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index bbc3b61b95454786757fd86d969eda5923d803e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6147 zcmeHK&2AGh5FV!ioFG9CNc89n5{C$-TA&A1X%)($H>5>y0MzcXfv&V&N7+py2toTA z@CG~zPr&2AH@2x#rCe!+W~A{q_RQGvw~l{^NR8+D4$**!G?cN^LvewypLIhzp`{B{ zu8%pD)KGm;+IJh#(r^_S;BTiXrwP5Ml-9mqR@w|cUKmfH_kTHobwPZ#sHY+RM>Z{s zx*3grs?JvT+VvY+_jSMjHaWJ7q)D53Jx*t@x%ND5jz?i%4z`!eD0(zBQ8Zc&&2o2lG&B#R$E#IO z-@Ui9cW`v_@ze72>dRL*6H-{WPHqSM1K(h5@N$~Ws?t^;;N!eoj<-{ASCXYEoxrNF z{vW`~`9HA6;djKZbBL;lFdz&F1DC}>*!uL%%lZK_t}q}BTv-Nqe=tzSIAH71Z5=4w z3joNsNGGuQ#>hD)U>vaZ2oFU0RG?2);f0}mI@(Q$ivzYEeLAV|_E2GD6&@(cjgJ0} z3nvwOlu{TF2F^3E<*Nfe|DXN+`F}o1YQlgp@Lw^Yy8Frg7*h&o>&E2xtToUhC=186 m9?w!>xT6@cd=zg(ouJ*Y0gMB-9?=4ki-4m+3Sr=%GVmK*zHiO| diff --git a/docs/defaults/.DS_Store b/docs/defaults/.DS_Store deleted file mode 100644 index 16c8f7af9ca7aecef92a210d5524ff6825e2c5f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6147 zcmeHKPiqrF6rX9fb`lE)5n4RWMeq=0!>T=qu*USzo3Nq>m3B89nuX0y$Zi@mrtHD9 zc&!J|`V~BS^Aq@O)c0my(}bs)y*Gb;!_Mq5#&~BEw;5|P#sny$(}3a} zK|g9m)~IC@kn27ai&=j!RlO*!MB4_-fMwucV*tP14R(hev7GhT()X((@ZhoV0QB}R zEnrom)5CVqQ^S$=vGwcKh@t9sqg3}NHa~s+`R?YoN9RSwe-SkrERW{mpf#BJnDxx5 zvzYZ4@GQ@oqM~U&qPcvJMro24uKR)oHv>tgFx`{CZf@b#P7+xhVcE)ot{IAOJ1BRqwVV9@GT_rm#b z=2_l@_n#MgKzT!T#(mYh%DKdGDeov4XQ|2#q2+XT=(Tbw7@#c^S1-kE?IbM&mVt|8 z0M7>ris%!T2KCVag?<45I?${IZ2V`y97*UCmIlEC!c8imN#*py;3gf~CB^xKr9qR< zIK4eMjm+tR!u9CTztrK3`vz@k8L$kjGEg(sCf@(Me}4Y2CfS;0z%uY(F~FT}(CxsI z=x(hn4)0nCdH{-oaiu|>0tH>i+Q6%L8&nJUBpQG|VQCOrKO()N*wY$q{?VPe9CXmDHpmAd+3$==ZtWm^ANQyG zji=it&4W1Yk8E-r^&#ZrZk$GD+BK6j8ryz+*Pv8Q)%F{!vsq_jqp3UX*1V}_o13ks ze$jb3pV!p0wf5_sgW=~dv*Y>KQ@aWw;d{06gzyH=z$mRTIcocdW|+Bv>dCL|L(}UK z2P!`Qe)aA7#nxg>^w*edaCaPy!_bpvZdm0RDjklfEXtDRB(CyD%gbgSZATw&F$MHw+ZJ0JVShZ&c;*f z!XA{EH$i^M>z_jP3+LPKaFSUy@#B0?CV5uX{r(TtT5I3Adr#}G?snfqCw3OqaXqa@ zad|**dvSe|`1qBz`9&Njud{S^6g+%ki#pDVv}AHNPBGY3r7zv!9y_IAH#o(!KZ79IU)WAJ?U_`~Vh{L|v|7ghii{{Gn>cwE9) z46fDZV^kKoE$Dx;Xb(a9*U nad<(&fRAF#rK5Nqoek>^1&E=?#v#_A$%g>TAcZLKM-})9?=EtQ diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 05723999d7596de1c247510db5a12640544a15e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 zcmeI1&u-H|5XNWQ5S$c24oJ;$FGw76NM)c0gk(ZEJyQJF12?6^Oq*qW#4Ff zX66QzA)Y9va|)<{iVbf&VF_3QmVhN-30MOE0|C6VWplQ?_w}l^mVhPDNCNWtz|p08 zMoX>g(E+1M0B8%-s$q;eK*eyQp3zdP3dK2f^}tLhGbIMo;aKO=9qJh^wd!zUI-Hof zGBXtlQ&&eESMJ0-t=3usmcS+fS-T(5W18WURO^n4#F34 zv^eeEej?H$h|?%j!SOVL%d3+(or=Xs%+qPE&g1I^$LTno(_VkMblv*{?z+R(fG>}a zhXa1keXv?}oWnauk0xiA?>{U*u0DNH`4BUY7P_U6*Y@l7Y~T4=nuzo*JY;m6#@P9| z#2!dYb$;Kl{wKeR?~YQdvAZ&MM_FE( zbB%4APAH;K-`6#kpKB~DzB|gUl4Fe(aM)%EG>pK$&bKdX|EJsc{u@TcrfUf_ivVkl z{qYDn|Nik?PhZyA9Q_PkHtAPtRUt5{6o;x(9J>Cq5MvHk8RHo(wPFVCpKk)FI>)~M K6?|(NOW+r7Ct#%j diff --git a/src/WebApp/.DS_Store b/src/WebApp/.DS_Store deleted file mode 100644 index c18c2bf4c689489584183c2cca9d9c3cf8fcfa93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8195 zcmeHMJ8u&~5T3OYa&d%60g6R+O(cpaiWNeTP$b7O66qot5s8PAyV!CJ_MPzqD>z0j zNKXlfl7@;J1PvX(AfiB`;|I`D0N*}r-=5D26(X=}?auo4o89kb=5}vvB4U|lK1Gxy zA`6wv=_xc3g^%+(RATDNEF^v(1;WOatxP6K_7X5(6Nv1dhfFKkl~Sq`lj_9O%1mV_Osoz)Tfm8>r8KRvfU&@^1$geBpn2r&C29oo z_w};BE{GUmq&?_+f5rCd5s{>I@U#fz`%?JlB@q{dg>ShA;!RqcA#W zu~)^x)up?-CD}oUtwL!$V=Mc@Rzg3>@Z8N$@xCS1=z!bssKzSx1(VV^ZIFYgC{R7b z>>Eadkq|&??C2V27Z?pPd~?{hp@tZ+j7DfomAbNW` zRoq`q#Qo5Havf$Jr{lKjRTaM<-D;^L)FXVRLPO|7hNSN0yZ_dAcCarffh)ImyT zKYly@J{ru$h+upM>0z2^daahgw@--oH&Ih@gSN6Rk`0;y8P!1k; zgrA#Kjf@YzZw2FH3K|8(QkCvO?m?$Ub#nA4fuN;D$Z6UH+ND+KsdXTEY=)n1z83}8 zo1m8XaI8-aeI2nE9D&yTlKhOhL-Pea^7Zojo=1jI17D0r>0U@%x+l0V2- zNB{hPGH=eXHWn}z_$>>tv1~4z0kro<5Z2 Date: Thu, 2 Apr 2020 23:42:00 +0530 Subject: [PATCH 04/16] Remove unused property --- src/Domain/Entities/EmailSettings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Domain/Entities/EmailSettings.cs b/src/Domain/Entities/EmailSettings.cs index 5562b49..bedf865 100644 --- a/src/Domain/Entities/EmailSettings.cs +++ b/src/Domain/Entities/EmailSettings.cs @@ -6,7 +6,6 @@ public class EmailSettings public int Port { get; set; } public string SenderName { get; set; } public string Sender { get; set; } - public string Password { get; set; } public bool EnableSsl { get; set; } } } From b0a535392101a0bca622d7213c8a25f9b373035c Mon Sep 17 00:00:00 2001 From: weegee Date: Thu, 2 Apr 2020 23:44:12 +0530 Subject: [PATCH 05/16] Remove unnecessary comments --- src/Infrastructure/Services/EmailSender.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Infrastructure/Services/EmailSender.cs b/src/Infrastructure/Services/EmailSender.cs index 534a298..7508ad3 100644 --- a/src/Infrastructure/Services/EmailSender.cs +++ b/src/Infrastructure/Services/EmailSender.cs @@ -32,7 +32,6 @@ public async Task SendEmailAsync(string email, string subject, string textMessag Text = textMessage }; var secrets = _secretsService.GetService(); - //Be careful that the SmtpClient class is the one from Mailkit not the framework! using (var emailClient = new SmtpClient()) { emailClient.Connect(_emailConfiguration.Host, _emailConfiguration.Port, _emailConfiguration.EnableSsl); From 0a7de76f8618cb39072f0c2ddb52f339871e3c46 Mon Sep 17 00:00:00 2001 From: weegee Date: Fri, 3 Apr 2020 02:17:09 +0530 Subject: [PATCH 06/16] Made necessary changes Rename files and and adopted the options pattern. Remove the placeholder and place the username there. Added entry in appSettings.json file in docs and other changes --- .config/dotnet-tools.json | 12 +++++ docs/defaults/src/WebApp/appsettings.json | 45 ++++++++++--------- .../{EmailSettings.cs => MailOptions.cs} | 2 +- .../Common/Interfaces/IEmailSender.cs | 10 ----- .../Common/Interfaces/IMailService.cs | 12 +++++ src/Infrastructure/DependencyInjection.cs | 6 +-- .../{EmailSender.cs => MailService.cs} | 17 ++++--- .../Pages/Account/Forgot-Password.cshtml.cs | 6 +-- .../Pages/Account/Reset-Password.cshtml.cs | 2 +- src/WebApp/Startup.cs | 12 +++++ 10 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 .config/dotnet-tools.json rename src/Domain/Entities/{EmailSettings.cs => MailOptions.cs} (90%) delete mode 100644 src/Infrastructure/Common/Interfaces/IEmailSender.cs create mode 100644 src/Infrastructure/Common/Interfaces/IMailService.cs rename src/Infrastructure/Services/{EmailSender.cs => MailService.cs} (64%) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..ce5ccf9 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-format": { + "version": "3.3.111304", + "commands": [ + "dotnet-format" + ] + } + } +} \ No newline at end of file diff --git a/docs/defaults/src/WebApp/appsettings.json b/docs/defaults/src/WebApp/appsettings.json index 362d4b8..3333633 100644 --- a/docs/defaults/src/WebApp/appsettings.json +++ b/docs/defaults/src/WebApp/appsettings.json @@ -6,29 +6,32 @@ } }, "IdentityServer": { - "Clients": [ - { - "ClientId": "codidact_client", - "ClientSecrets": [ - { - "Value": "LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=" - } - ], - "AllowedGrantTypes": [ - "authorization_code" - ], - "AllowedScopes": [ - "openid", - "profile" - ], - "RedirectUris": [ - "http://localhost:8000/signin-oidc" - ], - "RequireConsent": false - } - ] + "Clients": [{ + "ClientId": "codidact_client", + "ClientSecrets": [{ + "Value": "LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=" + }], + "AllowedGrantTypes": [ + "authorization_code" + ], + "AllowedScopes": [ + "openid", + "profile" + ], + "RedirectUris": [ + "http://localhost:8000/signin-oidc" + ], + "RequireConsent": false + }] }, "ConnectionStrings": { "Authentication": "Data Source=authentication.db" + }, + "Mail": { + "Host": "smtp.gmail.com", + "Port": 465, + "Sender": "example@gmail.com", + "SenderName": "example", + "EnableSsl": true } } diff --git a/src/Domain/Entities/EmailSettings.cs b/src/Domain/Entities/MailOptions.cs similarity index 90% rename from src/Domain/Entities/EmailSettings.cs rename to src/Domain/Entities/MailOptions.cs index bedf865..4dcbee2 100644 --- a/src/Domain/Entities/EmailSettings.cs +++ b/src/Domain/Entities/MailOptions.cs @@ -1,6 +1,6 @@ namespace Codidact.Authentication.Domain.Entities { - public class EmailSettings + public class MailOptions { public string Host { get; set; } public int Port { get; set; } diff --git a/src/Infrastructure/Common/Interfaces/IEmailSender.cs b/src/Infrastructure/Common/Interfaces/IEmailSender.cs deleted file mode 100644 index 73d6b6a..0000000 --- a/src/Infrastructure/Common/Interfaces/IEmailSender.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; - -namespace Codidact.Authentication.Infrastructure.Common.Interfaces -{ - public interface IEmailSender - { - Task SendEmailAsync(string email, string subject, string message); - Task SendResetPassword(string email, string token, string returnUrl); - } -} diff --git a/src/Infrastructure/Common/Interfaces/IMailService.cs b/src/Infrastructure/Common/Interfaces/IMailService.cs new file mode 100644 index 0000000..7d84098 --- /dev/null +++ b/src/Infrastructure/Common/Interfaces/IMailService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Codidact.Authentication.Domain.Entities; + + +namespace Codidact.Authentication.Infrastructure.Common.Interfaces +{ + public interface IMailService + { + Task SendEmailAsync(ApplicationUser user, string subject, string message); + Task SendResetPassword(ApplicationUser user, string token, string returnUrl); + } +} diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs index d5b9f39..5c550e8 100644 --- a/src/Infrastructure/DependencyInjection.cs +++ b/src/Infrastructure/DependencyInjection.cs @@ -58,9 +58,9 @@ public static IServiceCollection AddInfrastructure( identityServerBuilder.AddDeveloperSigningCredential(); } services.AddSingleton(configuration - .GetSection("EmailConfiguration") - .Get()); - services.AddScoped, EmailSender>(); + .GetSection("Mail") + .Get()); + services.AddScoped(); services.AddAuthentication() .AddIdentityCookies(); diff --git a/src/Infrastructure/Services/EmailSender.cs b/src/Infrastructure/Services/MailService.cs similarity index 64% rename from src/Infrastructure/Services/EmailSender.cs rename to src/Infrastructure/Services/MailService.cs index 7508ad3..25a395a 100644 --- a/src/Infrastructure/Services/EmailSender.cs +++ b/src/Infrastructure/Services/MailService.cs @@ -7,24 +7,25 @@ using Codidact.Authentication.Infrastructure.Common.Interfaces; using Codidact.Authentication.Domain.Entities; + using Microsoft.Extensions.DependencyInjection; namespace Codidact.Authentication.Infrastructure.Services { - public class EmailSender : IEmailSender + public class MailService : IMailService { - private EmailSettings _emailConfiguration; + private MailOptions _emailConfiguration; private IServiceProvider _secretsService; - public EmailSender(EmailSettings emailConfiguration, IServiceProvider secretsService) + public MailService(MailOptions emailConfiguration, IServiceProvider secretsService) { _emailConfiguration = emailConfiguration; _secretsService = secretsService; } - public async Task SendEmailAsync(string email, string subject, string textMessage) + public async Task SendEmailAsync(ApplicationUser user, string subject, string textMessage) { var message = new MimeMessage(); message.From.Add(new MailboxAddress(_emailConfiguration.SenderName, _emailConfiguration.Sender)); - message.To.Add(new MailboxAddress("Username", email)); + message.To.Add(new MailboxAddress(user.UserName, user.Email)); message.Subject = subject; message.Body = new TextPart(TextFormat.Html) @@ -32,6 +33,7 @@ public async Task SendEmailAsync(string email, string subject, string textMessag Text = textMessage }; var secrets = _secretsService.GetService(); + using (var emailClient = new SmtpClient()) { emailClient.Connect(_emailConfiguration.Host, _emailConfiguration.Port, _emailConfiguration.EnableSsl); @@ -46,9 +48,10 @@ public async Task SendEmailAsync(string email, string subject, string textMessag } } - public async Task SendResetPassword(string email, string token, string returnUrl) + public async Task SendResetPassword(ApplicationUser user, string token, string returnUrl) { - await SendEmailAsync(email, "Reset your Password", $"Click here to reset your password Test"); + var email = HttpUtility.UrlEncode(user.Email); + await SendEmailAsync(user, "Reset your Password", $"Click here to reset your password Test"); } } } diff --git a/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs b/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs index e6e3121..0dcafa5 100644 --- a/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs +++ b/src/WebApp/Pages/Account/Forgot-Password.cshtml.cs @@ -13,11 +13,11 @@ namespace Codidact.Authentication.WebApp.Pages.Account public class ForgotPasswordModel : PageModel { private readonly UserManager _userManager; - private readonly IEmailSender _emailService; + private readonly IMailService _emailService; public ForgotPasswordModel( UserManager userManager, - IEmailSender emailService + IMailService emailService ) { _userManager = userManager; @@ -38,7 +38,7 @@ public async Task OnPostAsync() if (user != null) { var token = await _userManager.GeneratePasswordResetTokenAsync(user); - await _emailService.SendResetPassword(Email, token, "http://localhost:8001/"); + await _emailService.SendResetPassword(user, token, "http://localhost:8001/"); Sent = true; } else diff --git a/src/WebApp/Pages/Account/Reset-Password.cshtml.cs b/src/WebApp/Pages/Account/Reset-Password.cshtml.cs index 49d84ad..052d89f 100644 --- a/src/WebApp/Pages/Account/Reset-Password.cshtml.cs +++ b/src/WebApp/Pages/Account/Reset-Password.cshtml.cs @@ -54,7 +54,7 @@ public async Task OnPostAsync() } if (ModelState.IsValid) { - var user = await _userManager.FindByEmailAsync(Email); + var user = await _userManager.FindByEmailAsync(HttpUtility.UrlDecode(Email)); if (user == null) { ModelState.AddModelError("Email", "Email not found"); diff --git a/src/WebApp/Startup.cs b/src/WebApp/Startup.cs index 33850d7..74ef359 100644 --- a/src/WebApp/Startup.cs +++ b/src/WebApp/Startup.cs @@ -10,7 +10,10 @@ using Codidact.Authentication.Application; using Codidact.Authentication.Infrastructure; +using Codidact.Authentication.Infrastructure.Common.Interfaces; using Codidact.Authentication.Infrastructure.Persistance; +using Codidact.Authentication.Infrastructure.Services; +using Codidact.Authentication.Domain.Entities; namespace Codidact.Authentication.WebApp { @@ -40,6 +43,15 @@ public void ConfigureServices(IServiceCollection services) options.LowercaseUrls = true; }); + services.Configure(_configuration.GetSection("Mail")); + + services.Configure(options => + { + options.Sender = "Codidact"; + }); + + services.AddTransient(); + services.AddRazorPages() .AddRazorRuntimeCompilation(); From c915399beed8792e6605a13f5817355a11d0a835 Mon Sep 17 00:00:00 2001 From: weegee Date: Fri, 3 Apr 2020 14:59:27 +0530 Subject: [PATCH 07/16] Replace file from entities to Options folder; Propagate returnurl --- src/{Domain/Entities => Application/Options}/MailOptions.cs | 2 +- src/Infrastructure/DependencyInjection.cs | 1 + src/Infrastructure/Services/MailService.cs | 1 + src/WebApp/Pages/Account/Forgot-Password.cshtml | 1 + src/WebApp/Pages/Account/Forgot-Password.cshtml.cs | 5 ++++- src/WebApp/Startup.cs | 2 +- 6 files changed, 9 insertions(+), 3 deletions(-) rename src/{Domain/Entities => Application/Options}/MailOptions.cs (82%) diff --git a/src/Domain/Entities/MailOptions.cs b/src/Application/Options/MailOptions.cs similarity index 82% rename from src/Domain/Entities/MailOptions.cs rename to src/Application/Options/MailOptions.cs index 4dcbee2..cb28a99 100644 --- a/src/Domain/Entities/MailOptions.cs +++ b/src/Application/Options/MailOptions.cs @@ -1,4 +1,4 @@ -namespace Codidact.Authentication.Domain.Entities +namespace Codidact.Authentication.Application.Options { public class MailOptions { diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs index 5c550e8..ea099d3 100644 --- a/src/Infrastructure/DependencyInjection.cs +++ b/src/Infrastructure/DependencyInjection.cs @@ -9,6 +9,7 @@ using Codidact.Authentication.Application.Common.Interfaces; using Codidact.Authentication.Infrastructure.Services; using Codidact.Authentication.Domain.Entities; +using Codidact.Authentication.Application.Options; namespace Codidact.Authentication.Infrastructure { diff --git a/src/Infrastructure/Services/MailService.cs b/src/Infrastructure/Services/MailService.cs index 25a395a..a86ccbd 100644 --- a/src/Infrastructure/Services/MailService.cs +++ b/src/Infrastructure/Services/MailService.cs @@ -7,6 +7,7 @@ using Codidact.Authentication.Infrastructure.Common.Interfaces; using Codidact.Authentication.Domain.Entities; +using Codidact.Authentication.Application.Options; using Microsoft.Extensions.DependencyInjection; diff --git a/src/WebApp/Pages/Account/Forgot-Password.cshtml b/src/WebApp/Pages/Account/Forgot-Password.cshtml index 10603a0..12e26b3 100644 --- a/src/WebApp/Pages/Account/Forgot-Password.cshtml +++ b/src/WebApp/Pages/Account/Forgot-Password.cshtml @@ -14,6 +14,7 @@
+