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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  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. // New key, so let's upsert their key into git
  404. if (Config.GitConfig.Enabled)
  405. {
  406. UserHelper.CreateUserGitTwoFactor(Config, user.Username, newKey, DateTimeHelper.GetUnixTimestamp());
  407. }
  408. }
  409. else if (!twoFactorEnabled)
  410. {
  411. // remove the key when it's disabled
  412. newKey = string.Empty;
  413. // Removed the key, so delete it from git as well
  414. if (Config.GitConfig.Enabled)
  415. {
  416. UserHelper.DeleteUserGitTwoFactor(Config, user.Username);
  417. }
  418. }
  419. else
  420. {
  421. // No change, let's use the old value
  422. newKey = user.SecuritySettings.TwoFactorKey;
  423. }
  424. user.SecuritySettings.TwoFactorKey = newKey;
  425. // Profile Info
  426. user.UserSettings.Website = website;
  427. user.UserSettings.Quote = quote;
  428. user.UserSettings.About = about;
  429. // Blogs
  430. user.BlogSettings.Title = blogTitle;
  431. user.BlogSettings.Description = blogDesc;
  432. // Uploads
  433. user.UploadSettings.Encrypt = encrypt;
  434. UserHelper.EditAccount(db, Config, user, changePass, newPass);
  435. // If they have a recovery email, let's send a verification
  436. if (!string.IsNullOrEmpty(recoveryEmail) && newRecovery)
  437. {
  438. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  439. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  440. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  441. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  442. }
  443. if (!oldTwoFactor && twoFactorEnabled)
  444. {
  445. return Json(new { result = new { checkAuth = true, key = newKey, qrUrl = Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = newKey }) } });
  446. }
  447. return Json(new { result = true });
  448. }
  449. return Json(new { error = "User does not exist" });
  450. }
  451. }
  452. catch (Exception ex)
  453. {
  454. return Json(new { error = ex.GetFullMessage(true) });
  455. }
  456. }
  457. return Json(new { error = "Invalid Parameters" });
  458. }
  459. [HttpPost]
  460. [ValidateAntiForgeryToken]
  461. public ActionResult Delete()
  462. {
  463. if (ModelState.IsValid)
  464. {
  465. try
  466. {
  467. using (TeknikEntities db = new TeknikEntities())
  468. {
  469. User user = UserHelper.GetUser(db, User.Identity.Name);
  470. if (user != null)
  471. {
  472. UserHelper.DeleteAccount(db, Config, user);
  473. // Sign Out
  474. Logout();
  475. return Json(new { result = true });
  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 delete user" });
  485. }
  486. [HttpGet]
  487. public ActionResult VerifyRecoveryEmail(string code)
  488. {
  489. bool verified = true;
  490. if (string.IsNullOrEmpty(code))
  491. verified &= false;
  492. // Is there a code?
  493. if (verified)
  494. {
  495. using (TeknikEntities db = new TeknikEntities())
  496. {
  497. verified &= UserHelper.VerifyRecoveryEmail(db, Config, User.Identity.Name, code);
  498. }
  499. }
  500. RecoveryEmailVerificationViewModel model = new RecoveryEmailVerificationViewModel();
  501. model.Success = verified;
  502. return View("/Areas/User/Views/User/ViewRecoveryEmailVerification.cshtml", model);
  503. }
  504. [HttpPost]
  505. [ValidateAntiForgeryToken]
  506. public ActionResult ResendVerifyRecoveryEmail()
  507. {
  508. if (ModelState.IsValid)
  509. {
  510. try
  511. {
  512. using (TeknikEntities db = new TeknikEntities())
  513. {
  514. User user = UserHelper.GetUser(db, User.Identity.Name);
  515. if (user != null)
  516. {
  517. // If they have a recovery email, let's send a verification
  518. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail))
  519. {
  520. if (!user.SecuritySettings.RecoveryVerified)
  521. {
  522. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  523. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  524. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  525. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  526. return Json(new { result = true });
  527. }
  528. return Json(new { error = "The recovery email is already verified" });
  529. }
  530. }
  531. }
  532. }
  533. catch (Exception ex)
  534. {
  535. return Json(new { error = ex.GetFullMessage(true) });
  536. }
  537. }
  538. return Json(new { error = "Unable to resend verification" });
  539. }
  540. [HttpGet]
  541. [AllowAnonymous]
  542. public ActionResult ResetPassword(string username)
  543. {
  544. ResetPasswordViewModel model = new ResetPasswordViewModel();
  545. model.Username = username;
  546. return View("/Areas/User/Views/User/ResetPassword.cshtml", model);
  547. }
  548. [HttpPost]
  549. [AllowAnonymous]
  550. [ValidateAntiForgeryToken]
  551. public ActionResult SendResetPasswordVerification(string username)
  552. {
  553. if (ModelState.IsValid)
  554. {
  555. try
  556. {
  557. using (TeknikEntities db = new TeknikEntities())
  558. {
  559. User user = UserHelper.GetUser(db, username);
  560. if (user != null)
  561. {
  562. // If they have a recovery email, let's send a verification
  563. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail) && user.SecuritySettings.RecoveryVerified)
  564. {
  565. string verifyCode = UserHelper.CreateResetPasswordVerification(db, Config, user);
  566. string resetUrl = Url.SubRouteUrl("user", "User.VerifyResetPassword", new { Username = user.Username, Code = verifyCode });
  567. UserHelper.SendResetPasswordVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl);
  568. return Json(new { result = true });
  569. }
  570. return Json(new { error = "The username doesn't have a recovery email specified" });
  571. }
  572. return Json(new { error = "The username is not valid" });
  573. }
  574. }
  575. catch (Exception ex)
  576. {
  577. return Json(new { error = ex.GetFullMessage(true) });
  578. }
  579. }
  580. return Json(new { error = "Unable to send reset link" });
  581. }
  582. [HttpGet]
  583. [AllowAnonymous]
  584. public ActionResult VerifyResetPassword(string username, string code)
  585. {
  586. bool verified = true;
  587. if (string.IsNullOrEmpty(code))
  588. verified &= false;
  589. // Is there a code?
  590. if (verified)
  591. {
  592. using (TeknikEntities db = new TeknikEntities())
  593. {
  594. verified &= UserHelper.VerifyResetPassword(db, Config, username, code);
  595. if (verified)
  596. {
  597. // The password reset code is valid, let's get their user account for this session
  598. User user = UserHelper.GetUser(db, username);
  599. Session["AuthenticatedUser"] = user;
  600. Session["AuthCode"] = code;
  601. }
  602. }
  603. }
  604. ResetPasswordVerificationViewModel model = new ResetPasswordVerificationViewModel();
  605. model.Success = verified;
  606. return View("/Areas/User/Views/User/ResetPasswordVerification.cshtml", model);
  607. }
  608. [HttpPost]
  609. [AllowAnonymous]
  610. [ValidateAntiForgeryToken]
  611. public ActionResult SetUserPassword(string password, string confirmPassword)
  612. {
  613. if (ModelState.IsValid)
  614. {
  615. try
  616. {
  617. string code = Session["AuthCode"].ToString();
  618. if (!string.IsNullOrEmpty(code))
  619. {
  620. User user = (User)Session["AuthenticatedUser"];
  621. if (user != null)
  622. {
  623. if (string.IsNullOrEmpty(password))
  624. {
  625. return Json(new { error = "Password must not be empty" });
  626. }
  627. if (password != confirmPassword)
  628. {
  629. return Json(new { error = "Passwords must match" });
  630. }
  631. using (TeknikEntities db = new TeknikEntities())
  632. {
  633. User newUser = UserHelper.GetUser(db, user.Username);
  634. UserHelper.EditAccount(db, Config, newUser, true, password);
  635. }
  636. return Json(new { result = true });
  637. }
  638. return Json(new { error = "User does not exist" });
  639. }
  640. return Json(new { error = "Invalid Code" });
  641. }
  642. catch (Exception ex)
  643. {
  644. return Json(new { error = ex.GetFullMessage(true) });
  645. }
  646. }
  647. return Json(new { error = "Unable to reset user password" });
  648. }
  649. [HttpGet]
  650. [AllowAnonymous]
  651. public ActionResult ConfirmTwoFactorAuth(string returnUrl, bool rememberMe)
  652. {
  653. User user = (User)Session["AuthenticatedUser"];
  654. if (user != null)
  655. {
  656. ViewBag.Title = "Unknown Device - " + Config.Title;
  657. ViewBag.Description = "We do not recognize this device.";
  658. TwoFactorViewModel model = new TwoFactorViewModel();
  659. model.ReturnUrl = returnUrl;
  660. model.RememberMe = rememberMe;
  661. model.AllowTrustedDevice = user.SecuritySettings.AllowTrustedDevices;
  662. return View("/Areas/User/Views/User/TwoFactorCheck.cshtml", model);
  663. }
  664. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  665. }
  666. [HttpPost]
  667. [AllowAnonymous]
  668. [ValidateAntiForgeryToken]
  669. public ActionResult ConfirmAuthenticatorCode(string code, string returnUrl, bool rememberMe, bool rememberDevice, string deviceName)
  670. {
  671. User user = (User)Session["AuthenticatedUser"];
  672. if (user != null)
  673. {
  674. if (user.SecuritySettings.TwoFactorEnabled)
  675. {
  676. string key = user.SecuritySettings.TwoFactorKey;
  677. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  678. bool isValid = ta.CheckCode(key, code, user);
  679. if (isValid)
  680. {
  681. // the code was valid, let's log them in!
  682. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, rememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  683. Response.Cookies.Add(authcookie);
  684. if (user.SecuritySettings.AllowTrustedDevices && rememberDevice)
  685. {
  686. // They want to remember the device, and have allow trusted devices on
  687. HttpCookie trustedDeviceCookie = UserHelper.CreateTrustedDeviceCookie(user.Username, Request.Url.Host.GetDomain(), Request.IsLocal);
  688. Response.Cookies.Add(trustedDeviceCookie);
  689. using (TeknikEntities db = new TeknikEntities())
  690. {
  691. TrustedDevice device = new TrustedDevice();
  692. device.UserId = user.UserId;
  693. device.Name = (string.IsNullOrEmpty(deviceName)) ? "Unknown" : deviceName;
  694. device.DateSeen = DateTime.Now;
  695. device.Token = trustedDeviceCookie.Value;
  696. // Add the token
  697. db.TrustedDevices.Add(device);
  698. db.SaveChanges();
  699. }
  700. }
  701. if (string.IsNullOrEmpty(returnUrl))
  702. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  703. return Json(new { result = returnUrl });
  704. }
  705. return Json(new { error = "Invalid Authentication Code" });
  706. }
  707. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  708. }
  709. return Json(new { error = "User does not exist" });
  710. }
  711. [HttpPost]
  712. [ValidateAntiForgeryToken]
  713. public ActionResult VerifyAuthenticatorCode(string code)
  714. {
  715. using (TeknikEntities db = new TeknikEntities())
  716. {
  717. User user = UserHelper.GetUser(db, User.Identity.Name);
  718. if (user != null)
  719. {
  720. if (user.SecuritySettings.TwoFactorEnabled)
  721. {
  722. string key = user.SecuritySettings.TwoFactorKey;
  723. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  724. bool isValid = ta.CheckCode(key, code, user);
  725. if (isValid)
  726. {
  727. return Json(new { result = true });
  728. }
  729. return Json(new { error = "Invalid Authentication Code" });
  730. }
  731. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  732. }
  733. return Json(new { error = "User does not exist" });
  734. }
  735. }
  736. [HttpGet]
  737. public ActionResult GenerateAuthQrCode(string key)
  738. {
  739. var ProvisionUrl = string.Format("otpauth://totp/{0}:{1}?secret={2}", Config.Title, User.Identity.Name, key);
  740. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  741. QRCodeData qrCodeData = qrGenerator.CreateQrCode(ProvisionUrl, QRCodeGenerator.ECCLevel.Q);
  742. QRCode qrCode = new QRCode(qrCodeData);
  743. Bitmap qrCodeImage = qrCode.GetGraphic(20);
  744. return File(ByteHelper.ImageToByte(qrCodeImage), "image/png");
  745. }
  746. [HttpPost]
  747. [ValidateAntiForgeryToken]
  748. public ActionResult ClearTrustedDevices()
  749. {
  750. try
  751. {
  752. using (TeknikEntities db = new TeknikEntities())
  753. {
  754. User user = UserHelper.GetUser(db, User.Identity.Name);
  755. if (user != null)
  756. {
  757. if (user.SecuritySettings.AllowTrustedDevices)
  758. {
  759. // let's clear the trusted devices
  760. user.TrustedDevices.Clear();
  761. List<TrustedDevice> foundDevices = db.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  762. if (foundDevices != null)
  763. {
  764. foreach (TrustedDevice device in foundDevices)
  765. {
  766. db.TrustedDevices.Remove(device);
  767. }
  768. }
  769. db.Entry(user).State = EntityState.Modified;
  770. db.SaveChanges();
  771. return Json(new { result = true });
  772. }
  773. return Json(new { error = "User does not allow trusted devices" });
  774. }
  775. return Json(new { error = "User does not exist" });
  776. }
  777. }
  778. catch (Exception ex)
  779. {
  780. return Json(new { error = ex.GetFullMessage(true) });
  781. }
  782. }
  783. [HttpPost]
  784. [ValidateAntiForgeryToken]
  785. public ActionResult GenerateToken(string name)
  786. {
  787. try
  788. {
  789. using (TeknikEntities db = new TeknikEntities())
  790. {
  791. User user = UserHelper.GetUser(db, User.Identity.Name);
  792. if (user != null)
  793. {
  794. string newTokenStr = UserHelper.GenerateAuthToken(db, user.Username);
  795. if (!string.IsNullOrEmpty(newTokenStr))
  796. {
  797. AuthToken token = db.AuthTokens.Create();
  798. token.UserId = user.UserId;
  799. token.HashedToken = SHA256.Hash(newTokenStr);
  800. token.Name = name;
  801. db.AuthTokens.Add(token);
  802. db.SaveChanges();
  803. AuthTokenViewModel model = new AuthTokenViewModel();
  804. model.AuthTokenId = token.AuthTokenId;
  805. model.Name = token.Name;
  806. model.LastDateUsed = token.LastDateUsed;
  807. return Json(new { result = new { token = newTokenStr, html = PartialView("~/Areas/User/Views/User/AuthToken.cshtml", model).RenderToString() } });
  808. }
  809. return Json(new { error = "Unable to generate Auth Token" });
  810. }
  811. return Json(new { error = "User does not exist" });
  812. }
  813. }
  814. catch (Exception ex)
  815. {
  816. return Json(new { error = ex.GetFullMessage(true) });
  817. }
  818. }
  819. [HttpPost]
  820. [ValidateAntiForgeryToken]
  821. public ActionResult RevokeAllTokens()
  822. {
  823. try
  824. {
  825. using (TeknikEntities db = new TeknikEntities())
  826. {
  827. User user = UserHelper.GetUser(db, User.Identity.Name);
  828. if (user != null)
  829. {
  830. user.AuthTokens.Clear();
  831. List<AuthToken> foundTokens = db.AuthTokens.Where(d => d.UserId == user.UserId).ToList();
  832. if (foundTokens != null)
  833. {
  834. foreach (AuthToken token in foundTokens)
  835. {
  836. db.AuthTokens.Remove(token);
  837. }
  838. }
  839. db.Entry(user).State = EntityState.Modified;
  840. db.SaveChanges();
  841. return Json(new { result = true });
  842. }
  843. return Json(new { error = "User does not exist" });
  844. }
  845. }
  846. catch (Exception ex)
  847. {
  848. return Json(new { error = ex.GetFullMessage(true) });
  849. }
  850. }
  851. [HttpPost]
  852. [ValidateAntiForgeryToken]
  853. public ActionResult EditTokenName(int tokenId, string name)
  854. {
  855. try
  856. {
  857. using (TeknikEntities db = new TeknikEntities())
  858. {
  859. User user = UserHelper.GetUser(db, User.Identity.Name);
  860. if (user != null)
  861. {
  862. AuthToken foundToken = db.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  863. if (foundToken != null)
  864. {
  865. foundToken.Name = name;
  866. db.Entry(foundToken).State = EntityState.Modified;
  867. db.SaveChanges();
  868. return Json(new { result = new { name = name } });
  869. }
  870. return Json(new { error = "Authentication Token does not exist" });
  871. }
  872. return Json(new { error = "User does not exist" });
  873. }
  874. }
  875. catch (Exception ex)
  876. {
  877. return Json(new { error = ex.GetFullMessage(true) });
  878. }
  879. }
  880. [HttpPost]
  881. [ValidateAntiForgeryToken]
  882. public ActionResult DeleteToken(int tokenId)
  883. {
  884. try
  885. {
  886. using (TeknikEntities db = new TeknikEntities())
  887. {
  888. User user = UserHelper.GetUser(db, User.Identity.Name);
  889. if (user != null)
  890. {
  891. AuthToken foundToken = db.AuthTokens.Where(d => d.UserId == user.UserId && d.AuthTokenId == tokenId).FirstOrDefault();
  892. if (foundToken != null)
  893. {
  894. db.AuthTokens.Remove(foundToken);
  895. user.AuthTokens.Remove(foundToken);
  896. db.Entry(user).State = EntityState.Modified;
  897. db.SaveChanges();
  898. return Json(new { result = true });
  899. }
  900. return Json(new { error = "Authentication Token does not exist" });
  901. }
  902. return Json(new { error = "User does not exist" });
  903. }
  904. }
  905. catch (Exception ex)
  906. {
  907. return Json(new { error = ex.GetFullMessage(true) });
  908. }
  909. }
  910. }
  911. }