This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user