Functional implementation of licensegen interactive mode.

This commit is contained in:
Jeff Alyanak 2019-05-29 14:01:44 -04:00
parent fca0d599b9
commit 9e3701b272
No known key found for this signature in database
GPG Key ID: DD0CB89C105B276F
3 changed files with 68 additions and 69 deletions

View File

@ -42,14 +42,14 @@ dotnet add package Newtonsoft.Json --version 11.0.0
``` ```
## Building BitBetter ## Building BitBetter
Now that you've set up your build environment, you can run the main `BitBetter/build.sh` script to generate a modified version of the `bitwarden/api` and `bitwarden/identity` docker images. Now that you've set up your build environment, you can **run the main build script** to generate a modified version of the `bitwarden/api` and `bitwarden/identity` docker images.
From the BitBetter directory, simply run: From the BitBetter directory, simply run:
```bash ```bash
./build.sh ./build.sh
``` ```
This will create a new self-signed certificate in the `.keys` directory one does not already exist and then create a modified version of the official `bitwarden/api` called `bitbetter/api` and a modified version of the `bitwarden/identity` called `bitbetter/identity`. You may now simply edit your bitwarden docker-compose.yml to utilize the modified image. This will create a new self-signed certificate in the `.keys` directory one does not already exist and then create a modified version of the official `bitwarden/api` called `bitbetter/api` and a modified version of the `bitwarden/identity` called `bitbetter/identity`. You may **now simply edit your bitwarden docker-compose.yml to utilize the modified image**.
Edit your `/path/to/bwdata/docker/docker-compose.yml`. Edit your `/path/to/bwdata/docker/docker-compose.yml`.
@ -61,10 +61,10 @@ You'll also want to edit the `/path/to/bwdata/scripts/run.sh` file. In the `func
> Replace `dockerComposePull`<br>with `#dockerComposePull` > Replace `dockerComposePull`<br>with `#dockerComposePull`
You can now start or restart Bitwarden as normal and the modified api will be used. <b>It is now ready to accept self-issued licenses.</b> You can now start or restart Bitwarden as normal and the modified api will be used. **It is now ready to accept self-issued licenses.**
--- ---
**Note: Manually generating Certificate & Key** ### Note: Manually generating Certificate & Key
If you wish to generate your self-signed cert & key manually, you can run the following commands. If you wish to generate your self-signed cert & key manually, you can run the following commands.
@ -74,7 +74,7 @@ openssl x509 -inform DER -in cert.cert -out cert.pem
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -passin pass:test -passout pass:test openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -passin pass:test -passout pass:test
``` ```
Note that the password here must be `test`.<sup>[1](#f1)</sup> > Note that the password here must be `test`.<sup>[1](#f1)</sup>
--- ---
@ -82,22 +82,41 @@ Note that the password here must be `test`.<sup>[1](#f1)</sup>
There is a tool included in the directory `src/licenseGen/` that will generate new individual and organization licenses. These licenses will be accepted by the modified Bitwarden because they will be signed by the certificate you generated in earlier steps. There is a tool included in the directory `src/licenseGen/` that will generate new individual and organization licenses. These licenses will be accepted by the modified Bitwarden because they will be signed by the certificate you generated in earlier steps.
First, from the `BitBetter/src/licenseGen` directory, build the license generator.<sup>[2](#f2)</sup> First, from the `BitBetter` directory, **build the license generator**.<sup>[2](#f2)</sup>
```bash ```bash
./build.sh ./src/licenseGen/build.sh
``` ```
Now, from the `BitBetter/src/licenseGen` directory, you can run the tool to generate licenses. In order to run the tool and generate a license you'll need to get a **user's GUID** in order to generate an **invididual license** or the server's **install ID** to generate an **Organization license**. These can be retrieved most easily through the Bitwarden [Admin Portal](https://help.bitwarden.com/article/admin-portal/).
You'll need to get a user's <b>GUID</b> in order to generate an <b>invididual license</b> and the server's <b>install ID</b> to generate an <b>Organization license</b>. These can be retrieved most easily through the Bitwarden [Admin Portal](https://help.bitwarden.com/article/admin-portal/). If you generated your keys in the default `BitBetter/.keys` directory, you can **simply run the license gen in interactive mode** from the `Bitbetter` directory and **follow the prompts to generate your license**.
```bash ```bash
./run.sh ~/BitBetter/.keys/cert.pfx user "Name" "EMail" "User-GUID" ./src/licenseGen/run.sh interactive
./run.sh ~/BitBetter/.keys/cert.pfx org "Name" "EMail" "Install-ID used to install the server"
``` ```
<b>The license generator will spit out a JSON-formatted license which can then be used within the Bitwarden web front-end to license your user or org!</b> **The license generator will spit out a JSON-formatted license which can then be used within the Bitwarden web front-end to license your user or org!**
---
### Note: Alternative Ways to Generate License
If you wish to run the license gen from a directory aside from the root `BitBetter` one, you'll have to provide the absolute path to your cert.pfx.
```bash
./src/licenseGen/run.sh /Absolute/Path/To/BitBetter/.keys/cert.pfx interactive
```
Additional, instead of interactive mode, you can also pass the parameters directly to the command as follows.
```bash
./src/licenseGen/run.sh /Absolute/Path/To/BitBetter/.keys/cert.pfx user "Name" "EMail" "User-GUID"
./src/licenseGen/run.sh /Absolute/Path/To/BitBetter/.keys/cert.pfx org "Name" "EMail" "Install-ID used to install the server"
```
---
# FAQ: Questions (you might have?) # FAQ: Questions (you might have?)

View File

@ -35,30 +35,21 @@ namespace bitwardenSelfLicensor
app.Command("interactive", config => app.Command("interactive", config =>
{ {
string buff="", licensetype="", name="", email="", guid="", installid="", key="", businessname=""; string buff="", licensetype="", name="", email="", businessname="";
bool valid_guid = false, valid_installid = false;
Guid guid, installid;
config.OnExecute(() => config.OnExecute(() =>
{ {
if (!verifyTopOptions()) if (!verifyTopOptions())
{ {
if (!coreExists()) if (!coreExists()) config.Error.WriteLine($"Cant find core dll at: {coreDll.Value()}");
{ if (!certExists()) config.Error.WriteLine($"Cant find certificate at: {cert.Value()}");
config.Error.WriteLine($"Cant find core dll at: {coreDll.Value()}");
}
if (!certExists())
{
config.Error.WriteLine($"Cant find certificate at: {cert.Value()}");
}
config.ShowHelp(); config.ShowHelp();
return 1; return 1;
} }
else if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(email))
{
config.Error.WriteLine($"Some arguments are missing: Name='{name}' Email='{email}'");
config.ShowHelp("user");
return 1;
}
WriteLine("Interactive license mode..."); WriteLine("Interactive license mode...");
@ -71,31 +62,33 @@ namespace bitwardenSelfLicensor
{ {
licensetype = "user"; licensetype = "user";
WriteLineOver("Okay, we will generate a user license."); WriteLineOver("Okay, we will generate a user license.");
WriteLine("Please provide the user's guid — refer to the Readme for details on how to retrieve this. [GUID]:");
while (guid == "") while (valid_guid == false)
{ {
WriteLineOver("Please provide the user's guid — refer to the Readme for details on how to retrieve this. [GUID]:"); WriteLine("Please provide the user's guid — refer to the Readme for details on how to retrieve this. [GUID]:");
buff = Console.ReadLine(); buff = Console.ReadLine();
if ( checkGUID(buff) ) guid = buff;
if (Guid.TryParse(buff, out guid))valid_guid = true;
else WriteLineOver("The user-guid provided does not appear to be valid.");
} }
} }
else if (buff == "o") else if (buff == "o")
{ {
licensetype = "org"; licensetype = "org";
WriteLineOver("Okay, we will generate an organization license."); WriteLineOver("Okay, we will generate an organization license.");
WriteLine("Please provide your Bitwarden Install-ID — refer to the Readme for details on how to retrieve this. [Install-ID]:");
while (installid == "") while (valid_installid == false)
{ {
WriteLineOver("Please provide your Bitwarden Install-ID — refer to the Readme for details on how to retrieve this. [Install-ID]:"); WriteLine("Please provide your Bitwarden Install-ID — refer to the Readme for details on how to retrieve this. [Install-ID]:");
buff = Console.ReadLine(); buff = Console.ReadLine();
if ( checkGUID(buff) ) installid = buff;
if (Guid.TryParse(buff, out installid)) valid_installid = true;
else WriteLineOver("The install-id provided does not appear to be valid.");
} }
while (businessname == "") while (businessname == "")
{ {
WriteLineOver("Please enter an option business name, default is BitBetter. [Business Name]:"); WriteLineOver("Please enter a business name, default is BitBetter. [Business Name]:");
buff = Console.ReadLine(); buff = Console.ReadLine();
if (buff == "") businessname = "BitBetter"; if (buff == "") businessname = "BitBetter";
else if (checkBusinessName(buff)) businessname = buff; else if (checkBusinessName(buff)) businessname = buff;
@ -128,7 +121,7 @@ namespace bitwardenSelfLicensor
buff = Console.ReadLine(); buff = Console.ReadLine();
if ( buff == "" || buff == "y" || buff == "Y" ) if ( buff == "" || buff == "y" || buff == "Y" )
{ {
WriteLine("Okay."); GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name, email, guid, null);
} }
else else
{ {
@ -142,7 +135,7 @@ namespace bitwardenSelfLicensor
buff = Console.ReadLine(); buff = Console.ReadLine();
if ( buff == "" || buff == "y" || buff == "Y" ) if ( buff == "" || buff == "y" || buff == "Y" )
{ {
WriteLine("Okay."); GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name, email, installid, businessname, null);
} }
else else
{ {
@ -204,6 +197,7 @@ namespace bitwardenSelfLicensor
var name = config.Argument("Name", "your name"); var name = config.Argument("Name", "your name");
var email = config.Argument("Email", "your email"); var email = config.Argument("Email", "your email");
var installId = config.Argument("InstallId", "your installation id (GUID)"); var installId = config.Argument("InstallId", "your installation id (GUID)");
var businessName = config.Argument("BusinessName", "name For the organization (optional)");
var key = config.Argument("Key", "your key id (optional)"); var key = config.Argument("Key", "your key id (optional)");
var help = config.HelpOption("--help | -h | -?"); var help = config.HelpOption("--help | -h | -?");
@ -240,7 +234,7 @@ namespace bitwardenSelfLicensor
return 1; return 1;
} }
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name.Value, email.Value, installationId, key.Value); GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name.Value, email.Value, installationId, businessName.Value, key.Value);
return 0; return 0;
}); });
@ -265,31 +259,11 @@ namespace bitwardenSelfLicensor
} }
} }
// checkGUID Checks that the user-guid matches the correct format
static bool checkGUID(string s)
{
if (s == "") {
WriteLineOver("The User-GUID provided appears to be malformed.");
return false;
}
return true; // TODO: Actually validate
}
// checkInstallID Checks that the Install-ID matches the correct format
static bool checkInstallID(string s)
{
if (s == "") {
WriteLineOver("The Install-ID provided appears to be malformed.");
return false;
}
return true; // TODO: Actually validate
}
// checkUsername Checks that the username is a valid username // checkUsername Checks that the username is a valid username
static bool checkUsername(string s) static bool checkUsername(string s)
{ {
if (s == "") { if ( string.IsNullOrWhiteSpace(s) ) {
WriteLineOver("The username provided doesn't appear to be valid."); WriteLineOver("The username provided doesn't appear to be valid.\n");
return false; return false;
} }
return true; // TODO: Actually validate return true; // TODO: Actually validate
@ -298,8 +272,8 @@ namespace bitwardenSelfLicensor
// checkBusinessName Checks that the Business Name is a valid username // checkBusinessName Checks that the Business Name is a valid username
static bool checkBusinessName(string s) static bool checkBusinessName(string s)
{ {
if (s == "Microsoft") { if ( string.IsNullOrWhiteSpace(s) ) {
WriteLineOver("The Business Name provided doesn't appear to be valid."); WriteLineOver("The Business Name provided doesn't appear to be valid.\n");
return false; return false;
} }
return true; // TODO: Actually validate return true; // TODO: Actually validate
@ -308,8 +282,8 @@ namespace bitwardenSelfLicensor
// checkEmail Checks that the email address is a valid email address // checkEmail Checks that the email address is a valid email address
static bool checkEmail(string s) static bool checkEmail(string s)
{ {
if (s == "") { if ( string.IsNullOrWhiteSpace(s) ) {
WriteLineOver("The email provided doesn't appear to be valid."); WriteLineOver("The email provided doesn't appear to be valid.\n");
return false; return false;
} }
return true; // TODO: Actually validate return true; // TODO: Actually validate
@ -361,7 +335,7 @@ namespace bitwardenSelfLicensor
} }
static void GenerateOrgLicense(X509Certificate2 cert, string corePath, static void GenerateOrgLicense(X509Certificate2 cert, string corePath,
string userName, string email, Guid instalId, string key) string userName, string email, Guid instalId, string businessName, string key)
{ {
var core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath); var core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath);
@ -379,7 +353,7 @@ namespace bitwardenSelfLicensor
set("Id", Guid.NewGuid()); set("Id", Guid.NewGuid());
set("Name", userName); set("Name", userName);
set("BillingEmail", email); set("BillingEmail", email);
set("BusinessName", "BitBetter"); set("BusinessName", string.IsNullOrWhiteSpace(businessName) ? "BitBetter" : businessName);
set("Enabled", true); set("Enabled", true);
set("Plan", "Custom"); set("Plan", "Custom");
set("PlanType", (byte)6); set("PlanType", (byte)6);

View File

@ -2,11 +2,17 @@
script_dir=`cd $(dirname $0); pwd` script_dir=`cd $(dirname $0); pwd`
# Grab the absolute path to the default pfx location
cert_path=`cd ./.keys; ls -d -1 $PWD/cert.pfx`
if [ "$#" -lt "1" ]; then if [ "$#" -lt "1" ]; then
echo "USAGE: $0 <ABSOLUTE PATH TO CERT.PFX> [License Gen args...]" echo "USAGE: $0 <ABSOLUTE PATH TO CERT.PFX> [License Gen args...]"
exit 1 exit 1
elif [ "$#" -ge "2" ]; then
# If a cert path is provided manually, override the default
cert_path=$1
shift
fi fi
cert_path=$1
shift
docker run -it -v "$cert_path:/cert.pfx" bitbetter/licensegen "$@" docker run -it -v "$cert_path:/cert.pfx" bitbetter/licensegen "$@"