diff --git a/devdocs/todo.txt b/devdocs/todo.txt
index 72a20aa2..70e16496 100644
--- a/devdocs/todo.txt
+++ b/devdocs/todo.txt
@@ -10,6 +10,10 @@ todo: check attachment NOTES property is actually supported
//todo: search tables in schema, I think there is a missing index here, need to look at the search query section again as it was changed several times from the original schema creation
+
+todo: can a user be locked out from the server end even though they posess a valid token?
+ - and prevent download of images etc?
+
todo: api / server landing page is shitty on a mobile
todo: add query fail logging to datalist just like done with picklist so in production can catch mysterious problems more easily
diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs
index 50e5fb44..46d2580b 100644
--- a/server/AyaNova/Controllers/AttachmentController.cs
+++ b/server/AyaNova/Controllers/AttachmentController.cs
@@ -60,55 +60,54 @@ namespace AyaNova.Api.Controllers
+ //Moved this functionality to authentication and expiry follows jwt token expiry
+ // //LOOKAT: Centralize this code somewhere else, it's going to be needed for backup as well
+ // //consider the 1 hour thing, is this legit depending on client?
+ // ///
+ // /// Get download token
+ // /// A download token is good for 1 hour from issue
+ // ///
+ // /// Current download token for user
+ // [HttpGet("DownloadToken")]
+ // public async Task GetDownloadTokenAsync()
+ // {
+ // if (!serverState.IsOpen)
+ // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
- //LOOKAT: Centralize this code somewhere else, it's going to be needed for backup as well
- //consider the 1 hour thing, is this legit depending on client?
+ // long lUserId = UserIdFromContext.Id(HttpContext.Items);
+ // var u = await ct.User.FirstOrDefaultAsync(a => a.Id == lUserId);
+ // if (u == null)
+ // return NotFound();
+ // else
+ // {
- ///
- /// Get download token
- /// A download token is good for 1 hour from issue
- ///
- /// Current download token for user
- [HttpGet("DownloadToken")]
- public async Task GetDownloadTokenAsync()
- {
- if (!serverState.IsOpen)
- return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
+ // //Generate a download token and store it with the user account
+ // //users who are authenticated can get their token via download route
+ // Guid g = Guid.NewGuid();
+ // string dlkey = Convert.ToBase64String(g.ToByteArray());
+ // dlkey = dlkey.Replace("=", "");
+ // dlkey = dlkey.Replace("+", "");
- long lUserId = UserIdFromContext.Id(HttpContext.Items);
- var u = await ct.User.FirstOrDefaultAsync(a => a.Id == lUserId);
- if (u == null)
- return NotFound();
- else
- {
+ // //get expiry date for download token
+ // var exp = new DateTimeOffset(DateTime.Now.AddHours(1).ToUniversalTime(), TimeSpan.Zero);
- //Generate a download token and store it with the user account
- //users who are authenticated can get their token via download route
- Guid g = Guid.NewGuid();
- string dlkey = Convert.ToBase64String(g.ToByteArray());
- dlkey = dlkey.Replace("=", "");
- dlkey = dlkey.Replace("+", "");
+ // u.DlKey = dlkey;
+ // u.DlKeyExpire = exp.DateTime;
+ // ct.User.Update(u);
+ // try
+ // {
+ // await ct.SaveChangesAsync();//triggering concurrency exception here
+ // }
+ // catch (Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException)
+ // {
+ // log.LogInformation("Auth retry dlkey");
+ // };
- //get expiry date for download token
- var exp = new DateTimeOffset(DateTime.Now.AddHours(1).ToUniversalTime(), TimeSpan.Zero);
+ // return Ok(ApiOkResponse.Response(new { dlkey = u.DlKey, expires = u.DlKeyExpire }, true));
+ // }
- u.DlKey = dlkey;
- u.DlKeyExpire = exp.DateTime;
- ct.User.Update(u);
- try
- {
- await ct.SaveChangesAsync();//triggering concurrency exception here
- }
- catch (Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException)
- {
- log.LogInformation("Auth retry dlkey");
- };
-
- return Ok(ApiOkResponse.Response(new { dlkey = u.DlKey, expires = u.DlKeyExpire }, true));
- }
-
- }
+ // }
@@ -336,21 +335,25 @@ namespace AyaNova.Api.Controllers
var dlkeyUser = await ct.User.SingleOrDefaultAsync(m => m.DlKey == dlkey);
if (dlkeyUser == null)
{
- return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token not valid"));
+ //don't want to leak information so just say not found
+ //return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token not valid"));
+ return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
}
//Make sure the token provided is for the current user
long UserId = UserIdFromContext.Id(HttpContext.Items);
if (UserId != dlkeyUser.Id)
{
- return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token not valid"));
+ // return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token not valid"));
+ return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
}
var utcNow = new DateTimeOffset(DateTime.Now.ToUniversalTime(), TimeSpan.Zero);
if (dlkeyUser.DlKeyExpire < utcNow.DateTime)
{
- return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token has expired"));
+ // return BadRequest(new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, "dlkey", "Download token has expired"));
+ 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
diff --git a/server/AyaNova/Controllers/AuthController.cs b/server/AyaNova/Controllers/AuthController.cs
index 53dc071b..f45229ae 100644
--- a/server/AyaNova/Controllers/AuthController.cs
+++ b/server/AyaNova/Controllers/AuthController.cs
@@ -158,7 +158,7 @@ namespace AyaNova.Api.Controllers
//Multiple users are allowed the same password and login
//Salt will differentiate them so get all users that match login, then try to match pw
- var users = await ct.User.AsNoTracking().Where(m => m.Login == creds.Login).ToListAsync();
+ var users = await ct.User.Where(m => m.Login == creds.Login && m.Active == true).ToListAsync();
foreach (User u in users)
{
@@ -177,13 +177,15 @@ namespace AyaNova.Api.Controllers
}
- //If the user is inactive they may not login
- if (!u.Active)
- {
- //This is leaking information, instead just act like bad creds
- //return StatusCode(401, new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, null, "User deactivated"));
- return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
- }
+ // //If the user is inactive they may not login
+ // if (!u.Active)
+ // {
+ // //This is leaking information, instead just act like bad creds
+ // //return StatusCode(401, new ApiErrorResponse(ApiErrorCode.NOT_AUTHORIZED, null, "User deactivated"));
+ // return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
+ // }
+
+
//build the key (JWT set in startup.cs)
byte[] secretKey = System.Text.Encoding.ASCII.GetBytes(ServerBootConfig.AYANOVA_JWT_SECRET);
@@ -192,6 +194,18 @@ namespace AyaNova.Api.Controllers
var iat = new DateTimeOffset(DateTime.Now.ToUniversalTime(), TimeSpan.Zero);//timespan zero means zero time off utc / specifying this is a UTC datetime
var exp = new DateTimeOffset(DateTime.Now.AddDays(JWT_LIFETIME_DAYS).ToUniversalTime(), TimeSpan.Zero);
+
+ //=============== download token ===================
+ //Generate a download token and store it with the user account
+ //string DownloadToken = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
+ string DownloadToken = Hasher.GenerateSalt();
+ DownloadToken = DownloadToken.Replace("=", "");
+ DownloadToken = DownloadToken.Replace("+", "");
+ u.DlKey = DownloadToken;
+ u.DlKeyExpire = exp.DateTime;
+ await ct.SaveChangesAsync();
+ //=======================================================
+
var payload = new Dictionary()
{
{ "iat", iat.ToUnixTimeSeconds().ToString() },
@@ -200,7 +214,8 @@ namespace AyaNova.Api.Controllers
{ "id", u.Id.ToString() },
{ "name", u.Name},
{ "usertype", u.UserType},
- { "ayanova/roles", ((int)u.Roles).ToString() }
+ { "ayanova/roles", ((int)u.Roles).ToString()},
+ { "dlt", DownloadToken }
};