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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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.Runtime.InteropServices;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using System.Web;
  11. using System.Web.Security;
  12. using Teknik.Areas.Blog.Models;
  13. using Teknik.Areas.Shortener.Models;
  14. using Teknik.Areas.Users.Models;
  15. using Teknik.Configuration;
  16. using Teknik.Helpers;
  17. using Teknik.Models;
  18. namespace Teknik.Areas.Users.Utility
  19. {
  20. public static class UserHelper
  21. {
  22. public static List<string> GetReservedUsernames(Config config)
  23. {
  24. List<string> foundNames = new List<string>();
  25. if (config != null)
  26. {
  27. string path = config.UserConfig.ReservedUsernameDefinitionFile;
  28. if (File.Exists(path))
  29. {
  30. string[] names = File.ReadAllLines(path);
  31. foundNames = names.ToList();
  32. }
  33. }
  34. return foundNames;
  35. }
  36. #region User Management
  37. public static User GetUser(TeknikEntities db, string username)
  38. {
  39. User user = db.Users.Where(b => b.Username == username).FirstOrDefault();
  40. if (user != null)
  41. {
  42. user.UserSettings = db.UserSettings.Find(user.UserId);
  43. user.BlogSettings = db.BlogSettings.Find(user.UserId);
  44. user.UploadSettings = db.UploadSettings.Find(user.UserId);
  45. }
  46. return user;
  47. }
  48. public static bool UserExists(TeknikEntities db, string username)
  49. {
  50. User user = GetUser(db, username);
  51. if (user != null)
  52. {
  53. return true;
  54. }
  55. return false;
  56. }
  57. public static bool ValidUsername(TeknikEntities db, Config config, string username)
  58. {
  59. bool isValid = true;
  60. // Load reserved usernames
  61. List<string> reserved = GetReservedUsernames(config);
  62. if (reserved.Exists(u => u.ToLower() == username.ToLower()))
  63. isValid = false;
  64. return isValid;
  65. }
  66. public static bool UsernameAvailable(TeknikEntities db, Config config, string username)
  67. {
  68. bool isAvailable = true;
  69. isAvailable &= ValidUsername(db, config, username);
  70. isAvailable &= !UserExists(db, username);
  71. isAvailable &= !UserEmailExists(config, username);
  72. isAvailable &= !UserGitExists(config, username);
  73. return isAvailable;
  74. }
  75. public static DateTime GetLastActivity(TeknikEntities db, Config config, User user)
  76. {
  77. try
  78. {
  79. DateTime lastActive = new DateTime(1900, 1, 1);
  80. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  81. DateTime emailLastActive = UserEmailLastActive(config, user.Username);
  82. if (lastActive < emailLastActive)
  83. lastActive = emailLastActive;
  84. DateTime gitLastActive = UserGitLastActive(config, user.Username);
  85. if (lastActive < gitLastActive)
  86. lastActive = gitLastActive;
  87. if (lastActive < user.LastSeen)
  88. lastActive = user.LastSeen;
  89. return lastActive;
  90. }
  91. catch (Exception ex)
  92. {
  93. throw new Exception("Unable to determine last activity.", ex);
  94. }
  95. }
  96. public static void AddUser(TeknikEntities db, Config config, User user, string password)
  97. {
  98. try
  99. {
  100. // Create an Email Account
  101. AddUserEmail(config, user, password);
  102. // Create a Git Account
  103. AddUserGit(config, user, password);
  104. // Add User
  105. user.HashedPassword = SHA384.Hash(user.Username, password);
  106. db.Users.Add(user);
  107. db.SaveChanges();
  108. // Generate blog for the user
  109. var newBlog = db.Blogs.Create();
  110. newBlog.UserId = user.UserId;
  111. db.Blogs.Add(newBlog);
  112. db.SaveChanges();
  113. }
  114. catch (Exception ex)
  115. {
  116. throw new Exception("Unable to create user.", ex);
  117. }
  118. }
  119. public static void EditUser(TeknikEntities db, Config config, User user, bool changePass, string password)
  120. {
  121. try
  122. {
  123. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  124. // Changing Password?
  125. if (changePass)
  126. {
  127. // Change email password
  128. EditUserEmailPassword(config, user, password);
  129. // Update Git password
  130. EditUserGitPassword(config, user, password);
  131. // Update User password
  132. user.HashedPassword = SHA384.Hash(user.Username, password);
  133. }
  134. db.Entry(user).State = EntityState.Modified;
  135. db.SaveChanges();
  136. }
  137. catch (Exception ex)
  138. {
  139. throw new Exception("Unable to edit user.", ex);
  140. }
  141. }
  142. public static void DeleteUser(TeknikEntities db, Config config, User user)
  143. {
  144. try
  145. {
  146. // Delete Email Account
  147. DeleteUserEmail(config, user);
  148. // Delete Git Account
  149. DeleteUserGit(config, user);
  150. // Update uploads
  151. List<Upload.Models.Upload> uploads = db.Uploads.Include("User").Where(u => u.User.Username == user.Username).ToList();
  152. if (uploads != null)
  153. {
  154. foreach (Upload.Models.Upload upload in uploads)
  155. {
  156. upload.UserId = null;
  157. db.Entry(upload).State = EntityState.Modified;
  158. }
  159. }
  160. // Update pastes
  161. List<Paste.Models.Paste> pastes = db.Pastes.Include("User").Where(u => u.User.Username == user.Username).ToList();
  162. if (pastes != null)
  163. {
  164. foreach (Paste.Models.Paste paste in pastes)
  165. {
  166. paste.UserId = null;
  167. db.Entry(paste).State = EntityState.Modified;
  168. }
  169. }
  170. // Update shortened urls
  171. List<ShortenedUrl> shortUrls = db.ShortenedUrls.Include("User").Where(u => u.User.Username == user.Username).ToList();
  172. if (shortUrls != null)
  173. {
  174. foreach (ShortenedUrl shortUrl in shortUrls)
  175. {
  176. shortUrl.UserId = null;
  177. db.Entry(shortUrl).State = EntityState.Modified;
  178. }
  179. }
  180. // Delete Blogs
  181. Blog.Models.Blog blog = db.Blogs.Include("BlogPosts").Include("BlogPosts.Comments").Include("User").Where(u => u.User.Username == user.Username).FirstOrDefault();
  182. if (blog != null)
  183. {
  184. db.Blogs.Remove(blog);
  185. }
  186. // Delete post comments
  187. List<BlogPostComment> postComments = db.BlogComments.Include("User").Where(u => u.User.Username == user.Username).ToList();
  188. if (postComments != null)
  189. {
  190. foreach (BlogPostComment postComment in postComments)
  191. {
  192. db.BlogComments.Remove(postComment);
  193. }
  194. }
  195. // Delete podcast comments
  196. List<Podcast.Models.PodcastComment> podComments = db.PodcastComments.Include("User").Where(u => u.User.Username == user.Username).ToList();
  197. if (podComments != null)
  198. {
  199. foreach (Podcast.Models.PodcastComment podComment in podComments)
  200. {
  201. db.PodcastComments.Remove(podComment);
  202. }
  203. }
  204. // Delete User
  205. db.Users.Remove(user);
  206. db.SaveChanges();
  207. }
  208. catch (Exception ex)
  209. {
  210. throw new Exception("Unable to delete user.", ex);
  211. }
  212. }
  213. #endregion
  214. #region Email Management
  215. public static bool UserEmailExists(Config config, string username)
  216. {
  217. // If Email Server is enabled
  218. if (config.EmailConfig.Enabled)
  219. {
  220. string email = string.Format("{0}@{1}", username, config.EmailConfig.Domain);
  221. // Connect to hmailserver COM
  222. var app = new hMailServer.Application();
  223. app.Connect();
  224. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  225. try
  226. {
  227. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  228. var account = domain.Accounts.ItemByAddress[email];
  229. // We didn't error out, so the email exists
  230. return true;
  231. }
  232. catch { }
  233. }
  234. return false;
  235. }
  236. public static DateTime UserEmailLastActive(Config config, string username)
  237. {
  238. DateTime lastActive = new DateTime(1900, 1, 1);
  239. if (config.EmailConfig.Enabled)
  240. {
  241. string email = string.Format("{0}@{1}", username, config.EmailConfig.Domain);
  242. var app = new hMailServer.Application();
  243. app.Connect();
  244. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  245. try
  246. {
  247. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  248. var account = domain.Accounts.ItemByAddress[email];
  249. DateTime lastEmail = (DateTime)account.LastLogonTime;
  250. if (lastActive < lastEmail)
  251. lastActive = lastEmail;
  252. }
  253. catch { }
  254. }
  255. return lastActive;
  256. }
  257. public static void AddUserEmail(Config config, User user, string password)
  258. {
  259. try
  260. {
  261. // If Email Server is enabled
  262. if (config.EmailConfig.Enabled)
  263. {
  264. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  265. // Connect to hmailserver COM
  266. var app = new hMailServer.Application();
  267. app.Connect();
  268. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  269. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  270. var newAccount = domain.Accounts.Add();
  271. newAccount.Address = email;
  272. newAccount.Password = password;
  273. newAccount.Active = true;
  274. newAccount.MaxSize = config.EmailConfig.MaxSize;
  275. newAccount.Save();
  276. }
  277. }
  278. catch (Exception ex)
  279. {
  280. throw new Exception("Unable to add email.", ex);
  281. }
  282. }
  283. public static void EditUserEmailPassword(Config config, User user, string password)
  284. {
  285. try
  286. {
  287. // If Email Server is enabled
  288. if (config.EmailConfig.Enabled)
  289. {
  290. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  291. var app = new hMailServer.Application();
  292. app.Connect();
  293. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  294. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  295. var account = domain.Accounts.ItemByAddress[email];
  296. account.Password = password;
  297. account.Save();
  298. }
  299. }
  300. catch (Exception ex)
  301. {
  302. throw new Exception("Unable to edit email account password.", ex);
  303. }
  304. }
  305. public static void DeleteUserEmail(Config config, User user)
  306. {
  307. try
  308. {
  309. // If Email Server is enabled
  310. if (config.EmailConfig.Enabled)
  311. {
  312. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  313. var app = new hMailServer.Application();
  314. app.Connect();
  315. app.Authenticate(config.EmailConfig.Username, config.EmailConfig.Password);
  316. var domain = app.Domains.ItemByName[config.EmailConfig.Domain];
  317. var account = domain.Accounts.ItemByAddress[string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain)];
  318. if (account != null)
  319. {
  320. account.Delete();
  321. }
  322. }
  323. }
  324. catch (Exception ex)
  325. {
  326. throw new Exception("Unable to delete email account.", ex);
  327. }
  328. }
  329. #endregion
  330. #region Git Management
  331. public static bool UserGitExists(Config config, string username)
  332. {
  333. if (config.GitConfig.Enabled)
  334. {
  335. try
  336. {
  337. Uri baseUri = new Uri(config.GitConfig.Host);
  338. Uri finalUri = new Uri(baseUri, "api/v1/users/" + username + "?token=" + config.GitConfig.AccessToken);
  339. WebRequest request = WebRequest.Create(finalUri);
  340. request.Method = "GET";
  341. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  342. if (response.StatusCode == HttpStatusCode.OK)
  343. {
  344. return true;
  345. }
  346. }
  347. catch { }
  348. }
  349. return false;
  350. }
  351. public static DateTime UserGitLastActive(Config config, string username)
  352. {
  353. DateTime lastActive = new DateTime(1900, 1, 1);
  354. if (config.GitConfig.Enabled)
  355. {
  356. string email = string.Format("{0}@{1}", username, config.EmailConfig.Domain);
  357. // We need to check the actual git database
  358. MysqlDatabase mySQL = new MysqlDatabase(config.GitConfig.Database);
  359. string sql = @"SELECT MAX(gogs.repository.updated) AS LastUpdate
  360. FROM gogs.repository
  361. INNER JOIN gogs.user
  362. WHERE gogs.user.login_name = {0} AND gogs.user.id = gogs.repository.owner_id";
  363. object result = mySQL.ScalarQuery(sql, new object[] { email });
  364. if (result != null)
  365. {
  366. DateTime tmpLast = lastActive;
  367. DateTime.TryParse(result.ToString(), out tmpLast);
  368. if (lastActive < tmpLast)
  369. lastActive = tmpLast;
  370. }
  371. }
  372. return lastActive;
  373. }
  374. public static void AddUserGit(Config config, User user, string password)
  375. {
  376. try
  377. {
  378. // If Git is enabled
  379. if (config.GitConfig.Enabled)
  380. {
  381. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  382. // Add gogs user
  383. using (var client = new WebClient())
  384. {
  385. var obj = new { source_id = config.GitConfig.SourceId, username = user.Username, email = email, login_name = email, password = password };
  386. string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
  387. client.Headers[HttpRequestHeader.ContentType] = "application/json";
  388. Uri baseUri = new Uri(config.GitConfig.Host);
  389. Uri finalUri = new Uri(baseUri, "api/v1/admin/users?token=" + config.GitConfig.AccessToken);
  390. string result = client.UploadString(finalUri, "POST", json);
  391. }
  392. }
  393. }
  394. catch (Exception ex)
  395. {
  396. throw new Exception("Unable to add git account.", ex);
  397. }
  398. }
  399. public static void EditUserGitPassword(Config config, User user, string password)
  400. {
  401. try
  402. {
  403. // If Git is enabled
  404. if (config.GitConfig.Enabled)
  405. {
  406. string email = string.Format("{0}@{1}", user.Username, config.EmailConfig.Domain);
  407. using (var client = new WebClient())
  408. {
  409. var obj = new { source_id = config.GitConfig.SourceId, email = email, password = password };
  410. string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
  411. client.Headers[HttpRequestHeader.ContentType] = "application/json";
  412. Uri baseUri = new Uri(config.GitConfig.Host);
  413. Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + user.Username + "?token=" + config.GitConfig.AccessToken);
  414. string result = client.UploadString(finalUri, "PATCH", json);
  415. }
  416. }
  417. }
  418. catch (Exception ex)
  419. {
  420. throw new Exception("Unable to edit git account password.", ex);
  421. }
  422. }
  423. public static void DeleteUserGit(Config config, User user)
  424. {
  425. try
  426. {
  427. // If Git is enabled
  428. if (config.GitConfig.Enabled)
  429. {
  430. try
  431. {
  432. Uri baseUri = new Uri(config.GitConfig.Host);
  433. Uri finalUri = new Uri(baseUri, "api/v1/admin/users/" + user.Username + "?token=" + config.GitConfig.AccessToken);
  434. WebRequest request = WebRequest.Create(finalUri);
  435. request.Method = "DELETE";
  436. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  437. if (response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.OK)
  438. {
  439. throw new Exception("Unable to delete git account. Response Code: " + response.StatusCode);
  440. }
  441. }
  442. catch (HttpException htex)
  443. {
  444. if (htex.GetHttpCode() != 404)
  445. throw new Exception("Unable to delete git account. Http Exception: " + htex.Message);
  446. }
  447. catch (Exception ex)
  448. {
  449. // This error signifies the user doesn't exist, so we can continue deleting
  450. if (ex.Message != "The remote server returned an error: (404) Not Found.")
  451. {
  452. throw new Exception("Unable to delete git account. Exception: " + ex.Message);
  453. }
  454. }
  455. }
  456. }
  457. catch (Exception ex)
  458. {
  459. throw new Exception("Unable to delete git account.", ex);
  460. }
  461. }
  462. #endregion
  463. public static HttpCookie CreateAuthCookie(string username, bool remember, string domain, bool local)
  464. {
  465. Config config = Config.Load();
  466. HttpCookie authcookie = FormsAuthentication.GetAuthCookie(username, remember);
  467. authcookie.Name = "TeknikAuth";
  468. authcookie.HttpOnly = true;
  469. authcookie.Secure = true;
  470. // Set domain dependent on where it's being ran from
  471. if (local) // localhost
  472. {
  473. authcookie.Domain = null;
  474. }
  475. else if (config.DevEnvironment) // dev.example.com
  476. {
  477. authcookie.Domain = string.Format("dev.{0}", domain);
  478. }
  479. else // A production instance
  480. {
  481. authcookie.Domain = string.Format(".{0}", domain);
  482. }
  483. return authcookie;
  484. }
  485. }
  486. }