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.

UploadAPIv1Controller.cs 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Microsoft.AspNetCore.Authorization;
  7. using Microsoft.AspNetCore.Mvc;
  8. using Microsoft.EntityFrameworkCore;
  9. using Microsoft.Extensions.Logging;
  10. using MimeDetective;
  11. using MimeDetective.Extensions;
  12. using nClam;
  13. using Teknik.Areas.API.Controllers;
  14. using Teknik.Areas.API.V1.Models;
  15. using Teknik.Areas.Upload;
  16. using Teknik.Areas.Users.Models;
  17. using Teknik.Areas.Users.Utility;
  18. using Teknik.Configuration;
  19. using Teknik.Data;
  20. using Teknik.Logging;
  21. using Teknik.Utilities;
  22. namespace Teknik.Areas.API.V1.Controllers
  23. {
  24. [Authorize(AuthenticationSchemes = "Bearer", Policy = "AnyAPI")]
  25. public class UploadAPIv1Controller : APIv1Controller
  26. {
  27. public UploadAPIv1Controller(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
  28. [HttpPost]
  29. [AllowAnonymous]
  30. public async Task<IActionResult> Upload(UploadAPIv1Model model)
  31. {
  32. try
  33. {
  34. if (_config.UploadConfig.UploadEnabled)
  35. {
  36. if (model.file != null)
  37. {
  38. long maxUploadSize = _config.UploadConfig.MaxUploadSize;
  39. if (User.Identity.IsAuthenticated)
  40. {
  41. maxUploadSize = _config.UploadConfig.MaxUploadSizeBasic;
  42. IdentityUserInfo userInfo = await IdentityHelper.GetIdentityUserInfo(_config, User.Identity.Name);
  43. if (userInfo.AccountType == AccountType.Premium)
  44. {
  45. maxUploadSize = _config.UploadConfig.MaxUploadSizePremium;
  46. }
  47. }
  48. if (model.file.Length <= maxUploadSize)
  49. {
  50. // convert file to bytes
  51. string fileExt = Path.GetExtension(model.file.FileName);
  52. long contentLength = model.file.Length;
  53. // Scan the file to detect a virus
  54. if (_config.UploadConfig.VirusScanEnable)
  55. {
  56. ClamClient clam = new ClamClient(_config.UploadConfig.ClamServer, _config.UploadConfig.ClamPort);
  57. clam.MaxStreamSize = maxUploadSize;
  58. ClamScanResult scanResult = await clam.SendAndScanFileAsync(model.file.OpenReadStream());
  59. switch (scanResult.Result)
  60. {
  61. case ClamScanResults.Clean:
  62. break;
  63. case ClamScanResults.VirusDetected:
  64. return Json(new { error = new { message = string.Format("Virus Detected: {0}. As per our <a href=\"{1}\">Terms of Service</a>, Viruses are not permited.", scanResult.InfectedFiles.First().VirusName, Url.SubRouteUrl("tos", "TOS.Index")) } });
  65. case ClamScanResults.Error:
  66. break;
  67. case ClamScanResults.Unknown:
  68. break;
  69. }
  70. }
  71. // Need to grab the contentType if it's empty
  72. if (string.IsNullOrEmpty(model.contentType))
  73. {
  74. model.contentType = model.file.ContentType;
  75. if (string.IsNullOrEmpty(model.contentType))
  76. {
  77. using (System.IO.Stream fileStream = model.file.OpenReadStream())
  78. {
  79. fileStream.Seek(0, SeekOrigin.Begin);
  80. FileType fileType = fileStream.GetFileType();
  81. if (fileType != null)
  82. model.contentType = fileType.Mime;
  83. if (string.IsNullOrEmpty(model.contentType))
  84. {
  85. model.contentType = "application/octet-stream";
  86. }
  87. }
  88. }
  89. }
  90. // Check content type restrictions (Only for encrypting server side
  91. if (model.encrypt || !string.IsNullOrEmpty(model.key))
  92. {
  93. if (_config.UploadConfig.RestrictedContentTypes.Contains(model.contentType) || _config.UploadConfig.RestrictedExtensions.Contains(fileExt))
  94. {
  95. return Json(new { error = new { message = "File Type Not Allowed" } });
  96. }
  97. }
  98. // Initialize the key size and block size if empty
  99. if (model.keySize <= 0)
  100. model.keySize = _config.UploadConfig.KeySize;
  101. if (model.blockSize <= 0)
  102. model.blockSize = _config.UploadConfig.BlockSize;
  103. // Save the file data
  104. Upload.Models.Upload upload = UploadHelper.SaveFile(_dbContext, _config, model.file.OpenReadStream(), model.contentType, contentLength, model.encrypt, model.expirationUnit, model.expirationLength, fileExt, model.iv, model.key, model.keySize, model.blockSize);
  105. if (upload != null)
  106. {
  107. string fileKey = upload.Key;
  108. // Associate this with the user if they provided an auth key
  109. if (User.Identity.IsAuthenticated)
  110. {
  111. User foundUser = UserHelper.GetUser(_dbContext, User.Identity.Name);
  112. if (foundUser != null)
  113. {
  114. upload.UserId = foundUser.UserId;
  115. _dbContext.Entry(upload).State = EntityState.Modified;
  116. _dbContext.SaveChanges();
  117. }
  118. }
  119. // Generate delete key only if asked to
  120. if (!model.genDeletionKey)
  121. {
  122. upload.DeleteKey = string.Empty;
  123. _dbContext.Entry(upload).State = EntityState.Modified;
  124. _dbContext.SaveChanges();
  125. }
  126. // remove the key if we don't want to save it
  127. if (!model.saveKey)
  128. {
  129. upload.Key = null;
  130. _dbContext.Entry(upload).State = EntityState.Modified;
  131. _dbContext.SaveChanges();
  132. }
  133. // Pull all the information together
  134. string fullUrl = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url });
  135. var returnData = new
  136. {
  137. url = (model.saveKey || string.IsNullOrEmpty(fileKey)) ? fullUrl : fullUrl + "#" + fileKey,
  138. fileName = upload.Url,
  139. contentType = upload.ContentType,
  140. contentLength = upload.ContentLength,
  141. key = fileKey,
  142. keySize = upload.KeySize,
  143. iv = upload.IV,
  144. blockSize = upload.BlockSize,
  145. deletionKey = upload.DeleteKey
  146. };
  147. return Json(new { result = returnData });
  148. }
  149. return Json(new { error = new { message = "Unable to save file" } });
  150. }
  151. else
  152. {
  153. return Json(new { error = new { message = "File Too Large" } });
  154. }
  155. }
  156. return Json(new { error = new { message = "Invalid Upload Request" } });
  157. }
  158. return Json(new { error = new { message = "Uploads are Disabled" } });
  159. }
  160. catch (Exception ex)
  161. {
  162. return Json(new { error = new { message = "Exception: " + ex.Message } });
  163. }
  164. }
  165. }
  166. }