diff --git a/Dockerfile b/Dockerfile index ca427af..c9238f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,10 @@ COPY --from=build_node_modules /app /app # than what runs inside of docker. COPY --from=build_node_modules /node_modules /node_modules +# Copy the needed wg-password scripts +COPY --from=build_node_modules /app/wgpw.sh /bin/wgpw +RUN chmod +x /bin/wgpw + # Install Linux packages RUN apk add --no-cache \ dpkg \ @@ -42,4 +46,4 @@ ENV DEBUG=Server,WireGuard # Run Web UI WORKDIR /app -CMD ["/usr/bin/dumb-init", "node", "server.js"] +CMD ["/usr/bin/dumb-init", "node", "server.js"] \ No newline at end of file diff --git a/How_to_generate_an_bcrypt_hash.md b/How_to_generate_an_bcrypt_hash.md index 46cb227..ca3e5ee 100644 --- a/How_to_generate_an_bcrypt_hash.md +++ b/How_to_generate_an_bcrypt_hash.md @@ -1,110 +1,34 @@ -<!-- created by Mathys Lopinto (@mathys-lopinto) --> -# How to generate bcrypt hash +# wg-password -## Prerequisites -- Python 3 -- bcrypt library +`wg-password` (wgpg) is a script that generates bcrypt password hashes for use with `wg-easy`, enhancing security by requiring passwords. -## Prerequisites Installation -### Windows -Download and install Python 3 from [official website](https://www.python.org/downloads/). -Check "Add python.exe to PATH" before running "Install Now". +## Features + +- Generate bcrypt password hashes. +- Easily integrate with `wg-easy` to enforce password requirements. + +## Usage with Docker + +To generate a bcrypt password hash using Docker, run the following command: + +```sh +docker run ghcr.io/wg-easy/wg-easy wgpw YOUR_PASSWORD +PASSWORD_HASH='$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW' // litteraly YOUR_PASSWORD +``` + +## Important + +Make sure to enclose your password in single quotes when you run a linux host. -Open Command Prompt (win + r, type "cmd" and press enter) and run the following command to install bcrypt library: ```bash -pip install bcrypt +$ echo $2b$12$coPqCsPtcF +b2 +$ echo "$2b$12$coPqCsPtcF" +b2 +$ echo '$2b$12$coPqCsPtcF' +$2b$12$coPqCsPtcF ``` -### Debian based distributions -```bash -sudo apt-get update -sudo apt-get install python3 python3-pip -# If you use have install python using apt -sudo apt-get install python3-bcrypt -# If don't install python using apt -pip3 install bcrypt -# If you got externally-managed-environment error -pip3 install bcrypt --break-system-packages -``` +## LICENSE -### Fedora based distributions -```bash -sudo dnf update -sudo dnf install python3 python3-pip -# If you use have install python using dnf -sudo dnf install python3-bcrypt -# If don't install python using dnf -pip3 install bcrypt -# If you got externally-managed-environment error -pip3 install bcrypt --break-system-packages -``` - -### Arch Linux based distributions -```bash -sudo pacman -Syy -sudo pacman -S python python-pip -# If you use have install python using pacman -sudo pacman -S python-bcrypt -# If don't install python using pacman -pip3 install bcrypt -# If you got externally-managed-environment error -pip3 install bcrypt --break-system-packages -``` - -### macOS -```bash -brew install bcrypt -# If don't install bcrypt using homebrew -pip3 install bcrypt -# If you got externally-managed-environment error -pip3 install bcrypt --break-system-packages -``` - -## Generating bcrypt hash from the command line -You can use the following one-liner command to generate a bcrypt hash directly in the cmd/ terminal: -```bash -python3 -c "import bcrypt; password = b'your_password_here'; assert len(password) < 72, 'Password must be less than 72 bytes due to bcrypt limitation'; hashed = bcrypt.hashpw(password, bcrypt.gensalt()); print(f'The hashed password is: {hashed.decode()}'); docker_interpolation = hashed.decode().replace('$', '$'*2); print(f'The hashed password for a Docker env is: {docker_interpolation}')" # or python if you run this on Windows. CHANGE your_password_here BY YOUR PASSWORD -``` -Please change ``your_password_here`` in the line by your own password. - -## Generating bcrypt hash from an script file -### Do not name the file `bcrypt.py` as it will cause an error. -Create a python file with the following content: -```python -import bcrypt - -# Initial password -password = b"your_password_here" # DO NOT REMOVE THE b - -# Assert that the password is under 72 bytes -assert len(password) < 72, "Password must be less than 72 bytes due to bcrypt limitation" - -# Generate a salt and hash the password -hashed = bcrypt.hashpw(password, bcrypt.gensalt()) - -# Print the hashed password -print(f'The hashed password is: {hashed.decode()}') - -# Prepare the hashed password for Docker environment variables -docker_interpolation = hashed.decode().replace("$", "$$") -print(f'The hashed password for a Docker env is: {docker_interpolation}') -``` - -Replace `your_password_here` with the password you want to hash. - -Run the python file and you will get the hashed password. - -## Get the right hash -Copy the 2nd line of the output (after the : ) and use it as your hashed password. - -__Exemple__ -If the output is: -```txt -The hashed password is: $2b$12$NRiL4Kw4dKid.ix2WvZltOmaQBZjoX30shjHJXRVdEGshAxYWXXMe -The hashed password for an docker env is: $$2b$$12$$NRiL4Kw4dKid.ix2WvZltOmaQBZjoX30shjHJXRVdEGshAxYWXXMe -``` - -The docker line ``PASSWORD_HASH`` will be: -```txt -PASSWORD_HASH=$$2b$$12$$NRiL4Kw4dKid.ix2WvZltOmaQBZjoX30shjHJXRVdEGshAxYWXXMe -``` +[wg-easy license](./LICENSE) \ No newline at end of file diff --git a/README.md b/README.md index 81d531a..e559b99 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ To automatically install & run wg-easy, simply run: > 💡 Replace `YOUR_SERVER_IP` with your WAN IP, or a Dynamic DNS hostname. > -> 💡 Replace `YOUR_ADMIN_PASSWORD_HASH` with a bcrypt password hash to log in on the Web UI. See How_to_generate_an_bcrypt_hash.md for know how generate the hash. +> 💡 Replace `YOUR_ADMIN_PASSWORD_HASH` with a bcrypt password hash to log in on the Web UI. See [How_to_generate_an_bcrypt_hash.md](./How_to_generate_an_bcrypt_hash.md) for know how generate the hash. The Web UI will now be available on `http://0.0.0.0:51821`. diff --git a/src/config.js b/src/config.js index 40b70dd..ac4b407 100644 --- a/src/config.js +++ b/src/config.js @@ -5,7 +5,6 @@ const { release } = require('./package.json'); module.exports.RELEASE = release; module.exports.PORT = process.env.PORT || '51821'; module.exports.WEBUI_HOST = process.env.WEBUI_HOST || '0.0.0.0'; -module.exports.PASSWORD = process.env.PASSWORD; module.exports.PASSWORD_HASH = process.env.PASSWORD_HASH; module.exports.WG_PATH = process.env.WG_PATH || '/etc/wireguard/'; module.exports.WG_DEVICE = process.env.WG_DEVICE || 'eth0'; diff --git a/src/lib/Server.js b/src/lib/Server.js index d995bb6..7f06da5 100644 --- a/src/lib/Server.js +++ b/src/lib/Server.js @@ -28,22 +28,18 @@ const { PORT, WEBUI_HOST, RELEASE, - PASSWORD, PASSWORD_HASH, LANG, UI_TRAFFIC_STATS, UI_CHART_TYPE, } = require('../config'); -const requiresPassword = !!PASSWORD || !!PASSWORD_HASH; +const requiresPassword = !!PASSWORD_HASH; /** * Checks if `password` matches the PASSWORD_HASH. * - * For backward compatibility it also allows `password` to match the clear text PASSWORD, - * but only if no PASSWORD_HASH is provided. - * - * If both enviornment variables are not set, the password is always invalid. + * If environment variable is not set, the password is always invalid. * * @param {string} password String to test * @returns {boolean} true if matching environment, otherwise false @@ -56,9 +52,6 @@ const isPasswordValid = (password) => { if (PASSWORD_HASH) { return bcrypt.compareSync(password, PASSWORD_HASH); } - if (PASSWORD) { - return password === PASSWORD; - } return false; }; diff --git a/src/wgpw.mjs b/src/wgpw.mjs new file mode 100644 index 0000000..4062a73 --- /dev/null +++ b/src/wgpw.mjs @@ -0,0 +1,54 @@ +'use strict'; + +// Import needed libraries +import bcrypt from 'bcryptjs'; + +// Function to generate hash +const generateHash = async (password) => { + try { + const salt = await bcrypt.genSalt(12); + const hash = await bcrypt.hash(password, salt); + // eslint-disable-next-line no-console + console.log(`PASSWORD_HASH='${hash}'`); + } catch (error) { + throw new Error(`Failed to generate hash : ${error}`); + } +}; + +// Function to compare password with hash +const comparePassword = async (password, hash) => { + try { + const match = await bcrypt.compare(password, hash); + if (match) { + // eslint-disable-next-line no-console + console.log('Password matches the hash !'); + } else { + // eslint-disable-next-line no-console + console.log('Password does not match the hash.'); + } + } catch (error) { + throw new Error(`Failed to compare password and hash : ${error}`); + } +}; + +(async () => { + try { + // Retrieve command line arguments + const args = process.argv.slice(2); // Ignore the first two arguments + if (args.length > 2) { + throw new Error('Usage : wgpw YOUR_PASSWORD [HASH]'); + } + + const [password, hash] = args; + if (password && hash) { + await comparePassword(password, hash); + } else if (password) { + await generateHash(password); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + // eslint-disable-next-line no-process-exit + process.exit(1); + } +})(); diff --git a/src/wgpw.sh b/src/wgpw.sh new file mode 100755 index 0000000..aac6afa --- /dev/null +++ b/src/wgpw.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# This script is intended to be run only inside a docker container, not on the development host machine +set -e +# proxy command +node /app/wgpw.mjs "$@" \ No newline at end of file