maintenance expiration vs build date checking code

This commit is contained in:
2022-08-05 23:31:37 +00:00
parent 379ba76b31
commit d95510cf48
8 changed files with 96 additions and 14 deletions

View File

@@ -12,7 +12,12 @@ Updates:
it should also have some license route fetch prevention i.e. license has updates end date so server won't send if expired? Or something along those lines??
Or maybe that would be bad if they downgrade and want to put back in the license they paid for (restore from backup?)
Update scenarios to handle
boot with newer version than licensed and no db at all
in this case it's ok to do the schema update and install the fresh empty db then fetch the license
LICENSE FETCH SHOULD COMPARE DATES BEFORE INSTALLING A FETCHED LICENSE AND BALK IF MISMATCH
Boot with newer version and have existing db with outdated schema
TODO: it should check the license version *before* the schema update in order to not break anything
todo: RELEASE FINAL RELEASE
@@ -23,7 +28,7 @@ todo: RELEASE FINAL RELEASE
test carefully once done reversion everything to 8.0.1 for official release
Post in /next download folder for testing before posting fully
Re-run the smoke tests and e2e tests before posting 8.0.1 officially
todo: test on every platform every installer and be certain they work as advertised, yes this is a pain but it's necessary

View File

@@ -7,7 +7,7 @@ theme:
site_name: AyaNova manual
site_dir: '../../../server/AyaNova/wwwroot/docs'
strict: true
copyright: Copyright © 2022 Ground Zero Tech-Works Inc. REV-2022-08-04
copyright: Copyright © 2022 Ground Zero Tech-Works Inc. REV-2022-08-05
extra:
generator: false
# Extensions

View File

@@ -9,6 +9,7 @@
<ApplicationIcon>ayanova.ico</ApplicationIcon>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<noWarn>1591</noWarn>
<Deterministic>False</Deterministic>
</PropertyGroup>
<!-- https://andrewlock.net/version-vs-versionsuffix-vs-packageversion-what-do-they-all-mean/ -->
<ItemGroup>

View File

@@ -208,6 +208,11 @@ namespace AyaNova
logger.Info($"AYANOVA SERVER {AyaNovaVersion.VersionString} BOOTING");
#if (DEBUG)
logger.Info($"### Linker timestamp is {Util.FileUtil.GetLinkerTimestampUtc(System.Reflection.Assembly.GetExecutingAssembly())}");
#endif
//log configuration
logger.Info($"Config {DiagConfig}");
logger.Debug($"Full configuration is {config.GetDebugView()}");
@@ -294,7 +299,7 @@ namespace AyaNova
catch (Exception e)
{
logger.Fatal(e, "E1090 - AyaNova server can't start due to unexpected exception during initialization");
throw;
//throw;
}
finally
{

View File

@@ -593,7 +593,35 @@ namespace AyaNova
//log each item individually from runtime parameters
//Initialize license unless it doesn't exist yet then wait and do it after schema update and fingerprint
//this is necessary to accomodate checking build date against subscription and preventing schema update if they upgrade but are not entitled to
//so they don't fuck their database
//if there is a build date issue or a license issue it will fail with an exception, log to log file, log to console and not go beyond the license check preserving the db
//Note: case 4160 is to build an external license fetcher utility to allow a user to upgrade without uninstalling the newer version by purchasing a new sub and installing the key out of AyaNova
//If they don't want to purchase then they must downgrade
var tempSchema = dbContext.SchemaVersion.AsNoTracking().SingleOrDefault();
var tempLicense = dbContext.License.AsNoTracking().SingleOrDefault();
bool licenseChecked = false;
if (tempSchema != null && tempLicense != null && !string.IsNullOrWhiteSpace(tempSchema.Id))
{
//we have a schema and a license, check it now thus triggering build date vs maintenance expiry check
try
{
AyaNova.Core.License.InitializeAsync(apiServerState, dbContext, _newLog).Wait();
licenseChecked = true;
}
catch (Exception ex)
{
//Only re-throw if it's a 1020 error with the text VERSION-TOO-NEW included, any other error allow it to keep doing it's thing below before the second license init
//our exception is buried inside multiple inner exceptions but it's the innermost so drill down into it
while (ex.InnerException != null)
ex = ex.InnerException;
if (ex.Message.Contains("1020") && ex.Message.Contains("VERSION-TOO-NEW "))
{
throw new Exception("AyaNova did not start to protect the integrity of your data, see the console and / or error log for details");
}
}
}
@@ -602,7 +630,6 @@ namespace AyaNova
AySchema.CheckAndUpdateAsync(dbContext, _newLog).Wait();
//Check database integrity
_newLog.LogDebug("DB integrity check");
DbUtil.CheckFingerPrintAsync(AySchema.EXPECTED_COLUMN_COUNT,
@@ -613,8 +640,9 @@ namespace AyaNova
AySchema.EXPECTED_ROUTINES,
_newLog).Wait();
//Initialize license
AyaNova.Core.License.InitializeAsync(apiServerState, dbContext, _newLog).Wait();
//Initialize license if not already done (due to there being no db at all yet)
if (!licenseChecked)
AyaNova.Core.License.InitializeAsync(apiServerState, dbContext, _newLog).Wait();
//Set static global biz settings
_newLog.LogDebug("Global settings");

View File

@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using AyaNova.Models;
using AyaNova.Biz;
using System.Reflection;
namespace AyaNova.Util
{
@@ -481,7 +482,7 @@ namespace AyaNova.Util
AttachToAType = attachToObject.AType,
LastModified = lastModified,
Size = FileSize,
AttachedByUserId=attachedByUserId
AttachedByUserId = attachedByUserId
};
@@ -828,7 +829,7 @@ namespace AyaNova.Util
{
return string.Empty;
}
//Linux ~ home folder special handling here
if (path.Contains('~'))
{
@@ -841,6 +842,34 @@ namespace AyaNova.Util
}
#endregion general utilities
#region licensing related utility to qualify upgradability
//https://www.meziantou.net/getting-the-date-of-build-of-a-dotnet-assembly-at-runtime.htm
public static DateTime GetLinkerTimestampUtc(Assembly assembly)
{
var location = assembly.Location;
return GetLinkerTimestampUtc(location);
}
public static DateTime GetLinkerTimestampUtc(string filePath)
{
const int peHeaderOffset = 60;
const int linkerTimestampOffset = 8;
var bytes = new byte[2048];
using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
file.Read(bytes, 0, bytes.Length);
}
var headerPos = BitConverter.ToInt32(bytes, peHeaderOffset);
var secondsSince1970 = BitConverter.ToInt32(bytes, headerPos + linkerTimestampOffset);
var dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return dt.AddSeconds(secondsSince1970);
}
#endregion
}//eoc
}//eons

View File

@@ -1,8 +1,6 @@
using System;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
namespace AyaNova.Util
{
@@ -63,7 +61,8 @@ namespace AyaNova.Util
}
}//eoc

View File

@@ -799,7 +799,7 @@ namespace AyaNova.Core
throw new ApplicationException("E1020 - Can't install a trial key into a non empty AyaNova database. Erase the database first.");
}
//TODO: TECHCOUNT - new license causes exceeding count?
//TECHCOUNT - new license causes exceeding count?
long NewTechCount = ParsedNewKey.GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME).Count;
if (await AyaNova.Biz.UserBiz.ActiveCountAsync() > NewTechCount)
{
@@ -925,6 +925,15 @@ EQIDAQAB
#endregion get values
//Check if attempting to use a build of AyaNova that is newer than maintenance subscription expiry
if (MExBB(Util.FileUtil.GetLinkerTimestampUtc(System.Reflection.Assembly.GetExecutingAssembly()), key))
{
Console.WriteLine("E1020 - Not licensed for this version of AyaNova. Fix: downgrade back to previous version in use or contact technical support for options.");
//NOTE: VERSION-TOO-NEW bit below is checked for in startup.cs DO NOT remove this without fixing the side effects
throw new ApplicationException("E1020 VERSION-TOO-NEW - Not licensed for this version of AyaNova. Fix: downgrade back to previous version in use or contact technical support for options.");
}
//All is well return key
return key;
@@ -942,6 +951,12 @@ EQIDAQAB
#region Validate Build date against maintenance date in license
//MaintenanceExpirationBeforeBuild?
internal static bool MExBB(DateTime dtB, AyaNovaLicenseKey k) => k.MaintenanceExpiration < dtB;
#endregion
}//eoc