1
0
mirror of https://git.teknik.io/Teknikode/Teknik.git synced 2023-08-02 14:16:22 +02:00

Added scanning based on sha1 hash of the file to an endpoint

This commit is contained in:
Uncled1023 2020-07-17 00:48:24 -07:00
parent 2b14547c25
commit c701493859
15 changed files with 431 additions and 154 deletions

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Teknik.Configuration
{
public class ClamConfig
{
// Virus Scanning Settings
public bool Enabled { get; set; }
public string Server { get; set; }
public int Port { get; set; }
public ClamConfig()
{
Enabled = false;
Server = "localhost";
Port = 3310;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Teknik.Configuration
{
public class HashScanConfig
{
public bool Enabled { get; set; }
public string Endpoint { get; set; }
public bool Authenticate { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public HashScanConfig()
{
Enabled = false;
Endpoint = string.Empty;
Authenticate = false;
Username = string.Empty;
Password = string.Empty;
}
}
}

View File

@ -31,9 +31,9 @@ namespace Teknik.Configuration
// The size of the chunk that the file will be encrypted/decrypted in (bytes) // The size of the chunk that the file will be encrypted/decrypted in (bytes)
public int ChunkSize { get; set; } public int ChunkSize { get; set; }
// Virus Scanning Settings // Virus Scanning Settings
public bool VirusScanEnable { get; set; } public ClamConfig ClamConfig { get; set; }
public string ClamServer { get; set; } // Hash Scanning Settings
public int ClamPort { get; set; } public HashScanConfig HashScanConfig { get; set; }
// Content Type Restrictions // Content Type Restrictions
public List<string> RestrictedContentTypes { get; set; } public List<string> RestrictedContentTypes { get; set; }
public List<string> RestrictedExtensions { get; set; } public List<string> RestrictedExtensions { get; set; }
@ -61,9 +61,8 @@ namespace Teknik.Configuration
BlockSize = 128; BlockSize = 128;
IncludeExtension = true; IncludeExtension = true;
ChunkSize = 1024; ChunkSize = 1024;
VirusScanEnable = false; ClamConfig = new ClamConfig();
ClamServer = "localhost"; HashScanConfig = new HashScanConfig();
ClamPort = 3310;
RestrictedContentTypes = new List<string>(); RestrictedContentTypes = new List<string>();
RestrictedExtensions = new List<string>(); RestrictedExtensions = new List<string>();
} }

View File

@ -0,0 +1,50 @@
using nClam;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Teknik.Configuration;
namespace Teknik.ContentScanningService
{
public class ClamScanner : ContentScanner
{
public ClamScanner(Config config) : base(config)
{ }
public async override Task<ScanResult> ScanFile(Stream stream)
{
var result = new ScanResult();
if (stream != null)
{
// Set the start of the stream
stream.Seek(0, SeekOrigin.Begin);
ClamClient clam = new ClamClient(_config.UploadConfig.ClamConfig.Server, _config.UploadConfig.ClamConfig.Port);
clam.MaxStreamSize = stream.Length;
ClamScanResult scanResult = await clam.SendAndScanFileAsync(stream);
result.RawResult = scanResult.RawResult;
switch (scanResult.Result)
{
case ClamScanResults.Clean:
result.ResultType = ScanResultType.Clean;
break;
case ClamScanResults.VirusDetected:
result.ResultType = ScanResultType.VirusDetected;
result.RawResult = scanResult.InfectedFiles.First().VirusName;
break;
case ClamScanResults.Error:
result.ResultType = ScanResultType.Error;
break;
case ClamScanResults.Unknown:
result.ResultType = ScanResultType.Unknown;
break;
}
}
return result;
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Teknik.Configuration;
namespace Teknik.ContentScanningService
{
public abstract class ContentScanner
{
protected readonly Config _config;
public ContentScanner(Config config)
{
_config = config;
}
public abstract Task<ScanResult> ScanFile(Stream stream);
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Teknik.ContentScanningService</AssemblyName>
<RootNamespace>Teknik.ContentScanningService</RootNamespace>
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;linux-arm;osx-x64</RuntimeIdentifiers>
<Configurations>Debug;Release;Test</Configurations>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nClam" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Configuration\Configuration.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Teknik.Configuration;
using Teknik.Utilities.Cryptography;
namespace Teknik.ContentScanningService
{
public class HashScanner : ContentScanner
{
private static readonly HttpClient _client = new HttpClient();
public HashScanner(Config config) : base(config)
{ }
public async override Task<ScanResult> ScanFile(Stream stream)
{
var result = new ScanResult();
if (stream != null)
{
// Set the start of the stream
stream.Seek(0, SeekOrigin.Begin);
if (_config.UploadConfig.HashScanConfig.Authenticate)
{
var byteArray = Encoding.UTF8.GetBytes($"{_config.UploadConfig.HashScanConfig.Username}:{_config.UploadConfig.HashScanConfig.Password}");
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
}
// compute the hash of the stream
var hash = Utilities.Cryptography.SHA1.Hash(stream);
HttpResponseMessage response = await _client.PostAsync(_config.UploadConfig.HashScanConfig.Endpoint, new StringContent(hash));
HttpContent content = response.Content;
string resultStr = await content.ReadAsStringAsync();
if (resultStr == "true")
{
// The hash matched a CP entry, let's return the result as such
result.ResultType = ScanResultType.ChildPornography;
}
else
{
result.RawResult = resultStr + " | " + hash + _client.DefaultRequestHeaders.Authorization.ToString();
}
}
return result;
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace Teknik.ContentScanningService
{
public class ScanResult
{
public string RawResult { get; set;}
public ScanResultType ResultType { get; set; }
public ScanResult()
{
RawResult = string.Empty;
ResultType = ScanResultType.Clean;
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Teknik.ContentScanningService
{
public enum ScanResultType
{
Unknown = 0,
Clean = 1,
VirusDetected = 2,
ChildPornography = 3,
Error = 4
}
}

View File

@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceWorker", "ServiceWor
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentityServer", "IdentityServer\IdentityServer.csproj", "{3434645B-B8B4-457A-8C85-342E6727CCEE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentityServer", "IdentityServer\IdentityServer.csproj", "{3434645B-B8B4-457A-8C85-342E6727CCEE}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContentScanningService", "ContentScanningService\ContentScanningService.csproj", "{491FE626-ABC8-4D00-8C7F-0849C357201A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -92,6 +94,12 @@ Global
{3434645B-B8B4-457A-8C85-342E6727CCEE}.Release|Any CPU.Build.0 = Release|Any CPU {3434645B-B8B4-457A-8C85-342E6727CCEE}.Release|Any CPU.Build.0 = Release|Any CPU
{3434645B-B8B4-457A-8C85-342E6727CCEE}.Test|Any CPU.ActiveCfg = Test|Any CPU {3434645B-B8B4-457A-8C85-342E6727CCEE}.Test|Any CPU.ActiveCfg = Test|Any CPU
{3434645B-B8B4-457A-8C85-342E6727CCEE}.Test|Any CPU.Build.0 = Test|Any CPU {3434645B-B8B4-457A-8C85-342E6727CCEE}.Test|Any CPU.Build.0 = Test|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Release|Any CPU.Build.0 = Release|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Test|Any CPU.ActiveCfg = Debug|Any CPU
{491FE626-ABC8-4D00-8C7F-0849C357201A}.Test|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -16,6 +16,7 @@ using Teknik.Areas.Upload;
using Teknik.Areas.Users.Models; using Teknik.Areas.Users.Models;
using Teknik.Areas.Users.Utility; using Teknik.Areas.Users.Utility;
using Teknik.Configuration; using Teknik.Configuration;
using Teknik.ContentScanningService;
using Teknik.Data; using Teknik.Data;
using Teknik.Filters; using Teknik.Filters;
using Teknik.Logging; using Teknik.Logging;
@ -29,7 +30,6 @@ namespace Teknik.Areas.API.V1.Controllers
public UploadAPIv1Controller(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { } public UploadAPIv1Controller(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
[HttpPost] [HttpPost]
[AllowAnonymous]
[TrackPageView] [TrackPageView]
public async Task<IActionResult> Upload(UploadAPIv1Model model) public async Task<IActionResult> Upload(UploadAPIv1Model model)
{ {
@ -73,37 +73,47 @@ namespace Teknik.Areas.API.V1.Controllers
string fileExt = FileHelper.GetFileExtension(model.file.FileName); string fileExt = FileHelper.GetFileExtension(model.file.FileName);
long contentLength = model.file.Length; long contentLength = model.file.Length;
// Scan the file to detect a virus using (var fs = model.file.OpenReadStream())
if (_config.UploadConfig.VirusScanEnable)
{ {
ClamClient clam = new ClamClient(_config.UploadConfig.ClamServer, _config.UploadConfig.ClamPort); ScanResult scanResult = null;
clam.MaxStreamSize = maxUploadSize;
ClamScanResult scanResult = await clam.SendAndScanFileAsync(model.file.OpenReadStream());
switch (scanResult.Result) // Scan the file to detect a virus
if (_config.UploadConfig.ClamConfig.Enabled)
{ {
case ClamScanResults.Clean: var clamScanner = new ClamScanner(_config);
break; scanResult = await clamScanner.ScanFile(fs);
case ClamScanResults.VirusDetected:
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")) } });
case ClamScanResults.Error:
break;
case ClamScanResults.Unknown:
break;
} }
}
// Need to grab the contentType if it's empty // Scan the files against an endpoint based on hash
if (string.IsNullOrEmpty(model.contentType)) if (_config.UploadConfig.HashScanConfig.Enabled && (scanResult == null || scanResult.ResultType == ScanResultType.Clean))
{ {
model.contentType = model.file.ContentType; var hashScanner = new HashScanner(_config);
scanResult = await hashScanner.ScanFile(fs);
}
switch (scanResult?.ResultType)
{
case ScanResultType.Clean:
break;
case ScanResultType.VirusDetected:
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.RawResult, Url.SubRouteUrl("tos", "TOS.Index")) } });
case ScanResultType.ChildPornography:
return Json(new { error = new { message = string.Format("Child Pornography Detected: As per our <a href=\"{0}\">Terms of Service</a>, Child Pornography is strictly not permited.", Url.SubRouteUrl("tos", "TOS.Index")) } });
case ScanResultType.Error:
return Json(new { error = new { message = string.Format("Error scanning the file upload. {0}", scanResult.RawResult) } });
case ScanResultType.Unknown:
return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload. {0}", scanResult.RawResult) } });
}
// Need to grab the contentType if it's empty
if (string.IsNullOrEmpty(model.contentType)) if (string.IsNullOrEmpty(model.contentType))
{ {
using (Stream fileStream = model.file.OpenReadStream()) model.contentType = model.file.ContentType;
if (string.IsNullOrEmpty(model.contentType))
{ {
fileStream.Seek(0, SeekOrigin.Begin); fs.Seek(0, SeekOrigin.Begin);
FileType fileType = fileStream.GetFileType(); FileType fileType = fs.GetFileType();
if (fileType != null) if (fileType != null)
model.contentType = fileType.Mime; model.contentType = fileType.Mime;
if (string.IsNullOrEmpty(model.contentType)) if (string.IsNullOrEmpty(model.contentType))
@ -112,76 +122,76 @@ namespace Teknik.Areas.API.V1.Controllers
} }
} }
} }
}
// Check content type restrictions (Only for encrypting server side // Check content type restrictions (Only for encrypting server side
if (model.encrypt || !string.IsNullOrEmpty(model.key)) if (model.encrypt || !string.IsNullOrEmpty(model.key))
{
if (_config.UploadConfig.RestrictedContentTypes.Contains(model.contentType) || _config.UploadConfig.RestrictedExtensions.Contains(fileExt))
{ {
return Json(new { error = new { message = "File Type Not Allowed" } }); if (_config.UploadConfig.RestrictedContentTypes.Contains(model.contentType) || _config.UploadConfig.RestrictedExtensions.Contains(fileExt))
}
}
// Initialize the key size and block size if empty
if (model.keySize <= 0)
model.keySize = _config.UploadConfig.KeySize;
if (model.blockSize <= 0)
model.blockSize = _config.UploadConfig.BlockSize;
// Save the file data
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);
if (upload != null)
{
string fileKey = upload.Key;
// Associate this with the user if they provided an auth key
if (User.Identity.IsAuthenticated)
{
User foundUser = UserHelper.GetUser(_dbContext, User.Identity.Name);
if (foundUser != null)
{ {
upload.UserId = foundUser.UserId; return Json(new { error = new { message = "File Type Not Allowed" } });
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges();
} }
} }
// Generate delete key only if asked to // Initialize the key size and block size if empty
if (!model.genDeletionKey) if (model.keySize <= 0)
model.keySize = _config.UploadConfig.KeySize;
if (model.blockSize <= 0)
model.blockSize = _config.UploadConfig.BlockSize;
// Save the file data
Upload.Models.Upload upload = UploadHelper.SaveFile(_dbContext, _config, fs, model.contentType, contentLength, model.encrypt, model.expirationUnit, model.expirationLength, fileExt, model.iv, model.key, model.keySize, model.blockSize);
if (upload != null)
{ {
upload.DeleteKey = string.Empty; string fileKey = upload.Key;
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges(); // Associate this with the user if they provided an auth key
if (User.Identity.IsAuthenticated)
{
User foundUser = UserHelper.GetUser(_dbContext, User.Identity.Name);
if (foundUser != null)
{
upload.UserId = foundUser.UserId;
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges();
}
}
// Generate delete key only if asked to
if (!model.genDeletionKey)
{
upload.DeleteKey = string.Empty;
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges();
}
// remove the key if we don't want to save it
if (!model.saveKey)
{
upload.Key = null;
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges();
}
// Pull all the information together
string fullUrl = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url });
var returnData = new
{
url = (model.saveKey || string.IsNullOrEmpty(fileKey)) ? fullUrl : fullUrl + "#" + fileKey,
fileName = upload.Url,
contentType = upload.ContentType,
contentLength = upload.ContentLength,
key = fileKey,
keySize = upload.KeySize,
iv = upload.IV,
blockSize = upload.BlockSize,
maxDownloads = upload.MaxDownloads,
expirationDate = upload.ExpireDate,
deletionKey = upload.DeleteKey
};
return Json(new { result = returnData });
} }
// remove the key if we don't want to save it
if (!model.saveKey)
{
upload.Key = null;
_dbContext.Entry(upload).State = EntityState.Modified;
_dbContext.SaveChanges();
}
// Pull all the information together
string fullUrl = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url });
var returnData = new
{
url = (model.saveKey || string.IsNullOrEmpty(fileKey)) ? fullUrl : fullUrl + "#" + fileKey,
fileName = upload.Url,
contentType = upload.ContentType,
contentLength = upload.ContentLength,
key = fileKey,
keySize = upload.KeySize,
iv = upload.IV,
blockSize = upload.BlockSize,
maxDownloads = upload.MaxDownloads,
expirationDate = upload.ExpireDate,
deletionKey = upload.DeleteKey
};
return Json(new { result = returnData });
} }
return Json(new { error = new { message = "Unable to save file" } }); return Json(new { error = new { message = "Unable to save file" } });

View File

@ -22,6 +22,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Teknik.Logging; using Teknik.Logging;
using Teknik.Areas.Users.Models; using Teknik.Areas.Users.Models;
using Teknik.ContentScanningService;
namespace Teknik.Areas.Upload.Controllers namespace Teknik.Areas.Upload.Controllers
{ {
@ -32,7 +33,6 @@ namespace Teknik.Areas.Upload.Controllers
public UploadController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { } public UploadController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
[HttpGet] [HttpGet]
[AllowAnonymous]
[TrackPageView] [TrackPageView]
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
{ {
@ -77,7 +77,6 @@ namespace Teknik.Areas.Upload.Controllers
} }
[HttpPost] [HttpPost]
[AllowAnonymous]
[DisableRequestSizeLimit] [DisableRequestSizeLimit]
public async Task<IActionResult> Upload([FromForm] UploadFileViewModel uploadFile) public async Task<IActionResult> Upload([FromForm] UploadFileViewModel uploadFile)
{ {
@ -118,51 +117,58 @@ namespace Teknik.Areas.Upload.Controllers
// convert file to bytes // convert file to bytes
long contentLength = uploadFile.file.Length; long contentLength = uploadFile.file.Length;
// Scan the file to detect a virus
if (_config.UploadConfig.VirusScanEnable)
{
using (Stream fs = uploadFile.file.OpenReadStream())
{
ClamClient clam = new ClamClient(_config.UploadConfig.ClamServer, _config.UploadConfig.ClamPort);
clam.MaxStreamSize = maxUploadSize;
ClamScanResult scanResult = await clam.SendAndScanFileAsync(fs);
switch (scanResult.Result)
{
case ClamScanResults.Clean:
break;
case ClamScanResults.VirusDetected:
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")) } });
case ClamScanResults.Error:
return Json(new { error = new { message = string.Format("Error scanning the file upload for viruses. {0}", scanResult.RawResult) } });
case ClamScanResults.Unknown:
return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload for viruses. {0}", scanResult.RawResult) } });
}
}
}
// Check content type restrictions (Only for encrypting server side
if (!uploadFile.options.Encrypt)
{
if (_config.UploadConfig.RestrictedContentTypes.Contains(uploadFile.fileType) || _config.UploadConfig.RestrictedExtensions.Contains(uploadFile.fileExt))
{
return Json(new { error = new { message = "File Type Not Allowed" } });
}
}
using (Stream fs = uploadFile.file.OpenReadStream()) using (Stream fs = uploadFile.file.OpenReadStream())
{ {
Models.Upload upload = UploadHelper.SaveFile(_dbContext, ScanResult scanResult = null;
_config,
fs, // Scan the file to detect a virus
uploadFile.fileType, if (_config.UploadConfig.ClamConfig.Enabled)
contentLength, {
!uploadFile.options.Encrypt, var clamScanner = new ClamScanner(_config);
uploadFile.options.ExpirationUnit, scanResult = await clamScanner.ScanFile(fs);
uploadFile.options.ExpirationLength, }
uploadFile.fileExt,
uploadFile.iv, null, // Scan the files against an endpoint based on hash
uploadFile.keySize, if (_config.UploadConfig.HashScanConfig.Enabled && (scanResult == null || scanResult.ResultType == ScanResultType.Clean))
{
var hashScanner = new HashScanner(_config);
scanResult = await hashScanner.ScanFile(fs);
}
switch (scanResult?.ResultType)
{
case ScanResultType.Clean:
break;
case ScanResultType.VirusDetected:
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.RawResult, Url.SubRouteUrl("tos", "TOS.Index")) } });
case ScanResultType.ChildPornography:
return Json(new { error = new { message = string.Format("Child Pornography Detected: As per our <a href=\"{0}\">Terms of Service</a>, Child Pornography is not permited.", Url.SubRouteUrl("tos", "TOS.Index")) } });
case ScanResultType.Error:
return Json(new { error = new { message = string.Format("Error scanning the file upload. {0}", scanResult.RawResult) } });
case ScanResultType.Unknown:
return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload. {0}", scanResult.RawResult) } });
}
// Check content type restrictions (Only for encrypting server side
if (!uploadFile.options.Encrypt)
{
if (_config.UploadConfig.RestrictedContentTypes.Contains(uploadFile.fileType) || _config.UploadConfig.RestrictedExtensions.Contains(uploadFile.fileExt))
{
return Json(new { error = new { message = "File Type Not Allowed" } });
}
}
Models.Upload upload = UploadHelper.SaveFile(_dbContext,
_config,
fs,
uploadFile.fileType,
contentLength,
!uploadFile.options.Encrypt,
uploadFile.options.ExpirationUnit,
uploadFile.options.ExpirationLength,
uploadFile.fileExt,
uploadFile.iv, null,
uploadFile.keySize,
uploadFile.blockSize); uploadFile.blockSize);
if (upload != null) if (upload != null)
{ {
@ -176,17 +182,20 @@ namespace Teknik.Areas.Upload.Controllers
_dbContext.SaveChanges(); _dbContext.SaveChanges();
} }
} }
return Json(new { result = new return Json(new
{ {
name = upload.Url, result = new
url = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url }), {
contentType = upload.ContentType, name = upload.Url,
contentLength = StringHelper.GetBytesReadable(upload.ContentLength), url = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url }),
contentLengthRaw = upload.ContentLength, contentType = upload.ContentType,
deleteUrl = Url.SubRouteUrl("u", "Upload.DeleteByKey", new { file = upload.Url, key = upload.DeleteKey }), contentLength = StringHelper.GetBytesReadable(upload.ContentLength),
expirationUnit = uploadFile.options.ExpirationUnit.ToString(), contentLengthRaw = upload.ContentLength,
expirationLength = uploadFile.options.ExpirationLength deleteUrl = Url.SubRouteUrl("u", "Upload.DeleteByKey", new { file = upload.Url, key = upload.DeleteKey }),
} }); expirationUnit = uploadFile.options.ExpirationUnit.ToString(),
expirationLength = uploadFile.options.ExpirationLength
}
});
} }
} }
return Json(new { error = new { message = "Unable to upload file" } }); return Json(new { error = new { message = "Unable to upload file" } });

View File

@ -81,6 +81,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Configuration\Configuration.csproj" /> <ProjectReference Include="..\Configuration\Configuration.csproj" />
<ProjectReference Include="..\ContentScanningService\ContentScanningService.csproj" />
<ProjectReference Include="..\GitService\GitService.csproj" /> <ProjectReference Include="..\GitService\GitService.csproj" />
<ProjectReference Include="..\Logging\Logging.csproj" /> <ProjectReference Include="..\Logging\Logging.csproj" />
<ProjectReference Include="..\MailService\MailService.csproj" /> <ProjectReference Include="..\MailService\MailService.csproj" />

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Teknik.Utilities.Cryptography
{
public class SHA1
{
public static string Hash(string text)
{
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
return Hash(ms);
}
}
public static string Hash(Stream stream)
{
var hash = default(string);
using (var algo = System.Security.Cryptography.SHA1.Create())
{
var hashBytes = algo.ComputeHash(stream);
// Return as hexadecimal string
hash = hashBytes.ToHex();
}
return hash;
}
}
}

View File

@ -30,7 +30,6 @@ namespace Teknik.Utilities.Cryptography
public static string Hash(string value, string salt1, string salt2) public static string Hash(string value, string salt1, string salt2)
{ {
SHA256Managed hash = new SHA256Managed(); SHA256Managed hash = new SHA256Managed();
SHA1 sha1 = new SHA1Managed();
// gen salt2 hash // gen salt2 hash
byte[] dataSalt2 = Encoding.UTF8.GetBytes(salt2); byte[] dataSalt2 = Encoding.UTF8.GetBytes(salt2);
byte[] salt2Bytes = hash.ComputeHash(dataSalt2); byte[] salt2Bytes = hash.ComputeHash(dataSalt2);
@ -40,13 +39,7 @@ namespace Teknik.Utilities.Cryptography
salt2Str += String.Format("{0:x2}", x); salt2Str += String.Format("{0:x2}", x);
} }
string dataStr = salt1 + value + salt2Str; string dataStr = salt1 + value + salt2Str;
byte[] dataStrBytes = Encoding.UTF8.GetBytes(dataStr); string sha1Str = SHA1.Hash(dataStr);
byte[] shaBytes = sha1.ComputeHash(dataStrBytes);
string sha1Str = string.Empty;
foreach (byte x in shaBytes)
{
sha1Str += String.Format("{0:x2}", x);
}
byte[] sha1Bytes = Encoding.UTF8.GetBytes(sha1Str); byte[] sha1Bytes = Encoding.UTF8.GetBytes(sha1Str);
byte[] valueBytes = hash.ComputeHash(sha1Bytes); byte[] valueBytes = hash.ComputeHash(sha1Bytes);
string hashString = string.Empty; string hashString = string.Empty;