Comments (7)
Hello, funny thing is that you can create project using "Enterprise" license then switch back to "Custom" and everything will work normally apart project creation.
from bitbetter.
p.s. Simply changing "Plan" and "PlanType" in current licenses does not work - the license must be generated with those options set to begin with, not after-the-fact.
Yes, that's always the case, you can't just modify the license file, they always have to regenerated.
Someone would need to modify licenseGen and perform some tests, and then submit a PR.
from bitbetter.
I am still curious to know the initial reasoning for using "Custom" instead of "Enterprise". I have already tested changing it to Enterprise on my server and, so far, it works the same as Custom with the exception of being able to create Projects. But I do wish to avoid unintended consequences if there was a reason for not using Enterprise.
from bitbetter.
I think there is no restriction against changing the CustomPlan
as we are currently injecting the DLL for certificate replacement.
Anyway I am using this code successfully.
Feel free to use it as you want.
(based on unified, 2023.10.1 / 2023.12.0)
src/bitBetter/Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
using dnlib.IO;
namespace bitBetter
{
internal class Program
{
private static int Main(string[] args)
{
const string certFile = "/app/cert.cert";
string[] files = Directory.GetFiles("/app/mount", "Core.dll", SearchOption.AllDirectories);
foreach (string file in files)
{
Console.WriteLine(file);
ModuleDefMD moduleDefMd = ModuleDefMD.Load(file);
byte[] cert = File.ReadAllBytes(certFile);
EmbeddedResource embeddedResourceToRemove = moduleDefMd.Resources
.OfType<EmbeddedResource>()
.First(r => r.Name.Equals("Bit.Core.licensing.cer"));
Console.WriteLine(embeddedResourceToRemove.Name);
EmbeddedResource embeddedResourceToAdd = new("Bit.Core.licensing.cer", cert)
{
Attributes = embeddedResourceToRemove.Attributes
};
moduleDefMd.Resources.Add(embeddedResourceToAdd);
moduleDefMd.Resources.Remove(embeddedResourceToRemove);
DataReader reader = embeddedResourceToRemove.CreateReader();
X509Certificate2 existingCert = new(reader.ReadRemainingBytes());
Console.WriteLine($"Existing Cert Thumbprint: {existingCert.Thumbprint}");
X509Certificate2 certificate = new(cert);
Console.WriteLine($"New Cert Thumbprint: {certificate.Thumbprint}");
IEnumerable<TypeDef> services = moduleDefMd.Types.Where(t => t.Namespace == "Bit.Core.Services");
TypeDef type = services.First(t => t.Name == "LicensingService");
MethodDef constructor = type.FindConstructors().First();
Instruction instructionToPatch =
constructor.Body.Instructions
.FirstOrDefault(i => i.OpCode == OpCodes.Ldstr
&& string.Equals((string)i.Operand, existingCert.Thumbprint, StringComparison.InvariantCultureIgnoreCase));
if (instructionToPatch != null)
{
instructionToPatch.Operand = certificate.Thumbprint;
}
else
{
Console.WriteLine("Can't find constructor to patch");
}
// CustomPlan modify start
Console.WriteLine("Start to modify CustomPlan");
Console.WriteLine("Find the set method for the SecretsManager property in the Plan type");
TypeDef planType = moduleDefMd.Types.First(t => t.FullName == "Bit.Core.Models.StaticStore.Plan");
PropertyDef planSecretsManagerProperty = planType?.Properties.First(p => p.Name == "SecretsManager");
TypeDef customPlanType = moduleDefMd.Types.First(t => t.FullName == "Bit.Core.Models.StaticStore.Plans.CustomPlan");
MethodDef customPlanCtor = customPlanType?.FindConstructors().First();
TypeDef secretsManagerPlanFeaturesType = planType?.NestedTypes.First(t => t.Name == "SecretsManagerPlanFeatures");
PropertyDef secretsManagerPlanFeaturesAllowSeatAutoscaleProperty = secretsManagerPlanFeaturesType?.Properties.First(p => p.Name == "AllowSeatAutoscale");
PropertyDef secretsManagerPlanFeaturesAllowServiceAccountsAutoscaleProperty = secretsManagerPlanFeaturesType?.Properties.First(p => p.Name == "AllowServiceAccountsAutoscale");
if (customPlanType?.NestedTypes.FirstOrDefault(t => t.Name == "CustomSecretsManagerFeatures") != null)
{
Console.WriteLine("The content you are trying to modify is already defined.");
}
else if (customPlanCtor == null)
{
Console.WriteLine("Cannot find target constructor");
}
else if (planType != null
&& planSecretsManagerProperty != null
&& secretsManagerPlanFeaturesType != null
&& secretsManagerPlanFeaturesAllowSeatAutoscaleProperty != null
&& secretsManagerPlanFeaturesAllowServiceAccountsAutoscaleProperty != null)
{
Console.WriteLine("Create CustomSecretsManagerFeatures as a nested class within CustomPlan");
TypeDef customSecretsManagerFeaturesType = new TypeDefUser(customPlanType.Namespace, "CustomSecretsManagerPlanFeatures", secretsManagerPlanFeaturesType);
customSecretsManagerFeaturesType.Attributes = TypeAttributes.NestedPrivate | TypeAttributes.Class;
MethodDef customSecretsManagerFeaturesCtor = new MethodDefUser(".ctor",
MethodSig.CreateInstance(moduleDefMd.CorLibTypes.Void),
MethodImplAttributes.IL | MethodImplAttributes.Managed,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
customSecretsManagerFeaturesCtor.Body = new CilBody();
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction());
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Ldc_I4_1.ToInstruction());
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Call.ToInstruction(secretsManagerPlanFeaturesAllowSeatAutoscaleProperty.SetMethod));
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction());
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Ldc_I4_1.ToInstruction());
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Call.ToInstruction(secretsManagerPlanFeaturesAllowServiceAccountsAutoscaleProperty.SetMethod));
customSecretsManagerFeaturesCtor.Body.Instructions.Add(OpCodes.Ret.ToInstruction());
customSecretsManagerFeaturesType.Methods.Add(customSecretsManagerFeaturesCtor);
customPlanType.NestedTypes.Add(customSecretsManagerFeaturesType);
Console.WriteLine("Modify the CustomPlan class constructor");
Instruction[] newInstructions = new[]
{
OpCodes.Ldarg_0.ToInstruction(),
OpCodes.Newobj.ToInstruction(customSecretsManagerFeaturesCtor),
OpCodes.Call.ToInstruction(planSecretsManagerProperty.SetMethod),
};
foreach (var instruction in newInstructions.Reverse())
{
customPlanCtor.Body.Instructions.Insert(0, instruction);
}
customPlanCtor.Body.MaxStack += 2;
}
else
{
Console.WriteLine("WARNING: Cannot modifying CustomPlan");
}
// CustomPlan modify end
ModuleWriterOptions moduleWriterOptions = new(moduleDefMd);
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.KeepOldMaxStack;
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveAll;
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveRids;
moduleDefMd.Write(file + ".new");
moduleDefMd.Dispose();
File.Delete(file);
File.Move(file + ".new", file);
}
return 0;
}
}
}
from bitbetter.
PR #182 contains the same changes I made prior to posting this issue and they have been working fine. Though, forcing the SM class into the Custom plan is interesting, I still think its better to opt for keeping BW as-is as much as possible and using the Enterprise plan unless there is a specific reason CustomPlan type was used to begin with.
@raksta01 might want to add the new AllowAdminAccessToAllCollectionItems license option to the PR to save an extra PR later, but its fine either way.
set("AllowAdminAccessToAllCollectionItems", true);
from bitbetter.
PR #182 contains the same changes I made prior to posting this issue and they have been working fine. Though, forcing the SM class into the Custom plan is interesting, I still think its better to opt for keeping BW as-is as much as possible and using the Enterprise plan unless there is a specific reason CustomPlan type was used to begin with.
@raksta01 might want to add the new AllowAdminAccessToAllCollectionItems license option to the PR to save an extra PR later, but its fine either way.
set("AllowAdminAccessToAllCollectionItems", true);
I will add it in to the PR so a new PR doesn't need to be created however I will make it a question asked when generating the license wheter it should be true or false by default will set it to true
from bitbetter.
hi,
run into the same problem. What is the current status of the push request?
from bitbetter.
Related Issues (20)
- Member role "custom" is greyed out HOT 1
- Unable to update to 2023.8.0 HOT 2
- Compatibility Update HOT 1
- mssql access denied HOT 1
- ./update-bitwarden.sh Unable to update Bitwarden related mirrors HOT 1
- Version 2023.10.1 doesn't seem to work HOT 7
- How to active secrets manager HOT 3
- compatibility with Bitwarden offline setup HOT 5
- Secret manager - Create project error HOT 1
- Short URL (for version retrieval) no longer accessible HOT 1
- Execution error in /BitBetter/src/licenseGen# ./build.sh
- Invalid license HOT 1
- Key-connector not working HOT 1
- No longer building for v2024.2.2
- licenseGen.sh in unified branch isn't working (.NET?) HOT 4
- Cant pull docker
- Update error: COPY failed: no source files were specified
- Support for Duo Universal Prompt
- Host to Host | Migration steps for BitBetter
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bitbetter.