feat: PASSWORD_HASH helpers (#1180)

* feat: generate PASSWORD_HASH on the fly

* remove PASSWORD environment variable in favor of PASSWORD_HASH
* enhance password validity check server function
* update Dockerfile to include building a binary for generating hashed password
* update README with comprehensive Docker usage instructions hash generation

* fix: try fix git action docker build

* Dockerfile: use alpine-base image and install required build packages

* rewrite in js

* move files

* fix: lint errors

* some corrections

---------

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
This commit is contained in:
Philip H 2024-07-15 10:32:38 +02:00 committed by GitHub
commit c28e5befa6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 94 additions and 115 deletions

View file

@ -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';

View file

@ -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;
};

54
src/wgpw.mjs Normal file
View file

@ -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);
}
})();

5
src/wgpw.sh Executable file
View file

@ -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 "$@"