diff --git a/.env.sample b/.env.sample index 34a9095c..1cda1d54 100644 --- a/.env.sample +++ b/.env.sample @@ -29,6 +29,9 @@ SERVER_HOST = 0.0.0.0 SERVER_PORT = 7801 SERVER_MAX_UPLOAD_SIZE = 3 SERVER_BENCHMARKING = false +SERVER_BASIC_AUTH_ENABLE = true +SERVER_BASIC_AUTH_LOGIN = login +SERVER_BASIC_AUTH_PASSWORD = password # SERVER PROXY CONFIG SERVER_PROXY_HOST = diff --git a/README.md b/README.md index 27c6921a..140e3807 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,12 @@ These variables are set in your environment and take precedence over options fro - `SERVER_SSL_PORT`: The port on which to run the SSL server (defaults to `443`). - `SERVER_SSL_CERT_PATH`: The path to the SSL certificate/key file (defaults to ``). +### Server Basic Authentification Config + +- `SERVER_BASIC_AUTH_ENABLE`: Enables or disables the basic auth support to protect your server +- `SERVER_BASIC_AUTH_LOGIN`: Login expected for basic auth +- `SERVER_BASIC_AUTH_PASSWORD`: Password expected for basic auth + ### Pool Config - `POOL_MIN_WORKERS`: The number of minimum and initial pool workers to spawn (defaults to `4`). diff --git a/lib/envs.js b/lib/envs.js index 5399293e..28605672 100644 --- a/lib/envs.js +++ b/lib/envs.js @@ -189,6 +189,11 @@ export const Config = z.object({ SERVER_SSL_PORT: v.positiveNum(), SERVER_SSL_CERT_PATH: v.string(), + // server basic auth + SERVER_BASIC_AUTH_ENABLE: v.boolean(), + SERVER_BASIC_AUTH_LOGIN: v.string(), + SERVER_BASIC_AUTH_PASSWORD: v.string(), + // pool POOL_MIN_WORKERS: v.nonNegativeNum(), POOL_MAX_WORKERS: v.nonNegativeNum(), diff --git a/lib/schemas/config.js b/lib/schemas/config.js index d6022db2..91a8996f 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -390,6 +390,26 @@ export const defaultConfig = { description: 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.' }, + basicAuth: { + enable: { + value: false, + type: 'boolean', + envLink: 'SERVER_BASIC_AUTH_ENABLE', + description: 'Enables basic authentication for the server.' + }, + login: { + value: 'login', + type: 'string', + envLink: 'SERVER_BASIC_AUTH_LOGIN', + description: 'The login for basic authentication.' + }, + password: { + value: 'password', + type: 'string', + envLink: 'SERVER_BASIC_AUTH_PASSWORD', + description: 'The password for basic authentication.' + } + }, proxy: { host: { value: false, @@ -399,7 +419,7 @@ export const defaultConfig = { description: 'The host of the proxy server to use, if it exists.' }, port: { - value: 8080, + value: 8086, type: 'number', envLink: 'SERVER_PROXY_PORT', cliName: 'proxyPort', @@ -963,6 +983,24 @@ export const promptsConfig = { name: 'ssl.certPath', message: 'The path to find the SSL certificate/key', initial: defaultConfig.server.ssl.certPath.value + }, + { + type: 'text', + name: 'basicAuth.enable', + message: 'Enable basic authentication', + initial: defaultConfig.server.basicAuth.enable.value + }, + { + type: 'text', + name: 'basicAuth.login', + message: 'Login for basic authentication', + initial: defaultConfig.server.basicAuth.login.value + }, + { + type: 'text', + name: 'basicAuth.password', + message: 'Password for basic authentication', + initial: defaultConfig.server.basicAuth.password.value } ], pool: [ diff --git a/lib/server/server.js b/lib/server/server.js index 530251aa..0e3125c1 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -182,6 +182,34 @@ export const startServer = async (serverConfig) => { } } + // Basic authentication middleware + app.use((req, res, next) => { + if (!serverConfig.basicAuth.enable) { + // Basic auth not enabled, skip authentication + return next(); + } + + const configLogin = serverConfig.basicAuth.login; + const configPassword = serverConfig.basicAuth.password; + const auth = { login: configLogin, password: configPassword }; + const b64auth = (req.headers.authorization || '').split(' ')[1] || ''; + const [login, password] = Buffer.from(b64auth, 'base64') + .toString() + .split(':'); + + if ( + login && + password && + login === auth.login && + password === auth.password + ) { + return next(); + } + + res.set('WWW-Authenticate', 'Basic realm="401"'); + res.status(401).send('Authentication required.'); + }); + // Enable the rate limiter if config says so if ( serverConfig.rateLimiting &&