The next generation of the Teknik Services. Written in ASP.NET. Fork for blog tags.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

UserHelper.cs 20KB

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