global support license and validation
This commit is contained in:
@@ -319,20 +319,27 @@ namespace Disco.Data.Configuration
|
||||
#endregion
|
||||
|
||||
#region UpdateCheck
|
||||
public string DeploymentId
|
||||
public bool IsLicensed
|
||||
{
|
||||
get
|
||||
get => LicenseKey != null && LicenseExpiresOn != null && LicenseExpiresOn > DateTime.UtcNow && LicenseError == null;
|
||||
}
|
||||
public string LicenseKey
|
||||
{
|
||||
return Get<string>(null);
|
||||
get => Get<string>(null);
|
||||
set => Set(value);
|
||||
}
|
||||
}
|
||||
public string DeploymentSecret
|
||||
public DateTime? LicenseExpiresOn
|
||||
{
|
||||
get
|
||||
get => Get<DateTime?>(null);
|
||||
set => Set(value);
|
||||
}
|
||||
public string LicenseError
|
||||
{
|
||||
return Get<string>(null);
|
||||
}
|
||||
get => Get<string>(null);
|
||||
set => Set(value);
|
||||
}
|
||||
public string DeploymentId => Get<string>(null);
|
||||
public string DeploymentSecret => Get<string>(null);
|
||||
public short DeploymentChecksum
|
||||
{
|
||||
get
|
||||
@@ -351,22 +358,10 @@ namespace Disco.Data.Configuration
|
||||
}
|
||||
public UpdateResponseV2 UpdateLastCheckResponse
|
||||
{
|
||||
get
|
||||
{
|
||||
return Get<UpdateResponseV2>(null);
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
public bool UpdateBetaDeployment
|
||||
{
|
||||
get
|
||||
{
|
||||
return Get(false);
|
||||
}
|
||||
get => Get<UpdateResponseV2>(null);
|
||||
set => Set(value);
|
||||
}
|
||||
public bool UpdateBetaDeployment => Get(false);
|
||||
public Version InstalledDatabaseVersion
|
||||
{
|
||||
get
|
||||
|
||||
@@ -367,6 +367,7 @@
|
||||
<Compile Include="Interop\ActiveDirectory\IADObject.cs" />
|
||||
<Compile Include="Interop\DiscoServices\DiscoServiceHelpers.cs" />
|
||||
<Compile Include="Interop\DiscoServices\Jobs.cs" />
|
||||
<Compile Include="Interop\DiscoServices\LicenseValidationTask.cs" />
|
||||
<Compile Include="Interop\DiscoServices\PluginLibrary.cs" />
|
||||
<Compile Include="Interop\DiscoServices\PluginLibraryUpdateTask.cs" />
|
||||
<Compile Include="Interop\MimeTypes.cs" />
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Services.Interop.DiscoServices
|
||||
{
|
||||
public class LicenseValidationTask : ScheduledTask
|
||||
{
|
||||
private const string jobMapLicenseKey = "License";
|
||||
public override string TaskName { get { return "License Validation"; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
if (Database.DiscoConfiguration.LicenseKey != null)
|
||||
{
|
||||
// Trigger in 1 + 0-29 minutes
|
||||
var rng = new Random();
|
||||
var delay = rng.Next(30) + 1;
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create()
|
||||
.StartAt(DateTimeOffset.Now.AddMinutes(delay));
|
||||
|
||||
ScheduleTask(triggerBuilder);
|
||||
|
||||
base.InitalizeScheduledTask(Database);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleNow(string license)
|
||||
{
|
||||
var taskStatus = RunningStatus;
|
||||
if (taskStatus != null)
|
||||
return taskStatus;
|
||||
else
|
||||
{
|
||||
var task = new LicenseValidationTask();
|
||||
|
||||
var taskData = new JobDataMap() { { jobMapLicenseKey, license } };
|
||||
|
||||
return task.ScheduleTask(taskData);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus RunningStatus =>
|
||||
ScheduledTasks.GetTaskStatuses(typeof(LicenseValidationTask)).Where(ts => ts.IsRunning).FirstOrDefault();
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
var license = ExecutionContext.JobDetail.JobDataMap.GetString(jobMapLicenseKey);
|
||||
string orgName;
|
||||
Guid deploymentId;
|
||||
using (var database = new DiscoDataContext())
|
||||
{
|
||||
if (license == null)
|
||||
license = database.DiscoConfiguration.LicenseKey;
|
||||
orgName = database.DiscoConfiguration.OrganisationName;
|
||||
deploymentId = Guid.Parse(database.DiscoConfiguration.DeploymentId);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(license))
|
||||
{
|
||||
var result = ValidateLicense(deploymentId, orgName, license, true, out var infrastructureError);
|
||||
|
||||
string infrastructureError2 = null;
|
||||
if (result == null)
|
||||
result = ValidateLicense(deploymentId, orgName, license, false, out infrastructureError2);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
var error = $"Validation failed. {infrastructureError ?? infrastructureError2}";
|
||||
Status.SetTaskException(new Exception(error));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.IsValid)
|
||||
{
|
||||
using (var database = new DiscoDataContext())
|
||||
{
|
||||
database.DiscoConfiguration.LicenseKey = license;
|
||||
database.DiscoConfiguration.LicenseExpiresOn = result.ExpiresOn;
|
||||
database.DiscoConfiguration.LicenseError = null;
|
||||
database.SaveChanges();
|
||||
}
|
||||
Status.UpdateStatus(100, "License validated");
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = result.ErrorMessage ?? "Validation failed";
|
||||
Status.SetTaskException(new Exception(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LicenseResponseV1 ValidateLicense(Guid deploymentId, string organisationName, string license, bool useProxy, out string infrastructureError)
|
||||
{
|
||||
Status.UpdateStatus(10, $"Validating license for {organisationName}");
|
||||
|
||||
var appVersion = typeof(LicenseValidationTask).Assembly.GetName().Version.ToString(4);
|
||||
var updateUrl = $"{DiscoServiceHelpers.ServicesUrl}API/License/V1";
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(updateUrl);
|
||||
|
||||
// Fix for Proxy Servers which don't support KeepAlive
|
||||
request.KeepAlive = false;
|
||||
|
||||
if (!useProxy)
|
||||
request.Proxy = new WebProxy();
|
||||
|
||||
request.ContentType = "application/x-www-form-urlencoded";
|
||||
request.Method = WebRequestMethods.Http.Post;
|
||||
request.UserAgent = $"Disco/{appVersion} (License)";
|
||||
|
||||
using (var requestStream = request.GetRequestStream())
|
||||
{
|
||||
using (var writer = new StreamWriter(requestStream, Encoding.GetEncoding(28591)))
|
||||
{
|
||||
writer.Write("deploymentId=");
|
||||
writer.Write(Uri.EscapeDataString(deploymentId.ToString()));
|
||||
writer.Write($"&license={Uri.EscapeDataString(license)}");
|
||||
}
|
||||
}
|
||||
|
||||
Status.UpdateStatus(50, "Waiting for validation response");
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
Status.UpdateStatus(90, "Reading validation response");
|
||||
string validationJson;
|
||||
LicenseResponseV1 updateResult;
|
||||
|
||||
using (var responseStream = response.GetResponseStream())
|
||||
{
|
||||
using (var responseReader = new StreamReader(responseStream))
|
||||
{
|
||||
validationJson = responseReader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
updateResult = JsonConvert.DeserializeObject<LicenseResponseV1>(validationJson);
|
||||
|
||||
infrastructureError = null;
|
||||
return updateResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
infrastructureError = $"Server responded with: [{response.StatusCode}] {response.StatusDescription}";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LicenseResponseV1
|
||||
{
|
||||
public bool IsValid { get; set; }
|
||||
public DateTime? ValidOn { get; set; }
|
||||
public DateTime? ExpiresOn { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,26 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(ts.SessionId));
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.System.Show)]
|
||||
[HttpPost, ValidateAntiForgeryToken]
|
||||
public virtual ActionResult LicenseCheck(string license)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(license))
|
||||
{
|
||||
Database.DiscoConfiguration.LicenseKey = null;
|
||||
Database.DiscoConfiguration.LicenseExpiresOn = null;
|
||||
Database.DiscoConfiguration.LicenseError = null;
|
||||
Database.SaveChanges();
|
||||
return RedirectToAction(MVC.Config.SystemConfig.Index());
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = Disco.Services.Interop.DiscoServices.LicenseValidationTask.ScheduleNow(license);
|
||||
ts.SetFinishedUrl(Url.Action(MVC.Config.SystemConfig.Index()));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(ts.SessionId));
|
||||
}
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.System.Show)]
|
||||
public virtual ActionResult UpdateCheck()
|
||||
{
|
||||
|
||||
@@ -112,6 +112,11 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
|
||||
public bool EmailIsConfigured { get; set; }
|
||||
#endregion
|
||||
|
||||
public ScheduledTaskStatus LicenseValidationRunningStatus { get; set; }
|
||||
public string License { get; set; }
|
||||
public DateTime? LicenseExpires { get; set; }
|
||||
public string LicenseError { get; set; }
|
||||
|
||||
public ScheduledTaskStatus UpdateRunningStatus { get; set; }
|
||||
public DateTime? UpdateNextScheduled { get; set; }
|
||||
public UpdateResponseV2 UpdateLatestResponse { get; set; }
|
||||
@@ -136,6 +141,10 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
|
||||
EmailUsername = config.EmailUsername,
|
||||
EmailPassword = null,
|
||||
EmailIsConfigured = EmailService.IsConfigured,
|
||||
License = config.LicenseKey,
|
||||
LicenseExpires = config.LicenseExpiresOn,
|
||||
LicenseError = config.LicenseError,
|
||||
LicenseValidationRunningStatus = LicenseValidationTask.RunningStatus,
|
||||
UpdateLatestResponse = config.UpdateLastCheckResponse,
|
||||
UpdateRunningStatus = UpdateQueryTask.RunningStatus,
|
||||
UpdateNextScheduled = UpdateQueryTask.NextScheduled,
|
||||
|
||||
@@ -69,6 +69,86 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="form" style="width: 450px; margin-top: 15px;">
|
||||
<h2>License</h2>
|
||||
<table>
|
||||
@{
|
||||
<tr>
|
||||
<th style="width: 135px">
|
||||
License:
|
||||
</th>
|
||||
<td>
|
||||
@using (Html.BeginForm(MVC.API.System.LicenseCheck(), FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken();
|
||||
<input id="license" type="text" name="license" value="@Model.License" />
|
||||
<button type="submit" class="button small">Activate</button>
|
||||
}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
const $element = $('#license');
|
||||
const original = $element.val();
|
||||
$element.on('keyup', function (e) {
|
||||
const $button = $element.next('button');
|
||||
const value = $element.val();
|
||||
if (!original) {
|
||||
$element.prop('required', true);
|
||||
$button.text('Activate');
|
||||
} else {
|
||||
if (original === value) {
|
||||
$button.text('Validate');
|
||||
} else {
|
||||
if (!value) {
|
||||
$button.text('Clear');
|
||||
} else {
|
||||
$button.text('Activate');
|
||||
}
|
||||
}
|
||||
}
|
||||
}).trigger('keyup');
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
if (Model.License != null)
|
||||
{
|
||||
<tr>
|
||||
<th style="width: 135px">
|
||||
Status:
|
||||
</th>
|
||||
<td>
|
||||
@if (Model.LicenseError != null)
|
||||
{
|
||||
<div class="error"><i class="fa fa-exclamation-circle fa-lg"></i> @Model.LicenseError</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Expires @CommonHelpers.FriendlyDate(Model.LicenseExpires)</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<strong>Official support is available</strong>
|
||||
<ul>
|
||||
<li>Initial implementation assistance.</li>
|
||||
<li>Commitment to maintaining Disco ICT functionality and associated plugins.</li>
|
||||
<li>Direct support.</li>
|
||||
<li>Access to additional functionality.</li>
|
||||
<li>Ability to suggest additional functionality, with a voice in feature prioritisation.</li>
|
||||
</ul>
|
||||
<div style="text-align: right; margin-top: 4px;">
|
||||
<a href="https://discoict.com.au/support.aspx" target="_blank" class="button small">Request More Information</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
<div class="form" style="width: 450px; margin-top: 15px;">
|
||||
<h2>Updates</h2>
|
||||
<table>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,12 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return RedirectToActionPermanent(taskResult.Result);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult LicenseCheck()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.LicenseCheck);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult UpdateOrganisationName()
|
||||
@@ -162,6 +168,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string UpdateLastNetworkLogonDates = "UpdateLastNetworkLogonDates";
|
||||
public readonly string UpdateAttachmentThumbnails = "UpdateAttachmentThumbnails";
|
||||
public readonly string UpdateADDeviceDescriptions = "UpdateADDeviceDescriptions";
|
||||
public readonly string LicenseCheck = "LicenseCheck";
|
||||
public readonly string UpdateCheck = "UpdateCheck";
|
||||
public readonly string UpdateOrganisationName = "UpdateOrganisationName";
|
||||
public readonly string OrganisationLogo = "OrganisationLogo";
|
||||
@@ -187,6 +194,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public const string UpdateLastNetworkLogonDates = "UpdateLastNetworkLogonDates";
|
||||
public const string UpdateAttachmentThumbnails = "UpdateAttachmentThumbnails";
|
||||
public const string UpdateADDeviceDescriptions = "UpdateADDeviceDescriptions";
|
||||
public const string LicenseCheck = "LicenseCheck";
|
||||
public const string UpdateCheck = "UpdateCheck";
|
||||
public const string UpdateOrganisationName = "UpdateOrganisationName";
|
||||
public const string OrganisationLogo = "OrganisationLogo";
|
||||
@@ -207,6 +215,14 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
|
||||
|
||||
static readonly ActionParamsClass_LicenseCheck s_params_LicenseCheck = new ActionParamsClass_LicenseCheck();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_LicenseCheck LicenseCheckParams { get { return s_params_LicenseCheck; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_LicenseCheck
|
||||
{
|
||||
public readonly string license = "license";
|
||||
}
|
||||
static readonly ActionParamsClass_UpdateOrganisationName s_params_UpdateOrganisationName = new ActionParamsClass_UpdateOrganisationName();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_UpdateOrganisationName UpdateOrganisationNameParams { get { return s_params_UpdateOrganisationName; } }
|
||||
@@ -404,6 +420,18 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
partial void LicenseCheckOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string license);
|
||||
|
||||
[NonAction]
|
||||
public override System.Web.Mvc.ActionResult LicenseCheck(string license)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.LicenseCheck);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "license", license);
|
||||
LicenseCheckOverride(callInfo, license);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
partial void UpdateCheckOverride(T4MVC_System_Web_Mvc_ActionResult callInfo);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user