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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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. namespace Teknik.Areas.Users.Controllers
  27. {
  28. public class UserController : DefaultController
  29. {
  30. private TeknikEntities db = new TeknikEntities();
  31. // GET: Profile/Profile
  32. [TrackPageView]
  33. [AllowAnonymous]
  34. public ActionResult Index(string username)
  35. {
  36. if (string.IsNullOrEmpty(username))
  37. {
  38. username = User.Identity.Name;
  39. }
  40. ProfileViewModel model = new ProfileViewModel();
  41. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  42. ViewBag.Description = "The User does not exist";
  43. try
  44. {
  45. User user = UserHelper.GetUser(db, username);
  46. if (user != null)
  47. {
  48. ViewBag.Title = username + "'s Profile - " + Config.Title;
  49. ViewBag.Description = "Viewing " + username + "'s Profile";
  50. model.UserID = user.UserId;
  51. model.Username = user.Username;
  52. if (Config.EmailConfig.Enabled)
  53. {
  54. model.Email = string.Format("{0}@{1}", user.Username, Config.EmailConfig.Domain);
  55. }
  56. model.JoinDate = user.JoinDate;
  57. model.LastSeen = UserHelper.GetLastAccountActivity(db, Config, user);
  58. model.UserSettings = user.UserSettings;
  59. model.SecuritySettings = user.SecuritySettings;
  60. model.BlogSettings = user.BlogSettings;
  61. model.UploadSettings = user.UploadSettings;
  62. model.Uploads = db.Uploads.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DateUploaded).ToList();
  63. model.Pastes = db.Pastes.Where(u => u.UserId == user.UserId).OrderByDescending(u => u.DatePosted).ToList();
  64. model.ShortenedUrls = db.ShortenedUrls.Where(s => s.UserId == user.UserId).OrderByDescending(s => s.DateAdded).ToList();
  65. return View(model);
  66. }
  67. model.Error = true;
  68. model.ErrorMessage = "The user does not exist";
  69. }
  70. catch (Exception ex)
  71. {
  72. model.Error = true;
  73. model.ErrorMessage = ex.GetFullMessage(true);
  74. }
  75. return View(model);
  76. }
  77. [TrackPageView]
  78. [AllowAnonymous]
  79. public ActionResult Settings()
  80. {
  81. if (User.Identity.IsAuthenticated)
  82. {
  83. string username = User.Identity.Name;
  84. SettingsViewModel model = new SettingsViewModel();
  85. ViewBag.Title = "User Does Not Exist - " + Config.Title;
  86. ViewBag.Description = "The User does not exist";
  87. User user = UserHelper.GetUser(db, username);
  88. if (user != null)
  89. {
  90. ViewBag.Title = "Settings - " + Config.Title;
  91. ViewBag.Description = "Your " + Config.Title + " Settings";
  92. model.UserID = user.UserId;
  93. model.Username = user.Username;
  94. model.UserSettings = user.UserSettings;
  95. model.SecuritySettings = user.SecuritySettings;
  96. model.BlogSettings = user.BlogSettings;
  97. model.UploadSettings = user.UploadSettings;
  98. return View(model);
  99. }
  100. model.Error = true;
  101. return View(model);
  102. }
  103. return Redirect(Url.SubRouteUrl("error", "Error.Http403"));
  104. }
  105. [HttpGet]
  106. [TrackPageView]
  107. [AllowAnonymous]
  108. public ActionResult ViewRawPGP(string username)
  109. {
  110. ViewBag.Title = username + "'s Public Key - " + Config.Title;
  111. ViewBag.Description = "The PGP public key for " + username;
  112. User user = UserHelper.GetUser(db, username);
  113. if (user != null)
  114. {
  115. if (!string.IsNullOrEmpty(user.SecuritySettings.PGPSignature))
  116. {
  117. return Content(user.SecuritySettings.PGPSignature, "text/plain");
  118. }
  119. }
  120. return Redirect(Url.SubRouteUrl("error", "Error.Http404"));
  121. }
  122. [HttpGet]
  123. [TrackPageView]
  124. [AllowAnonymous]
  125. public ActionResult Login(string ReturnUrl)
  126. {
  127. LoginViewModel model = new LoginViewModel();
  128. model.ReturnUrl = ReturnUrl;
  129. return View("/Areas/User/Views/User/ViewLogin.cshtml", model);
  130. }
  131. [HttpPost]
  132. [AllowAnonymous]
  133. public ActionResult Login([Bind(Prefix = "Login")]LoginViewModel model)
  134. {
  135. if (ModelState.IsValid)
  136. {
  137. string username = model.Username;
  138. User user = UserHelper.GetUser(db, username);
  139. if (user != null)
  140. {
  141. bool userValid = UserHelper.UserPasswordCorrect(db, Config, user, model.Password);
  142. if (userValid)
  143. {
  144. UserHelper.TransferUser(db, Config, user, model.Password);
  145. user.LastSeen = DateTime.Now;
  146. db.Entry(user).State = EntityState.Modified;
  147. db.SaveChanges();
  148. HttpCookie authcookie = UserHelper.CreateAuthCookie(model.Username, model.RememberMe, Request.Url.Host.GetDomain(), Request.IsLocal);
  149. Response.Cookies.Add(authcookie);
  150. if (string.IsNullOrEmpty(model.ReturnUrl))
  151. {
  152. return Json(new { result = "true" });
  153. }
  154. else
  155. {
  156. return Redirect(model.ReturnUrl);
  157. }
  158. }
  159. }
  160. }
  161. return Json(new { error = "Invalid Username or Password." });
  162. }
  163. public ActionResult Logout()
  164. {
  165. // Get cookie
  166. HttpCookie authCookie = Utility.UserHelper.CreateAuthCookie(User.Identity.Name, false, Request.Url.Host.GetDomain(), Request.IsLocal);
  167. // Signout
  168. FormsAuthentication.SignOut();
  169. Session.Abandon();
  170. // Destroy Cookies
  171. authCookie.Expires = DateTime.Now.AddYears(-1);
  172. Response.Cookies.Add(authCookie);
  173. return Redirect(Url.SubRouteUrl("www", "Home.Index"));
  174. }
  175. [HttpGet]
  176. [TrackPageView]
  177. [AllowAnonymous]
  178. public ActionResult Register(string ReturnUrl)
  179. {
  180. RegisterViewModel model = new RegisterViewModel();
  181. model.ReturnUrl = ReturnUrl;
  182. return View("/Areas/User/Views/User/ViewRegistration.cshtml", model);
  183. }
  184. [HttpPost]
  185. [AllowAnonymous]
  186. public ActionResult Register([Bind(Prefix="Register")]RegisterViewModel model)
  187. {
  188. if (ModelState.IsValid)
  189. {
  190. if (Config.UserConfig.RegistrationEnabled)
  191. {
  192. if (!UserHelper.ValidUsername(Config, model.Username))
  193. {
  194. return Json(new { error = "That username is not valid" });
  195. }
  196. if (!UserHelper.UsernameAvailable(db, Config, model.Username))
  197. {
  198. return Json(new { error = "That username is not available" });
  199. }
  200. if (model.Password != model.ConfirmPassword)
  201. {
  202. return Json(new { error = "Passwords must match" });
  203. }
  204. // PGP Key valid?
  205. if (!string.IsNullOrEmpty(model.PublicKey) && !PGP.IsPublicKey(model.PublicKey))
  206. {
  207. return Json(new { error = "Invalid PGP Public Key" });
  208. }
  209. try
  210. {
  211. User newUser = db.Users.Create();
  212. newUser.JoinDate = DateTime.Now;
  213. newUser.Username = model.Username;
  214. newUser.UserSettings = new UserSettings();
  215. newUser.SecuritySettings = new SecuritySettings();
  216. newUser.BlogSettings = new BlogSettings();
  217. newUser.UploadSettings = new UploadSettings();
  218. if (!string.IsNullOrEmpty(model.PublicKey))
  219. newUser.SecuritySettings.PGPSignature = model.PublicKey;
  220. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  221. newUser.SecuritySettings.RecoveryEmail = model.RecoveryEmail;
  222. UserHelper.AddAccount(db, Config, newUser, model.Password);
  223. // If they have a recovery email, let's send a verification
  224. if (!string.IsNullOrEmpty(model.RecoveryEmail))
  225. {
  226. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, newUser);
  227. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = model.Username });
  228. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  229. UserHelper.SendRecoveryEmailVerification(Config, model.Username, model.RecoveryEmail, resetUrl, verifyUrl);
  230. }
  231. }
  232. catch (Exception ex)
  233. {
  234. return Json(new { error = ex.GetFullMessage(true) });
  235. }
  236. return Login(new LoginViewModel { Username = model.Username, Password = model.Password, RememberMe = false, ReturnUrl = model.ReturnUrl });
  237. }
  238. return Json(new { error = "User Registration is Disabled" });
  239. }
  240. return Json(new { error = "You must include all fields." });
  241. }
  242. [HttpPost]
  243. public ActionResult Edit(string curPass, string newPass, string newPassConfirm, string pgpPublicKey, string recoveryEmail, bool twoFactorEnabled, string website, string quote, string about, string blogTitle, string blogDesc, bool saveKey, bool serverSideEncrypt)
  244. {
  245. if (ModelState.IsValid)
  246. {
  247. try
  248. {
  249. User user = UserHelper.GetUser(db, User.Identity.Name);
  250. if (user != null)
  251. {
  252. bool changePass = false;
  253. string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain);
  254. // Changing Password?
  255. if (!string.IsNullOrEmpty(curPass) && (!string.IsNullOrEmpty(newPass) || !string.IsNullOrEmpty(newPassConfirm)))
  256. {
  257. // Old Password Valid?
  258. if (!UserHelper.UserPasswordCorrect(db, Config, user, curPass))
  259. {
  260. return Json(new { error = "Invalid Original Password." });
  261. }
  262. // The New Password Match?
  263. if (newPass != newPassConfirm)
  264. {
  265. return Json(new { error = "New Password Must Match." });
  266. }
  267. changePass = true;
  268. }
  269. // PGP Key valid?
  270. if (!string.IsNullOrEmpty(pgpPublicKey) && !PGP.IsPublicKey(pgpPublicKey))
  271. {
  272. return Json(new { error = "Invalid PGP Public Key" });
  273. }
  274. user.SecuritySettings.PGPSignature = pgpPublicKey;
  275. bool newRecovery = false;
  276. if (recoveryEmail != user.SecuritySettings.RecoveryEmail)
  277. {
  278. newRecovery = true;
  279. user.SecuritySettings.RecoveryEmail = recoveryEmail;
  280. user.SecuritySettings.RecoveryVerified = false;
  281. }
  282. user.SecuritySettings.TwoFactorEnabled = twoFactorEnabled;
  283. string newKey = string.Empty;
  284. if (twoFactorEnabled)
  285. {
  286. newKey = Authenticator.GenerateKey();
  287. }
  288. user.SecuritySettings.TwoFactorKey = newKey;
  289. user.UserSettings.Website = website;
  290. user.UserSettings.Quote = quote;
  291. user.UserSettings.About = about;
  292. user.BlogSettings.Title = blogTitle;
  293. user.BlogSettings.Description = blogDesc;
  294. user.UploadSettings.SaveKey = saveKey;
  295. user.UploadSettings.ServerSideEncrypt = serverSideEncrypt;
  296. UserHelper.EditAccount(db, Config, user, changePass, newPass);
  297. // If they have a recovery email, let's send a verification
  298. if (!string.IsNullOrEmpty(recoveryEmail) && newRecovery)
  299. {
  300. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  301. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  302. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  303. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  304. }
  305. return Json(new { result = true });
  306. }
  307. return Json(new { error = "User does not exist" });
  308. }
  309. catch (Exception ex)
  310. {
  311. return Json(new { error = ex.GetFullMessage(true) });
  312. }
  313. }
  314. return Json(new { error = "Invalid Parameters" });
  315. }
  316. [HttpPost]
  317. public ActionResult Delete()
  318. {
  319. if (ModelState.IsValid)
  320. {
  321. try
  322. {
  323. User user = UserHelper.GetUser(db, User.Identity.Name);
  324. if (user != null)
  325. {
  326. UserHelper.DeleteAccount(db, Config, user);
  327. // Sign Out
  328. Logout();
  329. return Json(new { result = true });
  330. }
  331. }
  332. catch (Exception ex)
  333. {
  334. return Json(new { error = ex.GetFullMessage(true) });
  335. }
  336. }
  337. return Json(new { error = "Unable to delete user" });
  338. }
  339. [HttpGet]
  340. public ActionResult VerifyRecoveryEmail(string code)
  341. {
  342. bool verified = true;
  343. if (string.IsNullOrEmpty(code))
  344. verified &= false;
  345. verified &= UserHelper.VerifyRecoveryEmail(db, Config, User.Identity.Name, code);
  346. RecoveryEmailVerificationViewModel model = new RecoveryEmailVerificationViewModel();
  347. model.Success = verified;
  348. return View("/Areas/User/Views/User/ViewRecoveryEmailVerification.cshtml", model);
  349. }
  350. [HttpPost]
  351. public ActionResult ResendVerifyRecoveryEmail()
  352. {
  353. if (ModelState.IsValid)
  354. {
  355. try
  356. {
  357. User user = UserHelper.GetUser(db, User.Identity.Name);
  358. if (user != null)
  359. {
  360. // If they have a recovery email, let's send a verification
  361. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail))
  362. {
  363. if (!user.SecuritySettings.RecoveryVerified)
  364. {
  365. string verifyCode = UserHelper.CreateRecoveryEmailVerification(db, Config, user);
  366. string resetUrl = Url.SubRouteUrl("user", "User.ResetPassword", new { Username = user.Username });
  367. string verifyUrl = Url.SubRouteUrl("user", "User.VerifyRecoveryEmail", new { Code = verifyCode });
  368. UserHelper.SendRecoveryEmailVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl, verifyUrl);
  369. return Json(new { result = true });
  370. }
  371. return Json(new { error = "The recovery email is already verified" });
  372. }
  373. }
  374. }
  375. catch (Exception ex)
  376. {
  377. return Json(new { error = ex.GetFullMessage(true) });
  378. }
  379. }
  380. return Json(new { error = "Unable to resend verification" });
  381. }
  382. [HttpGet]
  383. [AllowAnonymous]
  384. public ActionResult ResetPassword(string username)
  385. {
  386. ResetPasswordViewModel model = new ResetPasswordViewModel();
  387. model.Username = username;
  388. return View("/Areas/User/Views/User/ResetPassword.cshtml", model);
  389. }
  390. [HttpPost]
  391. [AllowAnonymous]
  392. public ActionResult SendResetPasswordVerification(string username)
  393. {
  394. if (ModelState.IsValid)
  395. {
  396. try
  397. {
  398. User user = UserHelper.GetUser(db, username);
  399. if (user != null)
  400. {
  401. // If they have a recovery email, let's send a verification
  402. if (!string.IsNullOrEmpty(user.SecuritySettings.RecoveryEmail) && user.SecuritySettings.RecoveryVerified)
  403. {
  404. string verifyCode = UserHelper.CreateResetPasswordVerification(db, Config, user);
  405. string resetUrl = Url.SubRouteUrl("user", "User.VerifyResetPassword", new { Username = user.Username, Code = verifyCode });
  406. UserHelper.SendResetPasswordVerification(Config, user.Username, user.SecuritySettings.RecoveryEmail, resetUrl);
  407. return Json(new { result = true });
  408. }
  409. return Json(new { error = "The username doesn't have a recovery email specified" });
  410. }
  411. return Json(new { error = "The username is not valid" });
  412. }
  413. catch (Exception ex)
  414. {
  415. return Json(new { error = ex.GetFullMessage(true) });
  416. }
  417. }
  418. return Json(new { error = "Unable to send reset link" });
  419. }
  420. [HttpGet]
  421. [AllowAnonymous]
  422. public ActionResult VerifyResetPassword(string username, string code)
  423. {
  424. bool verified = true;
  425. if (string.IsNullOrEmpty(code))
  426. verified &= false;
  427. verified &= UserHelper.VerifyResetPassword(db, Config, username, code);
  428. if (verified)
  429. {
  430. // The password reset code is valid, let's log them in
  431. User user = UserHelper.GetUser(db, username);
  432. user.LastSeen = DateTime.Now;
  433. db.Entry(user).State = EntityState.Modified;
  434. db.SaveChanges();
  435. HttpCookie authcookie = UserHelper.CreateAuthCookie(user.Username, false, Request.Url.Host.GetDomain(), Request.IsLocal);
  436. Response.Cookies.Add(authcookie);
  437. }
  438. ResetPasswordVerificationViewModel model = new ResetPasswordVerificationViewModel();
  439. model.Success = verified;
  440. return View("/Areas/User/Views/User/ResetPasswordVerification.cshtml", model);
  441. }
  442. [HttpPost]
  443. public ActionResult SetUserPassword(string password, string confirmPassword)
  444. {
  445. if (ModelState.IsValid)
  446. {
  447. try
  448. {
  449. User user = UserHelper.GetUser(db, User.Identity.Name);
  450. if (user != null)
  451. {
  452. if (string.IsNullOrEmpty(password))
  453. {
  454. return Json(new { error = "Password must not be empty" });
  455. }
  456. if (password != confirmPassword)
  457. {
  458. return Json(new { error = "Passwords must match" });
  459. }
  460. UserHelper.EditAccount(db, Config, user, true, password);
  461. return Json(new { result = true });
  462. }
  463. return Json(new { error = "User does not exist" });
  464. }
  465. catch (Exception ex)
  466. {
  467. return Json(new { error = ex.GetFullMessage(true) });
  468. }
  469. }
  470. return Json(new { error = "Unable to reset user password" });
  471. }
  472. [HttpPost]
  473. public ActionResult ConfirmAuthenticatorCode(string code)
  474. {
  475. User user = UserHelper.GetUser(db, User.Identity.Name);
  476. if (user != null)
  477. {
  478. if (user.SecuritySettings.TwoFactorEnabled)
  479. {
  480. string key = user.SecuritySettings.TwoFactorKey;
  481. TimeAuthenticator ta = new TimeAuthenticator();
  482. bool isValid = false;
  483. return Json(new { result = true });
  484. }
  485. return Json(new { error = "User does not have Two Factor Authentication enabled" });
  486. }
  487. return Json(new { error = "User does not exist" });
  488. }
  489. [HttpPost]
  490. public ActionResult GenerateQrCode(string content)
  491. {
  492. QRCodeGenerator qrGenerator = new QRCodeGenerator();
  493. QRCodeData qrCodeData = qrGenerator.CreateQrCode(content, QRCodeGenerator.ECCLevel.Q);
  494. SvgQRCode qrCode = new SvgQRCode(qrCodeData);
  495. string qrCodeImage = qrCode.GetGraphic(20);
  496. return File(Encoding.UTF8.GetBytes(qrCodeImage), "image/svg+xml");
  497. }
  498. }
  499. }