mirror of
https://github.com/jakeswenson/BitBetter.git
synced 2026-04-19 17:59:40 +00:00
Add missing licence options, bump licence version and add Token claim (#277)
* Add license options, bump version, add Token claim Added the missing license options: - `ExpirationWithoutGracePeriod` - `UseAutomaticUserConfirmation` - `UsePhisingBlocker` - `UseDisableSmAdsForUsers` - `UseMyItems` Bumped the license version from 15 to 16 (`UseOrganizationDomains` is valid only with version 16). Added `GenerateUserToken` and `GenerateOrgToken` helpers to create the expected `Token` claim that’s still missing in our licenses. Signed-off-by: Lorenzo Moscati <lorenzo@moscati.page> * Address Copilot review - Capture `now = DateTime.UtcNow` once per license-generation call and pass it into GenerateUserToken/GenerateOrgToken, so all date fields in the JSON license and the embedded JWT derive from the same instant (fixes drift across separate DateTime.UtcNow calls) - Move set("Token", ...) before ComputeHash/Sign in both GenerateUserLicense and GenerateOrgLicense so all fields are finalised before signing - Add UseRiskInsights claim to the org JWT; confirmed present as a required claim in Bitwarden's OrganizationLicenseClaimsFactory Version is intentionally excluded from both JWTs: neither UserLicenseClaimsFactory nor OrganizationLicenseClaimsFactory generates it, and the claims-path VerifyData never reads it. Signed-off-by: Lorenzo Moscati <lorenzo@moscati.page> --------- Signed-off-by: Lorenzo Moscati <lorenzo@moscati.page>
This commit is contained in:
@@ -1,11 +1,15 @@
|
|||||||
namespace BitwardenSelfLicensor
|
namespace BitwardenSelfLicensor
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.CommandLineUtils;
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using SingleFileExtractor.Core;
|
using SingleFileExtractor.Core;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
@@ -360,19 +364,23 @@ namespace BitwardenSelfLicensor
|
|||||||
type.GetProperty(name).SetValue(license, value);
|
type.GetProperty(name).SetValue(license, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
set("LicenseKey", string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
var licenseKey = string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key;
|
||||||
|
|
||||||
|
set("LicenseKey", licenseKey);
|
||||||
set("Id", userId);
|
set("Id", userId);
|
||||||
set("Name", userName);
|
set("Name", userName);
|
||||||
set("Email", email);
|
set("Email", email);
|
||||||
set("Premium", true);
|
set("Premium", true);
|
||||||
set("MaxStorageGb", storage == 0 ? short.MaxValue : storage);
|
set("MaxStorageGb", storage == 0 ? short.MaxValue : storage);
|
||||||
set("Version", 1);
|
set("Version", 1);
|
||||||
set("Issued", DateTime.UtcNow);
|
var now = DateTime.UtcNow;
|
||||||
set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
set("Issued", now);
|
||||||
set("Expires", DateTime.UtcNow.AddYears(100));
|
set("Refresh", now.AddYears(100).AddMonths(-1));
|
||||||
|
set("Expires", now.AddYears(100));
|
||||||
set("Trial", false);
|
set("Trial", false);
|
||||||
set("LicenseType", Enum.Parse(licenseTypeEnum, "User"));
|
set("LicenseType", Enum.Parse(licenseTypeEnum, "User"));
|
||||||
|
|
||||||
|
set("Token", GenerateUserToken(cert, userId, licenseKey, userName, email, storage, now));
|
||||||
set("Hash", Convert.ToBase64String((byte[])type.GetMethod("ComputeHash").Invoke(license, new object[0])));
|
set("Hash", Convert.ToBase64String((byte[])type.GetMethod("ComputeHash").Invoke(license, new object[0])));
|
||||||
set("Signature", Convert.ToBase64String((byte[])type.GetMethod("Sign").Invoke(license, new object[] { cert })));
|
set("Signature", Convert.ToBase64String((byte[])type.GetMethod("Sign").Invoke(license, new object[] { cert })));
|
||||||
|
|
||||||
@@ -394,12 +402,15 @@ namespace BitwardenSelfLicensor
|
|||||||
type.GetProperty(name).SetValue(license, value);
|
type.GetProperty(name).SetValue(license, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
set("LicenseKey", string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
var licenseKey = string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key;
|
||||||
|
var businessNameFinal = string.IsNullOrWhiteSpace(businessName) ? "BitBetter" : businessName;
|
||||||
|
|
||||||
|
set("LicenseKey", licenseKey);
|
||||||
set("InstallationId", instalId);
|
set("InstallationId", instalId);
|
||||||
set("Id", Guid.NewGuid());
|
set("Id", Guid.NewGuid());
|
||||||
set("Name", userName);
|
set("Name", userName);
|
||||||
set("BillingEmail", email);
|
set("BillingEmail", email);
|
||||||
set("BusinessName", string.IsNullOrWhiteSpace(businessName) ? "BitBetter" : businessName);
|
set("BusinessName", businessNameFinal);
|
||||||
set("Enabled", true);
|
set("Enabled", true);
|
||||||
set("Plan", "Enterprise (Annually)");
|
set("Plan", "Enterprise (Annually)");
|
||||||
set("PlanType", Enum.Parse(planTypeEnum, "EnterpriseAnnually"));
|
set("PlanType", Enum.Parse(planTypeEnum, "EnterpriseAnnually"));
|
||||||
@@ -424,22 +435,134 @@ namespace BitwardenSelfLicensor
|
|||||||
set("UseSecretsManager", true);
|
set("UseSecretsManager", true);
|
||||||
set("SmSeats", int.MaxValue);
|
set("SmSeats", int.MaxValue);
|
||||||
set("SmServiceAccounts", int.MaxValue);
|
set("SmServiceAccounts", int.MaxValue);
|
||||||
set("Version", 15); //This is set to 15 to use AllowAdminAccessToAllCollectionItems can be changed to 13 to just use Secrets Manager
|
set("Version", 16);
|
||||||
set("Issued", DateTime.UtcNow);
|
var now = DateTime.UtcNow;
|
||||||
set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
set("Issued", now);
|
||||||
set("Expires", DateTime.UtcNow.AddYears(100));
|
set("Refresh", now.AddYears(100).AddMonths(-1));
|
||||||
|
set("Expires", now.AddYears(100));
|
||||||
|
set("ExpirationWithoutGracePeriod", now.AddYears(100));
|
||||||
set("Trial", false);
|
set("Trial", false);
|
||||||
set("LicenseType", Enum.Parse(licenseTypeEnum, "Organization"));
|
set("LicenseType", Enum.Parse(licenseTypeEnum, "Organization"));
|
||||||
set("LimitCollectionCreationDeletion", true); //This will be used in the new version of BitWarden but can be applied now
|
set("LimitCollectionCreationDeletion", true);
|
||||||
set("AllowAdminAccessToAllCollectionItems", true);
|
set("AllowAdminAccessToAllCollectionItems", true);
|
||||||
set("UseRiskInsights", true);
|
set("UseRiskInsights", true);
|
||||||
set("UseOrganizationDomains", true);
|
set("UseOrganizationDomains", true);
|
||||||
set("UseAdminSponsoredFamilies", true);
|
set("UseAdminSponsoredFamilies", true);
|
||||||
|
set("UseAutomaticUserConfirmation", true);
|
||||||
|
set("UsePhishingBlocker", true);
|
||||||
|
set("UseDisableSmAdsForUsers", true);
|
||||||
|
set("UseMyItems", true);
|
||||||
|
|
||||||
|
var orgId = (Guid)type.GetProperty("Id").GetValue(license);
|
||||||
|
|
||||||
|
set("Token", GenerateOrgToken(cert, orgId, instalId, licenseKey, email, businessNameFinal, userName, storage, planTypeEnum, now));
|
||||||
set("Hash", Convert.ToBase64String((byte[])type.GetMethod("ComputeHash").Invoke(license, new object[0])));
|
set("Hash", Convert.ToBase64String((byte[])type.GetMethod("ComputeHash").Invoke(license, new object[0])));
|
||||||
set("Signature", Convert.ToBase64String((byte[])type.GetMethod("Sign").Invoke(license, new object[] { cert })));
|
set("Signature", Convert.ToBase64String((byte[])type.GetMethod("Sign").Invoke(license, new object[] { cert })));
|
||||||
|
|
||||||
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GenerateUserToken(X509Certificate2 cert, Guid userId, string licenseKey, string name, string email, short maxStorageGb, DateTime now)
|
||||||
|
{
|
||||||
|
var secKey = new X509SecurityKey(cert);
|
||||||
|
var creds = new SigningCredentials(secKey, SecurityAlgorithms.RsaSha256);
|
||||||
|
var expires = now.AddYears(100);
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("LicenseType", "User"),
|
||||||
|
new Claim("LicenseKey", licenseKey),
|
||||||
|
new Claim("Id", userId.ToString()),
|
||||||
|
new Claim("Name", name),
|
||||||
|
new Claim("Email", email),
|
||||||
|
new Claim("Premium", "true"),
|
||||||
|
new Claim("MaxStorageGb", (maxStorageGb == 0 ? short.MaxValue : maxStorageGb).ToString()),
|
||||||
|
new Claim("Trial", "false"),
|
||||||
|
new Claim("Issued", now.ToString("o")),
|
||||||
|
new Claim("Expires", expires.ToString("o")),
|
||||||
|
new Claim("Refresh", now.AddYears(100).AddMonths(-1).ToString("o")),
|
||||||
|
};
|
||||||
|
|
||||||
|
var handler = new JwtSecurityTokenHandler();
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: "bitwarden",
|
||||||
|
audience: $"user:{userId}",
|
||||||
|
claims: claims,
|
||||||
|
notBefore: now,
|
||||||
|
expires: expires,
|
||||||
|
signingCredentials: creds);
|
||||||
|
|
||||||
|
return handler.WriteToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateOrgToken(X509Certificate2 cert, Guid orgId, Guid installationId, string licenseKey, string billingEmail, string businessName, string name, short maxStorageGb, Type planTypeEnum, DateTime now)
|
||||||
|
{
|
||||||
|
var secKey = new X509SecurityKey(cert);
|
||||||
|
var creds = new SigningCredentials(secKey, SecurityAlgorithms.RsaSha256);
|
||||||
|
var expires = now.AddYears(100);
|
||||||
|
|
||||||
|
// Resolve the integer value of EnterpriseAnnually from the runtime enum
|
||||||
|
var planTypeInt = Convert.ToInt32(Enum.Parse(planTypeEnum, "EnterpriseAnnually"));
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("LicenseType", "Organization"),
|
||||||
|
new Claim("LicenseKey", licenseKey),
|
||||||
|
new Claim("InstallationId", installationId.ToString()),
|
||||||
|
new Claim("Id", orgId.ToString()),
|
||||||
|
new Claim("Name", name),
|
||||||
|
new Claim("BillingEmail", billingEmail),
|
||||||
|
new Claim("BusinessName", businessName),
|
||||||
|
new Claim("Enabled", "true"),
|
||||||
|
new Claim("Plan", "Enterprise (Annually)"),
|
||||||
|
new Claim("PlanType", planTypeInt.ToString()),
|
||||||
|
new Claim("Seats", int.MaxValue.ToString()),
|
||||||
|
new Claim("MaxCollections", short.MaxValue.ToString()),
|
||||||
|
new Claim("MaxStorageGb", (maxStorageGb == 0 ? short.MaxValue : maxStorageGb).ToString()),
|
||||||
|
new Claim("SelfHost", "true"),
|
||||||
|
new Claim("UsersGetPremium", "true"),
|
||||||
|
new Claim("UseGroups", "true"),
|
||||||
|
new Claim("UseDirectory", "true"),
|
||||||
|
new Claim("UseEvents", "true"),
|
||||||
|
new Claim("UseTotp", "true"),
|
||||||
|
new Claim("Use2fa", "true"),
|
||||||
|
new Claim("UseApi", "true"),
|
||||||
|
new Claim("UsePolicies", "true"),
|
||||||
|
new Claim("UseSso", "true"),
|
||||||
|
new Claim("UseResetPassword", "true"),
|
||||||
|
new Claim("UseKeyConnector", "true"),
|
||||||
|
new Claim("UseScim", "true"),
|
||||||
|
new Claim("UseCustomPermissions", "true"),
|
||||||
|
new Claim("UsePasswordManager", "true"),
|
||||||
|
new Claim("UseSecretsManager", "true"),
|
||||||
|
new Claim("SmSeats", int.MaxValue.ToString()),
|
||||||
|
new Claim("SmServiceAccounts", int.MaxValue.ToString()),
|
||||||
|
new Claim("UseRiskInsights", "true"),
|
||||||
|
new Claim("UseAdminSponsoredFamilies", "true"),
|
||||||
|
new Claim("UseOrganizationDomains", "true"),
|
||||||
|
new Claim("UseAutomaticUserConfirmation", "true"),
|
||||||
|
new Claim("UseDisableSmAdsForUsers", "true"),
|
||||||
|
new Claim("UsePhishingBlocker", "true"),
|
||||||
|
new Claim("UseMyItems", "true"),
|
||||||
|
new Claim("LimitCollectionCreationDeletion", "true"),
|
||||||
|
new Claim("AllowAdminAccessToAllCollectionItems", "true"),
|
||||||
|
new Claim("Trial", "false"),
|
||||||
|
new Claim("Issued", now.ToString("o")),
|
||||||
|
new Claim("Expires", expires.ToString("o")),
|
||||||
|
new Claim("Refresh", now.AddYears(100).AddMonths(-1).ToString("o")),
|
||||||
|
new Claim("ExpirationWithoutGracePeriod", expires.ToString("o")),
|
||||||
|
};
|
||||||
|
|
||||||
|
var handler = new JwtSecurityTokenHandler();
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: "bitwarden",
|
||||||
|
audience: $"organization:{orgId}",
|
||||||
|
claims: claims,
|
||||||
|
notBefore: now,
|
||||||
|
expires: expires,
|
||||||
|
signingCredentials: creds);
|
||||||
|
|
||||||
|
return handler.WriteToken(token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="SingleFileExtractor.Core" Version="2.3.0" />
|
<PackageReference Include="SingleFileExtractor.Core" Version="2.3.0" />
|
||||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user