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.

VaultController.cs 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.EntityFrameworkCore;
  5. using Microsoft.Extensions.Logging;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Web;
  13. using Teknik.Areas.Paste;
  14. using Teknik.Areas.Users.Models;
  15. using Teknik.Areas.Users.Utility;
  16. using Teknik.Areas.Vault.Models;
  17. using Teknik.Areas.Vault.ViewModels;
  18. using Teknik.Attributes;
  19. using Teknik.Configuration;
  20. using Teknik.Controllers;
  21. using Teknik.Data;
  22. using Teknik.Filters;
  23. using Teknik.Logging;
  24. using Teknik.Models;
  25. using Teknik.Utilities;
  26. using Teknik.Utilities.Cryptography;
  27. namespace Teknik.Areas.Vault.Controllers
  28. {
  29. [Authorize]
  30. [Area("Vault")]
  31. public class VaultController : DefaultController
  32. {
  33. public VaultController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
  34. [AllowAnonymous]
  35. [TrackPageView]
  36. public async Task<IActionResult> ViewVault(string id)
  37. {
  38. Models.Vault foundVault = _dbContext.Vaults.Where(v => v.Url == id).FirstOrDefault();
  39. if (foundVault != null)
  40. {
  41. // Update view count
  42. foundVault.Views += 1;
  43. _dbContext.Entry(foundVault).State = EntityState.Modified;
  44. _dbContext.SaveChanges();
  45. ViewBag.Title = foundVault.Title + " | Vault";
  46. VaultViewModel model = new VaultViewModel();
  47. model.CurrentSub = Subdomain;
  48. model.Url = foundVault.Url;
  49. model.UserId = foundVault.UserId;
  50. model.User = foundVault.User;
  51. model.Title = foundVault.Title;
  52. model.Description = foundVault.Description;
  53. model.DateCreated = foundVault.DateCreated;
  54. model.DateEdited = foundVault.DateEdited;
  55. if (foundVault.VaultItems.Any())
  56. {
  57. foreach (VaultItem item in foundVault.VaultItems.OrderBy(v => v.Index))
  58. {
  59. if (item.GetType().BaseType == typeof(UploadVaultItem))
  60. {
  61. UploadVaultItem upload = (UploadVaultItem)item;
  62. // Increment Views
  63. upload.Upload.Downloads += 1;
  64. _dbContext.Entry(upload.Upload).State = EntityState.Modified;
  65. _dbContext.SaveChanges();
  66. UploadItemViewModel uploadModel = new UploadItemViewModel();
  67. uploadModel.VaultItemId = item.VaultItemId;
  68. uploadModel.Title = item.Title;
  69. uploadModel.Description = item.Description;
  70. uploadModel.DateAdded = item.DateAdded;
  71. uploadModel.Upload = upload.Upload;
  72. model.Items.Add(uploadModel);
  73. }
  74. else if (item.GetType().BaseType == typeof(PasteVaultItem))
  75. {
  76. PasteVaultItem paste = (PasteVaultItem)item;
  77. // Increment Views
  78. paste.Paste.Views += 1;
  79. _dbContext.Entry(paste.Paste).State = EntityState.Modified;
  80. _dbContext.SaveChanges();
  81. // Check Expiration
  82. if (PasteHelper.CheckExpiration(paste.Paste))
  83. {
  84. _dbContext.Pastes.Remove(paste.Paste);
  85. _dbContext.SaveChanges();
  86. break;
  87. }
  88. PasteItemViewModel pasteModel = new PasteItemViewModel();
  89. pasteModel.VaultItemId = item.VaultItemId;
  90. pasteModel.Title = item.Title;
  91. pasteModel.Description = item.Description;
  92. pasteModel.DateAdded = item.DateAdded;
  93. pasteModel.PasteId = paste.Paste.PasteId;
  94. pasteModel.Url = paste.Paste.Url;
  95. pasteModel.DatePosted = paste.Paste.DatePosted;
  96. pasteModel.Syntax = paste.Paste.Syntax;
  97. pasteModel.HasPassword = !string.IsNullOrEmpty(paste.Paste.HashedPassword);
  98. if (!pasteModel.HasPassword)
  99. {
  100. // Read in the file
  101. string subDir = paste.Paste.FileName[0].ToString();
  102. string filePath = Path.Combine(_config.PasteConfig.PasteDirectory, subDir, paste.Paste.FileName);
  103. if (!System.IO.File.Exists(filePath))
  104. continue;
  105. byte[] ivBytes = Encoding.Unicode.GetBytes(paste.Paste.IV);
  106. byte[] keyBytes = AesCounterManaged.CreateKey(paste.Paste.Key, ivBytes, paste.Paste.KeySize);
  107. using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
  108. using (AesCounterStream cs = new AesCounterStream(fs, false, keyBytes, ivBytes))
  109. using (StreamReader sr = new StreamReader(cs, Encoding.Unicode))
  110. {
  111. pasteModel.Content = await sr.ReadToEndAsync();
  112. }
  113. }
  114. model.Items.Add(pasteModel);
  115. }
  116. }
  117. }
  118. return View(model);
  119. }
  120. return new StatusCodeResult(StatusCodes.Status404NotFound);
  121. }
  122. [HttpGet]
  123. [AllowAnonymous]
  124. [TrackPageView]
  125. public IActionResult NewVault()
  126. {
  127. ViewBag.Title = "Create Vault";
  128. ModifyVaultViewModel model = new ModifyVaultViewModel();
  129. model.CurrentSub = Subdomain;
  130. return View("~/Areas/Vault/Views/Vault/ModifyVault.cshtml", model);
  131. }
  132. [HttpGet]
  133. [AllowAnonymous]
  134. [TrackPageView]
  135. public IActionResult NewVaultFromService(string type, string items)
  136. {
  137. ViewBag.Title = "Create Vault";
  138. ModifyVaultViewModel model = new ModifyVaultViewModel();
  139. model.CurrentSub = Subdomain;
  140. string decodedItems = HttpUtility.UrlDecode(items);
  141. string[] allURLs = decodedItems.Split(',');
  142. int index = 0;
  143. foreach (string url in allURLs)
  144. {
  145. string[] urlInfo = url.Split(':');
  146. string uploadId = urlInfo[0];
  147. string title = string.Empty;
  148. if (urlInfo.GetUpperBound(0) >= 1)
  149. {
  150. // They also passed in the original filename, so let's use it as our title
  151. title = urlInfo[1];
  152. }
  153. if (IsValidItem(type, uploadId))
  154. {
  155. ModifyVaultItemViewModel item = new ModifyVaultItemViewModel();
  156. item.isTemplate = false;
  157. item.index = index;
  158. item.title = title;
  159. item.url = uploadId;
  160. item.type = type;
  161. model.items.Add(item);
  162. index++;
  163. }
  164. }
  165. return View("~/Areas/Vault/Views/Vault/ModifyVault.cshtml", model);
  166. }
  167. [HttpGet]
  168. [TrackPageView]
  169. public IActionResult EditVault(string url, string type, string items)
  170. {
  171. ViewBag.Title = "Edit Vault";
  172. Vault.Models.Vault foundVault = _dbContext.Vaults.Where(v => v.Url == url).FirstOrDefault();
  173. if (foundVault != null)
  174. {
  175. if (foundVault.User.Username == User.Identity.Name)
  176. {
  177. ViewBag.Title = "Edit Vault | " + foundVault.Title;
  178. ModifyVaultViewModel model = new ModifyVaultViewModel();
  179. model.CurrentSub = Subdomain;
  180. model.isEdit = true;
  181. model.vaultId = foundVault.VaultId;
  182. model.title = foundVault.Title;
  183. model.description = foundVault.Description;
  184. int index = 0;
  185. // Add all their existing items for the vault
  186. foreach (VaultItem item in foundVault.VaultItems.OrderBy(v => v.Index))
  187. {
  188. ModifyVaultItemViewModel itemModel = new ModifyVaultItemViewModel();
  189. itemModel.index = index;
  190. itemModel.isTemplate = false;
  191. if (item.GetType().BaseType == typeof(UploadVaultItem))
  192. {
  193. UploadVaultItem upload = (UploadVaultItem)item;
  194. itemModel.title = upload.Title;
  195. itemModel.description = upload.Description;
  196. itemModel.type = "Upload";
  197. itemModel.url = upload.Upload.Url;
  198. model.items.Add(itemModel);
  199. index++;
  200. }
  201. else if (item.GetType().BaseType == typeof(PasteVaultItem))
  202. {
  203. PasteVaultItem paste = (PasteVaultItem)item;
  204. itemModel.title = paste.Title;
  205. itemModel.description = paste.Description;
  206. itemModel.type = "Paste";
  207. itemModel.url = paste.Paste.Url;
  208. model.items.Add(itemModel);
  209. index++;
  210. }
  211. }
  212. // If they passed any new items in via the parameters, let's add them
  213. if (!string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(items))
  214. {
  215. string decodedItems = HttpUtility.UrlDecode(items);
  216. string[] allItems = decodedItems.Split(',');
  217. foreach (string newItem in allItems)
  218. {
  219. string[] urlInfo = newItem.Split(':');
  220. string itemId = urlInfo[0];
  221. string title = string.Empty;
  222. if (urlInfo.GetUpperBound(0) >= 1)
  223. {
  224. // They also passed in the original filename, so let's use it as our title
  225. title = urlInfo[1];
  226. }
  227. if (IsValidItem(type, itemId))
  228. {
  229. ModifyVaultItemViewModel item = new ModifyVaultItemViewModel();
  230. item.isTemplate = false;
  231. item.index = index;
  232. item.title = title;
  233. item.url = itemId;
  234. item.type = type;
  235. model.items.Add(item);
  236. index++;
  237. }
  238. }
  239. }
  240. return View("~/Areas/Vault/Views/Vault/ModifyVault.cshtml", model);
  241. }
  242. return new StatusCodeResult(StatusCodes.Status403Forbidden);
  243. }
  244. return new StatusCodeResult(StatusCodes.Status404NotFound);
  245. }
  246. [HttpPost]
  247. [AllowAnonymous]
  248. [ValidateAntiForgeryToken]
  249. public IActionResult CreateVault(ModifyVaultViewModel model)
  250. {
  251. if (model != null)
  252. {
  253. if (!string.IsNullOrEmpty(model.title))
  254. {
  255. Models.Vault newVault = new Models.Vault();
  256. // Create a new ID
  257. string url = StringHelper.RandomString(_config.VaultConfig.UrlLength);
  258. while (_dbContext.Vaults.Where(v => v.Url == url).FirstOrDefault() != null)
  259. {
  260. url = StringHelper.RandomString(_config.VaultConfig.UrlLength);
  261. }
  262. newVault.Url = url;
  263. newVault.DateCreated = DateTime.Now;
  264. newVault.Title = model.title;
  265. newVault.Description = model.description;
  266. if (User.Identity.IsAuthenticated)
  267. {
  268. User user = UserHelper.GetUser(_dbContext, User.Identity.Name);
  269. if (user != null)
  270. {
  271. newVault.UserId = user.UserId;
  272. }
  273. }
  274. // Add/Verify items
  275. if (model.items.Any())
  276. {
  277. int index = 0;
  278. foreach (ModifyVaultItemViewModel item in model.items)
  279. {
  280. if (IsValidItem(item.type, item.url))
  281. {
  282. switch (item.type.ToLower())
  283. {
  284. case "upload":
  285. UploadVaultItem newUpload = new UploadVaultItem();
  286. newUpload.Index = index;
  287. newUpload.DateAdded = DateTime.Now;
  288. newUpload.Title = item.title;
  289. newUpload.Description = item.description;
  290. newUpload.UploadId = _dbContext.Uploads.Where(u => u.Url == item.url).FirstOrDefault().UploadId;
  291. newVault.VaultItems.Add(newUpload);
  292. index++;
  293. break;
  294. case "paste":
  295. PasteVaultItem newPaste = new PasteVaultItem();
  296. newPaste.Index = index;
  297. newPaste.DateAdded = DateTime.Now;
  298. newPaste.Title = item.title;
  299. newPaste.Description = item.description;
  300. newPaste.PasteId = _dbContext.Pastes.Where(p => p.Url == item.url).FirstOrDefault().PasteId;
  301. newVault.VaultItems.Add(newPaste);
  302. index++;
  303. break;
  304. default:
  305. return Json(new { error = new { message = "You have an invalid item type: " + item.type } });
  306. }
  307. }
  308. else
  309. {
  310. return Json(new { error = new { message = "You have an invalid item URL: " + item.url } });
  311. }
  312. }
  313. }
  314. // Add and save the new vault
  315. _dbContext.Vaults.Add(newVault);
  316. _dbContext.SaveChanges();
  317. return Json(new { result = new { url = Url.SubRouteUrl("v", "Vault.ViewVault", new { id = url }) } });
  318. }
  319. return Json(new { error = new { message = "You must supply a Title" } });
  320. }
  321. return Json(new { error = new { message = "Invalid Parameters" } });
  322. }
  323. [HttpPost]
  324. [ValidateAntiForgeryToken]
  325. public IActionResult EditVault(ModifyVaultViewModel model)
  326. {
  327. if (model != null)
  328. {
  329. Vault.Models.Vault foundVault = _dbContext.Vaults.Where(v => v.VaultId == model.vaultId).FirstOrDefault();
  330. if (foundVault != null)
  331. {
  332. if (foundVault.User.Username == User.Identity.Name)
  333. {
  334. foundVault.DateEdited = DateTime.Now;
  335. foundVault.Title = model.title;
  336. foundVault.Description = model.description;
  337. // Clear previous items
  338. List<VaultItem> vaultItems = _dbContext.VaultItems.Where(v => v.VaultId == foundVault.VaultId).ToList();
  339. if (vaultItems != null)
  340. {
  341. foreach (VaultItem item in vaultItems)
  342. {
  343. _dbContext.VaultItems.Remove(item);
  344. }
  345. }
  346. foundVault.VaultItems.Clear();
  347. // Add/Verify items
  348. if (model.items.Any())
  349. {
  350. int index = 0;
  351. foreach (ModifyVaultItemViewModel item in model.items)
  352. {
  353. if (IsValidItem(item.type, item.url))
  354. {
  355. switch (item.type.ToLower())
  356. {
  357. case "upload":
  358. UploadVaultItem newUpload = new UploadVaultItem();
  359. newUpload.Index = index;
  360. newUpload.DateAdded = DateTime.Now;
  361. newUpload.Title = item.title;
  362. newUpload.Description = item.description;
  363. newUpload.UploadId = _dbContext.Uploads.Where(u => u.Url == item.url).FirstOrDefault().UploadId;
  364. foundVault.VaultItems.Add(newUpload);
  365. index++;
  366. break;
  367. case "paste":
  368. PasteVaultItem newPaste = new PasteVaultItem();
  369. newPaste.Index = index;
  370. newPaste.DateAdded = DateTime.Now;
  371. newPaste.Title = item.title;
  372. newPaste.Description = item.description;
  373. newPaste.PasteId = _dbContext.Pastes.Where(p => p.Url == item.url).FirstOrDefault().PasteId;
  374. foundVault.VaultItems.Add(newPaste);
  375. index++;
  376. break;
  377. default:
  378. return Json(new { error = new { message = "You have an invalid item type: " + item.type } });
  379. }
  380. }
  381. else
  382. {
  383. return Json(new { error = new { message = "You have an invalid item URL: " + item.url } });
  384. }
  385. }
  386. }
  387. _dbContext.Entry(foundVault).State = EntityState.Modified;
  388. _dbContext.SaveChanges();
  389. return Json(new { result = new { url = Url.SubRouteUrl("v", "Vault.ViewVault", new { id = foundVault.Url }) } });
  390. }
  391. return Json(new { error = new { message = "You do not have permission to edit this Vault" } });
  392. }
  393. return Json(new { error = new { message = "That Vault does not exist" } });
  394. }
  395. return Json(new { error = new { message = "Invalid Parameters" } });
  396. }
  397. [HttpPost]
  398. [HttpOptions]
  399. public IActionResult Delete(string id)
  400. {
  401. Vault.Models.Vault foundVault = _dbContext.Vaults.Where(v => v.Url == id).FirstOrDefault();
  402. if (foundVault != null)
  403. {
  404. if (foundVault.User.Username == User.Identity.Name)
  405. {
  406. _dbContext.Vaults.Remove(foundVault);
  407. _dbContext.SaveChanges();
  408. return Json(new { result = new { url = Url.SubRouteUrl("vault", "Vault.CreateVault") } });
  409. }
  410. return Json(new { error = new { message = "You do not have permission to edit this Vault" } });
  411. }
  412. return Json(new { error = new { message = "That Vault does not exist" } });
  413. }
  414. [HttpPost]
  415. [AllowAnonymous]
  416. [ValidateAntiForgeryToken]
  417. public IActionResult ValidateItem(string type, string url)
  418. {
  419. if (IsValidItem(type, url))
  420. {
  421. return Json(new { result = new { valid = true } });
  422. }
  423. else
  424. {
  425. return Json(new { error = new { message = "Invalid URL Id for this Item" } });
  426. }
  427. }
  428. private bool IsValidItem(string type, string url)
  429. {
  430. bool valid = false;
  431. if (!string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(url))
  432. {
  433. switch (type.ToLower())
  434. {
  435. case "upload":
  436. Upload.Models.Upload foundUpload = _dbContext.Uploads.Where(u => u.Url == url).FirstOrDefault();
  437. if (foundUpload != null)
  438. {
  439. valid = true;
  440. }
  441. break;
  442. case "paste":
  443. Paste.Models.Paste foundPaste = _dbContext.Pastes.Where(p => p.Url == url).FirstOrDefault();
  444. if (foundPaste != null)
  445. {
  446. valid = true;
  447. }
  448. break;
  449. }
  450. }
  451. return valid;
  452. }
  453. }
  454. }