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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Mail;
  7. using System.Runtime.InteropServices;
  8. using System.Security.Cryptography;
  9. using System.Text;
  10. using System.Text.RegularExpressions;
  11. using System.Threading.Tasks;
  12. using System.Web;
  13. using Teknik.Areas.Blog.Models;
  14. using Teknik.Areas.Shortener.Models;
  15. using Teknik.Areas.Users.Models;
  16. using Teknik.Configuration;
  17. using Teknik.Utilities;
  18. using Teknik.Models;
  19. using Teknik.Utilities.Cryptography;
  20. using MD5 = Teknik.Utilities.Cryptography.MD5;
  21. using SHA256 = Teknik.Utilities.Cryptography.SHA256;
  22. using SHA384 = Teknik.Utilities.Cryptography.SHA384;
  23. using Teknik.Data;
  24. using Microsoft.EntityFrameworkCore;
  25. using Microsoft.AspNetCore.Http;
  26. using System.Security.Claims;
  27. using Microsoft.AspNetCore.Authentication.Cookies;
  28. using Teknik.MailService;
  29. using Teknik.GitService;
  30. using IdentityModel.Client;
  31. using System.Net.Http;
  32. using Newtonsoft.Json.Linq;
  33. using Newtonsoft.Json;
  34. using Microsoft.AspNetCore.Mvc;
  35. namespace Teknik.Areas.Users.Utility
  36. {
  37. public static class UserHelper
  38. {
  39. #region Account Management
  40. public static List<string> GetReservedUsernames(Config config)
  41. {
  42. List<string> foundNames = new List<string>();
  43. if (config != null)
  44. {
  45. string path = config.UserConfig.ReservedUsernameDefinitionFile;
  46. if (File.Exists(path))
  47. {
  48. string[] names = File.ReadAllLines(path);
  49. foundNames = names.ToList();
  50. }
  51. }
  52. return foundNames;
  53. }
  54. public static bool UsernameReserved(Config config, string username)
  55. {
  56. // Load reserved usernames
  57. List<string> reserved = GetReservedUsernames(config);
  58. return (reserved.Exists(u => u.ToLower() == username.ToLower()));
  59. }
  60. public static bool ValidUsername(Config config, string username)
  61. {
  62. bool isValid = true;
  63. // Must be something there
  64. isValid &= !string.IsNullOrEmpty(username);
  65. // Is the format correct?
  66. Regex reg = new Regex(config.UserConfig.UsernameFilter);
  67. isValid &= reg.IsMatch(username);
  68. // Meets the min length?
  69. isValid &= (username.Length >= config.UserConfig.MinUsernameLength);
  70. // Meets the max length?
  71. isValid &= (username.Length <= config.UserConfig.MaxUsernameLength);
  72. return isValid;
  73. }
  74. public static async Task<bool> UsernameAvailable(TeknikEntities db, Config config, string username)
  75. {
  76. bool isAvailable = true;
  77. isAvailable &= ValidUsername(config, username);
  78. isAvailable &= !UsernameReserved(config, username);
  79. isAvailable &= !await IdentityHelper.UserExists(config, username);
  80. isAvailable &= !UserExists(db, username);
  81. isAvailable &= !UserEmailExists(config, GetUserEmailAddress(config, username));
  82. isAvailable &= !UserGitExists(config, username);
  83. return isAvailable;
  84. }
  85. public static async Task<DateTime> GetLastAccountActivity(TeknikEntities db, Config config, string username)
  86. {
  87. var userInfo = await IdentityHelper.GetIdentityUserInfo(config, username);
  88. return GetLastAccountActivity(db, config, username, userInfo);
  89. }
  90. public static DateTime GetLastAccountActivity(TeknikEntities db, Config config, string username, IdentityUserInfo userInfo)
  91. {
  92. try
  93. {
  94. DateTime lastActive = new DateTime(1900, 1, 1);
  95. if (UserEmailExists(config, GetUserEmailAddress(config, username)))
  96. {
  97. DateTime emailLastActive = UserEmailLastActive(config, GetUserEmailAddress(config, username));
  98. if (lastActive < emailLastActive)
  99. lastActive = emailLastActive;
  100. }
  101. if (UserGitExists(config, username))
  102. {
  103. DateTime gitLastActive = UserGitLastActive(config, username);
  104. if (lastActive < gitLastActive)
  105. lastActive = gitLastActive;
  106. }
  107. if (userInfo.LastSeen.HasValue)
  108. {
  109. DateTime userLastActive = userInfo.LastSeen.Value;
  110. if (lastActive < userLastActive)
  111. lastActive = userLastActive;
  112. }
  113. return lastActive;
  114. }
  115. catch (Exception ex)
  116. {
  117. throw new Exception("Unable to determine last account activity.", ex);
  118. }
  119. }
  120. public static async Task CreateAccount(TeknikEntities db, Config config, IUrlHelper url, string username, string password, string recoveryEmail, string inviteCode)
  121. {
  122. try
  123. {
  124. var result = await IdentityHelper.CreateUser(config, username, password, recoveryEmail);
  125. if (result.Success)
  126. {
  127. // Create an Email Account
  128. CreateUserEmail(config, GetUserEmailAddress(config, username), password);
  129. // Disable the email account
  130. DisableUserEmail(config, GetUserEmailAddress(config, username));
  131. // Create a Git Account
  132. CreateUserGit(config, username, password);
  133. // Add User
  134. User newUser = CreateUser(db, config, username, inviteCode);
  135. // If they have a recovery email, let's send a verification
  136. if (!string.IsNullOrEmpty(recoveryEmail))
  137. {
  138. var token = await IdentityHelper.UpdateRecoveryEmail(config, username, recoveryEmail);
  139. string resetUrl = url.SubRouteUrl("account", "User.ResetPassword", new { Username = username });
  140. string verifyUrl = url.SubRouteUrl("account", "User.VerifyRecoveryEmail", new { Code = WebUtility.UrlEncode(token) });
  141. SendRecoveryEmailVerification(config, username, recoveryEmail, resetUrl, verifyUrl);
  142. }
  143. return;
  144. }
  145. throw new Exception("Error creating account: " + result.Message);
  146. }
  147. catch (Exception ex)
  148. {
  149. throw new Exception("Unable to create account.", ex);
  150. }
  151. }
  152. public static void EditAccount(TeknikEntities db, Config config, User user)
  153. {
  154. try
  155. {
  156. // Update User
  157. EditUser(db, config, user);
  158. }
  159. catch (Exception ex)
  160. {
  161. throw new Exception("Unable to edit account.", ex);
  162. }
  163. }
  164. public static async Task ChangeAccountPassword(TeknikEntities db, Config config, string username, string currentPassword, string newPassword)
  165. {
  166. IdentityResult result = await IdentityHelper.UpdatePassword(config, username, currentPassword, newPassword);
  167. if (result.Success)
  168. {
  169. ChangeServicePasswords(db, config, username, newPassword);
  170. }
  171. else
  172. {
  173. throw new Exception(result.Message);
  174. }
  175. }
  176. public static async Task ResetAccountPassword(TeknikEntities db, Config config, string username, string token, string newPassword)
  177. {
  178. IdentityResult result = await IdentityHelper.ResetPassword(config, username, token, newPassword);
  179. if (result.Success)
  180. {
  181. ChangeServicePasswords(db, config, username, newPassword);
  182. }
  183. else
  184. {
  185. throw new Exception(result.Message);
  186. }
  187. }
  188. public static void ChangeServicePasswords(TeknikEntities db, Config config, string username, string newPassword)
  189. {
  190. try
  191. {
  192. // Make sure they have a git and email account before resetting their password
  193. string email = GetUserEmailAddress(config, username);
  194. if (config.EmailConfig.Enabled && !UserEmailExists(config, email))
  195. {
  196. CreateUserEmail(config, email, newPassword);
  197. }
  198. if (config.GitConfig.Enabled && !UserGitExists(config, username))
  199. {
  200. CreateUserGit(config, username, newPassword);
  201. }
  202. // Change email password
  203. EditUserEmailPassword(config, GetUserEmailAddress(config, username), newPassword);
  204. // Update Git password
  205. EditUserGitPassword(config, username, newPassword);
  206. }
  207. catch (Exception ex)
  208. {
  209. throw new Exception("Unable to change service password.", ex);
  210. }
  211. }
  212. public static async Task EditAccountType(TeknikEntities db, Config config, string username, AccountType type)
  213. {
  214. try
  215. {
  216. if (!UserExists(db, username))
  217. throw new Exception($"The user provided does not exist: {username}");
  218. var result = await IdentityHelper.UpdateAccountType(config, username, type);
  219. if (result.Success)
  220. {
  221. string email = GetUserEmailAddress(config, username);
  222. // Add/Remove account type features depending on the type
  223. switch (type)
  224. {
  225. case AccountType.Basic:
  226. // Disable their email
  227. DisableUserEmail(config, email);
  228. break;
  229. case AccountType.Premium:
  230. // Enable their email account
  231. EnableUserEmail(config, email);
  232. break;
  233. }
  234. }
  235. else
  236. {
  237. throw new Exception($"Unable to edit the account type [{type}] for {username}: " + result.Message);
  238. }
  239. }
  240. catch (Exception ex)
  241. {
  242. throw new Exception($"Unable to edit the account type [{type}] for: {username}", ex);
  243. }
  244. }
  245. public static async Task EditAccountStatus(TeknikEntities db, Config config, string username, AccountStatus status)
  246. {
  247. try
  248. {
  249. if (!UserExists(db, username))
  250. throw new Exception($"The user provided does not exist: {username}");
  251. var result = await IdentityHelper.UpdateAccountStatus(config, username, status);
  252. if (result.Success)
  253. {
  254. string email = GetUserEmailAddress(config, username);
  255. // Add/Remove account type features depending on the type
  256. switch (status)
  257. {
  258. case AccountStatus.Active:
  259. // Enable Email
  260. EnableUserEmail(config, email);
  261. // Enable Git
  262. EnableUserGit(config, username);
  263. break;
  264. case AccountStatus.Banned:
  265. // Disable Email
  266. DisableUserEmail(config, email);
  267. // Disable Git
  268. DisableUserGit(config, username);
  269. break;
  270. }
  271. }
  272. else
  273. {
  274. throw new Exception($"Unable to edit the account status [{status}] for {username}: " + result.Message);
  275. }
  276. }
  277. catch (Exception ex)
  278. {
  279. throw new Exception($"Unable to edit the account status [{status}] for: {username}", ex);
  280. }
  281. }
  282. public static async Task DeleteAccount(TeknikEntities db, Config config, User user)
  283. {
  284. try
  285. {
  286. string username = user.Username;
  287. // Delete identity account
  288. var result = await IdentityHelper.DeleteUser(config, username);
  289. if (result)
  290. {
  291. // Delete User Account
  292. DeleteUser(db, config, user);
  293. // Delete Email Account
  294. if (UserEmailExists(config, GetUserEmailAddress(config, username)))
  295. DeleteUserEmail(config, GetUserEmailAddress(config, username));
  296. // Delete Git Account
  297. if (UserGitExists(config, username))
  298. DeleteUserGit(config, username);
  299. }
  300. else
  301. {
  302. throw new Exception("Unable to delete identity account.");
  303. }
  304. }
  305. catch (Exception ex)
  306. {
  307. throw new Exception("Unable to delete account.", ex);
  308. }
  309. }
  310. #endregion
  311. #region User Management
  312. public static User GetUser(TeknikEntities db, string username)
  313. {
  314. User user = db.Users
  315. .Include(u => u.UserSettings)
  316. .Include(u => u.BlogSettings)
  317. .Include(u => u.UploadSettings)
  318. .Where(b => b.Username == username).FirstOrDefault();
  319. return user;
  320. }
  321. public static bool UserExists(TeknikEntities db, string username)
  322. {
  323. User user = GetUser(db, username);
  324. if (user != null)
  325. {
  326. return true;
  327. }
  328. return false;
  329. }
  330. public static async Task<bool> UserPasswordCorrect(Config config, string username, string password)
  331. {
  332. try
  333. {
  334. return await IdentityHelper.CheckPassword(config, username, password);
  335. }
  336. catch (Exception ex)
  337. {
  338. throw new Exception("Unable to determine if password is correct.", ex);
  339. }
  340. }
  341. public static User CreateUser(TeknikEntities db, Config config, string username, string inviteCode)
  342. {
  343. try
  344. {
  345. User newUser = new User();
  346. newUser.Username = username;
  347. newUser.UserSettings = new UserSettings();
  348. newUser.BlogSettings = new BlogSettings();
  349. newUser.UploadSettings = new UploadSettings();
  350. // if they provided an invite code, let's assign them to it
  351. if (!string.IsNullOrEmpty(inviteCode))
  352. {
  353. InviteCode code = db.InviteCodes.Where(c => c.Code == inviteCode).FirstOrDefault();
  354. db.Entry(code).State = EntityState.Modified;
  355. newUser.ClaimedInviteCode = code;
  356. }
  357. // Add User
  358. db.Users.Add(newUser);
  359. // Generate blog for the user
  360. var newBlog = new Blog.Models.Blog();
  361. newBlog.User = newUser;
  362. db.Blogs.Add(newBlog);
  363. // Save the changes
  364. db.SaveChanges();
  365. return newUser;
  366. }
  367. catch (Exception ex)
  368. {
  369. throw new Exception("Unable to create user.", ex);
  370. }
  371. }
  372. public static void EditUser(TeknikEntities db, Config config, User user)
  373. {
  374. try
  375. {
  376. db.Entry(user).State = EntityState.Modified;
  377. db.SaveChanges();
  378. }
  379. catch (Exception ex)
  380. {
  381. throw new Exception(string.Format("Unable to edit user {0}.", user.Username), ex);
  382. }
  383. }
  384. public static void DeleteUser(TeknikEntities db, Config config, User user)
  385. {
  386. try
  387. {
  388. // Update uploads
  389. List<Upload.Models.Upload> uploads = db.Uploads.Where(u => u.User.Username == user.Username).ToList();
  390. if (uploads.Any())
  391. {
  392. foreach (Upload.Models.Upload upload in uploads)
  393. {
  394. upload.UserId = null;
  395. db.Entry(upload).State = EntityState.Modified;
  396. }
  397. db.SaveChanges();
  398. }
  399. // Update pastes
  400. List<Paste.Models.Paste> pastes = db.Pastes.Where(u => u.User.Username == user.Username).ToList();
  401. if (pastes.Any())
  402. {
  403. foreach (Paste.Models.Paste paste in pastes)
  404. {
  405. paste.UserId = null;
  406. db.Entry(paste).State = EntityState.Modified;
  407. }
  408. db.SaveChanges();
  409. }
  410. // Update shortened urls
  411. List<ShortenedUrl> shortUrls = db.ShortenedUrls.Where(u => u.User.Username == user.Username).ToList();
  412. if (shortUrls.Any())
  413. {
  414. foreach (ShortenedUrl shortUrl in shortUrls)
  415. {
  416. shortUrl.UserId = null;
  417. db.Entry(shortUrl).State = EntityState.Modified;
  418. }
  419. db.SaveChanges();
  420. }
  421. // Update vaults
  422. List<Vault.Models.Vault> vaults = db.Vaults.Where(u => u.User.Username == user.Username).ToList();
  423. if (vaults.Any())
  424. {
  425. foreach (Vault.Models.Vault vault in vaults)
  426. {
  427. vault.UserId = null;
  428. db.Entry(vault).State = EntityState.Modified;
  429. }
  430. db.SaveChanges();
  431. }
  432. // Delete Blogs
  433. Blog.Models.Blog blog = db.Blogs.Where(u => u.User.Username == user.Username).FirstOrDefault();
  434. if (blog != null)
  435. {
  436. db.Blogs.Remove(blog);
  437. db.SaveChanges();
  438. }
  439. // Delete post comments
  440. List<BlogPostComment> postComments = db.BlogPostComments.Where(u => u.User.Username == user.Username).ToList();
  441. if (postComments.Any())
  442. {
  443. foreach (BlogPostComment postComment in postComments)
  444. {
  445. db.BlogPostComments.Remove(postComment);
  446. }
  447. db.SaveChanges();
  448. }
  449. // Delete podcast comments
  450. List<Podcast.Models.PodcastComment> podComments = db.PodcastComments.Where(u => u.User.Username == user.Username).ToList();
  451. if (podComments.Any())
  452. {
  453. foreach (Podcast.Models.PodcastComment podComment in podComments)
  454. {
  455. db.PodcastComments.Remove(podComment);
  456. }
  457. db.SaveChanges();
  458. }
  459. // Delete Owned Invite Codes
  460. List<InviteCode> ownedCodes = db.InviteCodes.Where(i => i.Owner.Username == user.Username).ToList();
  461. if (ownedCodes.Any())
  462. {
  463. foreach (InviteCode code in ownedCodes)
  464. {
  465. db.InviteCodes.Remove(code);
  466. }
  467. db.SaveChanges();
  468. }
  469. // Delete Claimed Invite Code
  470. List<InviteCode> claimedCodes = db.InviteCodes.Where(i => i.ClaimedUser.Username == user.Username).ToList();
  471. if (claimedCodes.Any())
  472. {
  473. foreach (InviteCode code in claimedCodes)
  474. {
  475. db.InviteCodes.Remove(code);
  476. }
  477. db.SaveChanges();
  478. }
  479. // Delete Auth Tokens
  480. //List<AuthToken> authTokens = db.AuthTokens.Where(t => t.User.UserId == user.UserId).ToList();
  481. //if (authTokens.Any())
  482. //{
  483. // foreach (AuthToken authToken in authTokens)
  484. // {
  485. // db.AuthTokens.Remove(authToken);
  486. // }
  487. // db.SaveChanges();
  488. //}
  489. // Delete User
  490. db.Users.Remove(user);
  491. db.SaveChanges();
  492. }
  493. catch (Exception ex)
  494. {
  495. throw new Exception(string.Format("Unable to delete user {0}.", user.Username), ex);
  496. }
  497. }
  498. public static void SendRecoveryEmailVerification(Config config, string username, string email, string resetUrl, string verifyUrl)
  499. {
  500. SmtpClient client = new SmtpClient();
  501. client.Host = config.ContactConfig.EmailAccount.Host;
  502. client.Port = config.ContactConfig.EmailAccount.Port;
  503. client.EnableSsl = config.ContactConfig.EmailAccount.SSL;
  504. client.DeliveryMethod = SmtpDeliveryMethod.Network;
  505. client.UseDefaultCredentials = true;
  506. client.Credentials = new NetworkCredential(config.ContactConfig.EmailAccount.Username, config.ContactConfig.EmailAccount.Password);
  507. client.Timeout = 5000;
  508. MailMessage mail = new MailMessage(new MailAddress(config.ContactConfig.EmailAccount.EmailAddress, "Teknik"), new MailAddress(email, username));
  509. mail.Subject = "Recovery Email Validation";
  510. mail.Body = string.Format(@"Hello {0},
  511. 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.
  512. In order to verify that you own this email, please click the following link or paste it into your browser: {2}
  513. If you recieved this email and you did not sign up for an account, please email us at {3} and ignore the verification link.
  514. - Teknik", username, resetUrl, verifyUrl, config.SupportEmail);
  515. mail.BodyEncoding = UTF8Encoding.UTF8;
  516. mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
  517. client.Send(mail);
  518. }
  519. public static void SendResetPasswordVerification(Config config, string username, string email, string resetUrl)
  520. {
  521. SmtpClient client = new SmtpClient();
  522. client.Host = config.ContactConfig.EmailAccount.Host;
  523. client.Port = config.ContactConfig.EmailAccount.Port;
  524. client.EnableSsl = config.ContactConfig.EmailAccount.SSL;
  525. client.DeliveryMethod = SmtpDeliveryMethod.Network;
  526. client.UseDefaultCredentials = true;
  527. client.Credentials = new NetworkCredential(config.ContactConfig.EmailAccount.Username, config.ContactConfig.EmailAccount.Password);
  528. client.Timeout = 5000;
  529. MailMessage mail = new MailMessage(new MailAddress(config.ContactConfig.EmailAccount.EmailAddress, "Teknik"), new MailAddress(email, username));
  530. mail.Subject = "Password Reset Request";
  531. mail.Body = string.Format(@"Hello {0},
  532. 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.
  533. To proceed in resetting your password, please click the following link or paste it into your browser: {1}
  534. 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.
  535. - Teknik", username, resetUrl, config.SupportEmail);
  536. mail.BodyEncoding = UTF8Encoding.UTF8;
  537. mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
  538. client.Send(mail);
  539. }
  540. #endregion
  541. #region Email Management
  542. public static string GetUserEmailAddress(Config config, string username)
  543. {
  544. return string.Format("{0}@{1}", username, config.EmailConfig.Domain);
  545. }
  546. public static IMailService CreateMailService(Config config)
  547. {
  548. return new HMailService(
  549. config.EmailConfig.MailHost,
  550. config.EmailConfig.Username,
  551. config.EmailConfig.Password,
  552. config.EmailConfig.Domain,
  553. config.EmailConfig.CounterDatabase.Server,
  554. config.EmailConfig.CounterDatabase.Database,
  555. config.EmailConfig.CounterDatabase.Username,
  556. config.EmailConfig.CounterDatabase.Password,
  557. config.EmailConfig.CounterDatabase.Port
  558. );
  559. }
  560. public static bool UserEmailExists(Config config, string email)
  561. {
  562. // If Email Server is enabled
  563. if (config.EmailConfig.Enabled)
  564. {
  565. var svc = CreateMailService(config);
  566. return svc.AccountExists(email);
  567. }
  568. return false;
  569. }
  570. public static DateTime UserEmailLastActive(Config config, string email)
  571. {
  572. DateTime lastActive = new DateTime(1900, 1, 1);
  573. if (config.EmailConfig.Enabled)
  574. {
  575. var svc = CreateMailService(config);
  576. var lastEmail = svc.LastActive(email);
  577. if (lastActive < lastEmail)
  578. lastActive = lastEmail;
  579. }
  580. return lastActive;
  581. }
  582. public static bool UserEmailEnabled(Config config, string email)
  583. {
  584. try
  585. {
  586. // If Email Server is enabled
  587. if (config.EmailConfig.Enabled)
  588. {
  589. var svc = CreateMailService(config);
  590. return svc.Enabled(email);
  591. }
  592. }
  593. catch (Exception ex)
  594. {
  595. throw new Exception("Unable to get email account status.", ex);
  596. }
  597. return false;
  598. }
  599. public static void CreateUserEmail(Config config, string email, string password)
  600. {
  601. try
  602. {
  603. // If Email Server is enabled
  604. if (config.EmailConfig.Enabled)
  605. {
  606. var svc = CreateMailService(config);
  607. svc.CreateAccount(email, password, config.EmailConfig.MaxSize);
  608. }
  609. }
  610. catch (Exception ex)
  611. {
  612. throw new Exception("Unable to add email.", ex);
  613. }
  614. }
  615. public static void EnableUserEmail(Config config, string email)
  616. {
  617. try
  618. {
  619. // If Email Server is enabled
  620. if (config.EmailConfig.Enabled)
  621. {
  622. var svc = CreateMailService(config);
  623. svc.EnableAccount(email);
  624. }
  625. }
  626. catch (Exception ex)
  627. {
  628. throw new Exception("Unable to enable email account.", ex);
  629. }
  630. }
  631. public static void DisableUserEmail(Config config, string email)
  632. {
  633. try
  634. {
  635. // If Email Server is enabled
  636. if (config.EmailConfig.Enabled)
  637. {
  638. var svc = CreateMailService(config);
  639. svc.DisableAccount(email);
  640. }
  641. }
  642. catch (Exception ex)
  643. {
  644. throw new Exception("Unable to disable email account.", ex);
  645. }
  646. }
  647. public static void EditUserEmailPassword(Config config, string email, string password)
  648. {
  649. try
  650. {
  651. // If Email Server is enabled
  652. if (config.EmailConfig.Enabled)
  653. {
  654. var svc = CreateMailService(config);
  655. svc.EditPassword(email, password);
  656. }
  657. }
  658. catch (Exception ex)
  659. {
  660. throw new Exception("Unable to edit email account password.", ex);
  661. }
  662. }
  663. public static void EditUserEmailMaxSize(Config config, string email, int size)
  664. {
  665. try
  666. {
  667. // If Email Server is enabled
  668. if (config.EmailConfig.Enabled)
  669. {
  670. var svc = CreateMailService(config);
  671. svc.EditMaxSize(email, size);
  672. }
  673. }
  674. catch (Exception ex)
  675. {
  676. throw new Exception("Unable to edit email account mailbox size.", ex);
  677. }
  678. }
  679. public static void EditUserEmailMaxEmailsPerDay(Config config, string email, int maxPerDay)
  680. {
  681. try
  682. {
  683. // If Email Server is enabled
  684. if (config.EmailConfig.Enabled)
  685. {
  686. var svc = CreateMailService(config);
  687. svc.EditMaxEmailsPerDay(email, maxPerDay);
  688. }
  689. }
  690. catch (Exception ex)
  691. {
  692. throw new Exception("Unable to edit email account mailbox size.", ex);
  693. }
  694. }
  695. public static void DeleteUserEmail(Config config, string email)
  696. {
  697. try
  698. {
  699. // If Email Server is enabled
  700. if (config.EmailConfig.Enabled)
  701. {
  702. var svc = CreateMailService(config);
  703. svc.DeleteAccount(email);
  704. }
  705. }
  706. catch (Exception ex)
  707. {
  708. throw new Exception("Unable to delete email account.", ex);
  709. }
  710. }
  711. #endregion
  712. #region Git Management
  713. public static IGitService CreateGitService(Config config)
  714. {
  715. return new GiteaService(
  716. config.GitConfig.SourceId,
  717. config.GitConfig.Host,
  718. config.GitConfig.AccessToken,
  719. config.GitConfig.Database.Server,
  720. config.GitConfig.Database.Database,
  721. config.GitConfig.Database.Username,
  722. config.GitConfig.Database.Password,
  723. config.GitConfig.Database.Port
  724. );
  725. }
  726. public static bool UserGitExists(Config config, string username)
  727. {
  728. if (config.GitConfig.Enabled)
  729. {
  730. try
  731. {
  732. var svc = CreateGitService(config);
  733. return svc.AccountExists(username);
  734. }
  735. catch { }
  736. }
  737. return false;
  738. }
  739. public static DateTime UserGitLastActive(Config config, string username)
  740. {
  741. DateTime lastActive = new DateTime(1900, 1, 1);
  742. if (config.GitConfig.Enabled)
  743. {
  744. // Git user exists?
  745. if (!UserGitExists(config, username))
  746. {
  747. throw new Exception($"Git User '{username}' does not exist.");
  748. }
  749. string email = GetUserEmailAddress(config, username);
  750. var svc = CreateGitService(config);
  751. DateTime tmpLast = svc.LastActive(email);
  752. if (lastActive < tmpLast)
  753. lastActive = tmpLast;
  754. }
  755. return lastActive;
  756. }
  757. public static void CreateUserGit(Config config, string username, string password)
  758. {
  759. try
  760. {
  761. // If Git is enabled
  762. if (config.GitConfig.Enabled)
  763. {
  764. string email = GetUserEmailAddress(config, username);
  765. var svc = CreateGitService(config);
  766. svc.CreateAccount(username, email, password);
  767. }
  768. }
  769. catch (Exception ex)
  770. {
  771. throw new Exception("Unable to add git account.", ex);
  772. }
  773. }
  774. public static void EditUserGitPassword(Config config, string username, string password)
  775. {
  776. try
  777. {
  778. // If Git is enabled
  779. if (config.GitConfig.Enabled)
  780. {
  781. // Git user exists?
  782. if (!UserGitExists(config, username))
  783. {
  784. throw new Exception($"Git User '{username}' does not exist.");
  785. }
  786. string email = GetUserEmailAddress(config, username);
  787. var svc = CreateGitService(config);
  788. svc.EditPassword(username, email, password);
  789. }
  790. }
  791. catch (Exception ex)
  792. {
  793. throw new Exception("Unable to edit git account password.", ex);
  794. }
  795. }
  796. public static void EnableUserGit(Config config, string username)
  797. {
  798. try
  799. {
  800. // If Git is enabled
  801. if (config.GitConfig.Enabled)
  802. {
  803. // Git user exists?
  804. if (!UserGitExists(config, username))
  805. {
  806. throw new Exception($"Git User '{username}' does not exist.");
  807. }
  808. string email = GetUserEmailAddress(config, username);
  809. var svc = CreateGitService(config);
  810. svc.EnableAccount(username, email);
  811. }
  812. }
  813. catch (Exception ex)
  814. {
  815. throw new Exception("Unable to enable git account.", ex);
  816. }
  817. }
  818. public static void DisableUserGit(Config config, string username)
  819. {
  820. try
  821. {
  822. // If Git is enabled
  823. if (config.GitConfig.Enabled)
  824. {
  825. // Git user exists?
  826. if (!UserGitExists(config, username))
  827. {
  828. throw new Exception($"Git User '{username}' does not exist.");
  829. }
  830. string email = GetUserEmailAddress(config, username);
  831. var svc = CreateGitService(config);
  832. svc.EnableAccount(username, email);
  833. }
  834. }
  835. catch (Exception ex)
  836. {
  837. throw new Exception("Unable to disable git account.", ex);
  838. }
  839. }
  840. public static void DeleteUserGit(Config config, string username)
  841. {
  842. try
  843. {
  844. // If Git is enabled
  845. if (config.GitConfig.Enabled)
  846. {
  847. // Git user exists?
  848. if (!UserGitExists(config, username))
  849. {
  850. throw new Exception($"Git User '{username}' does not exist.");
  851. }
  852. var svc = CreateGitService(config);
  853. svc.DeleteAccount(username);
  854. }
  855. }
  856. catch (Exception ex)
  857. {
  858. throw new Exception("Unable to delete git account.", ex);
  859. }
  860. }
  861. public static void CreateUserGitTwoFactor(Config config, string username, string secret, int unixTime)
  862. {
  863. try
  864. {
  865. // If Git is enabled
  866. if (config.GitConfig.Enabled)
  867. {
  868. // Git user exists?
  869. if (!UserGitExists(config, username))
  870. {
  871. throw new Exception($"Git User '{username}' does not exist.");
  872. }
  873. // Generate the scratch token
  874. string token = StringHelper.RandomString(8);
  875. // Get the Encryption Key from the git secret key
  876. byte[] keyBytes = MD5.Hash(Encoding.UTF8.GetBytes(config.GitConfig.SecretKey));
  877. // Modify the input secret
  878. byte[] secBytes = Encoding.UTF8.GetBytes(secret);
  879. // Generate the encrypted secret using AES CGM
  880. byte[] encValue = Aes128CFB.Encrypt(secBytes, keyBytes);
  881. string finalSecret = Convert.ToBase64String(encValue);
  882. // Create connection to the DB
  883. Utilities.MysqlDatabase mySQL = new Utilities.MysqlDatabase(config.GitConfig.Database.Server, config.GitConfig.Database.Database, config.GitConfig.Database.Username, config.GitConfig.Database.Password, config.GitConfig.Database.Port);
  884. mySQL.MysqlErrorEvent += (sender, s) =>
  885. {
  886. throw new Exception("Unable to edit git account two factor. Mysql Exception: " + s);
  887. };
  888. // Get the user's UID
  889. string email = GetUserEmailAddress(config, username);
  890. string userSelect = @"SELECT gogs.user.id FROM gogs.user WHERE gogs.user.login_name = {0}";
  891. var uid = mySQL.ScalarQuery(userSelect, new object[] { email });
  892. // See if they have Two Factor already
  893. string sqlSelect = @"SELECT tf.id
  894. FROM gogs.two_factor tf
  895. LEFT JOIN gogs.user u ON u.id = tf.uid
  896. WHERE u.login_name = {0}";
  897. var result = mySQL.ScalarQuery(sqlSelect, new object[] { email });
  898. if (result != null)
  899. {
  900. // They have an entry! Let's update it
  901. string update = @"UPDATE gogs.two_factor tf SET tf.uid = {1}, tf.secret = {2}, tf.scratch_token = {3}, tf.updated_unix = {4} WHERE tf.id = {0}";
  902. mySQL.Execute(update, new object[] { result, uid, finalSecret, token, unixTime });
  903. }
  904. else
  905. {
  906. // They need a new entry
  907. string insert = @"INSERT INTO gogs.two_factor (uid, secret, scratch_token, created_unix, updated_unix) VALUES ({0}, {1}, {2}, {3}, {4})";
  908. mySQL.Execute(insert, new object[] { uid, finalSecret, token, unixTime, 0 });
  909. }
  910. }
  911. }
  912. catch (Exception ex)
  913. {
  914. throw new Exception("Unable to edit git account two factor.", ex);
  915. }
  916. }
  917. public static void DeleteUserGitTwoFactor(Config config, string username)
  918. {
  919. try
  920. {
  921. // If Git is enabled
  922. if (config.GitConfig.Enabled)
  923. {
  924. // Git user exists?
  925. if (!UserGitExists(config, username))
  926. {
  927. throw new Exception($"Git User '{username}' does not exist.");
  928. }
  929. // Create connection to the DB
  930. Utilities.MysqlDatabase mySQL = new Utilities.MysqlDatabase(config.GitConfig.Database.Server, config.GitConfig.Database.Database, config.GitConfig.Database.Username, config.GitConfig.Database.Password, config.GitConfig.Database.Port);
  931. // Get the user's UID
  932. string email = GetUserEmailAddress(config, username);
  933. // See if they have Two Factor already
  934. string deleteSql = @"DELETE tf.*
  935. FROM gogs.two_factor tf
  936. LEFT JOIN gogs.user u ON u.id = tf.uid
  937. WHERE u.login_name = {0}";
  938. mySQL.Execute(deleteSql, new object[] { email });
  939. }
  940. }
  941. catch (Exception ex)
  942. {
  943. throw new Exception("Unable to delete git account two factor.", ex);
  944. }
  945. }
  946. #endregion
  947. }
  948. }