mirror of
https://github.com/jakeswenson/BitBetter.git
synced 2026-07-21 15:49:49 +00:00
Compare commits
3 Commits
lite
...
5983335e9f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5983335e9f | ||
|
|
a6a5a3a7df | ||
|
|
14d7d29845 |
@@ -1,21 +1,21 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
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: ./generateKeys.sh
|
||||||
- run:
|
- run:
|
||||||
name: Build script
|
name: Build script
|
||||||
command: ./build.sh update
|
command: ./build.sh update
|
||||||
- run:
|
- run:
|
||||||
name: Test generating user license
|
name: Test generating user license
|
||||||
command: ./licenseGen.sh user TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
command: ./licenseGen.sh user TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
||||||
- run:
|
- run:
|
||||||
name: Test generating organization license
|
name: Test generating organization license
|
||||||
command: ./licenseGen.sh org TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
command: ./licenseGen.sh org TestName TestEmail@example.com 4a619d4a-522d-4c70-8596-affb5b607c23
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
root=true
|
|
||||||
|
|
||||||
###############################
|
|
||||||
# Core EditorConfig Options #
|
|
||||||
###############################
|
|
||||||
# All files
|
|
||||||
[*]
|
|
||||||
indent_style=tab
|
|
||||||
indent_size=4
|
|
||||||
trim_trailing_whitespace=true
|
|
||||||
end_of_line=lf
|
|
||||||
charset=utf-8
|
|
||||||
|
|
||||||
[*.{cs}]
|
|
||||||
insert_final_newline=false
|
|
||||||
|
|
||||||
[*.{md,mkdn}]
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
indent_style = space
|
|
||||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
* text eol=lf
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,4 +9,3 @@ src/bitBetter/.vs/*
|
|||||||
*.pfx
|
*.pfx
|
||||||
*.cer
|
*.cer
|
||||||
*.vsidx
|
*.vsidx
|
||||||
.DS_Store
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Uncomment a line below and fill in the missing values or add your own. Every line in this file will be called by build.[sh|ps1] once the patched image is built.
|
# Uncomment a line below and fill in the missing values or add your own. Every line in this file will be called by build.[sh|ps1] once the patched image is built.
|
||||||
# docker run -d --name bitwarden --restart=always -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-patched
|
# docker run -d --name bitwarden --restart=always -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-patched
|
||||||
# <OR>
|
# <OR>
|
||||||
# docker-compose -f <full-local-path>/docker-compose.yml up -d
|
# docker-compose -f <full-local-path>/docker-compose.yml up -d
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -1,14 +1,12 @@
|
|||||||
# BitBetter lite
|
# 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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
Be aware that this branch is **only** for the lite (formerly unified) version of bitwarden. It has been rewritten and works in different ways than the master branch.
|
_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!_
|
||||||
|
|
||||||
_Beware! BitBetter is a solution that generates a personal certificate and uses that to generate custom licences. This requires (automated) modifying of libraries. 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 and https://github.com/GieltjE/BitBetter
|
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
- [BitBetter](#bitbetter)
|
- [BitBetter](#bitbetter)
|
||||||
@@ -32,14 +30,14 @@ The following instructions are for unix-based systems (Linux, BSD, macOS) and Wi
|
|||||||
## 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 2025.11.1 might work on lower versions), for safety always stay up to date
|
* 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, on Windows it will be auto installed using winget)
|
||||||
|
|
||||||
## 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:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/jakeswenson/BitBetter.git -b lite
|
git clone https://github.com/jakeswenson/BitBetter.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### Optional: Manually generating Certificate & Key
|
### Optional: Manually generating Certificate & Key
|
||||||
@@ -158,15 +156,6 @@ docker exec bitwarden ln -s /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime
|
|||||||
|
|
||||||
Require a recreation of the docker container, build.sh will suffice too.
|
Require a recreation of the docker container, build.sh will suffice too.
|
||||||
|
|
||||||
## Migrating from the old unified branch
|
|
||||||
|
|
||||||
```
|
|
||||||
git branch -m unified lite
|
|
||||||
git fetch origin
|
|
||||||
git branch -u origin/lite lite
|
|
||||||
git remote set-head origin -a
|
|
||||||
```
|
|
||||||
|
|
||||||
# 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>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.
|
||||||
|
|||||||
30
build.ps1
30
build.ps1
@@ -4,10 +4,6 @@ $PSNativeCommandUseErrorActionPreference = $true
|
|||||||
# detect buildx, ErrorActionPreference will ensure the script stops execution if not found
|
# detect buildx, ErrorActionPreference will ensure the script stops execution if not found
|
||||||
docker buildx version
|
docker buildx version
|
||||||
|
|
||||||
# Enable BuildKit for better build experience and to ensure platform args are populated
|
|
||||||
$env:DOCKER_BUILDKIT=1
|
|
||||||
$env:COMPOSE_DOCKER_CLI_BUILD=1
|
|
||||||
|
|
||||||
# define temporary directory
|
# define temporary directory
|
||||||
$tempdirectory = "$pwd\temp"
|
$tempdirectory = "$pwd\temp"
|
||||||
# define services to patch
|
# define services to patch
|
||||||
@@ -57,11 +53,11 @@ foreach ($instance in $oldinstances) {
|
|||||||
|
|
||||||
# update bitwarden itself
|
# update bitwarden itself
|
||||||
if ($args[0] -eq 'update') {
|
if ($args[0] -eq 'update') {
|
||||||
docker pull ghcr.io/bitwarden/lite:latest
|
docker pull ghcr.io/bitwarden/lite:beta
|
||||||
} else {
|
} else {
|
||||||
$confirmation = Read-Host "Update (or get) bitwarden source container (y/n)"
|
$confirmation = Read-Host "Update (or get) bitwarden source container (y/n)"
|
||||||
if ($confirmation -eq 'y') {
|
if ($confirmation -eq 'y') {
|
||||||
docker pull ghcr.io/bitwarden/lite:latest
|
docker pull ghcr.io/bitwarden/lite:beta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +80,7 @@ foreach ($instance in $oldinstances) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# start a new bitwarden instance so we can patch it
|
# start a new bitwarden instance so we can patch it
|
||||||
$patchinstance = docker run -d --name bitwarden-extract ghcr.io/bitwarden/lite:latest
|
$patchinstance = docker run -d --name bitwarden-extract ghcr.io/bitwarden/lite:beta
|
||||||
|
|
||||||
# create our temporary directory
|
# create our temporary directory
|
||||||
New-item -ItemType Directory -Path $tempdirectory
|
New-item -ItemType Directory -Path $tempdirectory
|
||||||
@@ -92,8 +88,7 @@ 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
|
# extract the files that need to be patched from the services that need to be patched into our temporary directory
|
||||||
foreach ($component in $components) {
|
foreach ($component in $components) {
|
||||||
New-item -itemtype Directory -path "$tempdirectory\$component"
|
New-item -itemtype Directory -path "$tempdirectory\$component"
|
||||||
docker cp $patchinstance`:/app/$component/$component "$tempdirectory\$component\$component"
|
docker cp $patchinstance`:/app/$component/Core.dll "$tempdirectory\$component\Core.dll"
|
||||||
docker cp $patchinstance`:/etc/supervisor.d/$($component.ToLower()).ini "$tempdirectory\$($component.ToLower()).ini"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# stop and remove our temporary container
|
# stop and remove our temporary container
|
||||||
@@ -104,25 +99,12 @@ docker rm bitwarden-extract
|
|||||||
docker run -v "$tempdirectory`:/app/mount" --rm bitbetter/bitbetter
|
docker run -v "$tempdirectory`:/app/mount" --rm bitbetter/bitbetter
|
||||||
|
|
||||||
# create a new image with the patched files
|
# create a new image with the patched files
|
||||||
if (Test-Path -Path "$pwd\Dockerfile-bitwarden-patch" -PathType Leaf) {
|
docker build . --tag bitwarden-patched --file "$pwd\src\bitBetter\Dockerfile-bitwarden-patch"
|
||||||
Remove-Item "$pwd\Dockerfile-bitwarden-patch" -Force
|
|
||||||
}
|
|
||||||
$dockerFile = "FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine3.23"
|
|
||||||
$dockerFile = -join($dockerFile, "FROM ghcr.io/bitwarden/lite:latest")
|
|
||||||
$dockerFile = -join($dockerFile, "COPY --from=0 /usr/share/dotnet /usr/share/dotnet")
|
|
||||||
foreach ($component in $components) {
|
|
||||||
$dockerFile = -join($dockerFile, "`n`nCOPY ./temp/$component/ /app/$component/")
|
|
||||||
$dockerFile = -join($dockerFile, "`nCOPY ./temp/$($component.ToLower()).ini /etc/supervisor.d/$($component.ToLower()).ini")
|
|
||||||
$dockerFile = -join($dockerFile, "`nRUN rm -f /app/$component/$component")
|
|
||||||
}
|
|
||||||
[System.IO.File]::WriteAllLines("$pwd\Dockerfile-bitwarden-patch", $dockerFile)
|
|
||||||
docker build . --tag bitwarden-patched --file "$pwd\Dockerfile-bitwarden-patch"
|
|
||||||
Remove-Item "$pwd\Dockerfile-bitwarden-patch" -Force
|
|
||||||
|
|
||||||
# start all user requested instances
|
# start all user requested instances
|
||||||
if (Test-Path -Path "$pwd\.servers\serverlist.txt" -PathType Leaf) {
|
if (Test-Path -Path "$pwd\.servers\serverlist.txt" -PathType Leaf) {
|
||||||
foreach($line in Get-Content "$pwd\.servers\serverlist.txt") {
|
foreach($line in Get-Content "$pwd\.servers\serverlist.txt") {
|
||||||
if ((-not ($line.StartsWith("#"))) -and (-not [string]::IsNullOrWhiteSpace($line))) {
|
if (!($line.StartsWith("#"))) {
|
||||||
Invoke-Expression "& $line"
|
Invoke-Expression "& $line"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
build.sh
38
build.sh
@@ -4,10 +4,6 @@ set -e
|
|||||||
# detect buildx, set -e will ensure the script stops execution if not found
|
# detect buildx, set -e will ensure the script stops execution if not found
|
||||||
docker buildx version
|
docker buildx version
|
||||||
|
|
||||||
# Enable BuildKit for better build experience and to ensure platform args are populated
|
|
||||||
export DOCKER_BUILDKIT=1
|
|
||||||
export COMPOSE_DOCKER_CLI_BUILD=1
|
|
||||||
|
|
||||||
# define temporary directory
|
# define temporary directory
|
||||||
TEMPDIRECTORY="$PWD/temp"
|
TEMPDIRECTORY="$PWD/temp"
|
||||||
|
|
||||||
@@ -20,19 +16,19 @@ if [ -d "$TEMPDIRECTORY" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$PWD/src/licenseGen/Core.dll" ]; then
|
if [ -f "$PWD/src/licenseGen/Core.dll" ]; then
|
||||||
rm -f "$PWD/src/licenseGen/Core.dll"
|
rm -f "$PWD/src/licenseGen/Core.dll"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$PWD/src/licenseGen/cert.pfx" ]; then
|
if [ -f "$PWD/src/licenseGen/cert.pfx" ]; then
|
||||||
rm -f "$PWD/src/licenseGen/cert.pfx"
|
rm -f "$PWD/src/licenseGen/cert.pfx"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$PWD/src/bitBetter/cert.cer" ]; then
|
if [ -f "$PWD/src/bitBetter/cert.cer" ]; then
|
||||||
rm -f "$PWD/src/bitBetter/cert.cer"
|
rm -f "$PWD/src/bitBetter/cert.cer"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$PWD/.keys/cert.cert" ]; then
|
if [ -f "$PWD/.keys/cert.cert" ]; then
|
||||||
mv "$PWD/.keys/cert.cert" "$PWD/.keys/cert.cer"
|
mv "$PWD/.keys/cert.cert" "$PWD/.keys/cert.cer"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# generate keys if none are available
|
# generate keys if none are available
|
||||||
@@ -58,11 +54,11 @@ done
|
|||||||
|
|
||||||
# update bitwarden itself
|
# update bitwarden itself
|
||||||
if [ "$1" = "update" ]; then
|
if [ "$1" = "update" ]; then
|
||||||
docker pull ghcr.io/bitwarden/lite:latest
|
docker pull ghcr.io/bitwarden/lite:beta
|
||||||
else
|
else
|
||||||
read -p "Update (or get) bitwarden source container (y/n): "
|
read -p "Update (or get) bitwarden source container (y/n): "
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
docker pull ghcr.io/bitwarden/lite:latest
|
docker pull ghcr.io/bitwarden/lite:beta
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -85,7 +81,7 @@ for INSTANCE in ${OLDINSTANCES[@]}; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# start a new bitwarden instance so we can patch it
|
# start a new bitwarden instance so we can patch it
|
||||||
PATCHINSTANCE=$(docker run -d --name bitwarden-extract ghcr.io/bitwarden/lite:latest)
|
PATCHINSTANCE=$(docker run -d --name bitwarden-extract ghcr.io/bitwarden/lite:beta)
|
||||||
|
|
||||||
# create our temporary directory
|
# create our temporary directory
|
||||||
mkdir $TEMPDIRECTORY
|
mkdir $TEMPDIRECTORY
|
||||||
@@ -93,8 +89,7 @@ mkdir $TEMPDIRECTORY
|
|||||||
# extract the files that need to be patched from the services that need to be patched into our temporary directory
|
# 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
|
for COMPONENT in ${COMPONENTS[@]}; do
|
||||||
mkdir "$TEMPDIRECTORY/$COMPONENT"
|
mkdir "$TEMPDIRECTORY/$COMPONENT"
|
||||||
docker cp $PATCHINSTANCE:/app/$COMPONENT/$COMPONENT "$TEMPDIRECTORY/$COMPONENT/$COMPONENT"
|
docker cp $PATCHINSTANCE:/app/$COMPONENT/Core.dll "$TEMPDIRECTORY/$COMPONENT/Core.dll"
|
||||||
docker cp $PATCHINSTANCE:/etc/supervisor.d/${COMPONENT,,}.ini "$TEMPDIRECTORY/${COMPONENT,,}.ini"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# stop and remove our temporary container
|
# stop and remove our temporary container
|
||||||
@@ -105,27 +100,14 @@ docker rm bitwarden-extract
|
|||||||
docker run -v "$TEMPDIRECTORY:/app/mount" --rm bitbetter/bitbetter
|
docker run -v "$TEMPDIRECTORY:/app/mount" --rm bitbetter/bitbetter
|
||||||
|
|
||||||
# create a new image with the patched files
|
# create a new image with the patched files
|
||||||
if [ -f "$PWD/Dockerfile-bitwarden-patch" ]; then
|
docker build . --tag bitwarden-patched --file "$PWD/src/bitBetter/Dockerfile-bitwarden-patch"
|
||||||
rm -f "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
fi
|
|
||||||
echo "FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine3.23" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
echo "FROM ghcr.io/bitwarden/lite:latest" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
echo "COPY --from=0 /usr/share/dotnet /usr/share/dotnet" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
for COMPONENT in ${COMPONENTS[@]}; do
|
|
||||||
echo "" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
echo "RUN rm -f /app/$COMPONENT/$COMPONENT" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
echo "COPY ./temp/${COMPONENT,,}.ini /etc/supervisor.d/${COMPONENT,,}.ini" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
echo "COPY ./temp/$COMPONENT/ /app/$COMPONENT/" >> "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
done
|
|
||||||
docker build . --tag bitwarden-patched --file "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
rm -f "$PWD/Dockerfile-bitwarden-patch"
|
|
||||||
|
|
||||||
# start all user requested instances
|
# start all user requested instances
|
||||||
if [ -f "$PWD/.servers/serverlist.txt" ]; then
|
if [ -f "$PWD/.servers/serverlist.txt" ]; then
|
||||||
# convert line endings to unix
|
# convert line endings to unix
|
||||||
sed -i 's/\r$//' "$PWD/.servers/serverlist.txt"
|
sed -i 's/\r$//' "$PWD/.servers/serverlist.txt"
|
||||||
cat "$PWD/.servers/serverlist.txt" | while read -r LINE; do
|
cat "$PWD/.servers/serverlist.txt" | while read -r LINE; do
|
||||||
if [[ $LINE != "#"* && -n $LINE ]]; then
|
if [[ $LINE != "#"* ]]; then
|
||||||
bash -c "$LINE"
|
bash -c "$LINE"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
$PSNativeCommandUseErrorActionPreference = $true
|
$PSNativeCommandUseErrorActionPreference = $true
|
||||||
|
|
||||||
# get the basic openssl binary path
|
# get the basic openssl binary path
|
||||||
$opensslbinary = "$Env:Programfiles\OpenSSL-Win64\bin\openssl.exe"
|
$opensslbinary = "$Env:Programfiles\OpenSSL-Win64\bin\openssl.exe"
|
||||||
|
|
||||||
# if openssl is not installed attempt to install it
|
# if openssl is not installed attempt to install it
|
||||||
if (!(Get-Command $opensslbinary -errorAction SilentlyContinue))
|
if (!(Get-Command $opensslbinary -errorAction SilentlyContinue))
|
||||||
{
|
{
|
||||||
winget install openssl
|
winget install openssl
|
||||||
}
|
}
|
||||||
|
|
||||||
# if previous keys exist, remove them
|
# if previous keys exist, remove them
|
||||||
if (Test-Path "$pwd\.keys")
|
if (Test-Path "$pwd\.keys")
|
||||||
{
|
{
|
||||||
Remove-Item "$pwd\.keys" -Recurse -Force
|
Remove-Item "$pwd\.keys" -Recurse -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
# create new directory
|
# create new directory
|
||||||
New-item -ItemType Directory -Path "$pwd\.keys"
|
New-item -ItemType Directory -Path "$pwd\.keys"
|
||||||
|
|
||||||
# generate actual keys
|
# generate actual keys
|
||||||
Invoke-Expression "& '$opensslbinary' req -x509 -newkey rsa:4096 -keyout `"$pwd\.keys\key.pem`" -out `"$pwd\.keys\cert.cer`" -days 36500 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' -outform DER -passout pass:test"
|
Invoke-Expression "& '$opensslbinary' req -x509 -newkey rsa:4096 -keyout `"$pwd\.keys\key.pem`" -out `"$pwd\.keys\cert.cer`" -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.cer`" -out `"$pwd\.keys\cert.pem`""
|
Invoke-Expression "& '$opensslbinary' x509 -inform DER -in `"$pwd\.keys\cert.cer`" -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 -certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256"
|
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"
|
||||||
@@ -17,4 +17,4 @@ mkdir "$DIR"
|
|||||||
# Generate new keys
|
# Generate new keys
|
||||||
openssl req -x509 -newkey rsa:4096 -keyout "$DIR/key.pem" -out "$DIR/cert.cer" -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.cer" -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.cer" -out "$DIR/cert.pem"
|
openssl x509 -inform DER -in "$DIR/cert.cer" -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 -certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256
|
openssl pkcs12 -export -out "$DIR/cert.pfx" -inkey "$DIR/key.pem" -in "$DIR/cert.pem" -passin pass:test -passout pass:test
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ $ErrorActionPreference = 'Stop'
|
|||||||
$PSNativeCommandUseErrorActionPreference = $true
|
$PSNativeCommandUseErrorActionPreference = $true
|
||||||
|
|
||||||
if ($($args.Count) -lt 1) {
|
if ($($args.Count) -lt 1) {
|
||||||
echo "USAGE: <License Gen action> [License Gen args...]"
|
echo "USAGE: <License Gen action> [License Gen args...]"
|
||||||
echo "ACTIONS:"
|
echo "ACTIONS:"
|
||||||
echo " interactive"
|
echo " interactive"
|
||||||
echo " user"
|
echo " user"
|
||||||
echo " org"
|
echo " org"
|
||||||
Exit 1
|
Exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($args[0] -eq "interactive") {
|
if ($args[0] -eq "interactive") {
|
||||||
docker run -it --rm bitbetter/licensegen interactive
|
docker run -it --rm bitbetter/licensegen interactive
|
||||||
} else {
|
} else {
|
||||||
docker run bitbetter/licensegen $args
|
docker run bitbetter/licensegen $args
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ $# -lt 1 ]; then
|
if [ $# -lt 1 ]; then
|
||||||
echo "USAGE: <License Gen action> [License Gen args...]"
|
echo "USAGE: <License Gen action> [License Gen args...]"
|
||||||
echo "ACTIONS:"
|
echo "ACTIONS:"
|
||||||
echo " interactive"
|
echo " interactive"
|
||||||
echo " user"
|
echo " user"
|
||||||
echo " org"
|
echo " org"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" = "interactive" ]; then
|
if [ "$1" = "interactive" ]; then
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
WORKDIR /bitBetter
|
WORKDIR /bitBetter
|
||||||
|
|
||||||
COPY . /bitBetter
|
COPY . /bitBetter
|
||||||
@@ -7,8 +7,8 @@ COPY cert.cer /app/
|
|||||||
RUN dotnet restore
|
RUN dotnet restore
|
||||||
RUN dotnet publish -c Release -o /app --no-restore
|
RUN dotnet publish -c Release -o /app --no-restore
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0
|
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=build /app .
|
COPY --from=build /app .
|
||||||
|
|
||||||
ENTRYPOINT ["dotnet", "/app/bitBetter.dll"]
|
ENTRYPOINT ["dotnet", "/app/bitBetter.dll"]
|
||||||
3
src/bitBetter/Dockerfile-bitwarden-patch
Normal file
3
src/bitBetter/Dockerfile-bitwarden-patch
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
FROM ghcr.io/bitwarden/lite:beta
|
||||||
|
|
||||||
|
COPY ./temp/ /app/
|
||||||
@@ -1,142 +1,67 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet.Emit;
|
||||||
using dnlib.DotNet.Writer;
|
using dnlib.DotNet.Writer;
|
||||||
using dnlib.IO;
|
using dnlib.IO;
|
||||||
using SingleFileExtractor.Core;
|
|
||||||
|
namespace bitBetter;
|
||||||
namespace bitBetter;
|
|
||||||
|
internal class Program
|
||||||
internal class Program
|
{
|
||||||
{
|
private static Int32 Main()
|
||||||
private static Int32 Main()
|
{
|
||||||
{
|
const String certFile = "/app/cert.cer";
|
||||||
const String certFile = "/app/cert.cer";
|
String[] files = Directory.GetFiles("/app/mount", "Core.dll", SearchOption.AllDirectories);
|
||||||
|
|
||||||
foreach (String iniFile in Directory.GetFiles("/app/mount/", "*.ini", SearchOption.TopDirectoryOnly))
|
foreach (String file in files)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Patching: " + iniFile);
|
Console.WriteLine(file);
|
||||||
|
ModuleDefMD moduleDefMd = ModuleDefMD.Load(file);
|
||||||
String[] lines = File.ReadAllLines(iniFile);
|
Byte[] cert = File.ReadAllBytes(certFile);
|
||||||
for (Int32 i = 0; i < lines.Length; i++)
|
|
||||||
{
|
EmbeddedResource embeddedResourceToRemove = moduleDefMd.Resources.OfType<EmbeddedResource>().First(r => r.Name.Equals("Bit.Core.licensing.cer"));
|
||||||
String line = lines[i];
|
EmbeddedResource embeddedResourceToAdd = new("Bit.Core.licensing.cer", cert) { Attributes = embeddedResourceToRemove.Attributes };
|
||||||
if (!line.StartsWith("command=", StringComparison.Ordinal)) continue;
|
moduleDefMd.Resources.Add(embeddedResourceToAdd);
|
||||||
|
moduleDefMd.Resources.Remove(embeddedResourceToRemove);
|
||||||
String appNameAndPath = line[(line.LastIndexOf('=') + 1)..];
|
|
||||||
lines[i] = "command=/usr/bin/dotnet \"" + appNameAndPath + ".dll\" --runtimeconfig \"" + appNameAndPath + ".runtimeconfig.json\"";
|
DataReader reader = embeddedResourceToRemove.CreateReader();
|
||||||
break;
|
X509Certificate2 existingCert = new(reader.ReadRemainingBytes());
|
||||||
}
|
|
||||||
File.WriteAllText(iniFile, String.Join("\n", lines), new UTF8Encoding(false));
|
Console.WriteLine($"Existing Cert Thumbprint: {existingCert.Thumbprint}");
|
||||||
}
|
X509Certificate2 certificate = new(cert);
|
||||||
|
|
||||||
foreach (String singleFile in Directory.GetFiles("/app/mount/", "*", SearchOption.AllDirectories))
|
Console.WriteLine($"New Cert Thumbprint: {certificate.Thumbprint}");
|
||||||
{
|
|
||||||
if (Path.HasExtension(singleFile)) continue;
|
IEnumerable<TypeDef> services = moduleDefMd.Types.Where(t => t.Namespace == "Bit.Core.Billing.Services");
|
||||||
|
TypeDef type = services.First(t => t.Name == "LicensingService");
|
||||||
Console.WriteLine("Extracting: " + singleFile);
|
MethodDef constructor = type.FindConstructors().First();
|
||||||
|
|
||||||
ExecutableReader reader1 = new(singleFile);
|
Instruction instructionToPatch = constructor.Body.Instructions.FirstOrDefault(i => i.OpCode == OpCodes.Ldstr && String.Equals((String)i.Operand, existingCert.Thumbprint, StringComparison.InvariantCultureIgnoreCase));
|
||||||
String currentDirectory = Path.GetDirectoryName(singleFile);
|
|
||||||
String newCoreDll = Path.Combine(currentDirectory, "Core.dll");
|
if (instructionToPatch != null)
|
||||||
reader1.ExtractToDirectory(currentDirectory);
|
{
|
||||||
reader1.Dispose();
|
instructionToPatch.Operand = certificate.Thumbprint;
|
||||||
|
}
|
||||||
File.Delete(singleFile);
|
else
|
||||||
|
{
|
||||||
if (!File.Exists(newCoreDll))
|
Console.WriteLine("Can't find constructor to patch");
|
||||||
{
|
}
|
||||||
Console.WriteLine("Could not extract Core.dll for " + singleFile);
|
|
||||||
Environment.Exit(-1);
|
ModuleWriterOptions moduleWriterOptions = new(moduleDefMd);
|
||||||
}
|
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.KeepOldMaxStack;
|
||||||
|
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveAll;
|
||||||
Console.WriteLine("Extracted: " + newCoreDll);
|
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveRids;
|
||||||
ModuleDefMD moduleDefMd = ModuleDefMD.Load(newCoreDll);
|
|
||||||
Byte[] cert = File.ReadAllBytes(certFile);
|
moduleDefMd.Write(file + ".new");
|
||||||
|
moduleDefMd.Dispose();
|
||||||
EmbeddedResource embeddedResourceToRemove = moduleDefMd.Resources.OfType<EmbeddedResource>().First(r => r.Name.Equals("Bit.Core.licensing.cer"));
|
File.Delete(file);
|
||||||
EmbeddedResource embeddedResourceToAdd = new("Bit.Core.licensing.cer", cert) { Attributes = embeddedResourceToRemove.Attributes };
|
File.Move(file + ".new", file);
|
||||||
moduleDefMd.Resources.Add(embeddedResourceToAdd);
|
}
|
||||||
moduleDefMd.Resources.Remove(embeddedResourceToRemove);
|
|
||||||
|
return 0;
|
||||||
DataReader reader = embeddedResourceToRemove.CreateReader();
|
}
|
||||||
|
}
|
||||||
X509Certificate2 existingCert = X509CertificateLoader.LoadCertificate(reader.ReadRemainingBytes());
|
|
||||||
X509Certificate2 certificate = X509CertificateLoader.LoadCertificate(cert);
|
|
||||||
Console.WriteLine($"Existing certificate Thumbprint: {existingCert.Thumbprint}");
|
|
||||||
Console.WriteLine($"New certificate Thumbprint: {certificate.Thumbprint}");
|
|
||||||
|
|
||||||
// Find LicensingService by class name (namespace-agnostic to handle renames)
|
|
||||||
TypeDef type = moduleDefMd.Types.FirstOrDefault(t => String.Equals(t.Name, "LicensingService", StringComparison.OrdinalIgnoreCase));
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine("ERROR: LicensingService class not found");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
Console.WriteLine($"Found: {type.FullName}");
|
|
||||||
|
|
||||||
MethodDef constructor = type.FindConstructors().First();
|
|
||||||
|
|
||||||
if (constructor == null)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine("ERROR: Cannot find constructor");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction[] instructionToPatch = constructor.Body.Instructions
|
|
||||||
.Where(i => i.OpCode == OpCodes.Ldstr)
|
|
||||||
.Where(i => ((String)i.Operand)
|
|
||||||
.Contains(existingCert.Thumbprint, StringComparison.OrdinalIgnoreCase))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (instructionToPatch.Length > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Found {instructionToPatch.Length} thumbprint Ldstr instruction(s) to replace");
|
|
||||||
foreach (Instruction inst in instructionToPatch)
|
|
||||||
{
|
|
||||||
Console.WriteLine($" Replacing: '{inst.Operand}'");
|
|
||||||
inst.Operand = certificate.Thumbprint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("ERROR: Can't find instruction to patch");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Writing: " + newCoreDll);
|
|
||||||
|
|
||||||
ModuleWriterOptions moduleWriterOptions = new(moduleDefMd);
|
|
||||||
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.KeepOldMaxStack;
|
|
||||||
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveAll;
|
|
||||||
moduleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveRids;
|
|
||||||
|
|
||||||
moduleDefMd.Write(newCoreDll + ".new");
|
|
||||||
moduleDefMd.Dispose();
|
|
||||||
File.Delete(newCoreDll);
|
|
||||||
File.Move(newCoreDll + ".new", newCoreDll);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (String runtimeConfigFile in Directory.GetFiles("/app/mount/", "*.runtimeconfig.json", SearchOption.AllDirectories))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Patching: " + runtimeConfigFile);
|
|
||||||
|
|
||||||
String[] lines = File.ReadAllLines(runtimeConfigFile);
|
|
||||||
for (Int32 i = 0; i < lines.Length; i++)
|
|
||||||
{
|
|
||||||
String line = lines[i];
|
|
||||||
if (!line.Contains("includedFrameworks", StringComparison.Ordinal)) continue;
|
|
||||||
|
|
||||||
lines[i] = lines[i].Replace("includedFrameworks", "frameworks", StringComparison.Ordinal);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
File.WriteAllText(runtimeConfigFile, String.Join("\n", lines), new UTF8Encoding(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="dnlib" Version="4.5.0" />
|
<PackageReference Include="dnlib" Version="4.5.0" />
|
||||||
<PackageReference Include="SingleFileExtractor.Core" Version="2.3.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
WORKDIR /licenseGen
|
WORKDIR /licenseGen
|
||||||
|
|
||||||
COPY . /licenseGen
|
COPY . /licenseGen
|
||||||
@@ -8,7 +8,7 @@ COPY cert.pfx /app/
|
|||||||
RUN dotnet restore
|
RUN dotnet restore
|
||||||
RUN dotnet publish -c Release -o /app --no-restore
|
RUN dotnet publish -c Release -o /app --no-restore
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0
|
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=build /app .
|
COPY --from=build /app .
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="5.1.0" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
|
||||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user