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

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