Giter Site home page Giter Site logo

Comments (7)

psychodracon avatar psychodracon commented on June 11, 2024

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.

captainhook avatar captainhook commented on June 11, 2024

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.

Ayitaka avatar Ayitaka commented on June 11, 2024

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.

blood72 avatar blood72 commented on June 11, 2024

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.

Ayitaka avatar Ayitaka commented on June 11, 2024

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.

raksta01 avatar raksta01 commented on June 11, 2024

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.

ruben-herold avatar ruben-herold commented on June 11, 2024

hi,

run into the same problem. What is the current status of the push request?

from bitbetter.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.