mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
license verification services for user/org
This commit is contained in:
@ -9,6 +9,14 @@
|
|||||||
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="licensing.cer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="licensing.cer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:4000",
|
"applicationUrl": "http://localhost:4000",
|
||||||
"sslPort": 44377
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
|
BIN
src/Api/licensing.cer
Normal file
BIN
src/Api/licensing.cer
Normal file
Binary file not shown.
@ -8,6 +8,10 @@
|
|||||||
<UserSecretsId>bitwarden-Billing</UserSecretsId>
|
<UserSecretsId>bitwarden-Billing</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="licensing.cer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
BIN
src/Billing/licensing.cer
Normal file
BIN
src/Billing/licensing.cer
Normal file
Binary file not shown.
@ -7,6 +7,7 @@
|
|||||||
public virtual string StripeApiKey { get; set; }
|
public virtual string StripeApiKey { get; set; }
|
||||||
public virtual string ProjectName { get; set; }
|
public virtual string ProjectName { get; set; }
|
||||||
public virtual string LogDirectory { get; set; }
|
public virtual string LogDirectory { get; set; }
|
||||||
|
public virtual string LicenseDirectory { get; set; }
|
||||||
public virtual BaseServiceUriSettings BaseServiceUri { get; set; } = new BaseServiceUriSettings();
|
public virtual BaseServiceUriSettings BaseServiceUri { get; set; } = new BaseServiceUriSettings();
|
||||||
public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings();
|
public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings();
|
||||||
public virtual MailSettings Mail { get; set; } = new MailSettings();
|
public virtual MailSettings Mail { get; set; } = new MailSettings();
|
||||||
|
17
src/Core/Models/Business/ILicense.cs
Normal file
17
src/Core/Models/Business/ILicense.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Business
|
||||||
|
{
|
||||||
|
public interface ILicense
|
||||||
|
{
|
||||||
|
string LicenseKey { get; set; }
|
||||||
|
int Version { get; set; }
|
||||||
|
DateTime Issued { get; set; }
|
||||||
|
DateTime Expires { get; set; }
|
||||||
|
bool Trial { get; set; }
|
||||||
|
string Signature { get; set; }
|
||||||
|
byte[] GetSignatureData();
|
||||||
|
bool VerifySignature(X509Certificate2 certificate);
|
||||||
|
}
|
||||||
|
}
|
119
src/Core/Models/Business/OrganizationLicense.cs
Normal file
119
src/Core/Models/Business/OrganizationLicense.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Business
|
||||||
|
{
|
||||||
|
public class OrganizationLicense : ILicense
|
||||||
|
{
|
||||||
|
public OrganizationLicense()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public OrganizationLicense(Organization org)
|
||||||
|
{
|
||||||
|
LicenseKey = "";
|
||||||
|
Id = org.Id;
|
||||||
|
Name = org.Name;
|
||||||
|
Enabled = org.Enabled;
|
||||||
|
Seats = org.Seats;
|
||||||
|
MaxCollections = org.MaxCollections;
|
||||||
|
UseGroups = org.UseGroups;
|
||||||
|
UseDirectory = org.UseDirectory;
|
||||||
|
UseTotp = org.UseTotp;
|
||||||
|
MaxStorageGb = org.MaxStorageGb;
|
||||||
|
SelfHost = org.SelfHost;
|
||||||
|
Version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LicenseKey { get; set; }
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string Plan { get; set; }
|
||||||
|
public PlanType PlanType { get; set; }
|
||||||
|
public short? Seats { get; set; }
|
||||||
|
public short? MaxCollections { get; set; }
|
||||||
|
public bool UseGroups { get; set; }
|
||||||
|
public bool UseDirectory { get; set; }
|
||||||
|
public bool UseTotp { get; set; }
|
||||||
|
public short? MaxStorageGb { get; set; }
|
||||||
|
public bool SelfHost { get; set; }
|
||||||
|
public int Version { get; set; }
|
||||||
|
public DateTime Issued { get; set; }
|
||||||
|
public DateTime Expires { get; set; }
|
||||||
|
public bool Trial { get; set; }
|
||||||
|
public string Signature { get; set; }
|
||||||
|
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
||||||
|
|
||||||
|
public byte[] GetSignatureData()
|
||||||
|
{
|
||||||
|
string data = null;
|
||||||
|
if(Version == 1)
|
||||||
|
{
|
||||||
|
data = string.Format("organization:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}_{11}_{12}_{13}",
|
||||||
|
Version,
|
||||||
|
Utilities.CoreHelpers.ToEpocMilliseconds(Issued),
|
||||||
|
Utilities.CoreHelpers.ToEpocMilliseconds(Expires),
|
||||||
|
LicenseKey,
|
||||||
|
Id,
|
||||||
|
Enabled,
|
||||||
|
PlanType,
|
||||||
|
Seats,
|
||||||
|
MaxCollections,
|
||||||
|
UseGroups,
|
||||||
|
UseDirectory,
|
||||||
|
UseTotp,
|
||||||
|
MaxStorageGb,
|
||||||
|
SelfHost);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyData(Organization organization)
|
||||||
|
{
|
||||||
|
if(Issued > DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Expires < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Version == 1)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
organization.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
|
||||||
|
organization.Enabled == Enabled &&
|
||||||
|
organization.PlanType == PlanType &&
|
||||||
|
organization.Seats == Seats &&
|
||||||
|
organization.MaxCollections == MaxCollections &&
|
||||||
|
organization.UseGroups == UseGroups &&
|
||||||
|
organization.UseDirectory == UseDirectory &&
|
||||||
|
organization.UseTotp == UseTotp &&
|
||||||
|
organization.SelfHost == SelfHost;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifySignature(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
using(var rsa = certificate.GetRSAPublicKey())
|
||||||
|
{
|
||||||
|
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
src/Core/Models/Business/UserLicense.cs
Normal file
90
src/Core/Models/Business/UserLicense.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Business
|
||||||
|
{
|
||||||
|
public class UserLicense : ILicense
|
||||||
|
{
|
||||||
|
public UserLicense()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public UserLicense(User user)
|
||||||
|
{
|
||||||
|
LicenseKey = "";
|
||||||
|
Id = user.Id;
|
||||||
|
Email = user.Email;
|
||||||
|
Version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LicenseKey { get; set; }
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public bool Premium { get; set; }
|
||||||
|
public short? MaxStorageGb { get; set; }
|
||||||
|
public int Version { get; set; }
|
||||||
|
public DateTime Issued { get; set; }
|
||||||
|
public DateTime Expires { get; set; }
|
||||||
|
public bool Trial { get; set; }
|
||||||
|
public string Signature { get; set; }
|
||||||
|
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
||||||
|
|
||||||
|
public byte[] GetSignatureData()
|
||||||
|
{
|
||||||
|
string data = null;
|
||||||
|
if(Version == 1)
|
||||||
|
{
|
||||||
|
data = string.Format("user:{0}_{1}_{2}_{3}_{4}_{5}_{6}_{7}",
|
||||||
|
Version,
|
||||||
|
Utilities.CoreHelpers.ToEpocMilliseconds(Issued),
|
||||||
|
Utilities.CoreHelpers.ToEpocMilliseconds(Expires),
|
||||||
|
LicenseKey,
|
||||||
|
Id,
|
||||||
|
Email,
|
||||||
|
Premium,
|
||||||
|
MaxStorageGb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyData(User user)
|
||||||
|
{
|
||||||
|
if(Issued > DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Expires < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Version == 1)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
user.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
|
||||||
|
user.Premium == Premium &&
|
||||||
|
user.Email.Equals(Email, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifySignature(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
using(var rsa = certificate.GetRSAPublicKey())
|
||||||
|
{
|
||||||
|
return rsa.VerifyData(GetSignatureData(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,12 +19,14 @@ namespace Bit.Core.Models.Table
|
|||||||
public bool UseGroups { get; set; }
|
public bool UseGroups { get; set; }
|
||||||
public bool UseDirectory { get; set; }
|
public bool UseDirectory { get; set; }
|
||||||
public bool UseTotp { get; set; }
|
public bool UseTotp { get; set; }
|
||||||
|
public bool SelfHost { get; set; }
|
||||||
public long? Storage { get; set; }
|
public long? Storage { get; set; }
|
||||||
public short? MaxStorageGb { get; set; }
|
public short? MaxStorageGb { get; set; }
|
||||||
public GatewayType? Gateway { get; set; }
|
public GatewayType? Gateway { get; set; }
|
||||||
public string GatewayCustomerId { get; set; }
|
public string GatewayCustomerId { get; set; }
|
||||||
public string GatewaySubscriptionId { get; set; }
|
public string GatewaySubscriptionId { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
|
public string LicenseKey { get; set; }
|
||||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ namespace Bit.Core.Models.Table
|
|||||||
public GatewayType? Gateway { get; set; }
|
public GatewayType? Gateway { get; set; }
|
||||||
public string GatewayCustomerId { get; set; }
|
public string GatewayCustomerId { get; set; }
|
||||||
public string GatewaySubscriptionId { get; set; }
|
public string GatewaySubscriptionId { get; set; }
|
||||||
|
public string LicenseKey { get; set; }
|
||||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
10
src/Core/Services/ILicenseVerificationService.cs
Normal file
10
src/Core/Services/ILicenseVerificationService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Bit.Core.Models.Table;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public interface ILicenseVerificationService
|
||||||
|
{
|
||||||
|
bool VerifyOrganizationPlan(Organization organization);
|
||||||
|
bool VerifyUserPremium(User user);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
using Bit.Core.Models.Business;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class RsaLicenseVerificationService : ILicenseVerificationService
|
||||||
|
{
|
||||||
|
private readonly X509Certificate2 _certificate;
|
||||||
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private IDictionary<string, UserLicense> _userLicenseCache;
|
||||||
|
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
|
||||||
|
|
||||||
|
public RsaLicenseVerificationService(
|
||||||
|
IHostingEnvironment environment,
|
||||||
|
GlobalSettings globalSettings)
|
||||||
|
{
|
||||||
|
if(!environment.IsDevelopment() && !globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
throw new Exception($"{nameof(RsaLicenseVerificationService)} can only be used for self hosted instances.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_globalSettings = globalSettings;
|
||||||
|
_certificate = CoreHelpers.GetCertificate("licensing.crt", null);
|
||||||
|
if(false && !_certificate.Thumbprint.Equals(""))
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid licensing certificate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!CoreHelpers.SettingHasValue(_globalSettings.LicenseDirectory))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("No license directory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyOrganizationPlan(Organization organization)
|
||||||
|
{
|
||||||
|
if(_globalSettings.SelfHosted && !organization.SelfHost)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var license = ReadOrganiztionLicense(organization);
|
||||||
|
return license != null && license.VerifyData(organization) && license.VerifySignature(_certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyUserPremium(User user)
|
||||||
|
{
|
||||||
|
if(!user.Premium)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var license = ReadUserLicense(user);
|
||||||
|
return license != null && license.VerifyData(user) && license.VerifySignature(_certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserLicense ReadUserLicense(User user)
|
||||||
|
{
|
||||||
|
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
|
||||||
|
{
|
||||||
|
return _userLicenseCache[user.LicenseKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.LicenseKey}.json";
|
||||||
|
if(!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = File.ReadAllText(filePath, Encoding.UTF8);
|
||||||
|
var obj = JsonConvert.DeserializeObject<UserLicense>(data);
|
||||||
|
if(_userLicenseCache == null)
|
||||||
|
{
|
||||||
|
_userLicenseCache = new Dictionary<string, UserLicense>();
|
||||||
|
}
|
||||||
|
_userLicenseCache.Add(obj.LicenseKey, obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrganizationLicense ReadOrganiztionLicense(Organization organization)
|
||||||
|
{
|
||||||
|
if(_organizationLicenseCache != null && _organizationLicenseCache.ContainsKey(organization.LicenseKey))
|
||||||
|
{
|
||||||
|
return _organizationLicenseCache[organization.LicenseKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.LicenseKey}.json";
|
||||||
|
if(!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = File.ReadAllText(filePath, Encoding.UTF8);
|
||||||
|
var obj = JsonConvert.DeserializeObject<OrganizationLicense>(data);
|
||||||
|
if(_organizationLicenseCache == null)
|
||||||
|
{
|
||||||
|
_organizationLicenseCache = new Dictionary<string, OrganizationLicense>();
|
||||||
|
}
|
||||||
|
_organizationLicenseCache.Add(obj.LicenseKey, obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class NoopLicenseVerificationService : ILicenseVerificationService
|
||||||
|
{
|
||||||
|
public NoopLicenseVerificationService(
|
||||||
|
IHostingEnvironment environment,
|
||||||
|
GlobalSettings globalSettings)
|
||||||
|
{
|
||||||
|
if(!environment.IsDevelopment() && globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
throw new Exception($"{nameof(NoopLicenseVerificationService)} cannot be used for self hosted instances.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyOrganizationPlan(Organization organization)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyUserPremium(User user)
|
||||||
|
{
|
||||||
|
return user.Premium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -107,6 +107,15 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
services.AddSingleton<ILicenseVerificationService, RsaLicenseVerificationService>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddNoopServices(this IServiceCollection services)
|
public static void AddNoopServices(this IServiceCollection services)
|
||||||
@ -117,6 +126,7 @@ namespace Bit.Core.Utilities
|
|||||||
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
|
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
|
||||||
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
||||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||||
|
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IdentityBuilder AddCustomIdentityServices(
|
public static IdentityBuilder AddCustomIdentityServices(
|
||||||
|
@ -9,6 +9,14 @@
|
|||||||
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="licensing.cer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="licensing.cer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:33656/",
|
"applicationUrl": "http://localhost:33656/",
|
||||||
"sslPort": 44392
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
|
BIN
src/Identity/licensing.cer
Normal file
BIN
src/Identity/licensing.cer
Normal file
Binary file not shown.
@ -10,12 +10,14 @@
|
|||||||
@UseGroups BIT,
|
@UseGroups BIT,
|
||||||
@UseDirectory BIT,
|
@UseDirectory BIT,
|
||||||
@UseTotp BIT,
|
@UseTotp BIT,
|
||||||
|
@SelfHost BIT,
|
||||||
@Storage BIGINT,
|
@Storage BIGINT,
|
||||||
@MaxStorageGb SMALLINT,
|
@MaxStorageGb SMALLINT,
|
||||||
@Gateway TINYINT,
|
@Gateway TINYINT,
|
||||||
@GatewayCustomerId VARCHAR(50),
|
@GatewayCustomerId VARCHAR(50),
|
||||||
@GatewaySubscriptionId VARCHAR(50),
|
@GatewaySubscriptionId VARCHAR(50),
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
|
@LicenseKey VARCHAR(100),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
AS
|
AS
|
||||||
@ -35,12 +37,14 @@ BEGIN
|
|||||||
[UseGroups],
|
[UseGroups],
|
||||||
[UseDirectory],
|
[UseDirectory],
|
||||||
[UseTotp],
|
[UseTotp],
|
||||||
|
[SelfHost],
|
||||||
[Storage],
|
[Storage],
|
||||||
[MaxStorageGb],
|
[MaxStorageGb],
|
||||||
[Gateway],
|
[Gateway],
|
||||||
[GatewayCustomerId],
|
[GatewayCustomerId],
|
||||||
[GatewaySubscriptionId],
|
[GatewaySubscriptionId],
|
||||||
[Enabled],
|
[Enabled],
|
||||||
|
[LicenseKey],
|
||||||
[CreationDate],
|
[CreationDate],
|
||||||
[RevisionDate]
|
[RevisionDate]
|
||||||
)
|
)
|
||||||
@ -57,12 +61,14 @@ BEGIN
|
|||||||
@UseGroups,
|
@UseGroups,
|
||||||
@UseDirectory,
|
@UseDirectory,
|
||||||
@UseTotp,
|
@UseTotp,
|
||||||
|
@SelfHost,
|
||||||
@Storage,
|
@Storage,
|
||||||
@MaxStorageGb,
|
@MaxStorageGb,
|
||||||
@Gateway,
|
@Gateway,
|
||||||
@GatewayCustomerId,
|
@GatewayCustomerId,
|
||||||
@GatewaySubscriptionId,
|
@GatewaySubscriptionId,
|
||||||
@Enabled,
|
@Enabled,
|
||||||
|
@LicenseKey,
|
||||||
@CreationDate,
|
@CreationDate,
|
||||||
@RevisionDate
|
@RevisionDate
|
||||||
)
|
)
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
@UseGroups BIT,
|
@UseGroups BIT,
|
||||||
@UseDirectory BIT,
|
@UseDirectory BIT,
|
||||||
@UseTotp BIT,
|
@UseTotp BIT,
|
||||||
|
@SelfHost BIT,
|
||||||
@Storage BIGINT,
|
@Storage BIGINT,
|
||||||
@MaxStorageGb SMALLINT,
|
@MaxStorageGb SMALLINT,
|
||||||
@Gateway TINYINT,
|
@Gateway TINYINT,
|
||||||
@GatewayCustomerId VARCHAR(50),
|
@GatewayCustomerId VARCHAR(50),
|
||||||
@GatewaySubscriptionId VARCHAR(50),
|
@GatewaySubscriptionId VARCHAR(50),
|
||||||
@Enabled BIT,
|
@Enabled BIT,
|
||||||
|
@LicenseKey VARCHAR(100),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
|
|
||||||
@ -36,12 +38,14 @@ BEGIN
|
|||||||
[UseGroups] = @UseGroups,
|
[UseGroups] = @UseGroups,
|
||||||
[UseDirectory] = @UseDirectory,
|
[UseDirectory] = @UseDirectory,
|
||||||
[UseTotp] = @UseTotp,
|
[UseTotp] = @UseTotp,
|
||||||
|
[SelfHost] = @SelfHost,
|
||||||
[Storage] = @Storage,
|
[Storage] = @Storage,
|
||||||
[MaxStorageGb] = @MaxStorageGb,
|
[MaxStorageGb] = @MaxStorageGb,
|
||||||
[Gateway] = @Gateway,
|
[Gateway] = @Gateway,
|
||||||
[GatewayCustomerId] = @GatewayCustomerId,
|
[GatewayCustomerId] = @GatewayCustomerId,
|
||||||
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
||||||
[Enabled] = @Enabled,
|
[Enabled] = @Enabled,
|
||||||
|
[LicenseKey] = @LicenseKey,
|
||||||
[CreationDate] = @CreationDate,
|
[CreationDate] = @CreationDate,
|
||||||
[RevisionDate] = @RevisionDate
|
[RevisionDate] = @RevisionDate
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
@Gateway TINYINT,
|
@Gateway TINYINT,
|
||||||
@GatewayCustomerId VARCHAR(50),
|
@GatewayCustomerId VARCHAR(50),
|
||||||
@GatewaySubscriptionId VARCHAR(50),
|
@GatewaySubscriptionId VARCHAR(50),
|
||||||
|
@LicenseKey VARCHAR(100),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
AS
|
AS
|
||||||
@ -51,6 +52,7 @@ BEGIN
|
|||||||
[Gateway],
|
[Gateway],
|
||||||
[GatewayCustomerId],
|
[GatewayCustomerId],
|
||||||
[GatewaySubscriptionId],
|
[GatewaySubscriptionId],
|
||||||
|
[LicenseKey],
|
||||||
[CreationDate],
|
[CreationDate],
|
||||||
[RevisionDate]
|
[RevisionDate]
|
||||||
)
|
)
|
||||||
@ -78,6 +80,7 @@ BEGIN
|
|||||||
@Gateway,
|
@Gateway,
|
||||||
@GatewayCustomerId,
|
@GatewayCustomerId,
|
||||||
@GatewaySubscriptionId,
|
@GatewaySubscriptionId,
|
||||||
|
@LicenseKey,
|
||||||
@CreationDate,
|
@CreationDate,
|
||||||
@RevisionDate
|
@RevisionDate
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
@Gateway TINYINT,
|
@Gateway TINYINT,
|
||||||
@GatewayCustomerId VARCHAR(50),
|
@GatewayCustomerId VARCHAR(50),
|
||||||
@GatewaySubscriptionId VARCHAR(50),
|
@GatewaySubscriptionId VARCHAR(50),
|
||||||
|
@LicenseKey VARCHAR(100),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
AS
|
AS
|
||||||
@ -51,6 +52,7 @@ BEGIN
|
|||||||
[Gateway] = @Gateway,
|
[Gateway] = @Gateway,
|
||||||
[GatewayCustomerId] = @GatewayCustomerId,
|
[GatewayCustomerId] = @GatewayCustomerId,
|
||||||
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
||||||
|
[LicenseKey] = @LicenseKey,
|
||||||
[CreationDate] = @CreationDate,
|
[CreationDate] = @CreationDate,
|
||||||
[RevisionDate] = @RevisionDate
|
[RevisionDate] = @RevisionDate
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
[UseGroups] BIT NOT NULL,
|
[UseGroups] BIT NOT NULL,
|
||||||
[UseDirectory] BIT NOT NULL,
|
[UseDirectory] BIT NOT NULL,
|
||||||
[UseTotp] BIT NOT NULL,
|
[UseTotp] BIT NOT NULL,
|
||||||
|
[SelfHost] BIT NOT NULL,
|
||||||
[Storage] BIGINT NULL,
|
[Storage] BIGINT NULL,
|
||||||
[MaxStorageGb] SMALLINT NULL,
|
[MaxStorageGb] SMALLINT NULL,
|
||||||
[Gateway] TINYINT NULL,
|
[Gateway] TINYINT NULL,
|
||||||
[GatewayCustomerId] VARCHAR (50) NULL,
|
[GatewayCustomerId] VARCHAR (50) NULL,
|
||||||
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
||||||
[Enabled] BIT NOT NULL,
|
[Enabled] BIT NOT NULL,
|
||||||
|
[LicenseKey] VARCHAR (100) NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
CONSTRAINT [PK_Organization] PRIMARY KEY CLUSTERED ([Id] ASC)
|
CONSTRAINT [PK_Organization] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
[Gateway] TINYINT NULL,
|
[Gateway] TINYINT NULL,
|
||||||
[GatewayCustomerId] VARCHAR (50) NULL,
|
[GatewayCustomerId] VARCHAR (50) NULL,
|
||||||
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
||||||
|
[LicenseKey] VARCHAR (100) NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
|
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||||
|
@ -260,6 +260,7 @@ globalSettings:attachment:baseDirectory={_outputDir}/core/attachments
|
|||||||
globalSettings:attachment:baseUrl={_url}/attachments
|
globalSettings:attachment:baseUrl={_url}/attachments
|
||||||
globalSettings:dataProtection:directory={_outputDir}/core/aspnet-dataprotection
|
globalSettings:dataProtection:directory={_outputDir}/core/aspnet-dataprotection
|
||||||
globalSettings:logDirectory={_outputDir}/core/logs
|
globalSettings:logDirectory={_outputDir}/core/logs
|
||||||
|
globalSettings:licenseDirectory={_outputDir}/core/licenses
|
||||||
globalSettings:duo:aKey={Helpers.SecureRandomString(32, alpha: true, numeric: true)}
|
globalSettings:duo:aKey={Helpers.SecureRandomString(32, alpha: true, numeric: true)}
|
||||||
globalSettings:yubico:clientId=REPLACE
|
globalSettings:yubico:clientId=REPLACE
|
||||||
globalSettings:yubico:REPLACE");
|
globalSettings:yubico:REPLACE");
|
||||||
|
26
util/SqlUpdate/2017-08-09_00_OrgSelfHost.sql
Normal file
26
util/SqlUpdate/2017-08-09_00_OrgSelfHost.sql
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
alter table [Organization] add [SelfHost] BIT NULL
|
||||||
|
go
|
||||||
|
|
||||||
|
|
||||||
|
update [Organization] set [SelfHost] = 0
|
||||||
|
go
|
||||||
|
|
||||||
|
update [Organization] set [SelfHost] = 1 where PlanType = 4 or PlanType = 5
|
||||||
|
go
|
||||||
|
|
||||||
|
|
||||||
|
alter table [Organization] alter column [SelfHost] BIT NOT NULL
|
||||||
|
go
|
||||||
|
|
||||||
|
|
||||||
|
drop view [dbo].[OrganizationView]
|
||||||
|
go
|
||||||
|
|
||||||
|
CREATE VIEW [dbo].[OrganizationView]
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[Organization]
|
||||||
|
GO
|
||||||
|
|
Reference in New Issue
Block a user