This commit is contained in:
2020-06-11 19:52:47 +00:00
parent 1c2f1c2c42
commit a98dfbc08d
5 changed files with 63 additions and 44 deletions

View File

@@ -444,6 +444,7 @@ namespace AyaNova.Api.Controllers
DBSchemaVersion = AySchema.currentSchema,
ServerLocalTime = DateUtil.ServerDateTimeString(System.DateTime.UtcNow),
ServerTimeZone = TimeZoneInfo.Local.Id,
ServerDbId= AyaNova.Core.License.ServerDbId,
License = AyaNova.Core.License.LicenseInfoAsJson
}
});

View File

@@ -5,7 +5,8 @@ namespace AyaNova.Models
{
public partial class AyContext : DbContext
{
public virtual DbSet<MetricMM> MetricMM { get; set; }
public virtual DbSet<SchemaVersion> SchemaVersion { get; set; }
public virtual DbSet<MetricMM> MetricMM { get; set; }
public virtual DbSet<MetricDD> MetricDD { get; set; }
public virtual DbSet<User> User { get; set; }
public virtual DbSet<UserOptions> UserOptions { get; set; }
@@ -127,7 +128,7 @@ namespace AyaNova.Models
modelBuilder.Entity<PM>().Property(z => z.Serial).UseIdentityByDefaultColumn();
//modelBuilder.Entity<PurchaseOrder>().Property(z => z.Serial).UseIdentityByDefaultColumn();
//modelBuilder.Entity<MetricCPU>().HasNoKey();
///////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,24 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace AyaNova.Models
{
/// <summary>
/// AyaNova Schema version table
/// </summary>
public class SchemaVersion
{
[Required]
[Key]
public Guid Id { get; set; }
public int Schema { get; set; }
//ef core requires this
public SchemaVersion() { }
}//eoc
}//eons

View File

@@ -22,7 +22,7 @@ namespace AyaNova.Util
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 11;
internal const long EXPECTED_COLUMN_COUNT = 323;
internal const long EXPECTED_COLUMN_COUNT = 324;
internal const long EXPECTED_INDEX_COUNT = 134;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!
@@ -173,10 +173,10 @@ namespace AyaNova.Util
using (var cm = ct.Database.GetDbConnection().CreateCommand())
{
await ct.Database.OpenConnectionAsync();
cm.CommandText = "CREATE TABLE aschemaversion (schema INTEGER NOT NULL);";
cm.CommandText = "CREATE TABLE aschemaversion (schema INTEGER NOT NULL, id uuid not null);";
await cm.ExecuteNonQueryAsync();
cm.CommandText = "insert into aschemaversion (schema) values (1);";
cm.CommandText = $"insert into aschemaversion (schema, id) values (1,'{Guid.NewGuid()}');";
await cm.ExecuteNonQueryAsync();
await ct.Database.CloseConnectionAsync();

View File

@@ -52,15 +52,15 @@ namespace AyaNova.Core
//Trial key magic number for development and testing, all other guids will be fully licensed
private static Guid TEST_TRIAL_KEY_DBID = new Guid("{A6D18A8A-5613-4979-99DA-80D07641A2FE}");
// private static Guid TEST_TRIAL_KEY_DBID = new Guid("{A6D18A8A-5613-4979-99DA-80D07641A2FE}");
//Current license key, can be empty
private static AyaNovaLicenseKey _ActiveLicense = new AyaNovaLicenseKey();
//The one and only DBID
private static Guid DbId { get; set; }
//The license dbid, separate from teh server dbid
private static Guid LicenseDbId { get; set; }
#region license classes
@@ -153,7 +153,6 @@ namespace AyaNova.Core
{
get
{
return LicenseStatus.Revoked;
if (string.IsNullOrWhiteSpace(RegisteredTo) || RegisteredTo == UNLICENSED_TOKEN)
return LicenseStatus.NONE;
@@ -287,7 +286,8 @@ namespace AyaNova.Core
#region Exposed properties
//The database id value stored in the schema table
internal static Guid ServerDbId { get; private set; }
/// <summary>
/// Fetch a summary of the license key for displaying to the end user
@@ -302,7 +302,7 @@ namespace AyaNova.Core
if (ActiveKey.IsEmpty)
{
sb.AppendLine(UNLICENSED_TOKEN);
sb.AppendLine($"DB ID: {DbId}");
sb.AppendLine($"DB ID: {LicenseDbId}");
}
else
{
@@ -311,7 +311,7 @@ namespace AyaNova.Core
sb.AppendLine($"Registered to: {ActiveKey.RegisteredTo}");
sb.AppendLine($"Key ID: {ActiveKey.Id}");
sb.AppendLine($"DB ID: {DbId}");
sb.AppendLine($"DB ID: {LicenseDbId}");
sb.AppendLine($"Type: {(ActiveKey.RentalLicense ? "Service" : "Perpetual")}");
if (ActiveKey.WillExpire)
sb.AppendLine($"License expires: {DateUtil.ServerDateTimeString(ActiveKey.LicenseExpiration)}");
@@ -347,7 +347,7 @@ namespace AyaNova.Core
if (ActiveKey.IsEmpty)
{
return $"UNLICENSED, DB ID: {DbId}";
return $"UNLICENSED, DB ID: {LicenseDbId}";
}
else
{
@@ -357,7 +357,7 @@ namespace AyaNova.Core
sb.Append($"regto: {ActiveKey.RegisteredTo}, ");
sb.Append($"keyid: {ActiveKey.Id}, ");
sb.Append($"dbid: {DbId}, ");
sb.Append($"dbid: {LicenseDbId}, ");
sb.Append($"type: {(ActiveKey.RentalLicense ? "service" : "perpetual")}, ");
if (ActiveKey.WillExpire)
sb.Append($"exp: {DateUtil.ServerDateTimeString(ActiveKey.LicenseExpiration)}, ");
@@ -438,27 +438,16 @@ namespace AyaNova.Core
/// <returns>Result string</returns>
internal static async Task<string> RequestTrialAsync(string email, string regto, ILogger log)
{
//BEFORE_RELEASE: DO THE FOLLOWING BEFORE RELEASE:
//TODO: TESTING REMOVE BEFORE RELEASE
//for test purposes if this route is hit and this code executed then the dbid is temporarily changed to the special trial request
//dbid so I can test remotely without hassle
//TO USE: just hit the trial key request route once then the license fetch route and it should be easy peasy
log.LogCritical("WARNING License::RequestTrial - DEVELOPMENT TEST FORCING TRIAL DB KEY ID. UPDATE BEFORE RELEASE!!");
DbId = TEST_TRIAL_KEY_DBID;
//TESTING
Microsoft.AspNetCore.Http.Extensions.QueryBuilder q = new Microsoft.AspNetCore.Http.Extensions.QueryBuilder();
q.Add("dbid", DbId.ToString());
q.Add("dbid", LicenseDbId.ToString());
q.Add("email", email);
q.Add("regto", regto);
log.LogDebug($"Requesting trial license for DBID {DbId.ToString()}");
log.LogDebug($"Requesting trial license for DBID {LicenseDbId.ToString()}");
string sUrl = $"{LICENSE_SERVER_URL}rvr" + q.ToQueryString();
try
{
//var res = await _Client.GetStringAsync(sUrl);
var res = await ServiceProviderProvider.HttpClientFactory.CreateClient().GetStringAsync(sUrl);
return res;
}
@@ -467,7 +456,6 @@ namespace AyaNova.Core
var msg = "E1020 - Error requesting trial license key see log for details";
log.LogError(ex, msg);
return msg;
// throw new ApplicationException(msg, ex);
}
}
#endregion trial license request handling
@@ -482,18 +470,9 @@ namespace AyaNova.Core
/// <returns>Result string</returns>
internal static async Task FetchKeyAsync(AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, AyContext ct, ILogger log)
{
log.LogDebug($"Fetching license for DBID {DbId.ToString()}");
string sUrl = $"{LICENSE_SERVER_URL}rvf/{DbId.ToString()}";
log.LogDebug($"Fetching license for DBID {LicenseDbId.ToString()}");
string sUrl = $"{LICENSE_SERVER_URL}rvf/{LicenseDbId.ToString()}";
//##########################################################################################################
//TODO: RELEASE WARNING: this needs to be dealt with before production release
if (ServerBootConfig.AYANOVA_SERVER_TEST_MODE)
{
log.LogInformation("Server is in test mode, fetching trial key");
sUrl = $"{LICENSE_SERVER_URL}rvf/{TEST_TRIAL_KEY_DBID.ToString()}";
// log.LogInformation(sUrl);
}
//##########################################################################################################
try
{
@@ -519,8 +498,8 @@ namespace AyaNova.Core
/// <summary>
/// Initialize the key
/// Handle if first boot scenario to tag DB ID etc
/// Initialize the license
///
/// </summary>
internal static async Task InitializeAsync(AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, AyContext ct, ILogger log)
{
@@ -528,6 +507,18 @@ namespace AyaNova.Core
try
{
//First fetch the schema db id for the servers database, the license must match
var schema = await ct.SchemaVersion.AsNoTracking().SingleOrDefaultAsync();
if (schema == null || schema.Id == Guid.Empty)
{
//cryptic message deliberately, this is probably caused by someone trying to circumvent licensing
var msg = "E1030 - Database integrity check failed (2). Contact support.";
apiServerState.SetOpsOnly(msg);
log.LogCritical(msg);
return;
}
ServerDbId = schema.Id;
//Fetch key from db as no tracking so doesn't hang round if need to immediately clear and then re-add the key
Models.License ldb = await ct.License.AsNoTracking().SingleOrDefaultAsync();
@@ -535,7 +526,7 @@ namespace AyaNova.Core
if (ldb == null)
{
ldb = new Models.License();
ldb.DbId = Guid.NewGuid();//<--Permanent and unchanging DB ID for this database, the license must match this
ldb.DbId = ServerDbId;
ldb.Key = "none";
ct.License.Add(ldb);
await ct.SaveChangesAsync();
@@ -544,7 +535,7 @@ namespace AyaNova.Core
//ensure DB ID
if (ldb.DbId == Guid.Empty)
{
ldb.DbId = Guid.NewGuid();//<--Permanent and unchanging DB ID for this database, the license must match this
ldb.DbId = ServerDbId;
//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
ct.Entry(ldb).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
@@ -552,7 +543,7 @@ namespace AyaNova.Core
}
//Get it early and set it here so that it can be displayed early to the user even if not licensed
DbId = ldb.DbId;
LicenseDbId = ldb.DbId;
if (ldb.Key == "none")
{
@@ -739,6 +730,8 @@ EQIDAQAB
key.Id = (string)token.SelectToken("Key.Id");
key.RegisteredTo = (string)token.SelectToken("Key.RegisteredTo");
key.DbId = (Guid)token.SelectToken("Key.DBID");
if (key.DbId != ServerDbId)
throw new ApplicationException($"E1020 - License.Parse -> License key does not match this server");
key.LicenseExpiration = (DateTime)token.SelectToken("Key.LicenseExpiration");
key.MaintenanceExpiration = (DateTime)token.SelectToken("Key.MaintenanceExpiration");