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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data.Entity;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Web;
  7. using System.Web.Mvc;
  8. using System.Web.Security;
  9. using Teknik.Areas.Shortener.Models;
  10. using Teknik.Areas.Blog.Models;
  11. using Teknik.Areas.Error.Controllers;
  12. using Teknik.Areas.Error.ViewModels;
  13. using Teknik.Areas.Users.Models;
  14. using Teknik.Areas.Users.ViewModels;
  15. using Teknik.Controllers;
  16. using Teknik.Helpers;
  17. using Teknik.Models;
  18. using Teknik.ViewModels;
  19. using System.Windows;
  20. using System.Net;
  21. using Teknik.Areas.Users.Utility;
  22. using Teknik.Filters;
  23. using QRCoder;
  24. using System.Text;
  25. using TwoStepsAuthenticator;
  26. using System.Drawing;
  27. namespace Teknik.Areas.Users.Controllers
  28. {
  29. public class UserController : DefaultController
  30. {
  31. private static readonly UsedCodesManager usedCodesManager = new UsedCodesManager();
  32. private TeknikEntities db = new TeknikEntities();
  33. // GET: Profile/Profile
  34. [TrackPageView]
  35. [AllowAnonymous]
  36. public ActionResult Index(string username)
  37. {
  38. if (string.IsNullOrEmpty(username))
  39. {
  40. username = User.Identity.Name;
  41. }
  42. ProfileViewModel model = new ProfileViewModel();
  43. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  44. ViewBag.Description = "The User does not exist";
  45. try
  46. {
  47. User user = UserHelper.GetUser(db, username);
  48. if (user != null)
  49. {
  50. ViewBag.Title = username + "'s Profile - " + Config.Title;
  51. ViewBag.Description = "Viewing " + username + "'s Profile";
  52. model.UserID = user.UserId;
  53. model.Username = user.Username;
  54. if (Config.EmailConfig.Enabled)
  55. {
  56. model.Email = string.Format("{0}@{1}", user.Username, Config.EmailConfig.Domain);
  57. }
  58. model.JoinDate = user.JoinDate;
  59. model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user);
  60. model.UserSettings = user.UserSettings;
  61. model.SecuritySettings = user.SecuritySettings;
  62. model.BlogSettings = user.BlogSettings;
  63. model.UploadSettings = user.UploadSettings;
  64. model.Uploads = db.Uploads.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DateUploaded).ToList();
  65. model.Pastes = db.Pastes.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DatePosted).ToList();
  66. model.ShortenedUrls = db.ShortenedUrls.Where(s => s.UserId == user.UserId).OrderByDescending(s => s.DateAdded).ToList();
  67. return View(model);
  68. }
  69. model.Error = true;
  70. model.ErrorMessage = "The user does not exist";
  71. }
  72. catch (Exception ex)
  73. {
  74. model.Error = true;
  75. model.ErrorMessage = ex.GetFullMessage(true);
  76. }
  77. return View(model);
  78. }
  79. [TrackPageView]
  80. [AllowAnonymous]
  81. public ActionResult Settings()
  82. {
  83. if (User.Identity.IsAuthenticated)
  84. {
  85. string username = User.Identity.Name;
  86. SettingsViewModel model = new SettingsViewModel();
  87. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  88. ViewBag.Description = "The User does not exist";
  89. User user = UserHelper.GetUser(db, username);
  90. if (user != null)
  91. {
  92. Session["AuthenticatedUser"] = user;
  93. ViewBag.Title = "Settings - " + Config.Title;
  94. ViewBag.Description = "Your " + Config.Title + " Settings";
  95. model.UserID = user.UserId;
  96. model.Username = user.Username;
  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. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  107. }
  108. [HttpGet]
  109. [TrackPageView]
  110. [AllowAnonymous]
  111. public ActionResult ViewRawPGP(string username)
  112. {
  113. ViewBag.Title = username + "'s Public Key - " + Config.Title;
  114. ViewBag.Description = "The PGP public key for " + username;
  115. User user = UserHelper.GetUser(db, username);
  116. if (user != null)
  117. {
  118. if (!string.IsNullOrEmpty(user.SecuritySettings.PGPSignature))
  119. {
  120. return Content(user.SecuritySettings.PGPSignature, "text/plain");
  121. }
  122. }
  123. return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  124. }
  125. [HttpGet]
  126. [TrackPageView]
  127. [AllowAnonymous]
  128. public ActionResult Login(string ReturnUrl)
  129. {
  130. LoginViewModel model = new LoginViewModel();
  131. model.ReturnUrl = ReturnUrl;
  132. return View("/Areas/User/Views/User/ViewLogin.cshtml", model);
  133. }
  134. [HttpPost]
  135. [AllowAnonymous]
  136. public ActionResult Login([Bind(Prefix = "Login")]LoginViewModel model)
  137. {
  138. if (ModelState.IsValid)
  139. {
  140. string username = model.Username;
  141. User user = UserHelper.GetUser(db, username);
  142. if (user != null)
  143. {
  144. bool userValid = UserHelper.UserPasswordCorrect(db, Config, user, model.Password);
  145. if (userValid)
  146. {
  147. bool twoFactor = false;
  148. string returnUrl = model.ReturnUrl;
  149. if (user.SecuritySettings.TwoFactorEnabled)
  150. {
  151. twoFactor = true;
  152. // We need to check their device, and two factor them
  153. if (user.SecuritySettings.AllowTrustedDevices)
  154. {
  155. // Check for the trusted device cookie
  156. HttpCookie cookie = Request.Cookies[Constants.TRUSTEDDEVICECOOKIE + "_" + username];
  157. if (cookie != null)
  158. {
  159. string token = cookie.Value;
  160. if (user.TrustedDevices.Where(d => d.Token == token).FirstOrDefault() != null)
  161. {
  162. // The device token is attached to the user, let's let it slide
  163. twoFactor = false;
  164. }
  165. }
  166. }
  167. }
  168. if (twoFactor)
  169. {
  170. Session["AuthenticatedUser"] = user;
  171. if (string.IsNullOrEmpty(model.ReturnUrl))
  172. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  173. returnUrl = Url.SubRouteUrl("user", "User.CheckAuthenticatorCode", new { returnUrl = returnUrl, rememberMe = model.RememberMe });
  174. model.ReturnUrl = string.Empty;
  175. }
  176. else
  177. {
  178. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  179. // They don't need two factor auth.
  180. UserHelper.TransferUser(db, Config, user, model.Password);
  181. user.LastSeen = DateTime.Now;
  182. db.Entry(user).State = EntityState.Modified;
  183. db.SaveChanges();
  184. HttpCookie authcookie = UserHelper.CreateAuthCookie(model.Username, model.RememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  185. Response.Cookies.Add(authcookie);
  186. }
  187. if (string.IsNullOrEmpty(model.ReturnUrl))
  188. {
  189. return Json(new { result = returnUrl });
  190. }
  191. else
  192. {
  193. return Redirect(model.ReturnUrl);
  194. }
  195. }
  196. }
  197. }
  198. return Json(new { error = "Invalid Username or Password." });
  199. }
  200. public ActionResult Logout()
  201. {
  202. // Get cookie
  203. HttpCookie authCookie = UserHelper.CreateAuthCookie(User.Identity.Name, false, Request.Url.Host.GetDomain(), Request.IsLocal);
  204. // Signout
  205. FormsAuthentication.SignOut();
  206. Session.Abandon();
  207. // Destroy Cookies
  208. authCookie.Expires = DateTime.Now.AddYears(-1);
  209. Response.Cookies.Add(authCookie);
  210. return Redirect(Url.SubRouteUrl("www", "Home.Index"));
  211. }
  212. [HttpGet]
  213. [TrackPageView]
  214. [AllowAnonymous]
  215. public ActionResult Register(string ReturnUrl)
  216. {
  217. RegisterViewModel model = new RegisterViewModel();
  218. model.ReturnUrl = ReturnUrl;
  219. return View("/Areas/User/Views/User/ViewRegistration.cshtml", model);
  220. }
  221. [HttpPost]
  222. [AllowAnonymous]
  223. public ActionResult Register([Bind(Prefix="Register")]RegisterViewModel model)
  224. {
  225. if (ModelState.IsValid)
  226. {
  227. if (Config.UserConfig.RegistrationEnabled)
  228. {
  229. if (!UserHelper.ValidUsername(Config, model.Username))
  230. {
  231. return Json(new { error = "That username is not valid" });
  232. }
  233. if (!UserHelper.UsernameAvailable(db, Config, model.Username))
  234. {
  235. return Json(new { error = "That username is not available" });
  236. }
  237. if (model.Password != model.ConfirmPassword)
  238. {
  239. return Json(new { error = "Passwords must match" });
  240. }
  241. // PGP Key valid?
  242. if (!string.IsNullOrEmpty(model.PublicKey) && !PGP.IsPublicKey(model.PublicKey))
  243. {
  244. return Json(new { error = "Invalid PGP Public Key" });
  245. }
  246. try
  247. {
  248. User newUser = db.Users.Create();
  249. newUser.JoinDate = DateTime.Now;
  250. newUser.Username = model.Username;
  251. newUser.UserSettings = new UserSettings();
  252. newUser.SecuritySettings = new SecuritySettings();
  253. newUser.BlogSettings = new BlogSettings();
  254. newUser.UploadSettings = new UploadSettings();
  255. if (!string.IsNullOrEmpty(model.PublicKey))
  256. newUser.SecuritySettings.PGPSignature = model.PublicKey;
  257. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  258. newUser.SecuritySettings.RecoveryEmail = model.RecoveryEmail;
  259. UserHelper.AddAccount(db, Config, newUser, model.Password);
  260. // If they have a recovery email, let's send a verification
  261. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  262. {
  263. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, newUser);
  264. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = model.Username });
  265. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  266. UserHelper.SendRecoveryEmailVerification(Config, model.Username, model.RecoveryEmail, resetUrl, verifyUrl);
  267. }
  268. }
  269. catch (Exception ex)
  270. {
  271. return Json(new { error = ex.GetFullMessage(true) });
  272. }
  273. return Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl });
  274. }
  275. return Json(new { error = "User Registration is Disabled" });
  276. }
  277. return Json(new { error = "You must include all fields." });
  278. }
  279. [HttpPost]
  280. 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)
  281. {
  282. if (ModelState.IsValid)
  283. {
  284. try
  285. {
  286. User user = UserHelper.GetUser(db, User.Identity.Name);
  287. if (user != null)
  288. {
  289. bool changePass = false;
  290. string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain);
  291. // Changing Password?
  292. if (!string.IsNullOrEmpty(curPass) && (!string.IsNullOrEmpty(newPass) || !string.IsNullOrEmpty(newPassConfirm)))
  293. {
  294. // Old Password Valid?
  295. if (!UserHelper.UserPasswordCorrect(db, Config, user, curPass))
  296. {
  297. return Json(new { error = "Invalid Original Password." });
  298. }
  299. // The New Password Match?
  300. if (newPass != newPassConfirm)
  301. {
  302. return Json(new { error = "New Password Must Match." });
  303. }
  304. changePass = true;
  305. }
  306. // PGP Key valid?
  307. if (!string.IsNullOrEmpty(pgpPublicKey) && !PGP.IsPublicKey(pgpPublicKey))
  308. {
  309. return Json(new { error = "Invalid PGP Public Key" });
  310. }
  311. user.SecuritySettings.PGPSignature = pgpPublicKey;
  312. // Recovery Email
  313. bool newRecovery = false;
  314. if (recoveryEmail != user.SecuritySettings.RecoveryEmail)
  315. {
  316. newRecovery = true;
  317. user.SecuritySettings.RecoveryEmail = recoveryEmail;
  318. user.SecuritySettings.RecoveryVerified = false;
  319. }
  320. // Trusted Devices
  321. user.SecuritySettings.AllowTrustedDevices = allowTrustedDevices;
  322. if (!allowTrustedDevices)
  323. {
  324. // They turned it off, let's clear the trusted devices
  325. user.TrustedDevices.Clear();
  326. List<TrustedDevice> foundDevices = db.TrustedDevices.Where(d => d.UserId == user.UserId).ToList();
  327. if (foundDevices != null)
  328. {
  329. foreach (TrustedDevice device in foundDevices)
  330. {
  331. db.TrustedDevices.Remove(device);
  332. }
  333. }
  334. }
  335. // Two Factor Authentication
  336. bool oldTwoFactor = user.SecuritySettings.TwoFactorEnabled;
  337. user.SecuritySettings.TwoFactorEnabled = twoFactorEnabled;
  338. string newKey = string.Empty;
  339. if (!oldTwoFactor && twoFactorEnabled)
  340. {
  341. // They just enabled it, let's regen the key
  342. newKey = Authenticator.GenerateKey();
  343. }
  344. else if (!twoFactorEnabled)
  345. {
  346. // remove the key when it's disabled
  347. newKey = string.Empty;
  348. }
  349. else
  350. {
  351. // No change, let's use the old value
  352. newKey = user.SecuritySettings.TwoFactorKey;
  353. }
  354. user.SecuritySettings.TwoFactorKey = newKey;
  355. // Profile Info
  356. user.UserSettings.Website = website;
  357. user.UserSettings.Quote = quote;
  358. user.UserSettings.About = about;
  359. // Blogs
  360. user.BlogSettings.Title = blogTitle;
  361. user.BlogSettings.Description = blogDesc;
  362. // Uploads
  363. user.UploadSettings.SaveKey = saveKey;
  364. user.UploadSettings.ServerSideEncrypt = serverSideEncrypt;
  365. UserHelper.EditAccount(db, Config, user, changePass, newPass);
  366. // If they have a recovery email, let's send a verification
  367. if (!string.IsNullOrEmpty(recoveryEmail) && newRecovery)
  368. {
  369. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  370. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  371. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  372. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  373. }
  374. if (!oldTwoFactor && twoFactorEnabled)
  375. {
  376. return Json(new { result = new { checkAuth = true, key = newKey, qrUrl = Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = newKey }) } });
  377. }
  378. return Json(new { result = true });
  379. }
  380. return Json(new { error = "User does not exist" });
  381. }
  382. catch (Exception ex)
  383. {
  384. return Json(new { error = ex.GetFullMessage(true) });
  385. }
  386. }
  387. return Json(new { error = "Invalid Parameters" });
  388. }
  389. [HttpPost]
  390. public ActionResult Delete()
  391. {
  392. if (ModelState.IsValid)
  393. {
  394. try
  395. {
  396. User user = UserHelper.GetUser(db, User.Identity.Name);
  397. if (user != null)
  398. {
  399. UserHelper.DeleteAccount(db, Config, user);
  400. // Sign Out
  401. Logout();
  402. return Json(new { result = true });
  403. }
  404. }
  405. catch (Exception ex)
  406. {
  407. return Json(new { error = ex.GetFullMessage(true) });
  408. }
  409. }
  410. return Json(new { error = "Unable to delete user" });
  411. }
  412. [HttpGet]
  413. public ActionResult VerifyRecoveryEmail(string code)
  414. {
  415. bool verified = true;
  416. if (string.IsNullOrEmpty(code))
  417. verified &= false;
  418. verified &= UserHelper.VerifyRecoveryEmail(db, Config, User.Identity.Name, code);
  419. RecoveryEmailVerificationViewModel model = new RecoveryEmailVerificationViewModel();
  420. model.Success = verified;
  421. return View("/Areas/User/Views/User/ViewRecoveryEmailVerification.cshtml", model);
  422. }
  423. [HttpPost]
  424. public ActionResult ResendVerifyRecoveryEmail()
  425. {
  426. if (ModelState.IsValid)
  427. {
  428. try
  429. {
  430. User user = UserHelper.GetUser(db, User.Identity.Name);
  431. if (user != null)
  432. {
  433. // If they have a recovery email, let's send a verification
  434. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail))
  435. {
  436. if (!user.SecuritySettings.RecoveryVerified)
  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. return Json(new { result = true });
  443. }
  444. return Json(new { error = "The recovery email is already verified" });
  445. }
  446. }
  447. }
  448. catch (Exception ex)
  449. {
  450. return Json(new { error = ex.GetFullMessage(true) });
  451. }
  452. }
  453. return Json(new { error = "Unable to resend verification" });
  454. }
  455. [HttpGet]
  456. [AllowAnonymous]
  457. public ActionResult ResetPassword(string username)
  458. {
  459. ResetPasswordViewModel model = new ResetPasswordViewModel();
  460. model.Username = username;
  461. return View("/Areas/User/Views/User/ResetPassword.cshtml", model);
  462. }
  463. [HttpPost]
  464. [AllowAnonymous]
  465. public ActionResult SendResetPasswordVerification(string username)
  466. {
  467. if (ModelState.IsValid)
  468. {
  469. try
  470. {
  471. User user = UserHelper.GetUser(db, username);
  472. if (user != null)
  473. {
  474. // If they have a recovery email, let's send a verification
  475. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail) && user.SecuritySettings.RecoveryVerified)
  476. {
  477. string verifyCode = UserHelper.CreateResetPasswordVerification(db, Config, user);
  478. string resetUrl = Url.SubRouteUrl("user", "User.VerifyResetPassword", new { Username = user.Username, Code = verifyCode });
  479. UserHelper.SendResetPasswordVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl);
  480. return Json(new { result = true });
  481. }
  482. return Json(new { error = "The username doesn't have a recovery email specified" });
  483. }
  484. return Json(new { error = "The username is not valid" });
  485. }
  486. catch (Exception ex)
  487. {
  488. return Json(new { error = ex.GetFullMessage(true) });
  489. }
  490. }
  491. return Json(new { error = "Unable to send reset link" });
  492. }
  493. [HttpGet]
  494. [AllowAnonymous]
  495. public ActionResult VerifyResetPassword(string username, string code)
  496. {
  497. bool verified = true;
  498. if (string.IsNullOrEmpty(code))
  499. verified &= false;
  500. verified &= UserHelper.VerifyResetPassword(db, Config, username, code);
  501. if (verified)
  502. {
  503. // The password reset code is valid, let's log them in
  504. User user = UserHelper.GetUser(db, username);
  505. user.LastSeen = DateTime.Now;
  506. db.Entry(user).State = EntityState.Modified;
  507. db.SaveChanges();
  508. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, false, Request.Url.Host.GetDomain(), Request.IsLocal);
  509. Response.Cookies.Add(authcookie);
  510. }
  511. ResetPasswordVerificationViewModel model = new ResetPasswordVerificationViewModel();
  512. model.Success = verified;
  513. return View("/Areas/User/Views/User/ResetPasswordVerification.cshtml", model);
  514. }
  515. [HttpPost]
  516. public ActionResult SetUserPassword(string password, string confirmPassword)
  517. {
  518. if (ModelState.IsValid)
  519. {
  520. try
  521. {
  522. User user = UserHelper.GetUser(db, User.Identity.Name);
  523. if (user != null)
  524. {
  525. if (string.IsNullOrEmpty(password))
  526. {
  527. return Json(new { error = "Password must not be empty" });
  528. }
  529. if (password != confirmPassword)
  530. {
  531. return Json(new { error = "Passwords must match" });
  532. }
  533. UserHelper.EditAccount(db, Config, user, true, password);
  534. return Json(new { result = true });
  535. }
  536. return Json(new { error = "User does not exist" });
  537. }
  538. catch (Exception ex)
  539. {
  540. return Json(new { error = ex.GetFullMessage(true) });
  541. }
  542. }
  543. return Json(new { error = "Unable to reset user password" });
  544. }
  545. [HttpGet]
  546. [AllowAnonymous]
  547. public ActionResult ConfirmTwoFactorAuth(string returnUrl, bool rememberMe)
  548. {
  549. User user = (User)Session["AuthenticatedUser"];
  550. if (user != null)
  551. {
  552. ViewBag.Title = "Unknown Device - " + Config.Title;
  553. ViewBag.Description = "We do not recognize this device.";
  554. TwoFactorViewModel model = new TwoFactorViewModel();
  555. model.ReturnUrl = returnUrl;
  556. model.RememberMe = rememberMe;
  557. model.AllowTrustedDevice = user.SecuritySettings.AllowTrustedDevices;
  558. return View("/Areas/User/Views/User/TwoFactorCheck.cshtml", model);
  559. }
  560. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  561. }
  562. [HttpPost]
  563. [AllowAnonymous]
  564. public ActionResult ConfirmAuthenticatorCode(string code, string returnUrl, bool rememberMe, bool rememberDevice, string deviceName)
  565. {
  566. User user = (User)Session["AuthenticatedUser"];
  567. if (user != null)
  568. {
  569. if (user.SecuritySettings.TwoFactorEnabled)
  570. {
  571. string key = user.SecuritySettings.TwoFactorKey;
  572. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  573. bool isValid = ta.CheckCode(key, code, user);
  574. if (isValid)
  575. {
  576. // the code was valid, let's log them in!
  577. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, rememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  578. Response.Cookies.Add(authcookie);
  579. if (user.SecuritySettings.AllowTrustedDevices && rememberDevice)
  580. {
  581. // They want to remember the device, and have allow trusted devices on
  582. HttpCookie trustedDeviceCookie = UserHelper.CreateTrustedDeviceCookie(user.Username, Request.Url.Host.GetDomain(), Request.IsLocal);
  583. Response.Cookies.Add(trustedDeviceCookie);
  584. TrustedDevice device = new TrustedDevice();
  585. device.UserId = user.UserId;
  586. device.Name = (string.IsNullOrEmpty(deviceName)) ? "Unknown" : deviceName;
  587. device.DateSeen = DateTime.Now;
  588. device.Token = trustedDeviceCookie.Value;
  589. // Add the token
  590. db.TrustedDevices.Add(device);
  591. db.SaveChanges();
  592. }
  593. if (string.IsNullOrEmpty(returnUrl))
  594. returnUrl = Request.UrlReferrer.AbsoluteUri.ToString();
  595. return Json(new { result = returnUrl });
  596. }
  597. return Json(new { error = "Invalid Authentication Code" });
  598. }
  599. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  600. }
  601. return Json(new { error = "User does not exist" });
  602. }
  603. [HttpPost]
  604. public ActionResult VerifyAuthenticatorCode(string code)
  605. {
  606. User user = UserHelper.GetUser(db, User.Identity.Name);
  607. if (user != null)
  608. {
  609. if (user.SecuritySettings.TwoFactorEnabled)
  610. {
  611. string key = user.SecuritySettings.TwoFactorKey;
  612. TimeAuthenticator ta = new TimeAuthenticator(usedCodeManager: usedCodesManager);
  613. bool isValid = ta.CheckCode(key, code, user);
  614. if (isValid)
  615. {
  616. return Json(new { result = true });
  617. }
  618. return Json(new { error = "Invalid Authentication Code" });
  619. }
  620. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  621. }
  622. return Json(new { error = "User does not exist" });
  623. }
  624. [HttpGet]
  625. public ActionResult GenerateAuthQrCode(string key)
  626. {
  627. var ProvisionUrl = string.Format("otpauth://totp/{0}:{1}?secret={2}", Config.Title, User.Identity.Name, key);
  628. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  629. QRCodeData qrCodeData = qrGenerator.CreateQrCode(ProvisionUrl, QRCodeGenerator.ECCLevel.Q);
  630. QRCode qrCode = new QRCode(qrCodeData);
  631. Bitmap qrCodeImage = qrCode.GetGraphic(20);
  632. return File(Helpers.Utility.ImageToByte(qrCodeImage), "image/png");
  633. }
  634. }
  635. }