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

Fixed range requests and consolidated data download

This commit is contained in:
Uncled1023 2022-05-25 23:30:14 -07:00
parent 22c5553d3a
commit dc76918300
6 changed files with 53 additions and 64 deletions

View File

@ -161,7 +161,7 @@ namespace Teknik.Areas.Paste.Controllers
Response.Headers.Add("Content-Disposition", cd.ToString()); Response.Headers.Add("Content-Disposition", cd.ToString());
return new BufferedFileStreamResult("application/octet-stream", async (response) => await ResponseHelper.StreamToOutput(response, true, new AesCounterStream(fileStream, false, keyBytes, ivBytes), contentSize, _config.PasteConfig.ChunkSize), false); return new BufferedFileStreamResult("application/octet-stream", async (response) => await ResponseHelper.StreamToOutput(response, new AesCounterStream(fileStream, false, keyBytes, ivBytes), contentSize, _config.PasteConfig.ChunkSize), false);
default: default:
return View("~/Areas/Paste/Views/Paste/Full.cshtml", model); return View("~/Areas/Paste/Views/Paste/Full.cshtml", model);
} }

View File

@ -83,7 +83,7 @@ namespace Teknik.Areas.Podcast.Controllers
[HttpGet] [HttpGet]
[AllowAnonymous] [AllowAnonymous]
[ResponseCache(Duration = 31536000, Location = ResponseCacheLocation.Any)] [ResponseCache(Duration = 31536000, Location = ResponseCacheLocation.Any, NoStore = false)]
[TrackDownload] [TrackDownload]
public IActionResult Download(int episode, string fileName) public IActionResult Download(int episode, string fileName)
{ {
@ -215,7 +215,7 @@ namespace Teknik.Areas.Podcast.Controllers
// Reset file stream to starting position (or start of range) // Reset file stream to starting position (or start of range)
fileStream.Seek(startByte, SeekOrigin.Begin); fileStream.Seek(startByte, SeekOrigin.Begin);
return new BufferedFileStreamResult(contentType, (response) => ResponseHelper.StreamToOutput(response, true, fileStream, (int)length, 4 * 1024), false); return new BufferedFileStreamResult(contentType, (response) => ResponseHelper.StreamToOutput(response, fileStream, (int)length, 4 * 1024), false);
} }
} }
return new StatusCodeResult(StatusCodes.Status404NotFound); return new StatusCodeResult(StatusCodes.Status404NotFound);

View File

@ -397,28 +397,7 @@ namespace Teknik.Areas.Upload.Controllers
// Reset file stream to starting position (or start of range) // Reset file stream to starting position (or start of range)
fileStream.Seek(startByte, SeekOrigin.Begin); fileStream.Seek(startByte, SeekOrigin.Begin);
try return DownloadData(url, fileStream, contentType, (int)length, key, iv);
{
// If the IV is set, and Key is set, then decrypt it while sending
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv))
{
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
var aesStream = new AesCounterStream(fileStream, false, keyBytes, ivBytes);
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, true, aesStream, (int)length, _config.UploadConfig.ChunkSize), false);
}
else // Otherwise just send it
{
// Send the file
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, true, fileStream, (int)length, _config.UploadConfig.ChunkSize), false);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Error in Download: {url}", new { url });
}
} }
} }
return new StatusCodeResult(StatusCodes.Status404NotFound); return new StatusCodeResult(StatusCodes.Status404NotFound);
@ -462,19 +441,7 @@ namespace Teknik.Areas.Upload.Controllers
Response.Headers.Add("Content-Disposition", cd.ToString()); Response.Headers.Add("Content-Disposition", cd.ToString());
// If the IV is set, and Key is set, then decrypt it while sending return DownloadData(upload.Url, fileStream, upload.ContentType, (int)upload.ContentLength, upload.Key, upload.IV);
if (decrypt && !string.IsNullOrEmpty(upload.Key) && !string.IsNullOrEmpty(upload.IV))
{
byte[] keyBytes = Encoding.UTF8.GetBytes(upload.Key);
byte[] ivBytes = Encoding.UTF8.GetBytes(upload.IV);
return new BufferedFileStreamResult(upload.ContentType, (response) => ResponseHelper.StreamToOutput(response, true, new AesCounterStream(fileStream, false, keyBytes, ivBytes), (int)upload.ContentLength, _config.UploadConfig.ChunkSize), false);
}
else // Otherwise just send it
{
// Send the file
return new BufferedFileStreamResult(upload.ContentType, (response) => ResponseHelper.StreamToOutput(response, true, fileStream, (int)upload.ContentLength, _config.UploadConfig.ChunkSize), false);
}
} }
} }
return Json(new { error = new { message = "File Does Not Exist" } }); return Json(new { error = new { message = "File Does Not Exist" } });
@ -540,5 +507,33 @@ namespace Teknik.Areas.Upload.Controllers
} }
return Json(new { error = new { message = "This Upload does not exist" } }); return Json(new { error = new { message = "This Upload does not exist" } });
} }
private IActionResult DownloadData(string url, Stream fileStream, string contentType, int length, string key, string iv)
{
try
{
// If the IV is set, and Key is set, then decrypt it while sending
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv))
{
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
var aesStream = new AesCounterStream(fileStream, false, keyBytes, ivBytes);
//return File(aesStream, contentType, true);
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, aesStream, length, _config.UploadConfig.ChunkSize), false);
}
else // Otherwise just send it
{
// Send the file
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, fileStream, length, _config.UploadConfig.ChunkSize), false);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Error in Download: {url}", new { url });
}
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
} }
} }

View File

@ -54,10 +54,10 @@ namespace Teknik.Utilities.Cryptography
} }
} }
public class CounterModeCryptoTransform : ICryptoTransform public class CounterModeCryptoTransform : ICryptoTransform, IDisposable
{ {
private readonly int _BlockSize; private readonly int _BlockSize;
private readonly Memory<byte> _IV; private readonly byte[] _IV;
private readonly byte[] _Counter; private readonly byte[] _Counter;
private readonly byte[] _EncryptedCounter; private readonly byte[] _EncryptedCounter;
private readonly ICryptoTransform _CounterEncryptor; private readonly ICryptoTransform _CounterEncryptor;
@ -103,13 +103,17 @@ namespace Teknik.Utilities.Cryptography
_BlockSize = symmetricAlgorithm.BlockSize; _BlockSize = symmetricAlgorithm.BlockSize;
// Initialize Counter
_Counter = new byte[initialCounter.Length];
initialCounter.CopyTo(_Counter, 0);
// Initialize the encrypted counter // Initialize the encrypted counter
_EncryptedCounter = new byte[_BlockSize / 8]; _EncryptedCounter = new byte[_BlockSize / 8];
_IV = iv; // Initialize IV
_IV = new byte[iv.Length];
iv.CopyTo(_IV, 0);
_Counter = initialCounter;
_CounterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv); _CounterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv);
// Initialize State // Initialize State
@ -204,7 +208,7 @@ namespace Teknik.Utilities.Cryptography
public void ResetCounter() public void ResetCounter()
{ {
_IV.CopyTo(_Counter); _IV.CopyTo(_Counter, 0);
_Iterations = 0; _Iterations = 0;
} }

View File

@ -45,7 +45,7 @@ namespace Teknik.Utilities.Cryptography
int processed = 0; int processed = 0;
// Read the data from the stream // Read the data from the stream
int bytesRead = await _Inner.ReadAsync(buffer); int bytesRead = await _Inner.ReadAsync(buffer).ConfigureAwait(false);
if (bytesRead > 0) if (bytesRead > 0)
{ {
// Process the read buffer // Process the read buffer
@ -128,21 +128,20 @@ namespace Teknik.Utilities.Cryptography
if (_Inner != null && CanWrite) if (_Inner != null && CanWrite)
{ {
// Process the cipher // Process the cipher
Memory<byte> output = buffer; Span<byte> output = buffer;
// Process the buffer // Process the buffer
int processed = _Cipher.TransformBlock(output.Span, offset, count); int processed = _Cipher.TransformBlock(output, offset, count);
// Do we have more? // Do we have more?
if (processed < count) if (processed < count)
{ {
// Finalize the cipher // Finalize the cipher
var finalProcessed = _Cipher.TransformFinalBlock(output.Span, processed + offset, count); var finalProcessed = _Cipher.TransformFinalBlock(output, processed + offset, count);
if (finalProcessed > 0) if (finalProcessed > 0)
processed += finalProcessed; processed += finalProcessed;
} }
ReadOnlyMemory<byte> readOnlyOutput = buffer; _Inner.Write(output);
_Inner.Write(readOnlyOutput.Span);
} }
} }
@ -255,12 +254,6 @@ namespace Teknik.Utilities.Cryptography
base.Dispose(disposing); base.Dispose(disposing);
} }
public override async ValueTask DisposeAsync()
{
await _Inner.DisposeAsync();
await base.DisposeAsync();
}
private void SyncCounter() private void SyncCounter()
{ {
if (_Cipher != null) if (_Cipher != null)

View File

@ -11,8 +11,9 @@ namespace Teknik.Utilities
{ {
public static class ResponseHelper public static class ResponseHelper
{ {
public async static Task StreamToOutput(HttpResponse response, bool flush, Stream stream, int length, int chunkSize) public async static Task StreamToOutput(HttpResponse response, Stream stream, int length, int chunkSize)
{ {
response.RegisterForDisposeAsync(stream);
var bufferSize = chunkSize; var bufferSize = chunkSize;
if (length < chunkSize) if (length < chunkSize)
bufferSize = length; bufferSize = length;
@ -27,11 +28,7 @@ namespace Teknik.Utilities
{ {
await response.Body.WriteAsync(buffer.Slice(0, processedBytes)); await response.Body.WriteAsync(buffer.Slice(0, processedBytes));
// Flush the response await response.Body.FlushAsync();
if (flush)
{
//await response.Body.FlushAsync();
}
} }
} }
while (processedBytes > 0); while (processedBytes > 0);
@ -42,10 +39,10 @@ namespace Teknik.Utilities
} }
finally finally
{ {
//await response.Body.FlushAsync(); await response.Body.FlushAsync();
// dispose of file stream // dispose of file stream
stream?.Dispose(); //stream?.Dispose();
} }
} }
} }