End User License consent system added
This commit is contained in:
@@ -90,7 +90,7 @@ sudo mkdir /usr/bin/ayanova
|
|||||||
|
|
||||||
[https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip](https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip)
|
[https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip](https://www.ayanova.com/download/ayanova-linux-x64-desktop.zip)
|
||||||
|
|
||||||
Download the the AyaNova server binary files folder created in the previous step or copy it there from the terminal:
|
Download the AyaNova server binary files to the folder created in the previous step or copy it there from the terminal:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp ayanova-linux-x64-desktop.zip /usr/bin/ayanova/
|
sudo cp ayanova-linux-x64-desktop.zip /usr/bin/ayanova/
|
||||||
|
|||||||
@@ -71,6 +71,12 @@ namespace AyaNova.Api.Controllers
|
|||||||
//NOTE: lockout or other login impacting state is processed later in ReturnUserCredsOnSuccessfulAuthentication() because many of those states need to have exceptions once the user is known
|
//NOTE: lockout or other login impacting state is processed later in ReturnUserCredsOnSuccessfulAuthentication() because many of those states need to have exceptions once the user is known
|
||||||
//or return alternate result of auth etc
|
//or return alternate result of auth etc
|
||||||
|
|
||||||
|
if (Core.License.LicenseConsentRequired)
|
||||||
|
{
|
||||||
|
await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);
|
||||||
|
return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED, "generalerror", "License agreement consent required"));
|
||||||
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(creds.Login) || string.IsNullOrWhiteSpace(creds.Password))
|
if (string.IsNullOrWhiteSpace(creds.Login) || string.IsNullOrWhiteSpace(creds.Password))
|
||||||
{
|
{
|
||||||
//Make a failed pw wait
|
//Make a failed pw wait
|
||||||
|
|||||||
@@ -274,8 +274,31 @@ namespace AyaNova.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="acceptCode"></param>
|
||||||
|
/// <returns>HTTP 204 No Content result code on success or fail code with explanation</returns>
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPost("lc")]
|
||||||
|
[ApiExplorerSettings(IgnoreApi = true)]
|
||||||
|
public async Task<IActionResult> lc([FromBody] string acceptCode)
|
||||||
|
{
|
||||||
|
//END USER LICENSE AGREEMENT ROUTE ONLY CALLED FROM WEBAPP AND HIDDEN FROM VIEW AS A ROUTE
|
||||||
|
|
||||||
|
|
||||||
|
//SuperUser only and must have accept code
|
||||||
|
if (string.IsNullOrWhiteSpace(acceptCode) || acceptCode.ToLowerInvariant() != "iaccepttheagreement")
|
||||||
|
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||||
|
|
||||||
|
await Core.License.FlagEULA(ct, log);
|
||||||
|
|
||||||
|
//Log
|
||||||
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, 0, AyaType.Global, AyaEvent.Modified, "End user license agreement consent obtained"), ct);
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|||||||
@@ -54,9 +54,10 @@ namespace AyaNova.Api.Controllers
|
|||||||
var logo = await ct.Logo.AsNoTracking().SingleOrDefaultAsync();
|
var logo = await ct.Logo.AsNoTracking().SingleOrDefaultAsync();
|
||||||
if (logo == null)
|
if (logo == null)
|
||||||
{
|
{
|
||||||
return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = false, ml = false, sl = false }));
|
return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = false, ml = false, sl = false, lcr = AyaNova.Core.License.LicenseConsentRequired }));
|
||||||
}
|
}
|
||||||
return Ok(ApiOkResponse.Response(new { eval = showSampleLogins, ll = logo.Large != null ? true : false, ml = logo.Medium != null ? true : false, sl = logo.Small != null ? true : false }));
|
return Ok(ApiOkResponse.Response(
|
||||||
|
new { eval = showSampleLogins, ll = logo.Large != null ? true : false, ml = logo.Medium != null ? true : false, sl = logo.Small != null ? true : false, lcr = AyaNova.Core.License.LicenseConsentRequired }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
public async Task<IActionResult> GetNewCount()
|
public async Task<IActionResult> GetNewCount()
|
||||||
{
|
{
|
||||||
var UserId = UserIdFromContext.Id(HttpContext.Items);
|
var UserId = UserIdFromContext.Id(HttpContext.Items);
|
||||||
if (serverState.IsClosed && UserId!=1)//bypass for superuser to fix fundamental problems
|
if (serverState.IsClosed && UserId != 1)//bypass for superuser to fix fundamental problems
|
||||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||||
|
|
||||||
return Ok(ApiOkResponse.Response(await ct.InAppNotification.CountAsync(z => z.UserId == UserId && z.Fetched == false)));
|
return Ok(ApiOkResponse.Response(await ct.InAppNotification.CountAsync(z => z.UserId == UserId && z.Fetched == false)));
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using AyaNova.Models;
|
using AyaNova.Models;
|
||||||
using AyaNova.Core;
|
|
||||||
using AyaNova.Util;
|
using AyaNova.Util;
|
||||||
|
|
||||||
namespace AyaNova.Biz
|
namespace AyaNova.Biz
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ namespace AyaNova.Models
|
|||||||
{
|
{
|
||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public string DbId { get; set; }
|
public string DbId { get; set; }
|
||||||
|
public bool LicenseAgree { get; set; }//flag indicating end user license agreement consent
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ namespace AyaNova.Util
|
|||||||
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
|
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
|
||||||
private const int DESIRED_SCHEMA_LEVEL = 1;
|
private const int DESIRED_SCHEMA_LEVEL = 1;
|
||||||
|
|
||||||
internal const long EXPECTED_COLUMN_COUNT = 1324;
|
internal const long EXPECTED_COLUMN_COUNT = 1325;
|
||||||
internal const long EXPECTED_INDEX_COUNT = 153;
|
internal const long EXPECTED_INDEX_COUNT = 153;
|
||||||
internal const long EXPECTED_CHECK_CONSTRAINTS = 519;
|
internal const long EXPECTED_CHECK_CONSTRAINTS = 520;
|
||||||
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 198;
|
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 198;
|
||||||
internal const long EXPECTED_VIEWS = 11;
|
internal const long EXPECTED_VIEWS = 11;
|
||||||
internal const long EXPECTED_ROUTINES = 2;
|
internal const long EXPECTED_ROUTINES = 2;
|
||||||
|
|
||||||
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
|
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
|
||||||
|
|
||||||
///////////////////////////////////////// C1324:I153:CC519:FC198:V11:R2
|
///////////////////////////////////////// C1325:I153:CC520:FC198:V11:R2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -624,7 +624,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
|
|||||||
await AyaNova.Biz.PrimeData.PrimeSuperUserAccount(ct);
|
await AyaNova.Biz.PrimeData.PrimeSuperUserAccount(ct);
|
||||||
|
|
||||||
//Add user table
|
//Add user table
|
||||||
await ExecQueryAsync("CREATE TABLE alicense (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, dbid TEXT, key TEXT NOT NULL)");
|
await ExecQueryAsync("CREATE TABLE alicense (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, licenseagree BOOL NOT NULL, dbid TEXT, key TEXT NOT NULL)");
|
||||||
|
|
||||||
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
|
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, "
|
||||||
+ "attachtoobjectid BIGINT NOT NULL, attachtoatype INTEGER NOT NULL, "
|
+ "attachtoobjectid BIGINT NOT NULL, attachtoatype INTEGER NOT NULL, "
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ namespace AyaNova.Core
|
|||||||
//The license dbid, separate from the server dbid
|
//The license dbid, separate from the server dbid
|
||||||
private static string LicenseDbId { get; set; }
|
private static string LicenseDbId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
#region license classes
|
#region license classes
|
||||||
|
|
||||||
//DTO object returned on license query
|
//DTO object returned on license query
|
||||||
@@ -184,6 +185,8 @@ namespace AyaNova.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Has any kind of valid license that is active
|
//Has any kind of valid license that is active
|
||||||
//used for auth route checking to allow for fixing this issue
|
//used for auth route checking to allow for fixing this issue
|
||||||
public bool KeyDoesNotNeedAttention
|
public bool KeyDoesNotNeedAttention
|
||||||
@@ -257,6 +260,7 @@ namespace AyaNova.Core
|
|||||||
public List<LicenseFeature> Features { get; set; }
|
public List<LicenseFeature> Features { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -302,6 +306,9 @@ namespace AyaNova.Core
|
|||||||
//The database id value stored in the schema table
|
//The database id value stored in the schema table
|
||||||
internal static string ServerDbId { get; private set; }
|
internal static string ServerDbId { get; private set; }
|
||||||
|
|
||||||
|
internal static bool LicenseConsentRequired { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fetch a summary of the license key for displaying to the end user
|
/// Fetch a summary of the license key for displaying to the end user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -443,10 +450,32 @@ namespace AyaNova.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region EULA consent
|
||||||
|
/// <summary>
|
||||||
|
/// Set consent flag for license agreement
|
||||||
|
/// </summary>
|
||||||
|
internal static async Task FlagEULA(AyContext ct, ILogger log)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var CurrentInDbKeyRecord = await ct.License.OrderBy(z => z.Id).FirstOrDefaultAsync();
|
||||||
|
if (CurrentInDbKeyRecord == null)
|
||||||
|
throw new ApplicationException("E1020 - Can't update EULA agreement, no key record found");
|
||||||
|
//Update current license
|
||||||
|
CurrentInDbKeyRecord.LicenseAgree = true;
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = "E1020 - Error during EULA agreement flagging";
|
||||||
|
log.LogError(ex, msg);
|
||||||
|
throw new ApplicationException(msg, ex);
|
||||||
|
}
|
||||||
|
LicenseConsentRequired = false;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Trial license request handling
|
#region Trial license request handling
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -484,7 +513,7 @@ namespace AyaNova.Core
|
|||||||
#endregion trial license request handling
|
#endregion trial license request handling
|
||||||
|
|
||||||
|
|
||||||
#region License fetching and handling
|
#region License fetching and handling
|
||||||
|
|
||||||
public class dtoFetchRequest
|
public class dtoFetchRequest
|
||||||
{
|
{
|
||||||
@@ -657,6 +686,7 @@ namespace AyaNova.Core
|
|||||||
ldb = new Models.License();
|
ldb = new Models.License();
|
||||||
ldb.DbId = ServerDbId;
|
ldb.DbId = ServerDbId;
|
||||||
ldb.Key = "none";
|
ldb.Key = "none";
|
||||||
|
ldb.LicenseAgree = false;
|
||||||
ct.License.Add(ldb);
|
ct.License.Add(ldb);
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
@@ -666,6 +696,7 @@ namespace AyaNova.Core
|
|||||||
if (string.IsNullOrWhiteSpace(ldb.DbId))
|
if (string.IsNullOrWhiteSpace(ldb.DbId))
|
||||||
{
|
{
|
||||||
ldb.DbId = ServerDbId;
|
ldb.DbId = ServerDbId;
|
||||||
|
ldb.LicenseAgree = false;
|
||||||
//Convert the no tracking record fetched above to tracking
|
//Convert the no tracking record fetched above to tracking
|
||||||
//this is required because a prior call to initialize before dumping the db would mean the license is still in memory in the context
|
//this is required because a prior call to initialize before dumping the db would mean the license is still in memory in the context
|
||||||
ct.Entry(ldb).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
|
ct.Entry(ldb).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
|
||||||
@@ -675,10 +706,13 @@ namespace AyaNova.Core
|
|||||||
//Get it early and set it here so that it can be displayed early to the user even if not licensed
|
//Get it early and set it here so that it can be displayed early to the user even if not licensed
|
||||||
LicenseDbId = ldb.DbId;
|
LicenseDbId = ldb.DbId;
|
||||||
|
|
||||||
|
//someone must agree to the license on first login from the client, this stores that
|
||||||
|
LicenseConsentRequired = !ldb.LicenseAgree;
|
||||||
|
|
||||||
if (ldb.Key == "none")
|
if (ldb.Key == "none")
|
||||||
{
|
{
|
||||||
var msg = "E1020 - License key not found in database, running in unlicensed mode";
|
var msg = "E1020 - License key not found in database, running in unlicensed mode";
|
||||||
apiServerState.SetSystemLock(msg);
|
apiServerState.SetSystemLock(msg);
|
||||||
log.LogWarning(msg);
|
log.LogWarning(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -790,6 +824,8 @@ namespace AyaNova.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PARSE and Validate key
|
#region PARSE and Validate key
|
||||||
|
|||||||
Reference in New Issue
Block a user