The next generation of the Teknik Services. Written in ASP.NET. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UserController.cs 53KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Teknik.Areas.Users.Models;
  5. using Teknik.Areas.Users.ViewModels;
  6. using Teknik.Controllers;
  7. using Teknik.Utilities;
  8. using Teknik.Areas.Users.Utility;
  9. using Teknik.Filters;
  10. using QRCoder;
  11. using TwoStepsAuthenticator;
  12. using Teknik.Attributes;
  13. using Teknik.Utilities.Cryptography;
  14. using Microsoft.Extensions.Logging;
  15. using Teknik.Configuration;
  16. using Teknik.Data;
  17. using Microsoft.AspNetCore.Authorization;
  18. using Microsoft.AspNetCore.Mvc;
  19. using Microsoft.EntityFrameworkCore;
  20. using System.Net;
  21. using Microsoft.AspNetCore.Mvc.ViewEngines;
  22. using System.Threading.Tasks;
  23. using Teknik.Logging;
  24. using System.Security.Claims;
  25. using Microsoft.AspNetCore.Authentication.Cookies;
  26. using Microsoft.AspNetCore.Authentication;
  27. namespace Teknik.Areas.Users.Controllers
  28. {
  29. [TeknikAuthorize]
  30. [Area("User")]
  31. public class UserController : DefaultController
  32. {
  33. public UserController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
  34. private static readonly UsedCodesManager usedCodesManager = new UsedCodesManager();
  35. private const string _AuthSessionKey = "AuthenticatedUser";
  36. [AllowAnonymous]
  37. public IActionResult GetPremium()
  38. {
  39. ViewBag.Title = "Get a Premium Account - " + _config.Title;
  40. GetPremiumViewModel model = new GetPremiumViewModel();
  41. return View(model);
  42. }
  43. // GET: Profile/Profile
  44. [AllowAnonymous]
  45. public IActionResult ViewProfile(string username)
  46. {
  47. if (string.IsNullOrEmpty(username))
  48. {
  49. username = User.Identity.Name;
  50. }
  51. ProfileViewModel model = new ProfileViewModel();
  52. ViewBag.Title = "User Does Not Exist - " + _config.Title;
  53. ViewBag.Description = "The User does not exist";
  54. try
  55. {
  56. User user = UserHelper.GetUser(_dbContext, username);
  57. if (user != null)
  58. {
  59. ViewBag.Title = username + "'s Profile - " + _config.Title;
  60. ViewBag.Description = "Viewing " + username + "'s Profile";
  61. model.UserID = user.UserId;
  62. model.Username = user.Username;
  63. if (_config.EmailConfig.Enabled)
  64. {
  65. model.Email = string.Format("{0}@{1}", user.Username, _config.EmailConfig.Domain);
  66. }
  67. model.JoinDate = user.JoinDate;
  68. model.LastSeen = UserHelper.GetLastAccountActivity(_dbContext, _config, user);
  69. model.AccountType = user.AccountType;
  70. model.AccountStatus = user.AccountStatus;
  71. model.UserSettings = user.UserSettings;
  72. model.SecuritySettings = user.SecuritySettings;
  73. model.BlogSettings = user.BlogSettings;
  74. model.UploadSettings = user.UploadSettings;
  75. model.Uploads = _dbContext.Uploads.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DateUploaded).ToList();
  76. model.Pastes = _dbContext.Pastes.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DatePosted).ToList();
  77. model.ShortenedUrls = _dbContext.ShortenedUrls.Where(s => s.UserId == user.UserId).OrderByDescending(s => s.DateAdded).ToList();
  78. model.Vaults = _dbContext.Vaults.Where(v => v.UserId == user.UserId).OrderByDescending(v => v.DateCreated).ToList();
  79. return View(model);
  80. }
  81. model.Error = true;
  82. model.ErrorMessage = "The user does not exist";
  83. }
  84. catch (Exception ex)
  85. {
  86. model.Error = true;
  87. model.ErrorMessage = ex.GetFullMessage(true);
  88. }
  89. return View(model);
  90. }
  91. public IActionResult Settings()
  92. {
  93. return Redirect(Url.SubRouteUrl("user", "User.SecuritySettings"));
  94. }
  95. public IActionResult ProfileSettings()
  96. {
  97. string username = User.Identity.Name;
  98. User user = UserHelper.GetUser(_dbContext, username);
  99. if (user != null)
  100. {
  101. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  102. ViewBag.Title = "Profile Settings - " + _config.Title;
  103. ViewBag.Description = "Your " + _config.Title + " Profile Settings";
  104. ProfileSettingsViewModel model = new ProfileSettingsViewModel();
  105. model.Page = "Profile";
  106. model.UserID = user.UserId;
  107. model.Username = user.Username;
  108. model.About = user.UserSettings.About;
  109. model.Quote = user.UserSettings.Quote;
  110. model.Website = user.UserSettings.Website;
  111. return View("/Areas/User/Views/User/Settings/ProfileSettings.cshtml", model);
  112. }
  113. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  114. }
  115. public IActionResult SecuritySettings()
  116. {
  117. string username = User.Identity.Name;
  118. User user = UserHelper.GetUser(_dbContext, username);
  119. if (user != null)
  120. {
  121. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  122. ViewBag.Title = "Security Settings - " + _config.Title;
  123. ViewBag.Description = "Your " + _config.Title + " Security Settings";
  124. SecuritySettingsViewModel model = new SecuritySettingsViewModel();
  125. model.Page = "Security";
  126. model.UserID = user.UserId;
  127. model.Username = user.Username;
  128. model.TrustedDeviceCount = user.TrustedDevices.Count;
  129. model.AuthTokens = new List<AuthTokenViewModel>();
  130. foreach (AuthToken token in user.AuthTokens)
  131. {
  132. AuthTokenViewModel tokenModel = new AuthTokenViewModel();
  133. tokenModel.AuthTokenId = token.AuthTokenId;
  134. tokenModel.Name = token.Name;
  135. tokenModel.LastDateUsed = token.LastDateUsed;
  136. model.AuthTokens.Add(tokenModel);
  137. }
  138. model.PgpPublicKey = user.SecuritySettings.PGPSignature;
  139. model.RecoveryEmail = user.SecuritySettings.RecoveryEmail;
  140. model.RecoveryVerified = user.SecuritySettings.RecoveryVerified;
  141. model.AllowTrustedDevices = user.SecuritySettings.AllowTrustedDevices;
  142. model.TwoFactorEnabled = user.SecuritySettings.TwoFactorEnabled;
  143. model.TwoFactorKey = user.SecuritySettings.TwoFactorKey;
  144. return View("/Areas/User/Views/User/Settings/SecuritySettings.cshtml", model);
  145. }
  146. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  147. }
  148. public IActionResult InviteSettings()
  149. {
  150. string username = User.Identity.Name;
  151. User user = UserHelper.GetUser(_dbContext, username);
  152. if (user != null)
  153. {
  154. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  155. ViewBag.Title = "Invite Settings - " + _config.Title;
  156. ViewBag.Description = "Your " + _config.Title + " Invite Settings";
  157. InviteSettingsViewModel model = new InviteSettingsViewModel();
  158. model.Page = "Invite";
  159. model.UserID = user.UserId;
  160. model.Username = user.Username;
  161. List<InviteCodeViewModel> availableCodes = new List<InviteCodeViewModel>();
  162. List<InviteCodeViewModel> claimedCodes = new List<InviteCodeViewModel>();
  163. if (user.OwnedInviteCodes != null)
  164. {
  165. foreach (InviteCode inviteCode in user.OwnedInviteCodes.Where(c => c.Active))
  166. {
  167. InviteCodeViewModel inviteCodeViewModel = new InviteCodeViewModel();
  168. inviteCodeViewModel.ClaimedUser = inviteCode.ClaimedUser;
  169. inviteCodeViewModel.Active = inviteCode.Active;
  170. inviteCodeViewModel.Code = inviteCode.Code;
  171. inviteCodeViewModel.InviteCodeId = inviteCode.InviteCodeId;
  172. inviteCodeViewModel.Owner = inviteCode.Owner;
  173. if (inviteCode.ClaimedUser == null)
  174. availableCodes.Add(inviteCodeViewModel);
  175. if (inviteCode.ClaimedUser != null)
  176. claimedCodes.Add(inviteCodeViewModel);
  177. }
  178. }
  179. model.AvailableCodes = availableCodes;
  180. model.ClaimedCodes = claimedCodes;
  181. return View("/Areas/User/Views/User/Settings/InviteSettings.cshtml", model);
  182. }
  183. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  184. }
  185. public IActionResult BlogSettings()
  186. {
  187. string username = User.Identity.Name;
  188. User user = UserHelper.GetUser(_dbContext, username);
  189. if (user != null)
  190. {
  191. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  192. ViewBag.Title = "Blog Settings - " + _config.Title;
  193. ViewBag.Description = "Your " + _config.Title + " Blog Settings";
  194. BlogSettingsViewModel model = new BlogSettingsViewModel();
  195. model.Page = "Blog";
  196. model.UserID = user.UserId;
  197. model.Username = user.Username;
  198. model.Title = user.BlogSettings.Title;
  199. model.Description = user.BlogSettings.Description;
  200. return View("/Areas/User/Views/User/Settings/BlogSettings.cshtml", model);
  201. }
  202. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  203. }
  204. public IActionResult UploadSettings()
  205. {
  206. string username = User.Identity.Name;
  207. User user = UserHelper.GetUser(_dbContext, username);
  208. if (user != null)
  209. {
  210. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  211. ViewBag.Title = "Upload Settings - " + _config.Title;
  212. ViewBag.Description = "Your " + _config.Title + " Upload Settings";
  213. UploadSettingsViewModel model = new UploadSettingsViewModel();
  214. model.Page = "Upload";
  215. model.UserID = user.UserId;
  216. model.Username = user.Username;
  217. model.Encrypt = user.UploadSettings.Encrypt;
  218. return View("/Areas/User/Views/User/Settings/UploadSettings.cshtml", model);
  219. }
  220. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  221. }
  222. [HttpGet]
  223. [AllowAnonymous]
  224. public IActionResult ViewRawPGP(string username)
  225. {
  226. ViewBag.Title = username + "'s Public Key - " + _config.Title;
  227. ViewBag.Description = "The PGP public key for " + username;
  228. User user = UserHelper.GetUser(_dbContext, username);
  229. if (user != null)
  230. {
  231. if (!string.IsNullOrEmpty(user.SecuritySettings.PGPSignature))
  232. {
  233. return Content(user.SecuritySettings.PGPSignature, "text/plain");
  234. }
  235. }
  236. return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  237. }
  238. [HttpGet]
  239. [AllowAnonymous]
  240. public IActionResult Login(string ReturnUrl)
  241. {
  242. LoginViewModel model = new LoginViewModel();
  243. model.ReturnUrl = ReturnUrl;
  244. return View("/Areas/User/Views/User/ViewLogin.cshtml", model);
  245. }
  246. [HttpPost]
  247. [AllowAnonymous]
  248. public async Task<IActionResult> Login([Bind(Prefix = "Login")]LoginViewModel model)
  249. {
  250. if (ModelState.IsValid)
  251. {
  252. string username = model.Username;
  253. User user = UserHelper.GetUser(_dbContext, username);
  254. if (user != null)
  255. {
  256. bool userValid = UserHelper.UserPasswordCorrect(_dbContext, _config, user, model.Password);
  257. if (userValid)
  258. {
  259. // Perform transfer actions on the account
  260. UserHelper.TransferUser(_dbContext, _config, user, model.Password);
  261. user.LastSeen = DateTime.Now;
  262. _dbContext.Entry(user).State = EntityState.Modified;
  263. _dbContext.SaveChanges();
  264. // Make sure they aren't banned or anything
  265. if (user.AccountStatus == AccountStatus.Banned)
  266. {
  267. model.Error = true;
  268. model.ErrorMessage = "Account has been banned.";
  269. return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewLogin.cshtml", model));
  270. }
  271. // Let's double check their email and git accounts to make sure they exist
  272. string email = UserHelper.GetUserEmailAddress(_config, username);
  273. if (_config.EmailConfig.Enabled && !UserHelper.UserEmailExists(_config, email))
  274. {
  275. UserHelper.AddUserEmail(_config, email, model.Password);
  276. }
  277. if (_config.GitConfig.Enabled && !UserHelper.UserGitExists(_config, username))
  278. {
  279. UserHelper.AddUserGit(_config, username, model.Password);
  280. }
  281. bool twoFactor = false;
  282. string returnUrl = model.ReturnUrl;
  283. if (user.SecuritySettings.TwoFactorEnabled)
  284. {
  285. twoFactor = true;
  286. // We need to check their device, and two factor them
  287. if (user.SecuritySettings.AllowTrustedDevices)
  288. {
  289. // Check for the trusted device cookie
  290. string token = Request.Cookies[Constants.TRUSTEDDEVICECOOKIE + "_" + username];
  291. if (!string.IsNullOrEmpty(token))
  292. {
  293. if (user.TrustedDevices.Where(d => d.Token == token).FirstOrDefault() != null)
  294. {
  295. // The device token is attached to the user, let's let it slide
  296. twoFactor = false;
  297. }
  298. }
  299. }
  300. }
  301. if (twoFactor)
  302. {
  303. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  304. if (string.IsNullOrEmpty(model.ReturnUrl))
  305. returnUrl = Request.Headers["Referer"].ToString();
  306. returnUrl = Url.SubRouteUrl("user", "User.CheckAuthenticatorCode", new { returnUrl = returnUrl, rememberMe = model.RememberMe });
  307. model.ReturnUrl = string.Empty;
  308. }
  309. else
  310. {
  311. returnUrl = Request.Headers["Referer"].ToString();
  312. // They don't need two factor auth.
  313. await SignInUser(user, (string.IsNullOrEmpty(model.ReturnUrl)) ? returnUrl : model.ReturnUrl, model.RememberMe);
  314. }
  315. if (string.IsNullOrEmpty(model.ReturnUrl))
  316. {
  317. return GenerateActionResult(new { result = returnUrl }, Redirect(returnUrl));
  318. }
  319. else
  320. {
  321. return Redirect(model.ReturnUrl);
  322. }
  323. }
  324. }
  325. }
  326. model.Error = true;
  327. model.ErrorMessage = "Invalid Username or Password.";
  328. return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewLogin.cshtml", model));
  329. }
  330. public async Task<IActionResult> Logout()
  331. {
  332. await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
  333. return Redirect(Url.SubRouteUrl("www", "Home.Index"));
  334. }
  335. [HttpGet]
  336. [AllowAnonymous]
  337. public IActionResult Register(string inviteCode, string ReturnUrl)
  338. {
  339. RegisterViewModel model = new RegisterViewModel();
  340. model.InviteCode = inviteCode;
  341. model.ReturnUrl = ReturnUrl;
  342. return View("/Areas/User/Views/User/ViewRegistration.cshtml", model);
  343. }
  344. [HttpPost]
  345. [AllowAnonymous]
  346. public async Task<IActionResult> Register([Bind(Prefix = "Register")]RegisterViewModel model)
  347. {
  348. model.Error = false;
  349. model.ErrorMessage = string.Empty;
  350. if (ModelState.IsValid)
  351. {
  352. if (_config.UserConfig.RegistrationEnabled)
  353. {
  354. if (!model.Error && !UserHelper.ValidUsername(_config, model.Username))
  355. {
  356. model.Error = true;
  357. model.ErrorMessage = "That username is not valid";
  358. }
  359. if (!model.Error && !UserHelper.UsernameAvailable(_dbContext, _config, model.Username))
  360. {
  361. model.Error = true;
  362. model.ErrorMessage = "That username is not available";
  363. }
  364. if (!model.Error && model.Password != model.ConfirmPassword)
  365. {
  366. model.Error = true;
  367. model.ErrorMessage = "Passwords must match";
  368. }
  369. // Validate the Invite Code
  370. if (!model.Error && _config.UserConfig.InviteCodeRequired && string.IsNullOrEmpty(model.InviteCode))
  371. {
  372. model.Error = true;
  373. model.ErrorMessage = "An Invite Code is required to register";
  374. }
  375. if (!model.Error && !string.IsNullOrEmpty(model.InviteCode) && _dbContext.InviteCodes.Where(c => c.Code == model.InviteCode && c.Active && c.ClaimedUser == null).FirstOrDefault() == null)
  376. {
  377. model.Error = true;
  378. model.ErrorMessage = "Invalid Invite Code";
  379. }
  380. // PGP Key valid?
  381. if (!model.Error && !string.IsNullOrEmpty(model.PublicKey) && !PGP.IsPublicKey(model.PublicKey))
  382. {
  383. model.Error = true;
  384. model.ErrorMessage = "Invalid PGP Public Key";
  385. }
  386. if (!model.Error)
  387. {
  388. try
  389. {
  390. User newUser = new User();
  391. newUser.JoinDate = DateTime.Now;
  392. newUser.Username = model.Username;
  393. newUser.UserSettings = new UserSettings();
  394. newUser.SecuritySettings = new SecuritySettings();
  395. newUser.BlogSettings = new BlogSettings();
  396. newUser.UploadSettings = new UploadSettings();
  397. if (!string.IsNullOrEmpty(model.PublicKey))
  398. newUser.SecuritySettings.PGPSignature = model.PublicKey;
  399. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  400. newUser.SecuritySettings.RecoveryEmail = model.RecoveryEmail;
  401. // if they provided an invite code, let's assign them to it
  402. if (!string.IsNullOrEmpty(model.InviteCode))
  403. {
  404. InviteCode code = _dbContext.InviteCodes.Where(c => c.Code == model.InviteCode).FirstOrDefault();
  405. _dbContext.Entry(code).State = EntityState.Modified;
  406. _dbContext.SaveChanges();
  407. newUser.ClaimedInviteCode = code;
  408. }
  409. UserHelper.AddAccount(_dbContext, _config, newUser, model.Password);
  410. // If they have a recovery email, let's send a verification
  411. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  412. {
  413. string verifyCode = UserHelper.CreateRecoveryEmailVerification(_dbContext, _config, newUser);
  414. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = model.Username });
  415. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  416. UserHelper.SendRecoveryEmailVerification(_config, model.Username, model.RecoveryEmail, resetUrl, verifyUrl);
  417. }
  418. }
  419. catch (Exception ex)
  420. {
  421. model.Error = true;
  422. model.ErrorMessage = ex.GetFullMessage(true);
  423. }
  424. if (!model.Error)
  425. {
  426. return await Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl });
  427. }
  428. }
  429. }
  430. if (!model.Error)
  431. {
  432. model.Error = true;
  433. model.ErrorMessage = "User Registration is Disabled";
  434. }
  435. }
  436. else
  437. {
  438. model.Error = true;
  439. model.ErrorMessage = "Missing Required Fields";
  440. }
  441. return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewRegistration.cshtml", model));
  442. }
  443. [HttpPost]
  444. [ValidateAntiForgeryToken]
  445. public IActionResult EditBlog(BlogSettingsViewModel settings)
  446. {
  447. if (ModelState.IsValid)
  448. {
  449. try
  450. {
  451. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  452. if (user != null)
  453. {
  454. // Blogs
  455. user.BlogSettings.Title = settings.Title;
  456. user.BlogSettings.Description = settings.Description;
  457. UserHelper.EditAccount(_dbContext, _config, user);
  458. return Json(new { result = true });
  459. }
  460. return Json(new { error = "User does not exist" });
  461. }
  462. catch (Exception ex)
  463. {
  464. return Json(new { error = ex.GetFullMessage(true) });
  465. }
  466. }
  467. return Json(new { error = "Invalid Parameters" });
  468. }
  469. [HttpPost]
  470. [ValidateAntiForgeryToken]
  471. public IActionResult EditProfile(ProfileSettingsViewModel settings)
  472. {
  473. if (ModelState.IsValid)
  474. {
  475. try
  476. {
  477. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  478. if (user != null)
  479. {
  480. // Profile Info
  481. user.UserSettings.Website = settings.Website;
  482. user.UserSettings.Quote = settings.Quote;
  483. user.UserSettings.About = settings.About;
  484. UserHelper.EditAccount(_dbContext, _config, user);
  485. return Json(new { result = true });
  486. }
  487. return Json(new { error = "User does not exist" });
  488. }
  489. catch (Exception ex)
  490. {
  491. return Json(new { error = ex.GetFullMessage(true) });
  492. }
  493. }
  494. return Json(new { error = "Invalid Parameters" });
  495. }
  496. [HttpPost]
  497. [ValidateAntiForgeryToken]
  498. public IActionResult EditSecurity(SecuritySettingsViewModel settings)
  499. {
  500. if (ModelState.IsValid)
  501. {
  502. try
  503. {
  504. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  505. if (user != null)
  506. {
  507. bool changePass = false;
  508. // Changing Password?
  509. if (!string.IsNullOrEmpty(settings.CurrentPassword) && (!string.IsNullOrEmpty(settings.NewPassword) || !string.IsNullOrEmpty(settings.NewPasswordConfirm)))
  510. {
  511. // Old Password Valid?
  512. if (!UserHelper.UserPasswordCorrect(_dbContext, _config, user, settings.CurrentPassword))
  513. {
  514. return Json(new { error = "Invalid Original Password." });
  515. }
  516. // The New Password Match?
  517. if (settings.NewPassword != settings.NewPasswordConfirm)
  518. {
  519. return Json(new { error = "New Password Must Match." });
  520. }
  521. // Are password resets enabled?
  522. if (!_config.UserConfig.PasswordResetEnabled)
  523. {
  524. return Json(new { error = "Password resets are disabled." });
  525. }
  526. changePass = true;
  527. }
  528. // PGP Key valid?
  529. if (!string.IsNullOrEmpty(settings.PgpPublicKey) && !PGP.IsPublicKey(settings.PgpPublicKey))
  530. {
  531. return Json(new { error = "Invalid PGP Public Key" });
  532. }
  533. user.SecuritySettings.PGPSignature = settings.PgpPublicKey;
  534. // Recovery Email
  535. bool newRecovery = false;
  536. if (settings.RecoveryEmail != user.SecuritySettings.RecoveryEmail)
  537. {
  538. newRecovery = true;
  539. user.SecuritySettings.RecoveryEmail = settings.RecoveryEmail;
  540. user.SecuritySettings.RecoveryVerified = false;
  541. }
  542. // Trusted Devices
  543. user.SecuritySettings.AllowTrustedDevices = settings.AllowTrustedDevices;
  544. if (!settings.AllowTrustedDevices)
  545. {
  546. // They turned it off, let's clear the trusted devices
  547. user.TrustedDevices.Clear();
  548. List<TrustedDevice> foundDevices = _dbContext.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  549. if (foundDevices != null)
  550. {
  551. foreach (TrustedDevice device in foundDevices)
  552. {
  553. _dbContext.TrustedDevices.Remove(device);
  554. }
  555. }
  556. }
  557. // Two Factor Authentication
  558. bool oldTwoFactor = user.SecuritySettings.TwoFactorEnabled;
  559. user.SecuritySettings.TwoFactorEnabled = settings.TwoFactorEnabled;
  560. string newKey = string.Empty;
  561. if (!oldTwoFactor && settings.TwoFactorEnabled)
  562. {
  563. // They just enabled it, let's regen the key
  564. newKey = Authenticator.GenerateKey();
  565. // New key, so let's upsert their key into git
  566. if (_config.GitConfig.Enabled)
  567. {
  568. UserHelper.CreateUserGitTwoFactor(_config, user.Username, newKey, DateTimeHelper.GetUnixTimestamp());
  569. }
  570. }
  571. else if (!settings.TwoFactorEnabled)
  572. {
  573. // remove the key when it's disabled
  574. newKey = string.Empty;
  575. // Removed the key, so delete it from git as well
  576. if (_config.GitConfig.Enabled)
  577. {
  578. UserHelper.DeleteUserGitTwoFactor(_config, user.Username);
  579. }
  580. }
  581. else
  582. {
  583. // No change, let's use the old value
  584. newKey = user.SecuritySettings.TwoFactorKey;
  585. }
  586. user.SecuritySettings.TwoFactorKey = newKey;
  587. UserHelper.EditAccount(_dbContext, _config, user, changePass, settings.NewPassword);
  588. // If they have a recovery email, let's send a verification
  589. if (!string.IsNullOrEmpty(settings.RecoveryEmail) && newRecovery)
  590. {
  591. string verifyCode = UserHelper.CreateRecoveryEmailVerification(_dbContext, _config, user);
  592. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  593. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  594. UserHelper.SendRecoveryEmailVerification(_config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  595. }
  596. if (!oldTwoFactor && settings.TwoFactorEnabled)
  597. {
  598. return Json(new { result = new { checkAuth = true, key = newKey, qrUrl = Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = newKey }) } });
  599. }
  600. return Json(new { result = true });
  601. }
  602. return Json(new { error = "User does not exist" });
  603. }
  604. catch (Exception ex)
  605. {
  606. return Json(new { error = ex.GetFullMessage(true) });
  607. }
  608. }
  609. return Json(new { error = "Invalid Parameters" });
  610. }
  611. [HttpPost]
  612. [ValidateAntiForgeryToken]
  613. public IActionResult EditUpload(UploadSettingsViewModel settings)
  614. {
  615. if (ModelState.IsValid)
  616. {
  617. try
  618. {
  619. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  620. if (user != null)
  621. {
  622. // Profile Info
  623. user.UploadSettings.Encrypt = settings.Encrypt;
  624. UserHelper.EditAccount(_dbContext, _config, user);
  625. return Json(new { result = true });
  626. }
  627. return Json(new { error = "User does not exist" });
  628. }
  629. catch (Exception ex)
  630. {
  631. return Json(new { error = ex.GetFullMessage(true) });
  632. }
  633. }
  634. return Json(new { error = "Invalid Parameters" });
  635. }
  636. [HttpPost]
  637. [ValidateAntiForgeryToken]
  638. public async Task<IActionResult> Delete()
  639. {
  640. if (ModelState.IsValid)
  641. {
  642. try
  643. {
  644. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  645. if (user != null)
  646. {
  647. UserHelper.DeleteAccount(_dbContext, _config, user);
  648. // Sign Out
  649. await Logout();
  650. return Json(new { result = true });
  651. }
  652. }
  653. catch (Exception ex)
  654. {
  655. return Json(new { error = ex.GetFullMessage(true) });
  656. }
  657. }
  658. return Json(new { error = "Unable to delete user" });
  659. }
  660. [HttpGet]
  661. public IActionResult VerifyRecoveryEmail(string code)
  662. {
  663. bool verified = true;
  664. if (string.IsNullOrEmpty(code))
  665. verified &= false;
  666. // Is there a code?
  667. if (verified)
  668. {
  669. verified &= UserHelper.VerifyRecoveryEmail(_dbContext, _config, User.Identity.Name, code);
  670. }
  671. RecoveryEmailVerificationViewModel model = new RecoveryEmailVerificationViewModel();
  672. model.Success = verified;
  673. return View("/Areas/User/Views/User/ViewRecoveryEmailVerification.cshtml", model);
  674. }
  675. [HttpPost]
  676. [ValidateAntiForgeryToken]
  677. public IActionResult ResendVerifyRecoveryEmail()
  678. {
  679. if (ModelState.IsValid)
  680. {
  681. try
  682. {
  683. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  684. if (user != null)
  685. {
  686. // If they have a recovery email, let's send a verification
  687. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail))
  688. {
  689. if (!user.SecuritySettings.RecoveryVerified)
  690. {
  691. string verifyCode = UserHelper.CreateRecoveryEmailVerification(_dbContext, _config, user);
  692. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  693. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  694. UserHelper.SendRecoveryEmailVerification(_config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  695. return Json(new { result = true });
  696. }
  697. return Json(new { error = "The recovery email is already verified" });
  698. }
  699. }
  700. }
  701. catch (Exception ex)
  702. {
  703. return Json(new { error = ex.GetFullMessage(true) });
  704. }
  705. }
  706. return Json(new { error = "Unable to resend verification" });
  707. }
  708. [HttpGet]
  709. [AllowAnonymous]
  710. public IActionResult ResetPassword(string username)
  711. {
  712. ResetPasswordViewModel model = new ResetPasswordViewModel();
  713. model.Username = username;
  714. return View("/Areas/User/Views/User/ResetPassword.cshtml", model);
  715. }
  716. [HttpPost]
  717. [AllowAnonymous]
  718. [ValidateAntiForgeryToken]
  719. public IActionResult SendResetPasswordVerification(string username)
  720. {
  721. if (ModelState.IsValid)
  722. {
  723. try
  724. {
  725. User user = UserHelper.GetUser(_dbContext, username);
  726. if (user != null)
  727. {
  728. // If they have a recovery email, let's send a verification
  729. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail) && user.SecuritySettings.RecoveryVerified)
  730. {
  731. string verifyCode = UserHelper.CreateResetPasswordVerification(_dbContext, _config, user);
  732. string resetUrl = Url.SubRouteUrl("user", "User.VerifyResetPassword", new { Username = user.Username, Code = verifyCode });
  733. UserHelper.SendResetPasswordVerification(_config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl);
  734. return Json(new { result = true });
  735. }
  736. return Json(new { error = "The username doesn't have a recovery email specified" });
  737. }
  738. return Json(new { error = "The username is not valid" });
  739. }
  740. catch (Exception ex)
  741. {
  742. return Json(new { error = ex.GetFullMessage(true) });
  743. }
  744. }
  745. return Json(new { error = "Unable to send reset link" });
  746. }
  747. [HttpGet]
  748. [AllowAnonymous]
  749. public IActionResult VerifyResetPassword(string username, string code)
  750. {
  751. bool verified = true;
  752. if (string.IsNullOrEmpty(code))
  753. verified &= false;
  754. // Is there a code?
  755. if (verified)
  756. {
  757. verified &= UserHelper.VerifyResetPassword(_dbContext, _config, username, code);
  758. if (verified)
  759. {
  760. // The password reset code is valid, let's get their user account for this session
  761. User user = UserHelper.GetUser(_dbContext, username);
  762. HttpContext.Session.Set(_AuthSessionKey, user.Username);
  763. HttpContext.Session.Set("AuthCode", code);
  764. }
  765. }
  766. ResetPasswordVerificationViewModel model = new ResetPasswordVerificationViewModel();
  767. model.Success = verified;
  768. return View("/Areas/User/Views/User/ResetPasswordVerification.cshtml", model);
  769. }
  770. [HttpPost]
  771. [AllowAnonymous]
  772. [ValidateAntiForgeryToken]
  773. public IActionResult SetUserPassword(SetPasswordViewModel passwordViewModel)
  774. {
  775. if (ModelState.IsValid)
  776. {
  777. try
  778. {
  779. string code = HttpContext.Session.Get<string>("AuthCode");
  780. if (!string.IsNullOrEmpty(code))
  781. {
  782. string username = HttpContext.Session.Get<string>(_AuthSessionKey);
  783. if (!string.IsNullOrEmpty(username))
  784. {
  785. if (string.IsNullOrEmpty(passwordViewModel.Password))
  786. {
  787. return Json(new { error = "Password must not be empty" });
  788. }
  789. if (passwordViewModel.Password != passwordViewModel.PasswordConfirm)
  790. {
  791. return Json(new { error = "Passwords must match" });
  792. }
  793. User newUser = UserHelper.GetUser(_dbContext, username);
  794. UserHelper.EditAccount(_dbContext, _config, newUser, true, passwordViewModel.Password);
  795. return Json(new { result = true });
  796. }
  797. return Json(new { error = "User does not exist" });
  798. }
  799. return Json(new { error = "Invalid Code" });
  800. }
  801. catch (Exception ex)
  802. {
  803. return Json(new { error = ex.GetFullMessage(true) });
  804. }
  805. }
  806. return Json(new { error = "Unable to reset user password" });
  807. }
  808. [HttpGet]
  809. [AllowAnonymous]
  810. public IActionResult ConfirmTwoFactorAuth(string returnUrl, bool rememberMe)
  811. {
  812. string username = HttpContext.Session.Get<string>(_AuthSessionKey);
  813. if (!string.IsNullOrEmpty(username))
  814. {
  815. User user = UserHelper.GetUser(_dbContext, username);
  816. ViewBag.Title = "Unknown Device - " + _config.Title;
  817. ViewBag.Description = "We do not recognize this device.";
  818. TwoFactorViewModel model = new TwoFactorViewModel();
  819. model.ReturnUrl = returnUrl;
  820. model.RememberMe = rememberMe;
  821. model.AllowTrustedDevice = user.SecuritySettings.AllowTrustedDevices;
  822. return View("/Areas/User/Views/User/TwoFactorCheck.cshtml", model);
  823. }
  824. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  825. }
  826. [HttpPost]
  827. [AllowAnonymous]
  828. [ValidateAntiForgeryToken]
  829. public async Task<IActionResult> ConfirmAuthenticatorCode(string code, string returnUrl, bool rememberMe, bool rememberDevice, string deviceName)
  830. {
  831. string username = HttpContext.Session.Get<string>(_AuthSessionKey);
  832. if (!string.IsNullOrEmpty(username))
  833. {
  834. User user = UserHelper.GetUser(_dbContext, username);
  835. if (user.SecuritySettings.TwoFactorEnabled)
  836. {
  837. string key = user.SecuritySettings.TwoFactorKey;
  838. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  839. bool isValid = ta.CheckCode(key, code, user);
  840. if (isValid)
  841. {
  842. // the code was valid, let's log them in!
  843. await SignInUser(user, returnUrl, rememberMe);
  844. if (user.SecuritySettings.AllowTrustedDevices && rememberDevice)
  845. {
  846. // They want to remember the device, and have allow trusted devices on
  847. var cookieOptions = UserHelper.CreateTrustedDeviceCookie(_config, user.Username, Request.Host.Host.GetDomain(), Request.IsLocal());
  848. Response.Cookies.Append(Constants.TRUSTEDDEVICECOOKIE + "_" + username, cookieOptions.Item2, cookieOptions.Item1);
  849. TrustedDevice device = new TrustedDevice();
  850. device.UserId = user.UserId;
  851. device.Name = (string.IsNullOrEmpty(deviceName)) ? "Unknown" : deviceName;
  852. device.DateSeen = DateTime.Now;
  853. device.Token = cookieOptions.Item2;
  854. // Add the token
  855. _dbContext.TrustedDevices.Add(device);
  856. _dbContext.SaveChanges();
  857. }
  858. if (string.IsNullOrEmpty(returnUrl))
  859. returnUrl = Request.Headers["Referer"].ToString();
  860. return Json(new { result = returnUrl });
  861. }
  862. return Json(new { error = "Invalid Authentication Code" });
  863. }
  864. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  865. }
  866. return Json(new { error = "User does not exist" });
  867. }
  868. [HttpPost]
  869. [ValidateAntiForgeryToken]
  870. public IActionResult VerifyAuthenticatorCode(string code)
  871. {
  872. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  873. if (user != null)
  874. {
  875. if (user.SecuritySettings.TwoFactorEnabled)
  876. {
  877. string key = user.SecuritySettings.TwoFactorKey;
  878. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  879. bool isValid = ta.CheckCode(key, code, user);
  880. if (isValid)
  881. {
  882. return Json(new { result = true });
  883. }
  884. return Json(new { error = "Invalid Authentication Code" });
  885. }
  886. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  887. }
  888. return Json(new { error = "User does not exist" });
  889. }
  890. [HttpGet]
  891. public IActionResult GenerateAuthQrCode(string key)
  892. {
  893. var ProvisionUrl = string.Format("otpauth://totp/{0}:{1}?secret={2}", _config.Title, User.Identity.Name, key);
  894. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  895. QRCodeData qrCodeData = qrGenerator.CreateQrCode(ProvisionUrl, QRCodeGenerator.ECCLevel.Q);
  896. PngByteQRCode qrCode = new PngByteQRCode(qrCodeData);
  897. return File(qrCode.GetGraphic(20), "image/png");
  898. }
  899. [HttpPost]
  900. [ValidateAntiForgeryToken]
  901. public IActionResult ClearTrustedDevices()
  902. {
  903. try
  904. {
  905. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  906. if (user != null)
  907. {
  908. if (user.SecuritySettings.AllowTrustedDevices)
  909. {
  910. // let's clear the trusted devices
  911. user.TrustedDevices.Clear();
  912. List<TrustedDevice> foundDevices = _dbContext.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  913. if (foundDevices != null)
  914. {
  915. foreach (TrustedDevice device in foundDevices)
  916. {
  917. _dbContext.TrustedDevices.Remove(device);
  918. }
  919. }
  920. _dbContext.Entry(user).State = EntityState.Modified;
  921. _dbContext.SaveChanges();
  922. return Json(new { result = true });
  923. }
  924. return Json(new { error = "User does not allow trusted devices" });
  925. }
  926. return Json(new { error = "User does not exist" });
  927. }
  928. catch (Exception ex)
  929. {
  930. return Json(new { error = ex.GetFullMessage(true) });
  931. }
  932. }
  933. [HttpPost]
  934. [ValidateAntiForgeryToken]
  935. public async Task<IActionResult> GenerateToken(string name, [FromServices] ICompositeViewEngine viewEngine)
  936. {
  937. try
  938. {
  939. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  940. if (user != null)
  941. {
  942. string newTokenStr = UserHelper.GenerateAuthToken(_dbContext, user.Username);
  943. if (!string.IsNullOrEmpty(newTokenStr))
  944. {
  945. AuthToken token = new AuthToken();
  946. token.UserId = user.UserId;
  947. token.HashedToken = SHA256.Hash(newTokenStr);
  948. token.Name = name;
  949. _dbContext.AuthTokens.Add(token);
  950. _dbContext.SaveChanges();
  951. AuthTokenViewModel model = new AuthTokenViewModel();
  952. model.AuthTokenId = token.AuthTokenId;
  953. model.Name = token.Name;
  954. model.LastDateUsed = token.LastDateUsed;
  955. string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/AuthToken.cshtml", model);
  956. return Json(new { result = new { token = newTokenStr, html = renderedView } });
  957. }
  958. return Json(new { error = "Unable to generate Auth Token" });
  959. }
  960. return Json(new { error = "User does not exist" });
  961. }
  962. catch (Exception ex)
  963. {
  964. return Json(new { error = ex.GetFullMessage(true) });
  965. }
  966. }
  967. [HttpPost]
  968. [ValidateAntiForgeryToken]
  969. public IActionResult RevokeAllTokens()
  970. {
  971. try
  972. {
  973. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  974. if (user != null)
  975. {
  976. user.AuthTokens.Clear();
  977. List<AuthToken> foundTokens = _dbContext.AuthTokens.Where(d => d.UserId == user.UserId).ToList();
  978. if (foundTokens != null)
  979. {
  980. foreach (AuthToken token in foundTokens)
  981. {
  982. _dbContext.AuthTokens.Remove(token);
  983. }
  984. }
  985. _dbContext.Entry(user).State = EntityState.Modified;
  986. _dbContext.SaveChanges();
  987. return Json(new { result = true });
  988. }
  989. return Json(new { error = "User does not exist" });
  990. }
  991. catch (Exception ex)
  992. {
  993. return Json(new { error = ex.GetFullMessage(true) });
  994. }
  995. }
  996. [HttpPost]
  997. [ValidateAntiForgeryToken]
  998. public IActionResult EditTokenName(int tokenId, string name)
  999. {
  1000. try
  1001. {
  1002. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  1003. if (user != null)
  1004. {
  1005. AuthToken foundToken = _dbContext.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  1006. if (foundToken != null)
  1007. {
  1008. foundToken.Name = name;
  1009. _dbContext.Entry(foundToken).State = EntityState.Modified;
  1010. _dbContext.SaveChanges();
  1011. return Json(new { result = new { name = name } });
  1012. }
  1013. return Json(new { error = "Authentication Token does not exist" });
  1014. }
  1015. return Json(new { error = "User does not exist" });
  1016. }
  1017. catch (Exception ex)
  1018. {
  1019. return Json(new { error = ex.GetFullMessage(true) });
  1020. }
  1021. }
  1022. [HttpPost]
  1023. [ValidateAntiForgeryToken]
  1024. public IActionResult DeleteToken(int tokenId)
  1025. {
  1026. try
  1027. {
  1028. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  1029. if (user != null)
  1030. {
  1031. AuthToken foundToken = _dbContext.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  1032. if (foundToken != null)
  1033. {
  1034. _dbContext.AuthTokens.Remove(foundToken);
  1035. user.AuthTokens.Remove(foundToken);
  1036. _dbContext.Entry(user).State = EntityState.Modified;
  1037. _dbContext.SaveChanges();
  1038. return Json(new { result = true });
  1039. }
  1040. return Json(new { error = "Authentication Token does not exist" });
  1041. }
  1042. return Json(new { error = "User does not exist" });
  1043. }
  1044. catch (Exception ex)
  1045. {
  1046. return Json(new { error = ex.GetFullMessage(true) });
  1047. }
  1048. }
  1049. [HttpPost]
  1050. [ValidateAntiForgeryToken]
  1051. public IActionResult CreateInviteCodeLink(int inviteCodeId)
  1052. {
  1053. try
  1054. {
  1055. InviteCode code = _dbContext.InviteCodes.Where(c => c.InviteCodeId == inviteCodeId).FirstOrDefault();
  1056. if (code != null)
  1057. {
  1058. if (User.Identity.IsAuthenticated)
  1059. {
  1060. if (code.Owner.Username == User.Identity.Name)
  1061. {
  1062. return Json(new { result = Url.SubRouteUrl("user", "User.Register", new { inviteCode = code.Code }) });
  1063. }
  1064. }
  1065. return Json(new { error = "Invite Code not associated with this user" });
  1066. }
  1067. return Json(new { error = "Invalid Invite Code" });
  1068. }
  1069. catch (Exception ex)
  1070. {
  1071. return Json(new { error = ex.GetFullMessage(true) });
  1072. }
  1073. }
  1074. private async Task SignInUser(User user, string returnUrl, bool rememberMe)
  1075. {
  1076. var claims = new List<Claim>
  1077. {
  1078. new Claim(ClaimTypes.Name, user.Username)
  1079. };
  1080. // Add their roles
  1081. foreach (var role in user.UserRoles)
  1082. {
  1083. claims.Add(new Claim(ClaimTypes.Role, role.Role.Name));
  1084. }
  1085. var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  1086. var authProps = new AuthenticationProperties
  1087. {
  1088. IsPersistent = rememberMe,
  1089. ExpiresUtc = DateTime.UtcNow.AddMonths(1),
  1090. RedirectUri = returnUrl
  1091. };
  1092. await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProps);
  1093. }
  1094. }
  1095. }