mirror of
https://github.com/jakeswenson/BitBetter.git
synced 2025-12-18 20:26:19 +00:00
Compare commits
23 Commits
b47fe37279
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31a08b7e89 | ||
|
|
5387d1803d | ||
|
|
2c9e4fd9fa | ||
|
|
0e2c9d42aa | ||
|
|
063ab1d316 | ||
|
|
df9e74bb7a | ||
|
|
ac01b0c7ec | ||
|
|
f3e36ab404 | ||
|
|
b9c46fffb2 | ||
|
|
047c4ddf6f | ||
|
|
676dd7b85c | ||
|
|
0b33567820 | ||
|
|
180ad94838 | ||
|
|
38c43a43c9 | ||
|
|
bfc821e918 | ||
|
|
3ec7b3d843 | ||
|
|
7f64e2cd4a | ||
|
|
a65277198c | ||
|
|
12da7d7249 | ||
|
|
3c703f517d | ||
|
|
b93c9487eb | ||
|
|
e173c06320 | ||
|
|
80c0808e72 |
@@ -1,15 +1,24 @@
|
|||||||
version: 2.1
|
version: 2
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
machine: true
|
machine: true
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
name: Print the Current Time
|
name: Print the Current Time
|
||||||
command: date
|
command: date
|
||||||
- run:
|
- run:
|
||||||
name: Generate Keys
|
name: Generate Keys
|
||||||
command: ./generateKeys.sh
|
command: ./.keys/generate-keys.sh
|
||||||
- run:
|
- run:
|
||||||
name: Build script
|
name: Build script
|
||||||
command: ./build.sh y
|
command: ./build.sh
|
||||||
|
- run:
|
||||||
|
name: Build licenseGen
|
||||||
|
command: ./src/licenseGen/build.sh
|
||||||
|
- run:
|
||||||
|
name: Test generating user license
|
||||||
|
command: ./src/licenseGen/run.sh ./.keys/cert.pfx user TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
||||||
|
- run:
|
||||||
|
name: Test generating organization license
|
||||||
|
command: ./src/licenseGen/run.sh ./.keys/cert.pfx org TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,11 +1,8 @@
|
|||||||
.idea/
|
.idea/
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
src/licenseGen/.vs/*
|
|
||||||
src/bitBetter/.vs/*
|
|
||||||
*.dll
|
*.dll
|
||||||
*.pem
|
*.pem
|
||||||
.vscode/
|
.vscode/
|
||||||
*.pfx
|
*.pfx
|
||||||
*.cert
|
*.cert
|
||||||
*.vsidx
|
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
# Check for openssl
|
# Check for openssl
|
||||||
command -v openssl >/dev/null 2>&1 || { echo >&2 "openssl required but not found. Aborting."; exit 1; }
|
command -v openssl >/dev/null 2>&1 || { echo >&2 "openssl required but not found. Aborting."; exit 1; }
|
||||||
|
|
||||||
DIR="$PWD/.keys"
|
DIR=`dirname "$0"`
|
||||||
|
DIR=`exec 2>/dev/null;(cd -- "$DIR") && cd -- "$DIR"|| cd "$DIR"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
|
||||||
|
|
||||||
# if previous keys exist, remove them
|
# Remove any existing key files
|
||||||
if [ -d "$DIR" ]; then
|
[ ! -e "$DIR/cert.pem" ] || rm "$DIR/cert.pem"
|
||||||
rm -rf "$DIR"
|
[ ! -e "$DIR/key.pem" ] || rm "$DIR/key.pem"
|
||||||
fi
|
[ ! -e "$DIR/cert.cert" ] || rm "$DIR/cert.cert"
|
||||||
|
[ ! -e "$DIR/cert.pfx" ] || rm "$DIR/cert.pfx"
|
||||||
# create new directory
|
|
||||||
mkdir "$DIR"
|
|
||||||
|
|
||||||
# Generate new keys
|
# Generate new keys
|
||||||
openssl req -x509 -newkey rsa:4096 -keyout "$DIR/key.pem" -out "$DIR/cert.cert" -days 36500 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' -outform DER -passout pass:test
|
openssl req -x509 -newkey rsa:4096 -keyout "$DIR/key.pem" -out "$DIR/cert.cert" -days 36500 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' -outform DER -passout pass:test
|
||||||
openssl x509 -inform DER -in "$DIR/cert.cert" -out "$DIR/cert.pem"
|
openssl x509 -inform DER -in "$DIR/cert.cert" -out "$DIR/cert.pem"
|
||||||
openssl pkcs12 -export -out "$DIR/cert.pfx" -inkey "$DIR/key.pem" -in "$DIR/cert.pem" -passin pass:test -passout pass:test
|
openssl pkcs12 -export -out "$DIR/cert.pfx" -inkey "$DIR/key.pem" -in "$DIR/cert.pem" -passin pass:test -passout pass:test
|
||||||
|
|
||||||
|
ls
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
docker run -d --name bitwarden -v <full-local-path>\logs:/var/log/bitwarden -v <full-local-path>\bwdata:/etc/bitwarden -p 80:8080 --env-file <full-local-path>\settings.env bitwarden-patch
|
|
||||||
<OR>
|
|
||||||
docker-compose -f <full-local-path>/docker-compose.yml up -d
|
|
||||||
162
README.md
162
README.md
@@ -1,10 +1,12 @@
|
|||||||
# BitBetter
|
# BitBetter
|
||||||
|
|
||||||
BitBetter is is a tool to modify Bitwarden's core dll to allow you to generate your own individual and organisation licenses.
|
BitBetter is is a tool to modify Bitwarden's core dll to allow you to generate your own individual and organisation licenses. **You must have an existing installation of Bitwarden for BitBetter to modify.**
|
||||||
|
|
||||||
Please see the FAQ below for details on why this software was created.
|
Please see the FAQ below for details on why this software was created.
|
||||||
|
|
||||||
_Beware! BitBetter does some semi janky stuff to rewrite the bitwarden core dll and allow the installation of a self signed certificate. Use at your own risk!_
|
Looking for a solution to the Lite (formerly unified) version of bitwarden, [go to the Lite branch](../../tree/lite).
|
||||||
|
|
||||||
|
_Beware! BitBetter does janky stuff to rewrite the bitwarden core dll and allow the installation of a self signed certificate. Use at your own risk!_
|
||||||
|
|
||||||
Credit to https://github.com/h44z/BitBetter and https://github.com/jakeswenson/BitBetter
|
Credit to https://github.com/h44z/BitBetter and https://github.com/jakeswenson/BitBetter
|
||||||
|
|
||||||
@@ -14,8 +16,8 @@ Credit to https://github.com/h44z/BitBetter and https://github.com/jakeswenson/B
|
|||||||
- [Getting Started](#getting-started)
|
- [Getting Started](#getting-started)
|
||||||
- [Dependencies](#dependencies)
|
- [Dependencies](#dependencies)
|
||||||
- [Setting up BitBetter](#setting-up-bitbetter)
|
- [Setting up BitBetter](#setting-up-bitbetter)
|
||||||
|
- [Optional: Manually generating Certificate & Key](#optional-manually-generating-certificate--key)
|
||||||
- [Building BitBetter](#building-bitbetter)
|
- [Building BitBetter](#building-bitbetter)
|
||||||
- [Note: Manually generating Certificate & Key](#note-manually-generating-certificate--key)
|
|
||||||
- [Updating Bitwarden and BitBetter](#updating-bitwarden-and-bitbetter)
|
- [Updating Bitwarden and BitBetter](#updating-bitwarden-and-bitbetter)
|
||||||
- [Generating Signed Licenses](#generating-signed-licenses)
|
- [Generating Signed Licenses](#generating-signed-licenses)
|
||||||
- [Note: Alternative Ways to Generate License](#note-alternative-ways-to-generate-license)
|
- [Note: Alternative Ways to Generate License](#note-alternative-ways-to-generate-license)
|
||||||
@@ -25,82 +27,127 @@ Credit to https://github.com/h44z/BitBetter and https://github.com/jakeswenson/B
|
|||||||
- [Footnotes](#footnotes)
|
- [Footnotes](#footnotes)
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
The following instructions are for unix-based systems (Linux, BSD, macOS) and Windows, just choose the correct script extension (.sh or .ps1 respectively).
|
The following instructions are for unix-based systems (Linux, BSD, macOS), it is possible to use a Windows systems assuming you are able to enable and install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
Aside from docker, which you also need for Bitwarden, BitBetter requires the following:
|
Aside from docker, which you also need for Bitwarden, BitBetter requires the following:
|
||||||
|
|
||||||
* Bitwarden (tested with 1.47.1, might work on lower versions)
|
* Bitwarden (tested with 1.47.1, might work on lower versions)
|
||||||
* openssl (probably already installed on most Linux or WSL systems, any version should work, on Windows it will be auto installed using winget)
|
* openssl (probably already installed on most Linux or WSL systems, any version should work)
|
||||||
|
|
||||||
## Setting up BitBetter
|
## Setting up BitBetter
|
||||||
With your dependencies installed, begin the installation of BitBetter by downloading it through Github or using the git command:
|
With your dependencies installed, begin the installation of BitBetter by downloading it through Github or using the git command:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
git clone https://github.com/jakeswenson/BitBetter.git
|
git clone https://github.com/jakeswenson/BitBetter.git
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building BitBetter
|
### Optional: Manually generating Certificate & Key
|
||||||
|
|
||||||
Now that you've set up your build environment, we need to specify which servers to start after the work is done.
|
|
||||||
The scripts supports running and patching multi instances.
|
|
||||||
|
|
||||||
Edit the .servers/serverlist.txt file and fill in the missing values, they can be replaced with existing installation values.
|
|
||||||
This file may be empty, but there will be no containers will be spun up automatically.
|
|
||||||
|
|
||||||
Now it is time to **run the main build script** to generate a modified version of the `bitwarden/self-host` docker image and the license generator.
|
|
||||||
|
|
||||||
From the BitBetter directory, simply run:
|
|
||||||
```
|
|
||||||
./build.[sh|ps1]
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create a new self-signed certificate in the `.keys` directory if one does not already exist and then create a modified version of the official `bitwarden/self-host` image called `bitwarden-patch`.
|
|
||||||
|
|
||||||
Afterwards it will automatically generate the license generator and start all previously specified containers which are **now ready to accept self-issued licenses.**
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Updating Bitwarden and BitBetter
|
|
||||||
|
|
||||||
To update Bitwarden, the same `build.[sh|ps1]` script can be used. It will rebuild the BitBetter image and automatically update Bitwarden before doing so.
|
|
||||||
|
|
||||||
## Generating Signed Licenses
|
|
||||||
|
|
||||||
There is a tool included in the directory `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.
|
|
||||||
|
|
||||||
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/).
|
|
||||||
|
|
||||||
**The user must have a verified email address at the time of license import, otherwise Bitwarden will reject the license key. Nevertheless, the license key can be generated even before the user's email is verified.**
|
|
||||||
|
|
||||||
If you ran the build script, you can **simply run the license gen in interactive mode** from the `Bitbetter` directory and **follow the prompts to generate your license**.
|
|
||||||
|
|
||||||
```
|
|
||||||
./licenseGen.[sh|ps1] interactive
|
|
||||||
```
|
|
||||||
|
|
||||||
**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: 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.
|
||||||
Note that you should never have to do this yourself, but can also be triggered by running the generateKeys.[sh|ps1] script.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd .keys
|
||||||
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.cert -days 36500 -outform DER -passout pass:test
|
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.cert -days 36500 -outform DER -passout pass:test
|
||||||
openssl x509 -inform DER -in cert.cert -out cert.pem
|
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>[2](#f1)</sup>
|
> Note that the password here must be `test`.<sup>[1](#f1)</sup>
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Building BitBetter
|
||||||
|
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a new self-signed certificate in the `.keys` directory if 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 create the file `/path/to/bwdata/docker/docker-compose.override.yml` with the following contents to utilize the modified images.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
image: bitbetter/api
|
||||||
|
pull_policy: never
|
||||||
|
|
||||||
|
identity:
|
||||||
|
image: bitbetter/identity
|
||||||
|
pull_policy: never
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll also want to edit the `/path/to/bwdata/scripts/run.sh` file. In the `function restart()` block, comment out the call to `dockerComposePull`.
|
||||||
|
|
||||||
|
> Replace `dockerComposePull`<br>with `#dockerComposePull`
|
||||||
|
|
||||||
|
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.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Updating Bitwarden and BitBetter
|
||||||
|
|
||||||
|
To update Bitwarden, the provided `update-bitwarden.sh` script can be used. It will rebuild the BitBetter images and automatically update Bitwarden afterwards. Docker pull errors can be ignored for api and identity images.
|
||||||
|
|
||||||
|
You can either run this script without providing any parameters in interactive mode (`./update-bitwarden.sh`) or by setting the parameters as follows, to run the script in non-interactive mode:
|
||||||
|
```bash
|
||||||
|
./update-bitwarden.sh param1 param2 param3
|
||||||
|
```
|
||||||
|
`param1`: The path to the directory containing your bwdata directory
|
||||||
|
|
||||||
|
`param2`: If you want the docker-compose file to be overwritten (either `y` or `n`)
|
||||||
|
|
||||||
|
`param3`: If you want the bitbetter images to be rebuild (either `y` or `n`)
|
||||||
|
|
||||||
|
If you are updating from versions <= 1.46.2, you may need to run `update-bitwarden.sh` twice to complete the update process.
|
||||||
|
|
||||||
|
## Generating Signed Licenses
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
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/).
|
||||||
|
|
||||||
|
**The user must have a verified email address at the time of license import, otherwise Bitwarden will reject the license key. Nevertheless, the license key can be generated even before the user's email is verified.**
|
||||||
|
|
||||||
|
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
|
||||||
|
./src/licenseGen/run.sh interactive
|
||||||
|
```
|
||||||
|
|
||||||
|
**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" "E-Mail" "User-GUID" ["Storage Space in GB"] ["Custom LicenseKey"]
|
||||||
|
./src/licenseGen/run.sh /Absolute/Path/To/BitBetter/.keys/cert.pfx org "Name" "E-Mail" "Install-ID used to install the server" ["Storage Space in GB"] ["Custom LicenseKey"]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
# FAQ: Questions you might have.
|
# FAQ: Questions you might have.
|
||||||
|
|
||||||
## Why build a license generator for open source software?
|
## Why build a license generator for open source software?
|
||||||
@@ -118,6 +165,7 @@ UPDATE: Bitwarden now offers a cheap license called [Families Organization](http
|
|||||||
|
|
||||||
# Footnotes
|
# Footnotes
|
||||||
|
|
||||||
<a name="#f1"><sup>1</sup></a>This tool builds on top of the `bitbetter/api` container image so make sure you've built that above using the root `./build.sh` script.
|
<a name="#f1"><sup>1</sup></a> If you wish to change this you'll need to change the value that `src/licenseGen/Program.cs` uses for its `GenerateUserLicense` and `GenerateOrgLicense` calls. Remember, this is really unnecessary as this certificate does not represent any type of security-related certificate.
|
||||||
|
|
||||||
|
<a name="#f2"><sup>2</sup></a>This tool builds on top of the `bitbetter/api` container image so make sure you've built that above using the root `./build.sh` script.
|
||||||
|
|
||||||
<a name="#f2"><sup>2</sup></a> If you wish to change this you'll need to change the value that `licenseGen/Program.cs` uses for its `GenerateUserLicense` and `GenerateOrgLicense` calls. Remember, this is really unnecessary as this certificate does not represent any type of security-related certificate.
|
|
||||||
|
|||||||
104
build.ps1
104
build.ps1
@@ -1,104 +0,0 @@
|
|||||||
# define temporary directory
|
|
||||||
$tempdirectory = "$pwd\temp"
|
|
||||||
# define services to patch
|
|
||||||
$components = "Api","Identity"
|
|
||||||
|
|
||||||
# delete old directories / files if applicable
|
|
||||||
if (Test-Path "$tempdirectory") {
|
|
||||||
Remove-Item "$tempdirectory" -Recurse -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -Path "$pwd\src\licenseGen\Core.dll" -PathType Leaf) {
|
|
||||||
Remove-Item "$pwd\src\licenseGen\Core.dll" -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -Path "$pwd\src\licenseGen\cert.pfx" -PathType Leaf) {
|
|
||||||
Remove-Item "$pwd\src\licenseGen\cert.pfx" -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -Path "$pwd\src\bitBetter\cert.cert" -PathType Leaf) {
|
|
||||||
Remove-Item "$pwd\src\bitBetter\cert.cert" -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate keys if none are available
|
|
||||||
if (!(Test-Path "$pwd\.keys")) {
|
|
||||||
.\generateKeys.ps1
|
|
||||||
}
|
|
||||||
|
|
||||||
# copy the key to bitBetter and licenseGen
|
|
||||||
Copy-Item "$pwd\.keys\cert.cert" -Destination "$pwd\src\bitBetter"
|
|
||||||
Copy-Item "$pwd\.keys\cert.pfx" -Destination "$pwd\src\licenseGen"
|
|
||||||
|
|
||||||
# build bitBetter and clean the source directory after
|
|
||||||
docker build -t bitbetter/bitbetter "$pwd\src\bitBetter"
|
|
||||||
Remove-Item "$pwd\src\bitBetter\cert.cert" -Force
|
|
||||||
|
|
||||||
# gather all running instances
|
|
||||||
$oldinstances = docker container ps --all -f Name=bitwarden --format '{{.ID}}'
|
|
||||||
|
|
||||||
# stop all running instances
|
|
||||||
foreach ($instance in $oldinstances) {
|
|
||||||
docker stop $instance
|
|
||||||
docker rm $instance
|
|
||||||
}
|
|
||||||
|
|
||||||
# update bitwarden itself
|
|
||||||
if ($args[0] -eq 'y')
|
|
||||||
{
|
|
||||||
docker pull bitwarden/self-host:beta
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$confirmation = Read-Host "Update (or get) bitwarden source container"
|
|
||||||
if ($confirmation -eq 'y') {
|
|
||||||
docker pull bitwarden/self-host:beta
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# stop and remove previous existing patch(ed) container
|
|
||||||
docker stop bitwarden-patch
|
|
||||||
docker rm bitwarden-patch
|
|
||||||
docker image rm bitwarden-patch
|
|
||||||
|
|
||||||
# start a new bitwarden instance so we can patch it
|
|
||||||
$patchinstance = docker run -d --name bitwarden-patch bitwarden/self-host:beta
|
|
||||||
|
|
||||||
# create our temporary directory
|
|
||||||
New-item -ItemType Directory -Path $tempdirectory
|
|
||||||
|
|
||||||
# extract the files that need to be patched from the services that need to be patched into our temporary directory
|
|
||||||
foreach ($component in $components) {
|
|
||||||
New-item -itemtype Directory -path "$tempdirectory\$component"
|
|
||||||
docker cp $patchinstance`:/app/$component/Core.dll "$tempdirectory\$component\Core.dll"
|
|
||||||
}
|
|
||||||
|
|
||||||
# run bitBetter, this applies our patches to the required files
|
|
||||||
docker run -v "$tempdirectory`:/app/mount" --rm bitbetter/bitbetter
|
|
||||||
|
|
||||||
# create a new image with the patched files
|
|
||||||
docker build . --tag bitwarden-patch --file "$pwd\src\bitBetter\Dockerfile-bitwarden-patch"
|
|
||||||
|
|
||||||
# stop and remove our temporary container
|
|
||||||
docker stop bitwarden-patch
|
|
||||||
docker rm bitwarden-patch
|
|
||||||
|
|
||||||
# copy our patched library to the licenseGen source directory
|
|
||||||
Copy-Item "$tempdirectory\Identity\Core.dll" -Destination "$pwd\src\licenseGen"
|
|
||||||
|
|
||||||
# remove our temporary directory
|
|
||||||
Remove-Item "$tempdirectory" -Recurse -Force
|
|
||||||
|
|
||||||
# start all user requested instances
|
|
||||||
foreach($line in Get-Content "$pwd\.servers\serverlist.txt") {
|
|
||||||
Invoke-Expression "& $line"
|
|
||||||
}
|
|
||||||
|
|
||||||
# remove our bitBetter image
|
|
||||||
docker image rm bitbetter/bitbetter
|
|
||||||
|
|
||||||
# build the licenseGen
|
|
||||||
docker build -t bitbetter/licensegen "$pwd\src\licenseGen"
|
|
||||||
|
|
||||||
# clean the licenseGen source directory
|
|
||||||
Remove-Item "$pwd\src\licenseGen\Core.dll" -Force
|
|
||||||
Remove-Item "$pwd\src\licenseGen\cert.pfx" -Force
|
|
||||||
150
build.sh
150
build.sh
@@ -1,106 +1,68 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
DIR=`dirname "$0"`
|
||||||
|
DIR=`exec 2>/dev/null;(cd -- "$DIR") && cd -- "$DIR"|| cd "$DIR"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
|
||||||
|
BW_VERSION=$(curl -sL https://go.btwrdn.co/bw-sh-versions | grep '^ *"'coreVersion'":' | awk -F\: '{ print $2 }' | sed -e 's/,$//' -e 's/^"//' -e 's/"$//')
|
||||||
|
|
||||||
# define temporary directory
|
echo "Building BitBetter for BitWarden version $BW_VERSION"
|
||||||
TEMPDIRECTORY="$PWD/temp"
|
|
||||||
|
|
||||||
# define services to patch
|
# Enable BuildKit for better build experience and to ensure platform args are populated
|
||||||
COMPONENTS=("Api" "Identity")
|
export DOCKER_BUILDKIT=1
|
||||||
|
export COMPOSE_DOCKER_CLI_BUILD=1
|
||||||
|
|
||||||
# delete old directories / files if applicable
|
# Determine host architecture to use as default BUILDPLATFORM / TARGETPLATFORM if not supplied.
|
||||||
if [ -d "$TEMPDIRECTORY" ]; then
|
# Allow override via environment variables when invoking the script.
|
||||||
rm -rf "$TEMPDIRECTORY"
|
HOST_UNAME_ARCH=$(uname -m 2>/dev/null || echo unknown)
|
||||||
fi
|
case "$HOST_UNAME_ARCH" in
|
||||||
|
x86_64|amd64) DEFAULT_ARCH=amd64 ;;
|
||||||
|
aarch64|arm64) DEFAULT_ARCH=arm64 ;;
|
||||||
|
armv7l|armv7) DEFAULT_ARCH=arm/v7 ;;
|
||||||
|
*) DEFAULT_ARCH=amd64 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ -f "$PWD/src/licenseGen/Core.dll" ]; then
|
: "${BUILDPLATFORM:=linux/${DEFAULT_ARCH}}"
|
||||||
rm -f "$PWD/src/licenseGen/Core.dll"
|
: "${TARGETPLATFORM:=linux/${DEFAULT_ARCH}}"
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$PWD/src/licenseGen/cert.pfx" ]; then
|
echo "Using BUILDPLATFORM=$BUILDPLATFORM TARGETPLATFORM=$TARGETPLATFORM"
|
||||||
rm -f "$PWD/src/licenseGen/cert.pfx"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$PWD/src/bitBetter/cert.cert" ]; then
|
# If there aren't any keys, generate them first.
|
||||||
rm -f "$PWD/src/bitBetter/cert.cert"
|
[ -e "$DIR/.keys/cert.cert" ] || "$DIR/.keys/generate-keys.sh"
|
||||||
fi
|
|
||||||
|
|
||||||
# generate keys if none are available
|
# Prepare Bitwarden server repository
|
||||||
if [ ! -d "$PWD/.keys" ]; then
|
rm -rf $DIR/server
|
||||||
./generateKeys.sh
|
git clone --branch "v${BW_VERSION}" --depth 1 https://github.com/bitwarden/server.git $DIR/server
|
||||||
fi
|
|
||||||
|
|
||||||
# copy the key to bitBetter and licenseGen
|
# Replace certificate file and thumbprint
|
||||||
cp -f "$PWD/.keys/cert.cert" "$PWD/src/bitBetter"
|
old_thumbprint=$(openssl x509 -inform DER -fingerprint -noout -in $DIR/server/src/Core/licensing.cer | cut -d= -f2 | tr -d ':')
|
||||||
cp -f "$PWD/.keys/cert.pfx" "$PWD/src/licenseGen"
|
new_thumbprint=$(openssl x509 -inform DER -fingerprint -noout -in $DIR/.keys/cert.cert | cut -d= -f2 | tr -d ':')
|
||||||
|
sed -i -e "s/$old_thumbprint/$new_thumbprint/g" $DIR/server/src/Core/Billing/Services/Implementations/LicensingService.cs
|
||||||
|
cp $DIR/.keys/cert.cert $DIR/server/src/Core/licensing.cer
|
||||||
|
|
||||||
# build bitBetter and clean the source directory after
|
docker build \
|
||||||
docker build -t bitbetter/bitbetter "$PWD/src/bitBetter"
|
--no-cache \
|
||||||
rm -f "$PWD/src/bitBetter/cert.cert"
|
--platform "$TARGETPLATFORM" \
|
||||||
|
--build-arg BUILDPLATFORM="$BUILDPLATFORM" \
|
||||||
|
--build-arg TARGETPLATFORM="$TARGETPLATFORM" \
|
||||||
|
--label com.bitwarden.product="bitbetter" \
|
||||||
|
-f $DIR/server/src/Api/Dockerfile \
|
||||||
|
-t bitbetter/api \
|
||||||
|
$DIR/server
|
||||||
|
|
||||||
# gather all running instances
|
docker build \
|
||||||
OLDINSTANCES=$(docker container ps --all -f Name=bitwarden --format '{{.ID}}')
|
--no-cache \
|
||||||
|
--platform "$TARGETPLATFORM" \
|
||||||
|
--build-arg BUILDPLATFORM="$BUILDPLATFORM" \
|
||||||
|
--build-arg TARGETPLATFORM="$TARGETPLATFORM" \
|
||||||
|
--label com.bitwarden.product="bitbetter" \
|
||||||
|
-f $DIR/server/src/Identity/Dockerfile \
|
||||||
|
-t bitbetter/identity \
|
||||||
|
$DIR/server
|
||||||
|
|
||||||
# stop all running instances
|
docker tag bitbetter/api bitbetter/api:latest
|
||||||
for INSTANCE in ${OLDINSTANCES[@]}; do
|
docker tag bitbetter/identity bitbetter/identity:latest
|
||||||
docker stop $INSTANCE
|
docker tag bitbetter/api bitbetter/api:$BW_VERSION
|
||||||
docker rm $INSTANCE
|
docker tag bitbetter/identity bitbetter/identity:$BW_VERSION
|
||||||
done
|
|
||||||
|
|
||||||
# update bitwarden itself
|
# Remove old instances of the image after a successful build.
|
||||||
if [ "$1" = "y" ]; then
|
ids=$( docker image ls --format="{{ .ID }} {{ .Tag }}" 'bitbetter/*' | grep -E -v -- "CREATED|latest|${BW_VERSION}" | awk '{ ids = (ids ? ids FS $1 : $1) } END { print ids }' )
|
||||||
docker pull bitwarden/self-host:beta
|
[ -n "$ids" ] && docker rmi $ids || true
|
||||||
else
|
|
||||||
read -p "Update (or get) bitwarden source container: " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
|
||||||
then
|
|
||||||
docker pull bitwarden/self-host:beta
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# stop and remove previous existing patch(ed) container
|
|
||||||
docker stop bitwarden-patch
|
|
||||||
docker rm bitwarden-patch
|
|
||||||
docker image rm bitwarden-patch
|
|
||||||
|
|
||||||
# start a new bitwarden instance so we can patch it
|
|
||||||
PATCHINSTANCE=$(docker run -d --name bitwarden-patch bitwarden/self-host:beta)
|
|
||||||
|
|
||||||
# create our temporary directory
|
|
||||||
mkdir $TEMPDIRECTORY
|
|
||||||
|
|
||||||
# extract the files that need to be patched from the services that need to be patched into our temporary directory
|
|
||||||
for COMPONENT in ${COMPONENTS[@]}; do
|
|
||||||
mkdir "$TEMPDIRECTORY/$COMPONENT"
|
|
||||||
docker cp $PATCHINSTANCE:/app/$COMPONENT/Core.dll "$TEMPDIRECTORY/$COMPONENT/Core.dll"
|
|
||||||
done
|
|
||||||
|
|
||||||
# run bitBetter, this applies our patches to the required files
|
|
||||||
docker run -v "$TEMPDIRECTORY:/app/mount" --rm bitbetter/bitbetter
|
|
||||||
|
|
||||||
# create a new image with the patched files
|
|
||||||
docker build . --tag bitwarden-patch --file "$PWD/src/bitBetter/Dockerfile-bitwarden-patch"
|
|
||||||
|
|
||||||
# stop and remove our temporary container
|
|
||||||
docker stop bitwarden-patch
|
|
||||||
docker rm bitwarden-patch
|
|
||||||
|
|
||||||
# copy our patched library to the licenseGen source directory
|
|
||||||
cp -f "$TEMPDIRECTORY/Identity/Core.dll" "$PWD/src/licenseGen"
|
|
||||||
|
|
||||||
# remove our temporary directory
|
|
||||||
rm -rf "$TEMPDIRECTORY"
|
|
||||||
|
|
||||||
# start all user requested instances
|
|
||||||
cat "$PWD/.servers/serverlist.txt" | while read LINE; do
|
|
||||||
bash -c "$LINE"
|
|
||||||
done
|
|
||||||
|
|
||||||
# remove our bitBetter image
|
|
||||||
docker image rm bitbetter/bitbetter
|
|
||||||
|
|
||||||
# build the licenseGen
|
|
||||||
docker build -t bitbetter/licensegen "$PWD/src/licenseGen"
|
|
||||||
|
|
||||||
# clean the licenseGen source directory
|
|
||||||
rm -f "$PWD/src/licenseGen/Core.dll"
|
|
||||||
rm -f "$PWD/src/licenseGen/cert.pfx"
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
# get the basic openssl binary path
|
|
||||||
$opensslbinary = "$Env:Programfiles\OpenSSL-Win64\bin\openssl.exe"
|
|
||||||
|
|
||||||
# if openssl is not installed attempt to install it
|
|
||||||
if (!(Get-Command $opensslbinary -errorAction SilentlyContinue))
|
|
||||||
{
|
|
||||||
winget install openssl
|
|
||||||
}
|
|
||||||
|
|
||||||
# if previous keys exist, remove them
|
|
||||||
if (Test-Path "$pwd\.keys")
|
|
||||||
{
|
|
||||||
Remove-Item "$pwd\.keys" -Recurse -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
# create new directory
|
|
||||||
New-item -ItemType Directory -Path "$pwd\.keys"
|
|
||||||
|
|
||||||
# generate actual keys
|
|
||||||
Invoke-Expression "& '$opensslbinary' req -x509 -newkey rsa:4096 -keyout `"$pwd\.keys\key.pem`" -out `"$pwd\.keys\cert.cert`" -days 36500 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' -outform DER -passout pass:test"
|
|
||||||
Invoke-Expression "& '$opensslbinary' x509 -inform DER -in `"$pwd\.keys\cert.cert`" -out `"$pwd\.keys\cert.pem`""
|
|
||||||
Invoke-Expression "& '$opensslbinary' pkcs12 -export -out `"$pwd\.keys\cert.pfx`" -inkey `"$pwd\.keys\key.pem`" -in `"$pwd\.keys\cert.pem`" -passin pass:test -passout pass:test"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
if ($($args.Count) -lt 1) {
|
|
||||||
echo "USAGE: <License Gen action> [License Gen args...]"
|
|
||||||
echo "ACTIONS:"
|
|
||||||
echo " interactive"
|
|
||||||
echo " user"
|
|
||||||
echo " org"
|
|
||||||
Exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($args[0] = "interactive") {
|
|
||||||
docker run -it --rm bitbetter/licensegen interactive
|
|
||||||
} else {
|
|
||||||
docker run bitbetter/licensegen $args
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# -lt 1 ]; then
|
|
||||||
echo "USAGE: <License Gen action> [License Gen args...]"
|
|
||||||
echo "ACTIONS:"
|
|
||||||
echo " interactive"
|
|
||||||
echo " user"
|
|
||||||
echo " org"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" = "interactive" ]; then
|
|
||||||
docker run -it --rm bitbetter/licensegen interactive
|
|
||||||
else
|
|
||||||
docker run --rm bitbetter/licensegen "$@"
|
|
||||||
fi
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 as build
|
|
||||||
WORKDIR /bitBetter
|
|
||||||
|
|
||||||
COPY . /bitBetter
|
|
||||||
COPY cert.cert /app/
|
|
||||||
|
|
||||||
RUN dotnet restore
|
|
||||||
RUN dotnet publish -c Release -o /app --no-restore
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=build /app .
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/app/bitBetter" ]
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
FROM bitwarden/self-host:beta
|
|
||||||
|
|
||||||
COPY ./temp/Api/Core.dll /app/Api/Core.dll
|
|
||||||
COPY ./temp/Identity/Core.dll /app/Identity/Core.dll
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
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 Int32 Main()
|
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="dnlib" Version="4.4.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 as build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
|
||||||
WORKDIR /licenseGen
|
WORKDIR /licenseGen
|
||||||
|
|
||||||
COPY . /licenseGen
|
COPY . /licenseGen
|
||||||
COPY Core.dll /app/
|
|
||||||
COPY cert.pfx /app/
|
|
||||||
|
|
||||||
RUN dotnet restore
|
RUN set -e; set -x; \
|
||||||
RUN dotnet publish -c Release -o /app --no-restore
|
dotnet add package Newtonsoft.Json --version 13.0.1 \
|
||||||
|
&& dotnet restore \
|
||||||
|
&& dotnet publish
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=build /app .
|
|
||||||
|
|
||||||
ENTRYPOINT [ "dotnet", "/app/licenseGen.dll", "--core", "/app/Core.dll", "--cert", "/app/cert.pfx" ]
|
FROM bitbetter/api
|
||||||
|
|
||||||
|
COPY --from=build /licenseGen/bin/Release/net8.0/publish/* /app/
|
||||||
|
|
||||||
|
ENTRYPOINT [ "dotnet", "/app/licenseGen.dll", "--core", "/app/Core.dll", "--executable", "/app/Api", "--cert", "/cert.pfx" ]
|
||||||
|
|||||||
@@ -1,453 +1,445 @@
|
|||||||
using System;
|
namespace BitwardenSelfLicensor
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using McMaster.Extensions.CommandLineUtils;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace licenseGen;
|
|
||||||
|
|
||||||
internal class Program
|
|
||||||
{
|
{
|
||||||
private static Int32 Main(String[] args)
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SingleFileExtractor.Core;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
|
public static class Program
|
||||||
{
|
{
|
||||||
CommandLineApplication app = new();
|
public static int Main(string[] args)
|
||||||
CommandOption cert = app.Option("--cert", "cert file", CommandOptionType.SingleValue);
|
|
||||||
CommandOption coreDll = app.Option("--core", "path to core dll", CommandOptionType.SingleValue);
|
|
||||||
|
|
||||||
Boolean CertExists()
|
|
||||||
{
|
{
|
||||||
return File.Exists(cert.Value());
|
var app = new CommandLineApplication();
|
||||||
}
|
var cert = app.Option("--cert", "cert file", CommandOptionType.SingleValue);
|
||||||
|
var coreDll = app.Option("--core", "path to core dll", CommandOptionType.SingleValue);
|
||||||
|
var exec = app.Option("--executable", "path to Bitwarden single file executable", CommandOptionType.SingleValue);
|
||||||
|
|
||||||
Boolean CoreExists()
|
bool ExecExists() => File.Exists(exec.Value());
|
||||||
{
|
bool CertExists() => File.Exists(cert.Value());
|
||||||
return File.Exists(coreDll.Value());
|
bool CoreExists() => File.Exists(coreDll.Value());
|
||||||
}
|
bool VerifyTopOptions() =>
|
||||||
|
!string.IsNullOrWhiteSpace(cert.Value()) &&
|
||||||
Boolean VerifyTopOptions()
|
(!string.IsNullOrWhiteSpace(coreDll.Value()) || !string.IsNullOrWhiteSpace(exec.Value())) &&
|
||||||
{
|
CertExists() &&
|
||||||
return !String.IsNullOrWhiteSpace(cert.Value()) &&
|
(CoreExists() || ExecExists());
|
||||||
!String.IsNullOrWhiteSpace(coreDll.Value()) &&
|
string GetExtractedDll()
|
||||||
CertExists() && CoreExists();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Command("interactive", config =>
|
|
||||||
{
|
|
||||||
String buff, licenseType = "", name = "", email = "", businessName="";
|
|
||||||
Int16 storage = 0;
|
|
||||||
|
|
||||||
Boolean validGuid = false, validInstallid = false;
|
|
||||||
Guid guid = new(), installid = new();
|
|
||||||
|
|
||||||
config.OnExecute(() =>
|
|
||||||
{
|
{
|
||||||
if (!VerifyTopOptions())
|
var coreDllPath = Path.Combine("extract", "Core.dll");
|
||||||
{
|
var reader = new ExecutableReader(exec.Value());
|
||||||
if (!CoreExists()) config.Error.WriteLine($"Can't find core dll at: {coreDll.Value()}");
|
reader.ExtractToDirectory("extract");
|
||||||
if (!CertExists()) config.Error.WriteLine($"Can't find certificate at: {cert.Value()}");
|
var fileInfo = new FileInfo(coreDllPath);
|
||||||
|
return fileInfo.FullName;
|
||||||
config.ShowHelp();
|
}
|
||||||
return 1;
|
string GetCoreDllPath() => CoreExists() ? coreDll.Value() : GetExtractedDll();
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Interactive license mode...");
|
|
||||||
|
|
||||||
while (licenseType == "")
|
|
||||||
{
|
|
||||||
Console.WriteLine("What would you like to generate, a [u]ser license or an [o]rg license: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
|
|
||||||
if(buff == "u")
|
|
||||||
{
|
|
||||||
licenseType = "user";
|
|
||||||
Console.WriteLine("Okay, we will generate a user license.");
|
|
||||||
|
|
||||||
while (validGuid == false)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please provide the user's guid — refer to the Readme for details on how to retrieve this. [GUID]: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
|
|
||||||
if (Guid.TryParse(buff, out guid))validGuid = true;
|
|
||||||
else Console.WriteLine("The user-guid provided does not appear to be valid!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (buff == "o")
|
|
||||||
{
|
|
||||||
licenseType = "org";
|
|
||||||
Console.WriteLine("Okay, we will generate an organization license.");
|
|
||||||
|
|
||||||
while (validInstallid == false)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please provide your Bitwarden Install-ID — refer to the Readme for details on how to retrieve this. [Install-ID]: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
|
|
||||||
if (Guid.TryParse(buff, out installid)) validInstallid = true;
|
|
||||||
else Console.WriteLine("The install-id provided does not appear to be valid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (businessName == "")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please enter a business name, default is BitBetter. [Business Name]: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if (buff == "")
|
|
||||||
{
|
|
||||||
businessName = "BitBetter";
|
|
||||||
}
|
|
||||||
else if (CheckBusinessName(buff))
|
|
||||||
{
|
|
||||||
businessName = buff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("Unrecognized option \'" + buff + "\'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (name == "")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please provide the username this license will be registered to. [username]: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if ( CheckUsername(buff) ) name = buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (email == "")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please provide the email address for the user " + name + ". [email]: ");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if (CheckEmail(buff))
|
|
||||||
{
|
|
||||||
email = buff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (storage == 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Extra storage space for the user " + name + ". (max.: " + Int16.MaxValue + "). Defaults to maximum value. [storage]");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if (String.IsNullOrWhiteSpace(buff))
|
|
||||||
{
|
|
||||||
storage = Int16.MaxValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CheckStorage(buff))
|
|
||||||
{
|
|
||||||
storage = Int16.Parse(buff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (licenseType == "user")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Confirm creation of \"user\" license for username: \"" + name + "\", email: \"" + email + "\", Storage: \"" + storage + " GB\", User-GUID: \"" + guid + "\"? Y/n");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if ( buff is "" or "y" or "Y" )
|
|
||||||
{
|
|
||||||
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name, email, storage, guid, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("Exiting...");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (licenseType == "org")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Confirm creation of \"organization\" license for business name: \"" + businessName + "\", username: \"" + name + "\", email: \"" + email + "\", Storage: \"" + storage + " GB\", Install-ID: \"" + installid + "\"? Y/n");
|
|
||||||
buff = Console.ReadLine();
|
|
||||||
if ( buff is "" or "y" or "Y" )
|
|
||||||
{
|
|
||||||
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name, email, storage, installid, businessName, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("Exiting...");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
app.Command("user", config =>
|
|
||||||
{
|
|
||||||
CommandArgument name = config.Argument("Name", "your name");
|
|
||||||
CommandArgument email = config.Argument("Email", "your email");
|
|
||||||
CommandArgument userIdArg = config.Argument("User ID", "your user id");
|
|
||||||
CommandArgument storage = config.Argument("Storage", "extra storage space in GB. Maximum is " + Int16.MaxValue + " (optional, default = max)");
|
|
||||||
CommandArgument key = config.Argument("Key", "your key id (optional)");
|
|
||||||
|
|
||||||
config.OnExecute(() =>
|
|
||||||
{
|
|
||||||
if (!VerifyTopOptions())
|
|
||||||
{
|
|
||||||
if (!CoreExists())
|
|
||||||
{
|
|
||||||
config.Error.WriteLine($"Can't find core dll at: {coreDll.Value()}");
|
|
||||||
}
|
|
||||||
if (!CertExists())
|
|
||||||
{
|
|
||||||
config.Error.WriteLine($"Can't find certificate at: {cert.Value()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
config.ShowHelp();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(name.Value) || String.IsNullOrWhiteSpace(email.Value))
|
|
||||||
{
|
|
||||||
config.Error.WriteLine($"Some arguments are missing: Name='{name.Value}' Email='{email.Value}'");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(userIdArg.Value) || !Guid.TryParse(userIdArg.Value, out Guid userId))
|
|
||||||
{
|
|
||||||
config.Error.WriteLine("User ID not provided");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int16 storageShort = 0;
|
|
||||||
if (!String.IsNullOrWhiteSpace(storage.Value))
|
|
||||||
{
|
|
||||||
Double parsedStorage = Double.Parse(storage.Value);
|
|
||||||
if (parsedStorage is > Int16.MaxValue or < 0)
|
|
||||||
{
|
|
||||||
config.Error.WriteLine("The storage value provided is outside the accepted range of [0-" + Int16.MaxValue + "]");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
storageShort = (Int16) parsedStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name.Value, email.Value, storageShort, userId, key.Value);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
app.Command("org", config =>
|
|
||||||
{
|
|
||||||
CommandArgument name = config.Argument("Name", "your name");
|
|
||||||
CommandArgument email = config.Argument("Email", "your email");
|
|
||||||
CommandArgument installId = config.Argument("InstallId", "your installation id (GUID)");
|
|
||||||
CommandArgument storage = config.Argument("Storage", "extra storage space in GB. Maximum is " + Int16.MaxValue + " (optional, default = max)");
|
|
||||||
CommandArgument businessName = config.Argument("BusinessName", "name for the organization (optional)");
|
|
||||||
CommandArgument key = config.Argument("Key", "your key id (optional)");
|
|
||||||
|
|
||||||
config.OnExecute(() =>
|
app.Command("interactive", config =>
|
||||||
{
|
{
|
||||||
if (!VerifyTopOptions())
|
string buff="", licensetype="", name="", email="", businessname="";
|
||||||
|
short storage = 0;
|
||||||
|
|
||||||
|
bool valid_guid = false, valid_installid = false;
|
||||||
|
Guid guid = new Guid(), installid = new Guid();
|
||||||
|
|
||||||
|
config.OnExecute(() =>
|
||||||
{
|
{
|
||||||
if (!CoreExists())
|
if (!VerifyTopOptions())
|
||||||
{
|
{
|
||||||
config.Error.WriteLine($"Can't find core dll at: {coreDll.Value()}");
|
if (!ExecExists() && !string.IsNullOrWhiteSpace(exec.Value())) config.Error.WriteLine($"Cant find single file executable at: {exec.Value()}");
|
||||||
}
|
if (!CoreExists() && !string.IsNullOrWhiteSpace(coreDll.Value())) config.Error.WriteLine($"Cant find core dll at: {coreDll.Value()}");
|
||||||
if (!CertExists())
|
if (!CertExists()) config.Error.WriteLine($"Cant find certificate at: {cert.Value()}");
|
||||||
{
|
config.ShowHelp();
|
||||||
config.Error.WriteLine($"Can't find certificate at: {cert.Value()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
config.ShowHelp();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(name.Value) ||
|
|
||||||
String.IsNullOrWhiteSpace(email.Value) ||
|
|
||||||
String.IsNullOrWhiteSpace(installId.Value))
|
|
||||||
{
|
|
||||||
config.Error.WriteLine($"Some arguments are missing: Name='{name.Value}' Email='{email.Value}' InstallId='{installId.Value}'");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Guid.TryParse(installId.Value, out Guid installationId))
|
|
||||||
{
|
|
||||||
config.Error.WriteLine("Unable to parse your installation id as a GUID");
|
|
||||||
config.Error.WriteLine($"Here's a new guid: {Guid.NewGuid()}");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int16 storageShort = 0;
|
|
||||||
if (!String.IsNullOrWhiteSpace(storage.Value))
|
|
||||||
{
|
|
||||||
Double parsedStorage = Double.Parse(storage.Value);
|
|
||||||
if (parsedStorage is > Int16.MaxValue or < 0)
|
|
||||||
{
|
|
||||||
config.Error.WriteLine("The storage value provided is outside the accepted range of [0-" + Int16.MaxValue + "]");
|
|
||||||
config.ShowHelp(true);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
storageShort = (Int16) parsedStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), coreDll.Value(), name.Value, email.Value, storageShort, installationId, businessName.Value, key.Value);
|
WriteLine("Interactive license mode...");
|
||||||
|
|
||||||
return 0;
|
while (licensetype == "")
|
||||||
|
{
|
||||||
|
WriteLine("What would you like to generate, a [u]ser license or an [o]rg license?");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
|
||||||
|
if(buff == "u")
|
||||||
|
{
|
||||||
|
licensetype = "user";
|
||||||
|
WriteLineOver("Okay, we will generate a user license.");
|
||||||
|
|
||||||
|
while (valid_guid == false)
|
||||||
|
{
|
||||||
|
WriteLine("Please provide the user's guid — refer to the Readme for details on how to retrieve this. [GUID]:");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
|
||||||
|
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")
|
||||||
|
{
|
||||||
|
licensetype = "org";
|
||||||
|
WriteLineOver("Okay, we will generate an organization license.");
|
||||||
|
|
||||||
|
while (valid_installid == false)
|
||||||
|
{
|
||||||
|
WriteLine("Please provide your Bitwarden Install-ID — refer to the Readme for details on how to retrieve this. [Install-ID]:");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
|
||||||
|
if (Guid.TryParse(buff, out installid)) valid_installid = true;
|
||||||
|
else WriteLineOver("The install-id provided does not appear to be valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (businessname == "")
|
||||||
|
{
|
||||||
|
WriteLineOver("Please enter a business name, default is BitBetter. [Business Name]:");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if (buff == "") businessname = "BitBetter";
|
||||||
|
else if (CheckBusinessName(buff)) businessname = buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLineOver("Unrecognized option \'" + buff + "\'. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (name == "")
|
||||||
|
{
|
||||||
|
WriteLineOver("Please provide the username this license will be registered to. [username]:");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if ( CheckUsername(buff) ) name = buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (email == "")
|
||||||
|
{
|
||||||
|
WriteLineOver("Please provide the email address for the user " + name + ". [email]");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if ( CheckEmail(buff) ) email = buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (storage == 0)
|
||||||
|
{
|
||||||
|
WriteLineOver("Extra storage space for the user " + name + ". (max.: " + short.MaxValue + "). Defaults to maximum value. [storage]");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if (string.IsNullOrWhiteSpace(buff))
|
||||||
|
{
|
||||||
|
storage = short.MaxValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CheckStorage(buff)) storage = short.Parse(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (licensetype == "user")
|
||||||
|
{
|
||||||
|
WriteLineOver("Confirm creation of \"user\" license for username: \"" + name + "\", email: \"" + email + "\", Storage: \"" + storage + " GB\", User-GUID: \"" + guid + "\"? Y/n");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if ( buff == "" || buff == "y" || buff == "Y" )
|
||||||
|
{
|
||||||
|
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, guid, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLineOver("Exiting...");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (licensetype == "org")
|
||||||
|
{
|
||||||
|
WriteLineOver("Confirm creation of \"organization\" license for business name: \"" + businessname + "\", username: \"" + name + "\", email: \"" + email + "\", Storage: \"" + storage + " GB\", Install-ID: \"" + installid + "\"? Y/n");
|
||||||
|
buff = Console.ReadLine();
|
||||||
|
if ( buff == "" || buff == "y" || buff == "Y" )
|
||||||
|
{
|
||||||
|
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, installid, businessname, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLineOver("Exiting...");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
app.OnExecute(() =>
|
app.Command("user", config =>
|
||||||
{
|
{
|
||||||
app.ShowHelp();
|
var name = config.Argument("Name", "your name");
|
||||||
return 10;
|
var email = config.Argument("Email", "your email");
|
||||||
});
|
var userIdArg = config.Argument("User ID", "your user id");
|
||||||
|
var storage = config.Argument("Storage", "extra storage space in GB. Maximum is " + short.MaxValue + " (optional, default = max)");
|
||||||
|
var key = config.Argument("Key", "your key id (optional)");
|
||||||
|
var help = config.HelpOption("--help | -h | -?");
|
||||||
|
|
||||||
app.HelpOption("-? | -h | --help");
|
config.OnExecute(() =>
|
||||||
|
{
|
||||||
|
if (!VerifyTopOptions())
|
||||||
|
{
|
||||||
|
if (!ExecExists() && !string.IsNullOrWhiteSpace(exec.Value())) config.Error.WriteLine($"Cant find single file executable at: {exec.Value()}");
|
||||||
|
if (!CoreExists() && !string.IsNullOrWhiteSpace(coreDll.Value())) config.Error.WriteLine($"Cant find core dll at: {coreDll.Value()}");
|
||||||
|
if (!CertExists()) config.Error.WriteLine($"Cant find certificate at: {cert.Value()}");
|
||||||
|
config.ShowHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrWhiteSpace(name.Value) || string.IsNullOrWhiteSpace(email.Value))
|
||||||
|
{
|
||||||
|
config.Error.WriteLine($"Some arguments are missing: Name='{name.Value}' Email='{email.Value}'");
|
||||||
|
config.ShowHelp("user");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
if (string.IsNullOrWhiteSpace(userIdArg.Value) || !Guid.TryParse(userIdArg.Value, out Guid userId))
|
||||||
{
|
{
|
||||||
return app.Execute(args);
|
config.Error.WriteLine($"User ID not provided");
|
||||||
}
|
config.ShowHelp("user");
|
||||||
catch (Exception e)
|
return 1;
|
||||||
{
|
}
|
||||||
Console.Error.WriteLine("Oops: {0}", e);
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkUsername Checks that the username is a valid username
|
short storageShort = 0;
|
||||||
private static Boolean CheckUsername(String s)
|
if (!string.IsNullOrWhiteSpace(storage.Value))
|
||||||
{
|
{
|
||||||
// TODO: Actually validate
|
var parsedStorage = double.Parse(storage.Value);
|
||||||
if (!String.IsNullOrWhiteSpace(s)) return true;
|
if (parsedStorage > short.MaxValue || parsedStorage < 0)
|
||||||
|
{
|
||||||
|
config.Error.WriteLine("The storage value provided is outside the accepted range of [0-" + short.MaxValue + "]");
|
||||||
|
config.ShowHelp("org");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
storageShort = (short) parsedStorage;
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine("The username provided doesn't appear to be valid!");
|
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, userId, key.Value);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkBusinessName Checks that the Business Name is a valid username
|
return 0;
|
||||||
private static Boolean CheckBusinessName(String s)
|
});
|
||||||
{
|
});
|
||||||
// TODO: Actually validate
|
app.Command("org", config =>
|
||||||
if (!String.IsNullOrWhiteSpace(s)) return true;
|
{
|
||||||
|
var name = config.Argument("Name", "your name");
|
||||||
|
var email = config.Argument("Email", "your email");
|
||||||
|
var installId = config.Argument("InstallId", "your installation id (GUID)");
|
||||||
|
var storage = config.Argument("Storage", "extra storage space in GB. Maximum is " + short.MaxValue + " (optional, default = max)");
|
||||||
|
var businessName = config.Argument("BusinessName", "name for the organization (optional)");
|
||||||
|
var key = config.Argument("Key", "your key id (optional)");
|
||||||
|
var help = config.HelpOption("--help | -h | -?");
|
||||||
|
|
||||||
Console.WriteLine("The Business Name provided doesn't appear to be valid!");
|
config.OnExecute(() =>
|
||||||
return false;
|
{
|
||||||
}
|
if (!VerifyTopOptions())
|
||||||
|
{
|
||||||
|
if (!ExecExists() && !string.IsNullOrWhiteSpace(exec.Value())) config.Error.WriteLine($"Cant find single file executable at: {exec.Value()}");
|
||||||
|
if (!CoreExists() && !string.IsNullOrWhiteSpace(coreDll.Value())) config.Error.WriteLine($"Cant find core dll at: {coreDll.Value()}");
|
||||||
|
if (!CertExists()) config.Error.WriteLine($"Cant find certificate at: {cert.Value()}");
|
||||||
|
config.ShowHelp();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrWhiteSpace(name.Value) ||
|
||||||
|
string.IsNullOrWhiteSpace(email.Value) ||
|
||||||
|
string.IsNullOrWhiteSpace(installId.Value))
|
||||||
|
{
|
||||||
|
config.Error.WriteLine($"Some arguments are missing: Name='{name.Value}' Email='{email.Value}' InstallId='{installId.Value}'");
|
||||||
|
config.ShowHelp("org");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// checkEmail Checks that the email address is a valid email address
|
if (!Guid.TryParse(installId.Value, out Guid installationId))
|
||||||
private static Boolean CheckEmail(String s)
|
{
|
||||||
{
|
config.Error.WriteLine("Unable to parse your installation id as a GUID");
|
||||||
// TODO: Actually validate
|
config.Error.WriteLine($"Here's a new guid: {Guid.NewGuid()}");
|
||||||
if (!String.IsNullOrWhiteSpace(s)) return true;
|
config.ShowHelp("org");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine("The email provided doesn't appear to be valid!");
|
short storageShort = 0;
|
||||||
return false;
|
if (!string.IsNullOrWhiteSpace(storage.Value))
|
||||||
}
|
{
|
||||||
|
var parsedStorage = double.Parse(storage.Value);
|
||||||
|
if (parsedStorage > short.MaxValue || parsedStorage < 0)
|
||||||
|
{
|
||||||
|
config.Error.WriteLine("The storage value provided is outside the accepted range of [0-" + short.MaxValue + "]");
|
||||||
|
config.ShowHelp("org");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
storageShort = (short) parsedStorage;
|
||||||
|
}
|
||||||
|
|
||||||
// checkStorage Checks that the storage is in a valid range
|
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, installationId, businessName.Value, key.Value);
|
||||||
private static Boolean CheckStorage(String s)
|
|
||||||
{
|
return 0;
|
||||||
if (String.IsNullOrWhiteSpace(s))
|
});
|
||||||
{
|
});
|
||||||
Console.WriteLine("The storage provided doesn't appear to be valid!");
|
|
||||||
return false;
|
app.OnExecute(() =>
|
||||||
|
{
|
||||||
|
app.ShowHelp();
|
||||||
|
return 10;
|
||||||
|
});
|
||||||
|
|
||||||
|
app.HelpOption("-? | -h | --help");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return app.Execute(args);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Oops: {0}", e);
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(Double.Parse(s) > Int16.MaxValue) && !(Double.Parse(s) < 0)) return true;
|
// checkUsername Checks that the username is a valid username
|
||||||
|
private static bool CheckUsername(string s)
|
||||||
Console.WriteLine("The storage value provided is outside the accepted range of [0-" + Int16.MaxValue + "]!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GenerateUserLicense(X509Certificate2 cert, String corePath, String userName, String email, Int16 storage, Guid userId, String key)
|
|
||||||
{
|
|
||||||
Assembly core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath);
|
|
||||||
|
|
||||||
Type type = core.GetType("Bit.Core.Models.Business.UserLicense");
|
|
||||||
Type licenseTypeEnum = core.GetType("Bit.Core.Enums.LicenseType");
|
|
||||||
|
|
||||||
Object license = Activator.CreateInstance(type);
|
|
||||||
|
|
||||||
Set("LicenseKey", String.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
|
||||||
Set("Id", userId);
|
|
||||||
Set("Name", userName);
|
|
||||||
Set("Email", email);
|
|
||||||
Set("Premium", true);
|
|
||||||
Set("MaxStorageGb", storage == 0 ? Int16.MaxValue : storage);
|
|
||||||
Set("Version", 1);
|
|
||||||
Set("Issued", DateTime.UtcNow);
|
|
||||||
Set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
|
||||||
Set("Expires", DateTime.UtcNow.AddYears(100));
|
|
||||||
Set("Trial", false);
|
|
||||||
Set("LicenseType", Enum.Parse(licenseTypeEnum, "User"));
|
|
||||||
|
|
||||||
Set("Hash", Convert.ToBase64String((Byte[])type.GetMethod("ComputeHash").Invoke(license, [])));
|
|
||||||
Set("Signature", Convert.ToBase64String((Byte[])type.GetMethod("Sign").Invoke(license, [cert])));
|
|
||||||
|
|
||||||
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
|
||||||
return;
|
|
||||||
|
|
||||||
void Set(String name, Object value)
|
|
||||||
{
|
{
|
||||||
type.GetProperty(name)?.SetValue(license, value);
|
if ( string.IsNullOrWhiteSpace(s) ) {
|
||||||
|
WriteLineOver("The username provided doesn't appear to be valid.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // TODO: Actually validate
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkBusinessName Checks that the Business Name is a valid username
|
||||||
|
private static bool CheckBusinessName(string s)
|
||||||
|
{
|
||||||
|
if ( string.IsNullOrWhiteSpace(s) ) {
|
||||||
|
WriteLineOver("The Business Name provided doesn't appear to be valid.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // TODO: Actually validate
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkEmail Checks that the email address is a valid email address
|
||||||
|
private static bool CheckEmail(string s)
|
||||||
|
{
|
||||||
|
if ( string.IsNullOrWhiteSpace(s) ) {
|
||||||
|
WriteLineOver("The email provided doesn't appear to be valid.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // TODO: Actually validate
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkStorage Checks that the storage is in a valid range
|
||||||
|
private static bool CheckStorage(string s)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(s))
|
||||||
|
{
|
||||||
|
WriteLineOver("The storage provided doesn't appear to be valid.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (double.Parse(s) > short.MaxValue || double.Parse(s) < 0)
|
||||||
|
{
|
||||||
|
WriteLineOver("The storage value provided is outside the accepted range of [0-" + short.MaxValue + "].\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteLineOver Writes a new line to console over last line.
|
||||||
|
private static void WriteLineOver(string s)
|
||||||
|
{
|
||||||
|
Console.SetCursorPosition(0, Console.CursorTop -1);
|
||||||
|
Console.WriteLine(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteLine This wrapper is just here so that console writes all look similar.
|
||||||
|
private static void WriteLine(string s) => Console.WriteLine(s);
|
||||||
|
|
||||||
|
private static void GenerateUserLicense(X509Certificate2 cert, string corePath, string userName, string email, short storage, Guid userId, string key)
|
||||||
|
{
|
||||||
|
var core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath);
|
||||||
|
|
||||||
|
var type = core.GetType("Bit.Core.Billing.Models.Business.UserLicense");
|
||||||
|
var licenseTypeEnum = core.GetType("Bit.Core.Enums.LicenseType");
|
||||||
|
|
||||||
|
var license = Activator.CreateInstance(type);
|
||||||
|
|
||||||
|
void set(string name, object value)
|
||||||
|
{
|
||||||
|
type.GetProperty(name).SetValue(license, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
set("LicenseKey", string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
||||||
|
set("Id", userId);
|
||||||
|
set("Name", userName);
|
||||||
|
set("Email", email);
|
||||||
|
set("Premium", true);
|
||||||
|
set("MaxStorageGb", storage == 0 ? short.MaxValue : storage);
|
||||||
|
set("Version", 1);
|
||||||
|
set("Issued", DateTime.UtcNow);
|
||||||
|
set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
||||||
|
set("Expires", DateTime.UtcNow.AddYears(100));
|
||||||
|
set("Trial", false);
|
||||||
|
set("LicenseType", Enum.Parse(licenseTypeEnum, "User"));
|
||||||
|
|
||||||
|
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 })));
|
||||||
|
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateOrgLicense(X509Certificate2 cert, string corePath, string userName, string email, short storage, Guid instalId, string businessName, string key)
|
||||||
|
{
|
||||||
|
var core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath);
|
||||||
|
|
||||||
|
var type = core.GetType("Bit.Core.Billing.Organizations.Models.OrganizationLicense");
|
||||||
|
var licenseTypeEnum = core.GetType("Bit.Core.Enums.LicenseType");
|
||||||
|
var planTypeEnum = core.GetType("Bit.Core.Billing.Enums.PlanType");
|
||||||
|
|
||||||
|
var license = Activator.CreateInstance(type);
|
||||||
|
|
||||||
|
void set(string name, object value)
|
||||||
|
{
|
||||||
|
type.GetProperty(name).SetValue(license, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
set("LicenseKey", string.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
||||||
|
set("InstallationId", instalId);
|
||||||
|
set("Id", Guid.NewGuid());
|
||||||
|
set("Name", userName);
|
||||||
|
set("BillingEmail", email);
|
||||||
|
set("BusinessName", string.IsNullOrWhiteSpace(businessName) ? "BitBetter" : businessName);
|
||||||
|
set("Enabled", true);
|
||||||
|
set("Plan", "Enterprise (Annually)");
|
||||||
|
set("PlanType", Enum.Parse(planTypeEnum, "EnterpriseAnnually"));
|
||||||
|
set("Seats", int.MaxValue);
|
||||||
|
set("MaxCollections", short.MaxValue);
|
||||||
|
set("UsePolicies", true);
|
||||||
|
set("UseSso", true);
|
||||||
|
set("UseKeyConnector", true);
|
||||||
|
set("UseScim", true);
|
||||||
|
set("UseGroups", true);
|
||||||
|
set("UseEvents", true);
|
||||||
|
set("UseDirectory", true);
|
||||||
|
set("UseTotp", true);
|
||||||
|
set("Use2fa", true);
|
||||||
|
set("UseApi", true);
|
||||||
|
set("UseResetPassword", true);
|
||||||
|
set("UseCustomPermissions", true);
|
||||||
|
set("MaxStorageGb", storage == 0 ? short.MaxValue : storage);
|
||||||
|
set("SelfHost", true);
|
||||||
|
set("UsersGetPremium", true);
|
||||||
|
set("UsePasswordManager", true);
|
||||||
|
set("UseSecretsManager", true);
|
||||||
|
set("SmSeats", 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("Issued", DateTime.UtcNow);
|
||||||
|
set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
||||||
|
set("Expires", DateTime.UtcNow.AddYears(100));
|
||||||
|
set("Trial", false);
|
||||||
|
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("AllowAdminAccessToAllCollectionItems", true);
|
||||||
|
set("UseRiskInsights", true);
|
||||||
|
set("UseOrganizationDomains", true);
|
||||||
|
set("UseAdminSponsoredFamilies", true);
|
||||||
|
|
||||||
|
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 })));
|
||||||
|
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static void GenerateOrgLicense(X509Certificate2 cert, String corePath, String userName, String email, Int16 storage, Guid instalId, String businessName, String key)
|
|
||||||
{
|
|
||||||
Assembly core = AssemblyLoadContext.Default.LoadFromAssemblyPath(corePath);
|
|
||||||
|
|
||||||
Type type = core.GetType("Bit.Core.Models.Business.OrganizationLicense");
|
|
||||||
Type licenseTypeEnum = core.GetType("Bit.Core.Enums.LicenseType");
|
|
||||||
Type planTypeEnum = core.GetType("Bit.Core.Billing.Enums.PlanType");
|
|
||||||
|
|
||||||
Object license = Activator.CreateInstance(type);
|
|
||||||
|
|
||||||
Set("LicenseKey", String.IsNullOrWhiteSpace(key) ? Guid.NewGuid().ToString("n") : key);
|
|
||||||
Set("InstallationId", instalId);
|
|
||||||
Set("Id", Guid.NewGuid());
|
|
||||||
Set("Name", userName);
|
|
||||||
Set("BillingEmail", email);
|
|
||||||
Set("BusinessName", String.IsNullOrWhiteSpace(businessName) ? "BitBetter" : businessName);
|
|
||||||
Set("Enabled", true);
|
|
||||||
Set("Plan", "Enterprise (Annually)");
|
|
||||||
Set("PlanType", Enum.Parse(planTypeEnum, "EnterpriseAnnually"));
|
|
||||||
Set("Seats", Int32.MaxValue);
|
|
||||||
Set("MaxCollections", Int16.MaxValue);
|
|
||||||
Set("UsePolicies", true);
|
|
||||||
Set("UseSso", true);
|
|
||||||
Set("UseKeyConnector", true);
|
|
||||||
Set("UseScim", true);
|
|
||||||
Set("UseGroups", true);
|
|
||||||
Set("UseEvents", true);
|
|
||||||
Set("UseDirectory", true);
|
|
||||||
Set("UseTotp", true);
|
|
||||||
Set("Use2fa", true);
|
|
||||||
Set("UseApi", true);
|
|
||||||
Set("UseResetPassword", true);
|
|
||||||
Set("UseCustomPermissions", true);
|
|
||||||
Set("MaxStorageGb", storage == 0 ? Int16.MaxValue : storage);
|
|
||||||
Set("SelfHost", true);
|
|
||||||
Set("UsersGetPremium", true);
|
|
||||||
Set("UsePasswordManager", true);
|
|
||||||
Set("UseSecretsManager", true);
|
|
||||||
Set("SmSeats", Int32.MaxValue);
|
|
||||||
Set("SmServiceAccounts", Int32.MaxValue);
|
|
||||||
Set("Version", 15); //This is set to 15 to use AllowAdminAccessToAllCollectionItems can be changed to 13 to just use Secrets Manager
|
|
||||||
Set("Issued", DateTime.UtcNow);
|
|
||||||
Set("Refresh", DateTime.UtcNow.AddYears(100).AddMonths(-1));
|
|
||||||
Set("Expires", DateTime.UtcNow.AddYears(100));
|
|
||||||
Set("Trial", false);
|
|
||||||
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("AllowAdminAccessToAllCollectionItems", true);
|
|
||||||
|
|
||||||
Set("Hash", Convert.ToBase64String((Byte[])type.GetMethod("ComputeHash").Invoke(license, [])));
|
|
||||||
Set("Signature", Convert.ToBase64String((Byte[])type.GetMethod("Sign").Invoke(license, [cert])));
|
|
||||||
|
|
||||||
Console.WriteLine(JsonConvert.SerializeObject(license, Formatting.Indented));
|
|
||||||
return;
|
|
||||||
|
|
||||||
void Set(String name, Object value)
|
|
||||||
{
|
|
||||||
type.GetProperty(name)?.SetValue(license, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
6
src/licenseGen/build.sh
Executable file
6
src/licenseGen/build.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DIR=`dirname "$0"`
|
||||||
|
DIR=`exec 2>/dev/null;(cd -- "$DIR") && cd -- "$DIR"|| cd "$DIR"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
|
||||||
|
|
||||||
|
docker build -t bitbetter/licensegen "$DIR" # --squash
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
|
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
||||||
<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="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
26
src/licenseGen/run.sh
Executable file
26
src/licenseGen/run.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DIR=`dirname "$0"`
|
||||||
|
DIR=`exec 2>/dev/null;(cd -- "$DIR") && cd -- "$DIR"|| cd "$DIR"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
|
||||||
|
|
||||||
|
# Grab the absolute path to the default pfx location
|
||||||
|
cert_path="$DIR/../../.keys/cert.pfx"
|
||||||
|
|
||||||
|
if [ "$#" -lt "2" ]; then
|
||||||
|
echo "USAGE: $0 <ABSOLUTE PATH TO CERT.PFX> <License Gen action> [License Gen args...]"
|
||||||
|
echo "ACTIONS:"
|
||||||
|
echo " interactive"
|
||||||
|
echo " user"
|
||||||
|
echo " org"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cert_path="$1"
|
||||||
|
action="$2"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ $action = "interactive" ]; then
|
||||||
|
docker run -it --rm -v "$cert_path:/cert.pfx" bitbetter/licensegen "$@"
|
||||||
|
else
|
||||||
|
docker run --rm -v "$cert_path:/cert.pfx" bitbetter/licensegen "$@"
|
||||||
|
fi
|
||||||
85
update-bitwarden.sh
Executable file
85
update-bitwarden.sh
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
ask () {
|
||||||
|
local __resultVar=$1
|
||||||
|
local __result="$2"
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
read -p "$3" __result
|
||||||
|
fi
|
||||||
|
eval $__resultVar="'$__result'"
|
||||||
|
}
|
||||||
|
|
||||||
|
SCRIPT_BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
BW_VERSION=$(curl -sL https://go.btwrdn.co/bw-sh-versions | grep '^ *"'coreVersion'":' | awk -F\: '{ print $2 }' | sed -e 's/,$//' -e 's/^"//' -e 's/"$//')
|
||||||
|
|
||||||
|
echo "Starting Bitwarden update, newest server version: $BW_VERSION"
|
||||||
|
|
||||||
|
# Default path is the parent directory of the BitBetter location
|
||||||
|
BITWARDEN_BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
# Get Bitwarden base from user (or keep default value) or use first argument
|
||||||
|
ask tmpbase "$1" "Enter Bitwarden base directory [$BITWARDEN_BASE]: "
|
||||||
|
BITWARDEN_BASE=${tmpbase:-$BITWARDEN_BASE}
|
||||||
|
|
||||||
|
# Check if directory exists and is valid
|
||||||
|
[ -d "$BITWARDEN_BASE" ] || { echo "Bitwarden base directory $BITWARDEN_BASE not found!"; exit 1; }
|
||||||
|
[ -f "$BITWARDEN_BASE/bitwarden.sh" ] || { echo "Bitwarden base directory $BITWARDEN_BASE is not valid!"; exit 1; }
|
||||||
|
|
||||||
|
# Check if user wants to recreate the docker-compose override file
|
||||||
|
RECREATE_OV="y"
|
||||||
|
ask tmprecreate "$2" "Rebuild docker-compose override? [Y/n]: "
|
||||||
|
RECREATE_OV=${tmprecreate:-$RECREATE_OV}
|
||||||
|
|
||||||
|
if [[ $RECREATE_OV =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
{
|
||||||
|
echo "services:"
|
||||||
|
echo " api:"
|
||||||
|
echo " image: bitbetter/api:$BW_VERSION"
|
||||||
|
echo " pull_policy: never"
|
||||||
|
echo ""
|
||||||
|
echo " identity:"
|
||||||
|
echo " image: bitbetter/identity:$BW_VERSION"
|
||||||
|
echo " pull_policy: never"
|
||||||
|
echo ""
|
||||||
|
} > $BITWARDEN_BASE/bwdata/docker/docker-compose.override.yml
|
||||||
|
echo "BitBetter docker-compose override created!"
|
||||||
|
else
|
||||||
|
echo "Make sure to check if the docker override contains the correct image version ($BW_VERSION) in $BITWARDEN_BASE/bwdata/docker/docker-compose.override.yml!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if user wants to rebuild the bitbetter images
|
||||||
|
docker images bitbetter/api --format="{{ .Tag }}" | grep -F -- "${BW_VERSION}" > /dev/null
|
||||||
|
retval=$?
|
||||||
|
REBUILD_BB="n"
|
||||||
|
REBUILD_BB_DESCR="[y/N]"
|
||||||
|
if [ $retval -ne 0 ]; then
|
||||||
|
REBUILD_BB="y"
|
||||||
|
REBUILD_BB_DESCR="[Y/n]"
|
||||||
|
fi
|
||||||
|
ask tmprebuild "$3" "Rebuild BitBetter images? $REBUILD_BB_DESCR: "
|
||||||
|
REBUILD_BB=${tmprebuild:-$REBUILD_BB}
|
||||||
|
|
||||||
|
if [[ $REBUILD_BB =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
$SCRIPT_BASE/build.sh
|
||||||
|
echo "BitBetter images updated to version: $BW_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now start the bitwarden update
|
||||||
|
cd $BITWARDEN_BASE
|
||||||
|
|
||||||
|
./bitwarden.sh updateself
|
||||||
|
|
||||||
|
# Update the bitwarden.sh: automatically patch run.sh to fix docker-compose pull errors for private images
|
||||||
|
sed -i 's/chmod u+x $SCRIPTS_DIR\/run.sh/chmod u+x $SCRIPTS_DIR\/run.sh\n sed -i \x27s\/dccmd pull\/dccmd pull --ignore-pull-failures || true\/g\x27 $SCRIPTS_DIR\/run.sh/g' -i $BITWARDEN_BASE/bitwarden.sh
|
||||||
|
chmod +x $BITWARDEN_BASE/bitwarden.sh
|
||||||
|
echo "Patching bitwarden.sh completed..."
|
||||||
|
|
||||||
|
./bitwarden.sh update
|
||||||
|
|
||||||
|
# Prune Docker images without at least one container associated to them.
|
||||||
|
echo "Pruning Docker images without at least one container associated to them..."
|
||||||
|
docker image prune -a
|
||||||
|
|
||||||
|
cd $SCRIPT_BASE
|
||||||
|
echo "Bitwarden update completed!"
|
||||||
Reference in New Issue
Block a user