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.

UserHelper.cs 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data.Entity;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Mail;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Text.RegularExpressions;
  11. using System.Threading.Tasks;
  12. using System.Web;
  13. using System.Web.Security;
  14. using Teknik.Areas.Blog.Models;
  15. using Teknik.Areas.Shortener.Models;
  16. using Teknik.Areas.Users.Models;
  17. using Teknik.Configuration;
  18. using Teknik.Helpers;
  19. using Teknik.Models;
  20. namespace Teknik.Areas.Users.Utility
  21. {
  22. public static class UserHelper
  23. {
  24. #region Account Management
  25. public static List<string> GetReservedUsernames(Config config)
  26. {
  27. List<string> foundNames = new List<string>();
  28. if (config != null)
  29. {
  30. string path = config.UserConfig.ReservedUsernameDefinitionFile;
  31. if (File.Exists(path))
  32. {
  33. string[] names = File.ReadAllLines(path);
  34. foundNames = names.ToList();
  35. }
  36. }
  37. return foundNames;
  38. }
  39. public static bool UsernameReserved(Config config, string username)
  40. {
  41. // Load reserved usernames
  42. List<string> reserved = GetReservedUsernames(config);
  43. return (reserved.Exists(u => u.ToLower() == username.ToLower()));
  44. }
  45. public static bool ValidUsername(Config config, string username)
  46. {
  47. bool isValid = true;
  48. // Must be something there
  49. isValid &= !string.IsNullOrEmpty(username);
  50. // Is the format correct?
  51. Regex reg = new Regex(config.UserConfig.UsernameFilter);
  52. isValid &= reg.IsMatch(username);
  53. // Meets the min length?
  54. isValid &= (username.Length >= config.UserConfig.MinUsernameLength);
  55. // Meets the max length?
  56. isValid &= (username.Length <= config.UserConfig.MaxUsernameLength);
  57. return isValid;
  58. }
  59. public static bool UsernameAvailable(TeknikEntities db, Config config, string username)
  60. {
  61. bool isAvailable = true;
  62. isAvailable &= ValidUsername(config, username);
  63. isAvailable &= !UsernameReserved(config, username);
  64. isAvailable &= !UserExists(db, username);
  65. isAvailable &= !UserEmailExists(config, GetUserEmailAddress(config, username));
  66. isAvailable &= !UserGitExists(config, username);
  67. return isAvailable;
  68. }
  69. public static DateTime GetLastAccountActivity(TeknikEntities db, Config config, User user)
  70. {
  71. try
  72. {
  73. DateTime lastActive = new DateTime(1900, 1, 1);
  74. DateTime emailLastActive = UserEmailLastActive(config, GetUserEmailAddress(config, user.Username));
  75. if (lastActive < emailLastActive)
  76. lastActive = emailLastActive;
  77. DateTime gitLastActive = UserGitLastActive(config, user.Username);
  78. if (lastActive < gitLastActive)
  79. lastActive = gitLastActive;
  80. DateTime userLastActive = UserLastActive(db, config, user);
  81. if (lastActive < userLastActive)
  82. lastActive = userLastActive;
  83. return lastActive;
  84. }
  85. catch (Exception ex)
  86. {
  87. throw new Exception("Unable to determine last account activity.", ex);
  88. }
  89. }
  90. public static string GeneratePassword(Config config, User user, string password)
  91. {
  92. try
  93. {
  94. string username = user.Username.ToLower();
  95. if (user.Transfers.ToList().Exists(t => t.Type == TransferTypes.CaseSensitivePassword))
  96. {
  97. username = user.Username;
  98. }
  99. byte[] hashBytes = SHA384.Hash(username, password);
  100. string hash = hashBytes.ToHex();
  101. if (user.Transfers.ToList().Exists(t => t.Type == TransferTypes.ASCIIPassword))
  102. {
  103. hash = Encoding.ASCII.GetString(hashBytes);
  104. }
  105. if (user.Transfers.ToList().Exists(t => t.Type == TransferTypes.Sha256Password))
  106. {
  107. hash = SHA256.Hash(password, config.Salt1, config.Salt2);
  108. }
  109. return hash;
  110. }
  111. catch (Exception ex)
  112. {
  113. throw new Exception("Unable to generate password.", ex);
  114. }
  115. }
  116. public static void AddAccount(TeknikEntities db, Config config, User user, string password)
  117. {
  118. try
  119. {
  120. // Create an Email Account
  121. AddUserEmail(config, GetUserEmailAddress(config, user.Username), password);
  122. // Create a Git Account
  123. AddUserGit(config, user.Username, password);
  124. // Add User
  125. AddUser(db, config, user, password);
  126. }
  127. catch (Exception ex)
  128. {
  129. throw new Exception("Unable to create account.", ex);
  130. }
  131. }
  132. public static void EditAccount(TeknikEntities db, Config config, User user, bool changePass, string password)
  133. {
  134. try
  135. {
  136. // Changing Password?
  137. if (changePass)
  138. {
  139. // Change email password
  140. EditUserEmailPassword(config, GetUserEmailAddress(config, user.Username), password);
  141. // Update Git password
  142. EditUserGitPassword(config, user.Username, password);
  143. }
  144. // Update User
  145. EditUser(db, config, user, changePass, password);
  146. }
  147. catch (Exception ex)
  148. {
  149. throw new Exception("Unable to edit account.", ex);
  150. }
  151. }
  152. public static void DeleteAccount(TeknikEntities db, Config config, User user)
  153. {
  154. try
  155. {
  156. // Delete Email Account
  157. if (UserEmailExists(config, GetUserEmailAddress(config, user.Username)))
  158. DeleteUserEmail(config, GetUserEmailAddress(config, user.Username));
  159. // Delete Git Account
  160. if (UserGitExists(config, user.Username))
  161. DeleteUserGit(config, user.Username);
  162. // Delete User Account
  163. DeleteUser(db, config, user);
  164. }
  165. catch (Exception ex)
  166. {
  167. throw new Exception("Unable to delete account.", ex);
  168. }
  169. }
  170. #endregion
  171. #region User Management
  172. public static User GetUser(TeknikEntities db, string username)
  173. {
  174. User user = db.Users.Where(b => b.Username == username).FirstOrDefault();
  175. if (user != null)
  176. {
  177. user.UserSettings = db.UserSettings.Find(user.UserId);
  178. user.SecuritySettings = db.SecuritySettings.Find(user.UserId);
  179. user.BlogSettings = db.BlogSettings.Find(user.UserId);
  180. user.UploadSettings = db.UploadSettings.Find(user.UserId);
  181. }
  182. return user;
  183. }
  184. public static bool UserExists(TeknikEntities db, string username)
  185. {
  186. User user = GetUser(db, username);
  187. if (user != null)
  188. {
  189. return true;
  190. }
  191. return false;
  192. }
  193. public static DateTime UserLastActive(TeknikEntities db, Config config, User user)
  194. {
  195. try
  196. {
  197. DateTime lastActive = new DateTime(1900, 1, 1);
  198. if (lastActive < user.LastSeen)
  199. lastActive = user.LastSeen;
  200. return lastActive;
  201. }
  202. catch (Exception ex)
  203. {
  204. throw new Exception("Unable to determine last user activity.", ex);
  205. }
  206. }
  207. public static bool UserPasswordCorrect(TeknikEntities db, Config config, User user, string password)
  208. {
  209. try
  210. {
  211. string hash = GeneratePassword(config, user, password);
  212. return db.Users.Any(b => b.Username == user.Username && b.HashedPassword == hash);
  213. }
  214. catch (Exception ex)
  215. {
  216. throw new Exception("Unable to determine if password is correct.", ex);
  217. }
  218. }
  219. public static void TransferUser(TeknikEntities db, Config config, User user, string password)
  220. {
  221. try
  222. {
  223. List<TransferType> transfers = user.Transfers.ToList();
  224. for (int i = 0; i < transfers.Count; i++)
  225. {
  226. TransferType transfer = transfers[i];
  227. switch (transfer.Type)
  228. {
  229. case TransferTypes.Sha256Password:
  230. case TransferTypes.CaseSensitivePassword:
  231. case TransferTypes.ASCIIPassword:
  232. user.HashedPassword = SHA384.Hash(user.Username.ToLower(), password).ToHex();
  233. break;
  234. default:
  235. break;
  236. }
  237. user.Transfers.Remove(transfer);
  238. }
  239. db.Entry(user).State = EntityState.Modified;
  240. db.SaveChanges();
  241. }
  242. catch (Exception ex)
  243. {
  244. throw new Exception("Unable to transfer user info.", ex);
  245. }
  246. }
  247. public static void AddUser(TeknikEntities db, Config config, User user, string password)
  248. {
  249. try
  250. {
  251. // Add User
  252. user.HashedPassword = GeneratePassword(config, user, password);
  253. db.Users.Add(user);
  254. db.SaveChanges();
  255. // Generate blog for the user
  256. var newBlog = db.Blogs.Create();
  257. newBlog.UserId = user.UserId;
  258. db.Blogs.Add(newBlog);
  259. db.SaveChanges();
  260. }
  261. catch (Exception ex)
  262. {
  263. throw new Exception("Unable to create user.", ex);
  264. }
  265. }
  266. public static void EditUser(TeknikEntities db, Config config, User user, bool changePass, string password)
  267. {
  268. try
  269. {
  270. // Changing Password?
  271. if (changePass)
  272. {
  273. // Update User password
  274. user.HashedPassword = SHA384.Hash(user.Username.ToLower(), password).ToHex();
  275. }
  276. db.Entry(user).State = EntityState.Modified;
  277. db.SaveChanges();
  278. }
  279. catch (Exception ex)
  280. {
  281. throw new Exception(string.Format("Unable to edit user {0}.", user.Username), ex);
  282. }
  283. }
  284. public static void DeleteUser(TeknikEntities db, Config config, User user)
  285. {
  286. try
  287. {
  288. // Update uploads
  289. List<Upload.Models.Upload> uploads = db.Uploads.Where(u => u.User.Username == user.Username).ToList();
  290. if (uploads != null)
  291. {
  292. foreach (Upload.Models.Upload upload in uploads)
  293. {
  294. upload.UserId = null;
  295. db.Entry(upload).State = EntityState.Modified;
  296. }
  297. db.SaveChanges();
  298. }
  299. // Update pastes
  300. List<Paste.Models.Paste> pastes = db.Pastes.Where(u => u.User.Username == user.Username).ToList();
  301. if (pastes != null)
  302. {
  303. foreach (Paste.Models.Paste paste in pastes)
  304. {
  305. paste.UserId = null;
  306. db.Entry(paste).State = EntityState.Modified;
  307. }
  308. db.SaveChanges();
  309. }
  310. // Update shortened urls
  311. List<ShortenedUrl> shortUrls = db.ShortenedUrls.Where(u => u.User.Username == user.Username).ToList();
  312. if (shortUrls != null)
  313. {
  314. foreach (ShortenedUrl shortUrl in shortUrls)
  315. {
  316. shortUrl.UserId = null;
  317. db.Entry(shortUrl).State = EntityState.Modified;
  318. }
  319. db.SaveChanges();
  320. }
  321. // Delete Blogs
  322. Blog.Models.Blog blog = db.Blogs.Where(u => u.User.Username == user.Username).FirstOrDefault();
  323. if (blog != null)
  324. {
  325. db.Blogs.Remove(blog);
  326. db.SaveChanges();
  327. }
  328. // Delete post comments
  329. List<BlogPostComment> postComments = db.BlogComments.Where(u => u.User.Username == user.Username).ToList();
  330. if (postComments != null)
  331. {
  332. foreach (BlogPostComment postComment in postComments)
  333. {
  334. db.BlogComments.Remove(postComment);
  335. }
  336. db.SaveChanges();
  337. }
  338. // Delete podcast comments
  339. List<Podcast.Models.PodcastComment> podComments = db.PodcastComments.Where(u => u.User.Username == user.Username).ToList();
  340. if (podComments != null)
  341. {
  342. foreach (Podcast.Models.PodcastComment podComment in podComments)
  343. {
  344. db.PodcastComments.Remove(podComment);
  345. }
  346. db.SaveChanges();
  347. }
  348. // Delete Recovery Email Verifications
  349. List<RecoveryEmailVerification> verCodes = db.RecoveryEmailVerifications.Where(r => r.User.Username == user.Username).ToList();
  350. if (verCodes != null)
  351. {
  352. foreach (RecoveryEmailVerification verCode in verCodes)
  353. {
  354. db.RecoveryEmailVerifications.Remove(verCode);
  355. }
  356. db.SaveChanges();
  357. }
  358. // Delete Password Reset Verifications
  359. List<ResetPasswordVerification> verPass = db.ResetPasswordVerifications.Where(r => r.User.Username == user.Username).ToList();
  360. if (verPass != null)
  361. {
  362. foreach (ResetPasswordVerification ver in verPass)
  363. {
  364. db.ResetPasswordVerifications.Remove(ver);
  365. }
  366. db.SaveChanges();
  367. }
  368. // Delete User
  369. db.Users.Remove(user);
  370. db.SaveChanges();
  371. }
  372. catch (Exception ex)
  373. {
  374. throw new Exception(string.Format("Unable to delete user {0}.", user.Username), ex);
  375. }
  376. }
  377. public static string CreateRecoveryEmailVerification(TeknikEntities db, Config config, User user)
  378. {
  379. // Check to see if there already is a verification code for the user
  380. List<RecoveryEmailVerification> verCodes = db.RecoveryEmailVerifications.Where(r => r.User.Username == user.Username).ToList();
  381. if (verCodes != null && verCodes.Any())
  382. {
  383. foreach (RecoveryEmailVerification verCode in verCodes)
  384. {
  385. db.RecoveryEmailVerifications.Remove(verCode);
  386. }
  387. }
  388. // Create a new verification code and add it
  389. string verifyCode = Helpers.Utility.RandomString(24);
  390. RecoveryEmailVerification ver = new RecoveryEmailVerification();
  391. ver.UserId = user.UserId;
  392. ver.Code = verifyCode;
  393. ver.DateCreated = DateTime.Now;
  394. db.RecoveryEmailVerifications.Add(ver);
  395. db.SaveChanges();
  396. return verifyCode;
  397. }
  398. public static void SendRecoveryEmailVerification(Config config, string username, string email, string resetUrl, string verifyUrl)
  399. {
  400. SmtpClient client = new SmtpClient();
  401. client.Host = config.ContactConfig.Host;
  402. client.Port = config.ContactConfig.Port;
  403. client.EnableSsl = config.ContactConfig.SSL;
  404. client.DeliveryMethod = SmtpDeliveryMethod.Network;
  405. client.UseDefaultCredentials = true;
  406. client.Credentials = new NetworkCredential(config.NoReplyEmail, config.ContactConfig.Password);
  407. client.Timeout = 5000;
  408. MailMessage mail = new MailMessage(config.NoReplyEmail, email);
  409. mail.Subject = "Recovery Email Validation";
  410. mail.Body = string.Format(@"Hello {0},
  411. Welcome to Teknik!
  412. You are recieving this email because you have specified this email address as your recovery email. In the event that you forget your password, you can visit {1} and request a temporary password reset key be sent to this email. You will then be able to reset and choose a new password.
  413. In order to verify that you own this email, please click the following link or paste it into your browser: {2}
  414. If you recieved this email and you did not sign up for an account, please email us at {3} and ignore the verification link.
  415. Thank you and enjoy!
  416. - Teknik Administration", username, resetUrl, verifyUrl, config.SupportEmail);
  417. mail.BodyEncoding = UTF8Encoding.UTF8;
  418. mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
  419. client.Send(mail);
  420. }
  421. public static bool VerifyRecoveryEmail(TeknikEntities db, Config config, string username, string code)
  422. {
  423. User user = GetUser(db, username);
  424. RecoveryEmailVerification verCode = db.RecoveryEmailVerifications.Where(r => r.User.Username == username && r.Code == code).FirstOrDefault();
  425. if (verCode != null)
  426. {
  427. // We have a match, so clear out the verifications for that user
  428. List<RecoveryEmailVerification> verCodes = db.RecoveryEmailVerifications.Where(r => r.User.Username == username).ToList();
  429. if (verCodes != null && verCodes.Any())
  430. {
  431. foreach (RecoveryEmailVerification ver in verCodes)
  432. {
  433. db.RecoveryEmailVerifications.Remove(ver);
  434. }
  435. }
  436. // Update the user
  437. user.SecuritySettings.RecoveryVerified = true;
  438. db.Entry(user).State = EntityState.Modified;
  439. db.SaveChanges();
  440. return true;
  441. }
  442. return false;
  443. }
  444. public static string CreateResetPasswordVerification(TeknikEntities db, Config config, User user)
  445. {
  446. // Check to see if there already is a verification code for the user
  447. List<ResetPasswordVerification> verCodes = db.ResetPasswordVerifications.Where(r => r.User.Username == user.Username).ToList();
  448. if (verCodes != null && verCodes.Any())
  449. {
  450. foreach (ResetPasswordVerification verCode in verCodes)
  451. {
  452. db.ResetPasswordVerifications.Remove(verCode);
  453. }
  454. }
  455. // Create a new verification code and add it
  456. string verifyCode = Helpers.Utility.RandomString(24);
  457. ResetPasswordVerification ver = new ResetPasswordVerification();
  458. ver.UserId = user.UserId;
  459. ver.Code = verifyCode;
  460. ver.DateCreated = DateTime.Now;
  461. db.ResetPasswordVerifications.Add(ver);
  462. db.SaveChanges();
  463. return verifyCode;
  464. }
  465. public static void SendResetPasswordVerification(Config config, string username, string email, string resetUrl)
  466. {
  467. SmtpClient client = new SmtpClient();
  468. client.Host = config.ContactConfig.Host;
  469. client.Port = config.ContactConfig.Port;
  470. client.EnableSsl = config.ContactConfig.SSL;
  471. client.DeliveryMethod = SmtpDeliveryMethod.Network;
  472. client.UseDefaultCredentials = true;
  473. client.Credentials = new NetworkCredential(config.NoReplyEmail, config.ContactConfig.Password);
  474. client.Timeout = 5000;
  475. MailMessage mail = new MailMessage(config.NoReplyEmail, email);
  476. mail.Subject = "Password Reset Request";
  477. mail.Body = string.Format(@"Hello {0},
  478. You are recieving this email because either you or someone has requested a password reset for your account and this email was specified as the recovery email.
  479. To proceed in resetting your password, please click the following link or paste it into your browser: {1}
  480. If you recieved this email and you did not reset your password, you can ignore this email and email us at {2} to prevent it occuring again.
  481. - Teknik Administration", username, resetUrl, config.SupportEmail);
  482. mail.BodyEncoding = UTF8Encoding.UTF8;
  483. mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
  484. client.Send(mail);
  485. }
  486. public static bool VerifyResetPassword(TeknikEntities db, Config config, string username, string code)
  487. {
  488. User user = GetUser(db, username);
  489. ResetPasswordVerification verCode = db.ResetPasswordVerifications.Where(r => r.User.Username == username && r.Code == code).FirstOrDefault();
  490. if (verCode != null)
  491. {
  492. // We have a match, so clear out the verifications for that user
  493. List<ResetPasswordVerification> verCodes = db.ResetPasswordVerifications.Where(r => r.User.Username == username).ToList();
  494. if (verCodes != null && verCodes.Any())
  495. {
  496. foreach (ResetPasswordVerification ver in verCodes)
  497. {
  498. db.ResetPasswordVerifications.Remove(ver);
  499. }
  500. }
  501. db.SaveChanges();
  502. return true;
  503. }
  504. return false;
  505. }
  506. #endregion
  507. #region Email Management
  508. public static string GetUserEmailAddress(Config config, string username)
  509. {
  510. return string.Format("{0}@{1}", username, config.EmailConfig.Domain);
  511. }
  512. public static bool UserEmailExists(Config config, string email)
  513. {
  514. // If Email Server is enabled
  515. if (config.EmailConfig.Enabled)
  516. {
  517. // Connect to hmailserver COM
  518. var app = new hMailServer.Application();
  519. app.Connect();
  520. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  521. try
  522. {
  523. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  524. var account = domain.Accounts.ItemByAddress[email];
  525. // We didn't error out, so the email exists
  526. return true;
  527. }
  528. catch { }
  529. }
  530. return false;
  531. }
  532. public static DateTime UserEmailLastActive(Config config, string email)
  533. {
  534. DateTime lastActive = new DateTime(1900, 1, 1);
  535. if (config.EmailConfig.Enabled)
  536. {
  537. var app = new hMailServer.Application();
  538. app.Connect();
  539. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  540. try
  541. {
  542. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  543. var account = domain.Accounts.ItemByAddress[email];
  544. DateTime lastEmail = (DateTime)account.LastLogonTime;
  545. if (lastActive < lastEmail)
  546. lastActive = lastEmail;
  547. }
  548. catch { }
  549. }
  550. return lastActive;
  551. }
  552. public static void AddUserEmail(Config config, string email, string password)
  553. {
  554. try
  555. {
  556. // If Email Server is enabled
  557. if (config.EmailConfig.Enabled)
  558. {
  559. // Connect to hmailserver COM
  560. var app = new hMailServer.Application();
  561. app.Connect();
  562. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  563. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  564. var newAccount = domain.Accounts.Add();
  565. newAccount.Address = email;
  566. newAccount.Password = password;
  567. newAccount.Active = true;
  568. newAccount.MaxSize = config.EmailConfig.MaxSize;
  569. newAccount.Save();
  570. }
  571. }
  572. catch (Exception ex)
  573. {
  574. throw new Exception("Unable to add email.", ex);
  575. }
  576. }
  577. public static void EditUserEmailPassword(Config config, string email, string password)
  578. {
  579. try
  580. {
  581. // If Email Server is enabled
  582. if (config.EmailConfig.Enabled)
  583. {
  584. var app = new hMailServer.Application();
  585. app.Connect();
  586. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  587. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  588. var account = domain.Accounts.ItemByAddress[email];
  589. account.Password = password;
  590. account.Save();
  591. }
  592. }
  593. catch (Exception ex)
  594. {
  595. throw new Exception("Unable to edit email account password.", ex);
  596. }
  597. }
  598. public static void DeleteUserEmail(Config config, string email)
  599. {
  600. try
  601. {
  602. // If Email Server is enabled
  603. if (config.EmailConfig.Enabled)
  604. {
  605. var app = new hMailServer.Application();
  606. app.Connect();
  607. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  608. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  609. var account = domain.Accounts.ItemByAddress[email];
  610. if (account != null)
  611. {
  612. account.Delete();
  613. }
  614. }
  615. }
  616. catch (Exception ex)
  617. {
  618. throw new Exception("Unable to delete email account.", ex);
  619. }
  620. }
  621. #endregion
  622. #region Git Management
  623. public static bool UserGitExists(Config config, string username)
  624. {
  625. if (config.GitConfig.Enabled)
  626. {
  627. try
  628. {
  629. Uri baseUri = new Uri(config.GitConfig.Host);
  630. Uri finalUri = new Uri(baseUri, "api/v1/users/" + username + "?token=" + config.GitConfig.AccessToken);
  631. WebRequest request = WebRequest.Create(finalUri);
  632. request.Method = "GET";
  633. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  634. if (response.StatusCode == HttpStatusCode.OK)
  635. {
  636. return true;
  637. }
  638. }
  639. catch { }
  640. }
  641. return false;
  642. }
  643. public static DateTime UserGitLastActive(Config config, string username)
  644. {
  645. DateTime lastActive = new DateTime(1900, 1, 1);
  646. if (config.GitConfig.Enabled)
  647. {
  648. string email = GetUserEmailAddress(config, username);
  649. // We need to check the actual git database
  650. MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database);
  651. string sql = @"SELECT
  652. CASE
  653. WHEN MAX(gogs.action.created) >= MAX(gogs.user.updated) THEN MAX(gogs.action.created)
  654. WHEN MAX(gogs.user.updated) >= MAX(gogs.action.created) THEN MAX(gogs.user.updated)
  655. ELSE MAX(gogs.user.updated)
  656. END AS LastUpdate
  657. FROM gogs.user
  658. LEFT JOIN gogs.action ON gogs.user.id = gogs.action.act_user_id
  659. WHERE gogs.user.login_name = {0}";
  660. var results = mySQL.Query(sql, new object[] { email });
  661. if (results != null && results.Any())
  662. {
  663. var result = results.First();
  664. DateTime tmpLast = lastActive;
  665. DateTime.TryParse(result["LastUpdate"].ToString(), out tmpLast);
  666. if (lastActive < tmpLast)
  667. lastActive = tmpLast;
  668. }
  669. }
  670. return lastActive;
  671. }
  672. public static void AddUserGit(Config config, string username, string password)
  673. {
  674. try
  675. {
  676. // If Git is enabled
  677. if (config.GitConfig.Enabled)
  678. {
  679. string email = GetUserEmailAddress(config, username);
  680. // Add gogs user
  681. using (var client = new WebClient())
  682. {
  683. var obj = new { source_id = config.GitConfig.SourceId, username = username, email = email, login_name = email, password = password };
  684. string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
  685. client.Headers[HttpRequestHeader.ContentType] = "application/json";
  686. Uri baseUri = new Uri(config.GitConfig.Host);
  687. Uri finalUri = new Uri(baseUri, "api/v1/admin/users?token=" + config.GitConfig.AccessToken);
  688. string result = client.UploadString(finalUri, "POST", json);
  689. }
  690. }
  691. }
  692. catch (Exception ex)
  693. {
  694. throw new Exception("Unable to add git account.", ex);
  695. }
  696. }
  697. public static void EditUserGitPassword(Config config, string username, string password)
  698. {
  699. try
  700. {
  701. // If Git is enabled
  702. if (config.GitConfig.Enabled)
  703. {
  704. string email = GetUserEmailAddress(config, username);
  705. using (var client = new WebClient())
  706. {
  707. var obj = new { source_id = config.GitConfig.SourceId, email = email, password = password };
  708. string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
  709. client.Headers[HttpRequestHeader.ContentType] = "application/json";
  710. Uri baseUri = new Uri(config.GitConfig.Host);
  711. Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + username + "?token=" + config.GitConfig.AccessToken);
  712. string result = client.UploadString(finalUri, "PATCH", json);
  713. }
  714. }
  715. }
  716. catch (Exception ex)
  717. {
  718. throw new Exception("Unable to edit git account password.", ex);
  719. }
  720. }
  721. public static void DeleteUserGit(Config config, string username)
  722. {
  723. try
  724. {
  725. // If Git is enabled
  726. if (config.GitConfig.Enabled)
  727. {
  728. try
  729. {
  730. Uri baseUri = new Uri(config.GitConfig.Host);
  731. Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + username + "?token=" + config.GitConfig.AccessToken);
  732. WebRequest request = WebRequest.Create(finalUri);
  733. request.Method = "DELETE";
  734. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  735. if (response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.NoContent)
  736. {
  737. throw new Exception("Unable to delete git account. Response Code: " + response.StatusCode);
  738. }
  739. }
  740. catch (HttpException htex)
  741. {
  742. if (htex.GetHttpCode() != 404)
  743. throw new Exception("Unable to delete git account. Http Exception: " + htex.Message);
  744. }
  745. catch (Exception ex)
  746. {
  747. // This error signifies the user doesn't exist, so we can continue deleting
  748. if (ex.Message != "The remote server returned an error: (404) Not Found.")
  749. {
  750. throw new Exception("Unable to delete git account. Exception: " + ex.Message);
  751. }
  752. }
  753. }
  754. }
  755. catch (Exception ex)
  756. {
  757. throw new Exception("Unable to delete git account.", ex);
  758. }
  759. }
  760. #endregion
  761. public static HttpCookie CreateAuthCookie(string username, bool remember, string domain, bool local)
  762. {
  763. Config config = Config.Load();
  764. HttpCookie authcookie = FormsAuthentication.GetAuthCookie(username, remember);
  765. authcookie.Name = Constants.AUTHCOOKIE;
  766. authcookie.HttpOnly = true;
  767. authcookie.Secure = true;
  768. // Set domain dependent on where it's being ran from
  769. if (local) // localhost
  770. {
  771. authcookie.Domain = null;
  772. }
  773. else if (config.DevEnvironment) // dev.example.com
  774. {
  775. authcookie.Domain = string.Format("dev.{0}", domain);
  776. }
  777. else // A production instance
  778. {
  779. authcookie.Domain = string.Format(".{0}", domain);
  780. }
  781. return authcookie;
  782. }
  783. public static HttpCookie CreateTrustedDeviceCookie(string username, string domain, bool local)
  784. {
  785. Config config = Config.Load();
  786. byte[] time = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());
  787. byte[] key = Guid.NewGuid().ToByteArray();
  788. string token = Convert.ToBase64String(time.Concat(key).ToArray());
  789. HttpCookie trustCookie = new HttpCookie(Constants.TRUSTEDDEVICECOOKIE + "_" + username);
  790. trustCookie.Value = token;
  791. trustCookie.HttpOnly = true;
  792. trustCookie.Secure = true;
  793. trustCookie.Expires = DateTime.Now.AddYears(1);
  794. // Set domain dependent on where it's being ran from
  795. if (local) // localhost
  796. {
  797. trustCookie.Domain = null;
  798. }
  799. else if (config.DevEnvironment) // dev.example.com
  800. {
  801. trustCookie.Domain = string.Format("dev.{0}", domain);
  802. }
  803. else // A production instance
  804. {
  805. trustCookie.Domain = string.Format(".{0}", domain);
  806. }
  807. return trustCookie;
  808. }
  809. }
  810. }