Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for basic authentication #333

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ The boot configurations for Pa11y Dashboard are as follows. Look at the sample J

*(boolean)* If set to `true`, users will not be able to add, delete or run URLs (defaults to `false`). Set via a config file or the `READONLY` environment variable.

### `protection`

*(boolean)* If set to `true`, the dashboard will be protected by a basic authentication popup. This can be useful when setting up Pa11y Dashboard in combination with a public custom domain. Be sure to change your username and password accordingly.

### `siteMessage`

*(string)* A message to display prominently on the site home page. Defaults to `null`.
Expand Down
32 changes: 32 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ function initApp(config, callback) {
app.server = http.createServer(app.express);
app.webservice = createClient(webserviceUrl);

// Apply basic authentication if necessary
loadBasicAuth(app, config);

// Load middleware
loadMiddleware(app);

// View engine
Expand All @@ -63,6 +67,34 @@ function defaultConfig(config) {
return config;
}

function loadBasicAuth(app, config) {
app.express.use((request, response, next) => {
const protection = config.protection.enabled || false;
if (protection) {
const auth = request.headers.authorization;
if (!auth) {
// Prompt the user for credentials
response.set('WWW-Authenticate', 'Basic realm="401"');
return response.status(401).send('Authentication required.');
}

const credentials = Buffer.from(auth.split(' ')[1], 'base64').toString().split(':');
const [username, password] = credentials;

// Use credentials from config
const USER = config.protection.user || '';
const PASS = config.protection.pass || '';

if (username === USER && password === PASS) {
return next(); // Proceed to the next middleware or route
}
response.set('WWW-Authenticate', 'Basic realm="401"'); // Prompt again
return response.status(401).send('Authentication required.');
}
return next();
});
}

function loadMiddleware(app) {
app.express.use(compression());

Expand Down
5 changes: 5 additions & 0 deletions config/development.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
"port": 4000,
"noindex": true,
"readonly": false,
"protection": {
"enabled": false,
"user": "pa11y",
"pass": "pa11y"
},
"webservice": {
"database": "mongodb://localhost/pa11y-webservice-dev",
"host": "0.0.0.0",
Expand Down
5 changes: 5 additions & 0 deletions config/production.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
"port": 4000,
"noindex": true,
"readonly": false,
"protection": {
"enabled": true,
"user": "pa11y",
"pass": "pa11y"
},
"webservice": {
"database": "mongodb://localhost/pa11y-webservice",
"host": "0.0.0.0",
Expand Down
5 changes: 5 additions & 0 deletions config/test.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
"port": 4000,
"noindex": true,
"readonly": false,
"protection": {
"enabled": false,
"user": "pa11y",
"pass": "pa11y"
},
"webservice": {
"database": "mongodb://127.0.0.1/pa11y-dashboard-integration-test",
"host": "127.0.0.1",
Expand Down