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 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data.Entity;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7. using System.Web.Security;
  8. using Teknik.Areas.Users.Models;
  9. using Teknik.Areas.Users.ViewModels;
  10. using Teknik.Controllers;
  11. using Teknik.Utilities;
  12. using Teknik.Models;
  13. using Teknik.Areas.Users.Utility;
  14. using Teknik.Filters;
  15. using QRCoder;
  16. using TwoStepsAuthenticator;
  17. using System.Drawing;
  18. using Teknik.Attributes;
  19. namespace Teknik.Areas.Users.Controllers
  20. {
  21. [TeknikAuthorize]
  22. public class UserController : DefaultController
  23. {
  24. private static readonly UsedCodesManager usedCodesManager = new UsedCodesManager();
  25. private TeknikEntities db = new TeknikEntities();
  26. // GET: Profile/Profile
  27. [TrackPageView]
  28. [AllowAnonymous]
  29. public ActionResult Index(string username)
  30. {
  31. if (string.IsNullOrEmpty(username))
  32. {
  33. username = User.Identity.Name;
  34. }
  35. ProfileViewModel model = new ProfileViewModel();
  36. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  37. ViewBag.Description = "The User does not exist";
  38. try
  39. {
  40. User user = UserHelper.GetUser(db, username);
  41. if (user != null)
  42. {
  43. ViewBag.Title = username + "'s Profile - " + Config.Title;
  44. ViewBag.Description = "Viewing " + username + "'s Profile";
  45. model.UserID = user.UserId;
  46. model.Username = user.Username;
  47. if (Config.EmailConfig.Enabled)
  48. {
  49. model.Email = string.Format("{0}@{1}", user.Username, Config.EmailConfig.Domain);
  50. }
  51. model.JoinDate = user.JoinDate;
  52. model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user);
  53. model.UserSettings = user.UserSettings;
  54. model.SecuritySettings = user.SecuritySettings;
  55. model.BlogSettings = user.BlogSettings;
  56. model.UploadSettings = user.UploadSettings;
  57. model.Uploads = db.Uploads.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DateUploaded).ToList();
  58. model.Pastes = db.Pastes.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DatePosted).ToList();
  59. model.ShortenedUrls = db.ShortenedUrls.Where(s => s.UserId == user.UserId).OrderByDescending(s => s.DateAdded).ToList();
  60. return View(model);
  61. }
  62. model.Error = true;
  63. model.ErrorMessage = "The user does not exist";
  64. }
  65. catch (Exception ex)
  66. {
  67. model.Error = true;
  68. model.ErrorMessage = ex.GetFullMessage(true);
  69. }
  70. return View(model);
  71. }
  72. [TrackPageView]
  73. public ActionResult Settings()
  74. {
  75. string username = User.Identity.Name;
  76. SettingsViewModel model = new SettingsViewModel();
  77. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  78. ViewBag.Description = "The User does not exist";
  79. User user = UserHelper.GetUser(db, username);
  80. if (user != null)
  81. {
  82. Session["AuthenticatedUser"] = user;
  83. ViewBag.Title = "Settings - " + Config.Title;
  84. ViewBag.Description = "Your " + Config.Title + " Settings";
  85. model.UserID = user.UserId;
  86. model.Username = user.Username;
  87. model.TrustedDeviceCount = user.TrustedDevices.Count;
  88. model.AuthTokens = new List<AuthTokenViewModel>();
  89. foreach (AuthToken token in user.AuthTokens)
  90. {
  91. AuthTokenViewModel tokenModel = new AuthTokenViewModel();
  92. tokenModel.AuthTokenId = token.AuthTokenId;
  93. tokenModel.Name = token.Name;
  94. tokenModel.LastDateUsed = token.LastDateUsed;
  95. model.AuthTokens.Add(tokenModel);
  96. }
  97. model.UserSettings = user.UserSettings;
  98. model.SecuritySettings = user.SecuritySettings;
  99. model.BlogSettings = user.BlogSettings;
  100. model.UploadSettings = user.UploadSettings;
  101. return View(model);
  102. }
  103. model.Error = true;
  104. return View(model);
  105. }
  106. [HttpGet]
  107. [TrackPageView]
  108. [AllowAnonymous]
  109. public ActionResult ViewRawPGP(string username)
  110. {
  111. ViewBag.Title = username + "'s Public Key - " + Config.Title;
  112. ViewBag.Description = "The PGP public key for " + username;
  113. User user = UserHelper.GetUser(db, username);
  114. if (user != null)
  115. {
  116. if (!string.IsNullOrEmpty(user.SecuritySettings.PGPSignature))
  117. {
  118. return Content(user.SecuritySettings.PGPSignature, "text/plain");
  119. }
  120. }
  121. return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  122. }
  123. [HttpGet]
  124. [TrackPageView]
  125. [AllowAnonymous]
  126. public ActionResult Login(string ReturnUrl)
  127. {
  128. LoginViewModel model = new LoginViewModel();
  129. model.ReturnUrl = ReturnUrl;
  130. return View("/Areas/User/Views/User/ViewLogin.cshtml", model);
  131. }
  132. [HttpPost]
  133. [AllowAnonymous]
  134. public ActionResult Login([Bind(Prefix = "Login")]LoginViewModel model)
  135. {
  136. if (ModelState.IsValid)
  137. {
  138. string username = model.Username;
  139. User user = UserHelper.GetUser(db, username);
  140. if (user != null)
  141. {
  142. bool userValid = UserHelper.UserPasswordCorrect(db, Config, user, model.Password);
  143. if (userValid)
  144. {
  145. // Perform transfer actions on the account
  146. UserHelper.TransferUser(db, Config, user, model.Password);
  147. user.LastSeen = DateTime.Now;
  148. db.Entry(user).State = EntityState.Modified;
  149. db.SaveChanges();
  150. // Let's double check their email and git accounts to make sure they exist
  151. string email = UserHelper.GetUserEmailAddress(Config, username);
  152. if (Config.EmailConfig.Enabled && !UserHelper.UserEmailExists(Config, email))
  153. {
  154. UserHelper.AddUserEmail(Config, email, model.Password);
  155. }
  156. if (Config.GitConfig.Enabled && !UserHelper.UserGitExists(Config, username))
  157. {
  158. UserHelper.AddUserGit(Config, username, model.Password);
  159. }
  160. bool twoFactor = false;
  161. string returnUrl = model.ReturnUrl;
  162. if (user.SecuritySettings.TwoFactorEnabled)
  163. {
  164. twoFactor = true;
  165. // We need to check their device, and two factor them
  166. if (user.SecuritySettings.AllowTrustedDevices)
  167. {
  168. // Check for the trusted device cookie
  169. HttpCookie cookie = Request.Cookies[Constants.TRUSTEDDEVICECOOKIE + "_" + username];
  170. if (cookie != null)
  171. {
  172. string token = cookie.Value;
  173. if (user.TrustedDevices.Where(d => d.Token == token).FirstOrDefault() != null)
  174. {
  175. // The device token is attached to the user, let's let it slide
  176. twoFactor = false;
  177. }
  178. }
  179. }
  180. }
  181. if (twoFactor)
  182. {
  183. Session["AuthenticatedUser"] = user;
  184. if (string.IsNullOrEmpty(model.ReturnUrl))
  185. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  186. returnUrl = Url.SubRouteUrl("user", "User.CheckAuthenticatorCode", new { returnUrl = returnUrl, rememberMe = model.RememberMe });
  187. model.ReturnUrl = string.Empty;
  188. }
  189. else
  190. {
  191. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  192. // They don't need two factor auth.
  193. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, model.RememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  194. Response.Cookies.Add(authcookie);
  195. }
  196. if (string.IsNullOrEmpty(model.ReturnUrl))
  197. {
  198. return GenerateActionResult(new { result = returnUrl }, Redirect(returnUrl));
  199. }
  200. else
  201. {
  202. return Redirect(model.ReturnUrl);
  203. }
  204. }
  205. }
  206. }
  207. model.Error = true;
  208. model.ErrorMessage = "Invalid Username or Password.";
  209. return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewLogin.cshtml", model));
  210. }
  211. public ActionResult Logout()
  212. {
  213. // Get cookie
  214. HttpCookie authCookie = UserHelper.CreateAuthCookie(User.Identity.Name, false, Request.Url.Host.GetDomain(), Request.IsLocal);
  215. // Signout
  216. FormsAuthentication.SignOut();
  217. Session.Abandon();
  218. // Destroy Cookies
  219. authCookie.Expires = DateTime.Now.AddYears(-1);
  220. Response.Cookies.Add(authCookie);
  221. return Redirect(Url.SubRouteUrl("www", "Home.Index"));
  222. }
  223. [HttpGet]
  224. [TrackPageView]
  225. [AllowAnonymous]
  226. public ActionResult Register(string ReturnUrl)
  227. {
  228. RegisterViewModel model = new RegisterViewModel();
  229. model.ReturnUrl = ReturnUrl;
  230. return View("/Areas/User/Views/User/ViewRegistration.cshtml", model);
  231. }
  232. [HttpPost]
  233. [AllowAnonymous]
  234. public ActionResult Register([Bind(Prefix="Register")]RegisterViewModel model)
  235. {
  236. model.Error = false;
  237. model.ErrorMessage = string.Empty;
  238. if (ModelState.IsValid)
  239. {
  240. if (Config.UserConfig.RegistrationEnabled)
  241. {
  242. if (!model.Error && !UserHelper.ValidUsername(Config, model.Username))
  243. {
  244. model.Error = true;
  245. model.ErrorMessage = "That username is not valid";
  246. }
  247. if (!model.Error && !UserHelper.UsernameAvailable(db, Config, model.Username))
  248. {
  249. model.Error = true;
  250. model.ErrorMessage = "That username is not available";
  251. }
  252. if (!model.Error && model.Password != model.ConfirmPassword)
  253. {
  254. model.Error = true;
  255. model.ErrorMessage = "Passwords must match";
  256. }
  257. // PGP Key valid?
  258. if (!model.Error && !string.IsNullOrEmpty(model.PublicKey) && !PGP.IsPublicKey(model.PublicKey))
  259. {
  260. model.Error = true;
  261. model.ErrorMessage = "Invalid PGP Public Key";
  262. }
  263. if (!model.Error)
  264. {
  265. try
  266. {
  267. User newUser = db.Users.Create();
  268. newUser.JoinDate = DateTime.Now;
  269. newUser.Username = model.Username;
  270. newUser.UserSettings = new UserSettings();
  271. newUser.SecuritySettings = new SecuritySettings();
  272. newUser.BlogSettings = new BlogSettings();
  273. newUser.UploadSettings = new UploadSettings();
  274. if (!string.IsNullOrEmpty(model.PublicKey))
  275. newUser.SecuritySettings.PGPSignature = model.PublicKey;
  276. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  277. newUser.SecuritySettings.RecoveryEmail = model.RecoveryEmail;
  278. UserHelper.AddAccount(db, Config, newUser, model.Password);
  279. // If they have a recovery email, let's send a verification
  280. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  281. {
  282. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, newUser);
  283. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = model.Username });
  284. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  285. UserHelper.SendRecoveryEmailVerification(Config, model.Username, model.RecoveryEmail, resetUrl, verifyUrl);
  286. }
  287. }
  288. catch (Exception ex)
  289. {
  290. model.Error = true;
  291. model.ErrorMessage = ex.GetFullMessage(true);
  292. }
  293. if (!model.Error)
  294. {
  295. return Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl });
  296. }
  297. }
  298. }
  299. if (!model.Error)
  300. {
  301. model.Error = true;
  302. model.ErrorMessage = "User Registration is Disabled";
  303. }
  304. }
  305. return GenerateActionResult(new { error = model.ErrorMessage }, View("/Areas/User/Views/User/ViewRegistration.cshtml", model));
  306. }
  307. [HttpPost]
  308. [ValidateAntiForgeryToken]
  309. public ActionResult Edit(string curPass, string newPass, string newPassConfirm, string pgpPublicKey, string recoveryEmail, bool allowTrustedDevices, bool twoFactorEnabled, string website, string quote, string about, string blogTitle, string blogDesc, bool saveKey, bool serverSideEncrypt)
  310. {
  311. if (ModelState.IsValid)
  312. {
  313. try
  314. {
  315. User user = UserHelper.GetUser(db, User.Identity.Name);
  316. if (user != null)
  317. {
  318. bool changePass = false;
  319. string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain);
  320. // Changing Password?
  321. if (!string.IsNullOrEmpty(curPass) && (!string.IsNullOrEmpty(newPass) || !string.IsNullOrEmpty(newPassConfirm)))
  322. {
  323. // Old Password Valid?
  324. if (!UserHelper.UserPasswordCorrect(db, Config, user, curPass))
  325. {
  326. return Json(new { error = "Invalid Original Password." });
  327. }
  328. // The New Password Match?
  329. if (newPass != newPassConfirm)
  330. {
  331. return Json(new { error = "New Password Must Match." });
  332. }
  333. changePass = true;
  334. }
  335. // PGP Key valid?
  336. if (!string.IsNullOrEmpty(pgpPublicKey) && !PGP.IsPublicKey(pgpPublicKey))
  337. {
  338. return Json(new { error = "Invalid PGP Public Key" });
  339. }
  340. user.SecuritySettings.PGPSignature = pgpPublicKey;
  341. // Recovery Email
  342. bool newRecovery = false;
  343. if (recoveryEmail != user.SecuritySettings.RecoveryEmail)
  344. {
  345. newRecovery = true;
  346. user.SecuritySettings.RecoveryEmail = recoveryEmail;
  347. user.SecuritySettings.RecoveryVerified = false;
  348. }
  349. // Trusted Devices
  350. user.SecuritySettings.AllowTrustedDevices = allowTrustedDevices;
  351. if (!allowTrustedDevices)
  352. {
  353. // They turned it off, let's clear the trusted devices
  354. user.TrustedDevices.Clear();
  355. List<TrustedDevice> foundDevices = db.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  356. if (foundDevices != null)
  357. {
  358. foreach (TrustedDevice device in foundDevices)
  359. {
  360. db.TrustedDevices.Remove(device);
  361. }
  362. }
  363. }
  364. // Two Factor Authentication
  365. bool oldTwoFactor = user.SecuritySettings.TwoFactorEnabled;
  366. user.SecuritySettings.TwoFactorEnabled = twoFactorEnabled;
  367. string newKey = string.Empty;
  368. if (!oldTwoFactor && twoFactorEnabled)
  369. {
  370. // They just enabled it, let's regen the key
  371. newKey = Authenticator.GenerateKey();
  372. }
  373. else if (!twoFactorEnabled)
  374. {
  375. // remove the key when it's disabled
  376. newKey = string.Empty;
  377. }
  378. else
  379. {
  380. // No change, let's use the old value
  381. newKey = user.SecuritySettings.TwoFactorKey;
  382. }
  383. user.SecuritySettings.TwoFactorKey = newKey;
  384. // Profile Info
  385. user.UserSettings.Website = website;
  386. user.UserSettings.Quote = quote;
  387. user.UserSettings.About = about;
  388. // Blogs
  389. user.BlogSettings.Title = blogTitle;
  390. user.BlogSettings.Description = blogDesc;
  391. // Uploads
  392. user.UploadSettings.SaveKey = saveKey;
  393. user.UploadSettings.ServerSideEncrypt = serverSideEncrypt;
  394. UserHelper.EditAccount(db, Config, user, changePass, newPass);
  395. // If they have a recovery email, let's send a verification
  396. if (!string.IsNullOrEmpty(recoveryEmail) && newRecovery)
  397. {
  398. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  399. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  400. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  401. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  402. }
  403. if (!oldTwoFactor && twoFactorEnabled)
  404. {
  405. return Json(new { result = new { checkAuth = true, key = newKey, qrUrl = Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = newKey }) } });
  406. }
  407. return Json(new { result = true });
  408. }
  409. return Json(new { error = "User does not exist" });
  410. }
  411. catch (Exception ex)
  412. {
  413. return Json(new { error = ex.GetFullMessage(true) });
  414. }
  415. }
  416. return Json(new { error = "Invalid Parameters" });
  417. }
  418. [HttpPost]
  419. [ValidateAntiForgeryToken]
  420. public ActionResult Delete()
  421. {
  422. if (ModelState.IsValid)
  423. {
  424. try
  425. {
  426. User user = UserHelper.GetUser(db, User.Identity.Name);
  427. if (user != null)
  428. {
  429. UserHelper.DeleteAccount(db, Config, user);
  430. // Sign Out
  431. Logout();
  432. return Json(new { result = true });
  433. }
  434. }
  435. catch (Exception ex)
  436. {
  437. return Json(new { error = ex.GetFullMessage(true) });
  438. }
  439. }
  440. return Json(new { error = "Unable to delete user" });
  441. }
  442. [HttpGet]
  443. public ActionResult VerifyRecoveryEmail(string code)
  444. {
  445. bool verified = true;
  446. if (string.IsNullOrEmpty(code))
  447. verified &= false;
  448. verified &= UserHelper.VerifyRecoveryEmail(db, Config, User.Identity.Name, code);
  449. RecoveryEmailVerificationViewModel model = new RecoveryEmailVerificationViewModel();
  450. model.Success = verified;
  451. return View("/Areas/User/Views/User/ViewRecoveryEmailVerification.cshtml", model);
  452. }
  453. [HttpPost]
  454. [ValidateAntiForgeryToken]
  455. public ActionResult ResendVerifyRecoveryEmail()
  456. {
  457. if (ModelState.IsValid)
  458. {
  459. try
  460. {
  461. User user = UserHelper.GetUser(db, User.Identity.Name);
  462. if (user != null)
  463. {
  464. // If they have a recovery email, let's send a verification
  465. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail))
  466. {
  467. if (!user.SecuritySettings.RecoveryVerified)
  468. {
  469. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  470. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  471. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  472. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  473. return Json(new { result = true });
  474. }
  475. return Json(new { error = "The recovery email is already verified" });
  476. }
  477. }
  478. }
  479. catch (Exception ex)
  480. {
  481. return Json(new { error = ex.GetFullMessage(true) });
  482. }
  483. }
  484. return Json(new { error = "Unable to resend verification" });
  485. }
  486. [HttpGet]
  487. [AllowAnonymous]
  488. public ActionResult ResetPassword(string username)
  489. {
  490. ResetPasswordViewModel model = new ResetPasswordViewModel();
  491. model.Username = username;
  492. return View("/Areas/User/Views/User/ResetPassword.cshtml", model);
  493. }
  494. [HttpPost]
  495. [AllowAnonymous]
  496. [ValidateAntiForgeryToken]
  497. public ActionResult SendResetPasswordVerification(string username)
  498. {
  499. if (ModelState.IsValid)
  500. {
  501. try
  502. {
  503. User user = UserHelper.GetUser(db, username);
  504. if (user != null)
  505. {
  506. // If they have a recovery email, let's send a verification
  507. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail) && user.SecuritySettings.RecoveryVerified)
  508. {
  509. string verifyCode = UserHelper.CreateResetPasswordVerification(db, Config, user);
  510. string resetUrl = Url.SubRouteUrl("user", "User.VerifyResetPassword", new { Username = user.Username, Code = verifyCode });
  511. UserHelper.SendResetPasswordVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl);
  512. return Json(new { result = true });
  513. }
  514. return Json(new { error = "The username doesn't have a recovery email specified" });
  515. }
  516. return Json(new { error = "The username is not valid" });
  517. }
  518. catch (Exception ex)
  519. {
  520. return Json(new { error = ex.GetFullMessage(true) });
  521. }
  522. }
  523. return Json(new { error = "Unable to send reset link" });
  524. }
  525. [HttpGet]
  526. [AllowAnonymous]
  527. public ActionResult VerifyResetPassword(string username, string code)
  528. {
  529. bool verified = true;
  530. if (string.IsNullOrEmpty(code))
  531. verified &= false;
  532. verified &= UserHelper.VerifyResetPassword(db, Config, username, code);
  533. if (verified)
  534. {
  535. // The password reset code is valid, let's get their user account for this session
  536. User user = UserHelper.GetUser(db, username);
  537. Session["AuthenticatedUser"] = user;
  538. Session["AuthCode"] = code;
  539. }
  540. ResetPasswordVerificationViewModel model = new ResetPasswordVerificationViewModel();
  541. model.Success = verified;
  542. return View("/Areas/User/Views/User/ResetPasswordVerification.cshtml", model);
  543. }
  544. [HttpPost]
  545. [AllowAnonymous]
  546. [ValidateAntiForgeryToken]
  547. public ActionResult SetUserPassword(string password, string confirmPassword)
  548. {
  549. if (ModelState.IsValid)
  550. {
  551. try
  552. {
  553. string code = Session["AuthCode"].ToString();
  554. if (!string.IsNullOrEmpty(code))
  555. {
  556. User user = (User)Session["AuthenticatedUser"];
  557. if (user != null)
  558. {
  559. if (string.IsNullOrEmpty(password))
  560. {
  561. return Json(new { error = "Password must not be empty" });
  562. }
  563. if (password != confirmPassword)
  564. {
  565. return Json(new { error = "Passwords must match" });
  566. }
  567. User newUser = UserHelper.GetUser(db, user.Username);
  568. UserHelper.EditAccount(db, Config, newUser, true, password);
  569. return Json(new { result = true });
  570. }
  571. return Json(new { error = "User does not exist" });
  572. }
  573. return Json(new { error = "Invalid Code" });
  574. }
  575. catch (Exception ex)
  576. {
  577. return Json(new { error = ex.GetFullMessage(true) });
  578. }
  579. }
  580. return Json(new { error = "Unable to reset user password" });
  581. }
  582. [HttpGet]
  583. [AllowAnonymous]
  584. public ActionResult ConfirmTwoFactorAuth(string returnUrl, bool rememberMe)
  585. {
  586. User user = (User)Session["AuthenticatedUser"];
  587. if (user != null)
  588. {
  589. ViewBag.Title = "Unknown Device - " + Config.Title;
  590. ViewBag.Description = "We do not recognize this device.";
  591. TwoFactorViewModel model = new TwoFactorViewModel();
  592. model.ReturnUrl = returnUrl;
  593. model.RememberMe = rememberMe;
  594. model.AllowTrustedDevice = user.SecuritySettings.AllowTrustedDevices;
  595. return View("/Areas/User/Views/User/TwoFactorCheck.cshtml", model);
  596. }
  597. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  598. }
  599. [HttpPost]
  600. [AllowAnonymous]
  601. [ValidateAntiForgeryToken]
  602. public ActionResult ConfirmAuthenticatorCode(string code, string returnUrl, bool rememberMe, bool rememberDevice, string deviceName)
  603. {
  604. User user = (User)Session["AuthenticatedUser"];
  605. if (user != null)
  606. {
  607. if (user.SecuritySettings.TwoFactorEnabled)
  608. {
  609. string key = user.SecuritySettings.TwoFactorKey;
  610. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  611. bool isValid = ta.CheckCode(key, code, user);
  612. if (isValid)
  613. {
  614. // the code was valid, let's log them in!
  615. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, rememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  616. Response.Cookies.Add(authcookie);
  617. if (user.SecuritySettings.AllowTrustedDevices && rememberDevice)
  618. {
  619. // They want to remember the device, and have allow trusted devices on
  620. HttpCookie trustedDeviceCookie = UserHelper.CreateTrustedDeviceCookie(user.Username, Request.Url.Host.GetDomain(), Request.IsLocal);
  621. Response.Cookies.Add(trustedDeviceCookie);
  622. TrustedDevice device = new TrustedDevice();
  623. device.UserId = user.UserId;
  624. device.Name = (string.IsNullOrEmpty(deviceName)) ? "Unknown" : deviceName;
  625. device.DateSeen = DateTime.Now;
  626. device.Token = trustedDeviceCookie.Value;
  627. // Add the token
  628. db.TrustedDevices.Add(device);
  629. db.SaveChanges();
  630. }
  631. if (string.IsNullOrEmpty(returnUrl))
  632. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  633. return Json(new { result = returnUrl });
  634. }
  635. return Json(new { error = "Invalid Authentication Code" });
  636. }
  637. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  638. }
  639. return Json(new { error = "User does not exist" });
  640. }
  641. [HttpPost]
  642. [ValidateAntiForgeryToken]
  643. public ActionResult VerifyAuthenticatorCode(string code)
  644. {
  645. User user = UserHelper.GetUser(db, User.Identity.Name);
  646. if (user != null)
  647. {
  648. if (user.SecuritySettings.TwoFactorEnabled)
  649. {
  650. string key = user.SecuritySettings.TwoFactorKey;
  651. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  652. bool isValid = ta.CheckCode(key, code, user);
  653. if (isValid)
  654. {
  655. return Json(new { result = true });
  656. }
  657. return Json(new { error = "Invalid Authentication Code" });
  658. }
  659. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  660. }
  661. return Json(new { error = "User does not exist" });
  662. }
  663. [HttpGet]
  664. public ActionResult GenerateAuthQrCode(string key)
  665. {
  666. var ProvisionUrl = string.Format("otpauth://totp/{0}:{1}?secret={2}", Config.Title, User.Identity.Name, key);
  667. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  668. QRCodeData qrCodeData = qrGenerator.CreateQrCode(ProvisionUrl, QRCodeGenerator.ECCLevel.Q);
  669. QRCode qrCode = new QRCode(qrCodeData);
  670. Bitmap qrCodeImage = qrCode.GetGraphic(20);
  671. return File(ByteHelper.ImageToByte(qrCodeImage), "image/png");
  672. }
  673. [HttpPost]
  674. [ValidateAntiForgeryToken]
  675. public ActionResult ClearTrustedDevices()
  676. {
  677. try
  678. {
  679. User user = UserHelper.GetUser(db, User.Identity.Name);
  680. if (user != null)
  681. {
  682. if (user.SecuritySettings.AllowTrustedDevices)
  683. {
  684. // let's clear the trusted devices
  685. user.TrustedDevices.Clear();
  686. List<TrustedDevice> foundDevices = db.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  687. if (foundDevices != null)
  688. {
  689. foreach (TrustedDevice device in foundDevices)
  690. {
  691. db.TrustedDevices.Remove(device);
  692. }
  693. }
  694. db.Entry(user).State = EntityState.Modified;
  695. db.SaveChanges();
  696. return Json(new { result = true });
  697. }
  698. return Json(new { error = "User does not allow trusted devices" });
  699. }
  700. return Json(new { error = "User does not exist" });
  701. }
  702. catch (Exception ex)
  703. {
  704. return Json(new { error = ex.GetFullMessage(true) });
  705. }
  706. }
  707. [HttpPost]
  708. [ValidateAntiForgeryToken]
  709. public ActionResult GenerateToken(string name)
  710. {
  711. try
  712. {
  713. User user = UserHelper.GetUser(db, User.Identity.Name);
  714. if (user != null)
  715. {
  716. string newTokenStr = UserHelper.GenerateAuthToken(db, user.Username);
  717. if (!string.IsNullOrEmpty(newTokenStr))
  718. {
  719. AuthToken token = db.AuthTokens.Create();
  720. token.UserId = user.UserId;
  721. token.HashedToken = SHA256.Hash(newTokenStr);
  722. token.Name = name;
  723. db.AuthTokens.Add(token);
  724. db.SaveChanges();
  725. AuthTokenViewModel model = new AuthTokenViewModel();
  726. model.AuthTokenId = token.AuthTokenId;
  727. model.Name = token.Name;
  728. model.LastDateUsed = token.LastDateUsed;
  729. return Json(new { result = new { token = newTokenStr, html = PartialView("~/Areas/User/Views/User/AuthToken.cshtml", model).RenderToString() } });
  730. }
  731. return Json(new { error = "Unable to generate Auth Token" });
  732. }
  733. return Json(new { error = "User does not exist" });
  734. }
  735. catch (Exception ex)
  736. {
  737. return Json(new { error = ex.GetFullMessage(true) });
  738. }
  739. }
  740. [HttpPost]
  741. [ValidateAntiForgeryToken]
  742. public ActionResult RevokeAllTokens()
  743. {
  744. try
  745. {
  746. User user = UserHelper.GetUser(db, User.Identity.Name);
  747. if (user != null)
  748. {
  749. user.AuthTokens.Clear();
  750. List<AuthToken> foundTokens = db.AuthTokens.Where(d => d.UserId == user.UserId).ToList();
  751. if (foundTokens != null)
  752. {
  753. foreach (AuthToken token in foundTokens)
  754. {
  755. db.AuthTokens.Remove(token);
  756. }
  757. }
  758. db.Entry(user).State = EntityState.Modified;
  759. db.SaveChanges();
  760. return Json(new { result = true });
  761. }
  762. return Json(new { error = "User does not exist" });
  763. }
  764. catch (Exception ex)
  765. {
  766. return Json(new { error = ex.GetFullMessage(true) });
  767. }
  768. }
  769. [HttpPost]
  770. [ValidateAntiForgeryToken]
  771. public ActionResult EditTokenName(int tokenId, string name)
  772. {
  773. try
  774. {
  775. User user = UserHelper.GetUser(db, User.Identity.Name);
  776. if (user != null)
  777. {
  778. AuthToken foundToken = db.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  779. if (foundToken != null)
  780. {
  781. foundToken.Name = name;
  782. db.Entry(foundToken).State = EntityState.Modified;
  783. db.SaveChanges();
  784. return Json(new { result = new { name = name } });
  785. }
  786. return Json(new { error = "Authentication Token does not exist" });
  787. }
  788. return Json(new { error = "User does not exist" });
  789. }
  790. catch (Exception ex)
  791. {
  792. return Json(new { error = ex.GetFullMessage(true) });
  793. }
  794. }
  795. [HttpPost]
  796. [ValidateAntiForgeryToken]
  797. public ActionResult DeleteToken(int tokenId)
  798. {
  799. try
  800. {
  801. User user = UserHelper.GetUser(db, User.Identity.Name);
  802. if (user != null)
  803. {
  804. AuthToken foundToken = db.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  805. if (foundToken != null)
  806. {
  807. db.AuthTokens.Remove(foundToken);
  808. user.AuthTokens.Remove(foundToken);
  809. db.Entry(user).State = EntityState.Modified;
  810. db.SaveChanges();
  811. return Json(new { result = true });
  812. }
  813. return Json(new { error = "Authentication Token does not exist" });
  814. }
  815. return Json(new { error = "User does not exist" });
  816. }
  817. catch (Exception ex)
  818. {
  819. return Json(new { error = ex.GetFullMessage(true) });
  820. }
  821. }
  822. }
  823. }