This commit is contained in:
2020-09-07 15:50:24 +00:00
parent e854688523
commit b9f35d9d79
9 changed files with 98 additions and 408 deletions

View File

@@ -513,61 +513,32 @@ namespace AyaNova.Api.Controllers
[HttpGet("download/{id}")]
public async Task<IActionResult> DownloadAsync([FromRoute] long id, [FromQuery] string t)
{
int nFailedAuthDelay = 3000;//should be just long enough to make brute force a hassle but short enough to not annoy people who just mistyped their creds to login
//NOTE this is the only unauthorized route as it needs to work with wiki url links and relies on the dlkey to work
//copied from Rockfish
//https://dotnetcoretutorials.com/2017/03/12/uploading-files-asp-net-core/
//https://stackoverflow.com/questions/45763149/asp-net-core-jwt-in-uri-query-parameter/45811270#45811270
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
//NOTE: this is a potentially dangerous route since it's not Authorized so we need to treat it like Auth route and not leak any
//useful information to bad actors and also ensure a delay to avoid brute force or DOS attacks
if (string.IsNullOrWhiteSpace(t))
{
await Task.Delay(nFailedAuthDelay);//DOS protection
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
}
//get user by key, if not found then reject
//If user dlkeyexp has not expired then return file
var DownloadUser = await ct.User.AsNoTracking().SingleOrDefaultAsync(z => z.DlKey == t && z.Active == true);
var DownloadUser = await UserBiz.ValidateDownloadTokenAndReturnUserAsync(t, ct);
if (DownloadUser == null)
{
await Task.Delay(nFailedAuthDelay);//DOS protection
await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//DOS protection
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
}
//this is necessary because they might have an expired JWT but this would just keep on working without a date check
//the default is the same timespan as the jwt so it's all good
var utcNow = new DateTimeOffset(DateTime.Now.ToUniversalTime(), TimeSpan.Zero);
if (DownloadUser.DlKeyExpire < utcNow.DateTime)
{
await Task.Delay(nFailedAuthDelay);//DOS protection
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
}
//Ok, user has a valid download key and it's not expired yet so get the attachment record
var dbObject = await ct.FileAttachment.SingleOrDefaultAsync(z => z.Id == id);
if (dbObject == null)
{
await Task.Delay(nFailedAuthDelay);//fishing protection
await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//fishing protection
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
}
//is this allowed?
if (!Authorized.HasReadFullRole(DownloadUser.Roles, dbObject.AttachToObjectType))
{
await Task.Delay(nFailedAuthDelay);//DOS protection
await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//DOS protection
return StatusCode(403, new ApiNotAuthorizedResponse());
}