Skip to content

Commit 78d96c1

Browse files
committed
Added USER_LOGIN and USER_PASSWORD options
1 parent 87adf04 commit 78d96c1

9 files changed

+332
-57
lines changed

Dockerfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ ENV REDIS_USE_TLS false
1212
ENV REDIS_PASSWORD ''
1313
ENV BULL_PREFIX bull
1414
ENV BULL_VERSION BULLMQ
15+
ENV USER_LOGIN ''
16+
ENV USER_PASSWORD ''
1517

1618
RUN yarn install
1719

@@ -21,4 +23,4 @@ ARG PORT=3000
2123
ENV PORT $PORT
2224
EXPOSE $PORT
2325

24-
CMD ["node", "index.js"]
26+
CMD ["node", "src/index.js"]

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ see "Example with docker-compose" section for example with env parameters
3535
* `BULL_PREFIX` - prefix to your bull queue name (bull by default)
3636
* `BULL_VERSION` - version of bull lib to use 'BULLMQ' or 'BULL' ('BULLMQ' by default)
3737
* `BASE_PATH` - basePath for bull board, e.g. '/bull-board' ('/' by default)
38+
* `USER_LOGIN` - login to restrict access to bull-board interface (disabled by default)
39+
* `USER_PASSWORD` - password to restrict access to bull-board interface (disabled by default)
40+
41+
42+
### Restrict access with login and password
43+
44+
To restrict access to bull-board use `USER_LOGIN` and `USER_PASSWORD` env vars.
45+
Only when both `USER_LOGIN` and `USER_PASSWORD` specified, access will be restricted with login/password
46+
3847

3948
### Example with docker-compose
4049
```

index.js

-52
This file was deleted.

package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
{
22
"name": "bullboard",
33
"version": "1.0.0-alpha.7",
4-
"main": "index.js",
4+
"main": "src/index.js",
55
"license": "MIT",
66
"dependencies": {
7+
"body-parser": "^1.19.0",
78
"bull": "^3.13.0",
8-
"bull-board": "^1.0.0-alpha.8",
9+
"bull-board": "^1.2.0",
910
"bullmq": "^1.8.4",
11+
"connect-ensure-login": "^0.1.1",
1012
"express": "^4.17.1",
13+
"express-session": "^1.17.1",
14+
"passport": "^0.4.1",
15+
"passport-local": "^1.0.0",
1116
"redis": "^3.0.2"
1217
}
1318
}

src/config.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
let BASE_PATH = process.env.BASE_PATH || '/';
2+
3+
if (BASE_PATH.endsWith('/')) {
4+
BASE_PATH = BASE_PATH.substr(0, BASE_PATH.length - 1);
5+
}
6+
7+
const config = {
8+
REDIS_PORT: process.env.REDIS_PORT || 6379,
9+
REDIS_HOST: process.env.REDIS_HOST || 'localhost',
10+
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
11+
REDIS_USE_TLS: process.env.REDIS_USE_TLS,
12+
BULL_PREFIX: process.env.BULL_PREFIX || 'bull',
13+
BULL_VERSION: process.env.BULL_VERSION || 'BULLMQ',
14+
PORT: process.env.PORT || 3000,
15+
BASE_PATH: BASE_PATH,
16+
USER_LOGIN: process.env.USER_LOGIN,
17+
USER_PASSWORD: process.env.USER_PASSWORD,
18+
19+
AUTH_ENABLED: Boolean(process.env.USER_LOGIN && process.env.USER_PASSWORD),
20+
HOME_PAGE: BASE_PATH || '/',
21+
LOGIN_PAGE: `${BASE_PATH}/login`,
22+
};
23+
24+
module.exports = config;

src/index.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const {router, setQueues, BullMQAdapter, BullAdapter} = require('bull-board');
2+
const Queue = require('bull');
3+
const bullmq = require('bullmq');
4+
const express = require('express');
5+
const redis = require('redis');
6+
const session = require('express-session');
7+
const passport = require('passport');
8+
const {ensureLoggedIn} = require('connect-ensure-login');
9+
const bodyParser = require('body-parser');
10+
11+
const {authRouter} = require('./login');
12+
const config = require('./config');
13+
14+
const redisConfig = {
15+
redis: {
16+
port: config.REDIS_PORT,
17+
host: config.REDIS_HOST,
18+
...(config.REDIS_PASSWORD && {password: config.REDIS_PASSWORD}),
19+
tls: config.REDIS_USE_TLS === 'true',
20+
},
21+
};
22+
23+
const client = redis.createClient(redisConfig.redis);
24+
25+
client.KEYS(`${config.BULL_PREFIX}:*`, (err, keys) => {
26+
const uniqKeys = new Set(keys.map(key => key.replace(/^.+?:(.+?):.+?$/, '$1')));
27+
const queueList = Array.from(uniqKeys).sort().map(
28+
(item) => {
29+
if (config.BULL_VERSION === 'BULLMQ') {
30+
return new BullMQAdapter(new bullmq.Queue(item, {connection: redisConfig.redis}));
31+
}
32+
33+
return new BullAdapter(new Queue(item, redisConfig));
34+
}
35+
);
36+
37+
setQueues(queueList);
38+
});
39+
40+
const app = express();
41+
42+
app.set('views', __dirname + '/views');
43+
app.set('view engine', 'ejs');
44+
45+
app.use(session({secret: Math.random().toString(), resave: false, saveUninitialized: false}));
46+
app.use(passport.initialize({}));
47+
app.use(passport.session({}));
48+
49+
app.use(bodyParser.urlencoded({extended: false}));
50+
51+
if (config.AUTH_ENABLED) {
52+
app.use(config.LOGIN_PAGE, authRouter);
53+
app.use(config.HOME_PAGE, ensureLoggedIn(config.LOGIN_PAGE), router);
54+
}
55+
else {
56+
app.use(config.HOME_PAGE, router);
57+
}
58+
59+
app.listen(config.PORT, () => {
60+
console.log(`bull-board is started http://localhost:${config.PORT}${config.HOME_PAGE}`);
61+
});

src/login.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const passport = require('passport');
2+
const LocalStrategy = require('passport-local').Strategy;
3+
const express = require('express');
4+
5+
const config = require('./config');
6+
7+
const authRouter = express.Router();
8+
9+
passport.use(new LocalStrategy(
10+
function (username, password, cb) {
11+
if (username === config.USER_LOGIN && password === config.USER_PASSWORD) {
12+
return cb(null, {user: 'bull-board'});
13+
}
14+
15+
return cb(null, false);
16+
})
17+
);
18+
19+
passport.serializeUser((user, cb) => {
20+
cb(null, user);
21+
});
22+
23+
passport.deserializeUser((user, cb) => {
24+
cb(null, user);
25+
});
26+
27+
authRouter.route('/')
28+
.get((req, res) => {
29+
res.render('login');
30+
})
31+
.post(passport.authenticate('local', {
32+
successRedirect: config.HOME_PAGE,
33+
failureRedirect: config.LOGIN_PAGE,
34+
}));
35+
36+
exports.authRouter = authRouter;

src/views/login.ejs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<style>
2+
body {
3+
background: #f5f8fa;
4+
font-weight: 400;
5+
line-height: 1.25em;
6+
margin: 0;
7+
font-size: 16px;
8+
color: #454b52;
9+
-webkit-font-smoothing: antialiased;
10+
-moz-osx-font-smoothing: grayscale;
11+
}
12+
13+
.login-page {
14+
width: 360px;
15+
padding: 8% 0 0;
16+
margin: auto;
17+
}
18+
19+
.form {
20+
position: relative;
21+
z-index: 1;
22+
background: #FFFFFF;
23+
max-width: 360px;
24+
margin: 0 auto 100px;
25+
padding: 45px;
26+
text-align: center;
27+
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
28+
}
29+
30+
.form input {
31+
outline: 0;
32+
background: #f2f2f2;
33+
width: 100%;
34+
border: 0;
35+
margin: 0 0 15px;
36+
padding: 15px;
37+
box-sizing: border-box;
38+
font-size: 14px;
39+
}
40+
41+
.form button {
42+
text-transform: uppercase;
43+
outline: 0;
44+
background: hsl(217, 22%, 24%);
45+
width: 100%;
46+
border: 0;
47+
padding: 15px;
48+
color: #FFFFFF;
49+
font-size: 14px;
50+
-webkit-transition: all 0.3s ease;
51+
transition: all 0.3s ease;
52+
cursor: pointer;
53+
}
54+
55+
.form button:hover, .form button:active, .form button:focus {
56+
background: hsl(217, 22%, 28%);
57+
}
58+
59+
.form .message {
60+
margin: 15px 0 0;
61+
color: #b3b3b3;
62+
font-size: 12px;
63+
}
64+
65+
.form .message a {
66+
color: hsl(217, 22%, 24%);
67+
text-decoration: none;
68+
}
69+
70+
.container {
71+
position: relative;
72+
z-index: 1;
73+
max-width: 300px;
74+
margin: 0 auto;
75+
}
76+
77+
.container:before, .container:after {
78+
content: "";
79+
display: block;
80+
clear: both;
81+
}
82+
83+
.container .info {
84+
margin: 50px auto;
85+
text-align: center;
86+
}
87+
88+
.container .info h1 {
89+
margin: 0 0 15px;
90+
padding: 0;
91+
font-size: 36px;
92+
font-weight: 300;
93+
color: #1a1a1a;
94+
}
95+
96+
.container .info span {
97+
color: #4d4d4d;
98+
font-size: 12px;
99+
}
100+
101+
.container .info span a {
102+
color: #000000;
103+
text-decoration: none;
104+
}
105+
106+
.container .info span .fa {
107+
color: #EF3B3A;
108+
}
109+
</style>
110+
111+
<div class="login-page">
112+
<div class="form">
113+
<form class="login-form" method="post" action="">
114+
<input type="text" name="username" placeholder="Username"/>
115+
<input type="password" name="password" placeholder="Password"/>
116+
<button>Login</button>
117+
</form>
118+
</div>
119+
</div>

0 commit comments

Comments
 (0)