mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
license verification services for user/org
This commit is contained in:
parent
3deec076c7
commit
a1d064ed9e
@ -9,6 +9,14 @@
|
||||
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="licensing.cer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="licensing.cer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -4,7 +4,7 @@
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:4000",
|
||||
"sslPort": 44377
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"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>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="licensing.cer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</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 ProjectName { get; set; }
|
||||
public virtual string LogDirectory { get; set; }
|
||||
public virtual string LicenseDirectory { get; set; }
|
||||
public virtual BaseServiceUriSettings BaseServiceUri { get; set; } = new BaseServiceUriSettings();
|
||||
public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings();
|
||||
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 UseDirectory { get; set; }
|
||||
public bool UseTotp { get; set; }
|
||||
public bool SelfHost { get; set; }
|
||||
public long? Storage { get; set; }
|
||||
public short? MaxStorageGb { get; set; }
|
||||
public GatewayType? Gateway { get; set; }
|
||||
public string GatewayCustomerId { get; set; }
|
||||
public string GatewaySubscriptionId { get; set; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
public string LicenseKey { get; set; }
|
||||
public DateTime CreationDate { 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 string GatewayCustomerId { get; set; }
|
||||
public string GatewaySubscriptionId { get; set; }
|
||||
public string LicenseKey { get; set; }
|
||||
public DateTime CreationDate { 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>();
|
||||
}
|
||||
|
||||
if(globalSettings.SelfHosted)
|
||||
{
|
||||
services.AddSingleton<ILicenseVerificationService, RsaLicenseVerificationService>();
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddNoopServices(this IServiceCollection services)
|
||||
@ -117,6 +126,7 @@ namespace Bit.Core.Utilities
|
||||
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
|
||||
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
|
||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||
services.AddSingleton<ILicenseVerificationService, NoopLicenseVerificationService>();
|
||||
}
|
||||
|
||||
public static IdentityBuilder AddCustomIdentityServices(
|
||||
|
@ -9,6 +9,14 @@
|
||||
<DockerComposeProjectPath>..\..\docker\Docker.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="licensing.cer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="licensing.cer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -4,7 +4,7 @@
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:33656/",
|
||||
"sslPort": 44392
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"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,
|
||||
@UseDirectory BIT,
|
||||
@UseTotp BIT,
|
||||
@SelfHost BIT,
|
||||
@Storage BIGINT,
|
||||
@MaxStorageGb SMALLINT,
|
||||
@Gateway TINYINT,
|
||||
@GatewayCustomerId VARCHAR(50),
|
||||
@GatewaySubscriptionId VARCHAR(50),
|
||||
@Enabled BIT,
|
||||
@LicenseKey VARCHAR(100),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
@ -35,12 +37,14 @@ BEGIN
|
||||
[UseGroups],
|
||||
[UseDirectory],
|
||||
[UseTotp],
|
||||
[SelfHost],
|
||||
[Storage],
|
||||
[MaxStorageGb],
|
||||
[Gateway],
|
||||
[GatewayCustomerId],
|
||||
[GatewaySubscriptionId],
|
||||
[Enabled],
|
||||
[LicenseKey],
|
||||
[CreationDate],
|
||||
[RevisionDate]
|
||||
)
|
||||
@ -57,12 +61,14 @@ BEGIN
|
||||
@UseGroups,
|
||||
@UseDirectory,
|
||||
@UseTotp,
|
||||
@SelfHost,
|
||||
@Storage,
|
||||
@MaxStorageGb,
|
||||
@Gateway,
|
||||
@GatewayCustomerId,
|
||||
@GatewaySubscriptionId,
|
||||
@Enabled,
|
||||
@LicenseKey,
|
||||
@CreationDate,
|
||||
@RevisionDate
|
||||
)
|
||||
|
@ -10,12 +10,14 @@
|
||||
@UseGroups BIT,
|
||||
@UseDirectory BIT,
|
||||
@UseTotp BIT,
|
||||
@SelfHost BIT,
|
||||
@Storage BIGINT,
|
||||
@MaxStorageGb SMALLINT,
|
||||
@Gateway TINYINT,
|
||||
@GatewayCustomerId VARCHAR(50),
|
||||
@GatewaySubscriptionId VARCHAR(50),
|
||||
@Enabled BIT,
|
||||
@LicenseKey VARCHAR(100),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
|
||||
@ -36,12 +38,14 @@ BEGIN
|
||||
[UseGroups] = @UseGroups,
|
||||
[UseDirectory] = @UseDirectory,
|
||||
[UseTotp] = @UseTotp,
|
||||
[SelfHost] = @SelfHost,
|
||||
[Storage] = @Storage,
|
||||
[MaxStorageGb] = @MaxStorageGb,
|
||||
[Gateway] = @Gateway,
|
||||
[GatewayCustomerId] = @GatewayCustomerId,
|
||||
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
||||
[Enabled] = @Enabled,
|
||||
[LicenseKey] = @LicenseKey,
|
||||
[CreationDate] = @CreationDate,
|
||||
[RevisionDate] = @RevisionDate
|
||||
WHERE
|
||||
|
@ -21,6 +21,7 @@
|
||||
@Gateway TINYINT,
|
||||
@GatewayCustomerId VARCHAR(50),
|
||||
@GatewaySubscriptionId VARCHAR(50),
|
||||
@LicenseKey VARCHAR(100),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
@ -51,6 +52,7 @@ BEGIN
|
||||
[Gateway],
|
||||
[GatewayCustomerId],
|
||||
[GatewaySubscriptionId],
|
||||
[LicenseKey],
|
||||
[CreationDate],
|
||||
[RevisionDate]
|
||||
)
|
||||
@ -78,6 +80,7 @@ BEGIN
|
||||
@Gateway,
|
||||
@GatewayCustomerId,
|
||||
@GatewaySubscriptionId,
|
||||
@LicenseKey,
|
||||
@CreationDate,
|
||||
@RevisionDate
|
||||
)
|
||||
|
@ -21,6 +21,7 @@
|
||||
@Gateway TINYINT,
|
||||
@GatewayCustomerId VARCHAR(50),
|
||||
@GatewaySubscriptionId VARCHAR(50),
|
||||
@LicenseKey VARCHAR(100),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
@ -51,6 +52,7 @@ BEGIN
|
||||
[Gateway] = @Gateway,
|
||||
[GatewayCustomerId] = @GatewayCustomerId,
|
||||
[GatewaySubscriptionId] = @GatewaySubscriptionId,
|
||||
[LicenseKey] = @LicenseKey,
|
||||
[CreationDate] = @CreationDate,
|
||||
[RevisionDate] = @RevisionDate
|
||||
WHERE
|
||||
|
@ -10,12 +10,14 @@
|
||||
[UseGroups] BIT NOT NULL,
|
||||
[UseDirectory] BIT NOT NULL,
|
||||
[UseTotp] BIT NOT NULL,
|
||||
[SelfHost] BIT NOT NULL,
|
||||
[Storage] BIGINT NULL,
|
||||
[MaxStorageGb] SMALLINT NULL,
|
||||
[Gateway] TINYINT NULL,
|
||||
[GatewayCustomerId] VARCHAR (50) NULL,
|
||||
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
||||
[Enabled] BIT NOT NULL,
|
||||
[LicenseKey] VARCHAR (100) NULL,
|
||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||
CONSTRAINT [PK_Organization] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||
|
@ -21,6 +21,7 @@
|
||||
[Gateway] TINYINT NULL,
|
||||
[GatewayCustomerId] VARCHAR (50) NULL,
|
||||
[GatewaySubscriptionId] VARCHAR (50) NULL,
|
||||
[LicenseKey] VARCHAR (100) NULL,
|
||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||
|
@ -260,6 +260,7 @@ globalSettings:attachment:baseDirectory={_outputDir}/core/attachments
|
||||
globalSettings:attachment:baseUrl={_url}/attachments
|
||||
globalSettings:dataProtection:directory={_outputDir}/core/aspnet-dataprotection
|
||||
globalSettings:logDirectory={_outputDir}/core/logs
|
||||
globalSettings:licenseDirectory={_outputDir}/core/licenses
|
||||
globalSettings:duo:aKey={Helpers.SecureRandomString(32, alpha: true, numeric: true)}
|
||||
globalSettings:yubico:clientId=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
|
||||
|
Loading…
Reference in New Issue
Block a user