diff --git a/.env.sample b/.env.sample
index 4230985..6a7b94c 100644
--- a/.env.sample
+++ b/.env.sample
@@ -3,4 +3,11 @@ PORT=5000
# you can call `sudo bbb-conf --secret` for the following two values
BBB_API_URL=https://demo.bigbluebutton.org/bigbluebutton
BBB_API_SECRET=FIXME
-WELCOME_MESSAGE="Welcome to %%CONFNAME%%!
Invite others with following URL: %%JOINURL%%
Use a headset to avoid causing background noise for others."
+
+## Welcome Message for new users
+WELCOME_MESSAGE="Welcome to%%CONFNAME%%.
Use a headset to avoid causing background noise for others."
+## welcome message for new users if no manual password is set
+NOPW_WELCOME_MESSAGE=""Welcome to %%CONFNAME%%!
Invite others with following URL: %%JOINURL%%
Use a headset to avoid causing background noise for others."
+## welcome message for moderators only. Will only be shown if a manual roompassword is set
+MOD_WELCOME_MESSAGE="Dear Moderator,
Invite others with following URL: %%JOINURL%%
Provide the following passwords to join:
Moderator: %%MPASSWD%%
User: %%UPASSWD%%"
+
diff --git a/README.md b/README.md
index 42a3d48..f9e7a93 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
bbb-easy-join
-------------
-An easy frontend to BigBlueButton without signups - everybody can just entry a meeting room name, the first user gets moderator level access.
+An easy frontend to BigBlueButton without signups - everybody can just enter a meeting room name and an optional password.
+The first user gets moderator level access.
+
@@ -9,10 +11,16 @@ An easy frontend to BigBlueButton without signups - everybody can just entry a m
Tested with an BBB instance installed with [bbb-install.sh](https://github.com/bigbluebutton/bbb-install).
+Installation requires git and bbb to be installed on the same machine
+
+```bash
+sudo apt install git
+```
+
Checkout this repository to /var/www/bbb-easy-join
```
-git clone https://github.com/stadtulm/bbb-easy-join.git /var/www/bbb-easy-join
+git clone https://github.com/svoeth/bbb-easy-join.git /var/www/bbb-easy-join
sudo chown -r bigbluebutton: /var/www/bbb-easy-join
sudo -iu bigbluebutton
cd /var/www/bbb-easy-join
@@ -23,11 +31,21 @@ Create an `.env` file (use `.env.sample` as a template) and enter your BBB API U
For serving the pages, copy `bbb-easy-join.nginx` to `/etc/bigbluebutton/nginx/`. If there are already `greenlight-redirect.nginx` and/or `greenlight.nginx`, rename (remove the .nginx suffix) or delete them.
-If you want to keep the service running, the systemd service file `bbb-easy-join.service` can be copied to `/etc/systemd/system/` and activated by `sudo systemctl daemon-reload`, `sudo systemctl enable bbb-easy-join` and `sudo systemctl start bbb-easy-join`.
+You can start the service by running `/usr/bin/node /var/www/bbb-easy-join/app.js`
+If you want to keep the service running in background and on startup:
+```bash
+# copy the systemd service file and register it with systemd
+cp bbb-easy-join.service /etc/systemd/system/
+sudo systemctl daemon-reload
+# activate it to start on startup
+sudo systemctl enable bbb-easy-join
+# start it immediately
+sudo systemctl start bbb-easy-join
+```
### Note
-Your BigBlueButton Instance is then (if not only reachable from inside your network) public, everybody can create and moderate/present in a meeting. Therefore, you may want to think about disabling recordings, the security of accepting presentation files etc.
+Your BigBlueButton Instance is then (if not only reachable from inside your network or protected otherwise) public, everybody can create and moderate/present in a meeting. Therefore, you may want to think about disabling recordings, the security of accepting presentation files etc.
### Credits
diff --git a/app.js b/app.js
index 9d0e93f..0cac5c9 100644
--- a/app.js
+++ b/app.js
@@ -12,6 +12,8 @@ const host = process.env.HOST || '0.0.0.0'
const BBB_API_URL = process.env.BBB_API_URL
const BBB_API_SECRET = process.env.BBB_API_SECRET
const WELCOME_MESSAGE = process.env.WELCOME_MESSAGE
+const NOPW_WELCOME_MESSAGE = process.env.NOPW_WELCOME_MESSAGE
+const MOD_WELCOME_MESSAGE = process.env.MOD_WELCOME_MESSAGE
// TODO: internationalize more
slugify.extend({'ä': 'ae', 'ü': 'ue', 'ö': 'oe', 'ß': 'ss'})
@@ -56,6 +58,15 @@ const joinMeetingUrl = function (id, name, password) {
return buildApiUrl('join', params);
}
+const generateRandomPassword = function () {
+ const alpha = 'qwertyuiopasdfghjklzxcvbnm';
+ var password = '';
+ for (let i=0;i<24;i++) {
+ password += alpha[Math.floor(Math.random() * alpha.length)]
+ }
+ return password;
+}
+
app.use(express.static('public'))
app.set('view engine', 'ejs')
app.set('trust proxy', 'loopback')
@@ -66,39 +77,105 @@ app.get('/', function(req, res) {
})
app.get('/b', function (req, res) {
- res.render('index')
+ res.render('index', {
+ roomName: req.query.roomName,
+ roomBlocked: req.query.roomBlocked,
+ roomMissing: req.query.roomMissing })
})
+
+// create a room (optionally with password)
+// if password is set provide mod and user pw for welcome message
app.post('/b', async function (req, res) {
var roomName = req.body.room
var room = slugify(roomName, { lower: true })
- var options = {}
+ // if user provides password within room creation, set prefix "user-" otherwise set it to "auto-"
+ var room_password;
+ var custom_password = req.body.room_password;
+ if (custom_password) {
+ // generate random moderator password to give possibility to provide it in welcome message
+ var moderator_password = generateRandomPassword();
+ room_password = "user-" + custom_password;
+ // add passwords to options for room creation
+ var options = { 'attendeePW' : room_password, 'moderatorPW' : moderator_password }
+ }else {
+ // create random password with "auto-" prefix. Not entirely necessary, but theoretically random password
+ // could start with "user-" and might therefore accidentally be interpreted as manual pw
+ room_password = "auto-" + generateRandomPassword();
+ var options = { 'attendeePW' : room_password }
+ }
+
+ //set welcome message(s)
if (typeof WELCOME_MESSAGE === 'string') {
- var url = req.protocol + '://' + req.get('host') + '/b/' + room
+ var url = req.protocol + '://' + req.get('host') + '/b/' + roomName
var joinpattern = new RegExp('%%JOINURL%%', 'g')
- options.welcome = WELCOME_MESSAGE.replace(joinpattern, url)
+ //if the room has a manual password set we will provide two welcome msgs and only inform moderators about joining options and passwords
+ if (room_password.startsWith('user-')) {
+ var mpasswd = new RegExp('%%MPASSWD%%', 'g')
+ var upasswd = new RegExp('%%UPASSWD%%', 'g')
+ var modwelcome = MOD_WELCOME_MESSAGE.replace(joinpattern, url)
+ modwelcome = modwelcome.replace(mpasswd, moderator_password)
+ options.moderatorOnlyMessage = modwelcome.replace(upasswd, custom_password)
+ options.welcome = WELCOME_MESSAGE
+ } else {
+ // welcome message with no manual pw gets joinurl
+ options.welcome = NOPW_WELCOME_MESSAGE.replace(joinpattern, url)
+ }
}
var meet = await createMeeting(roomName, room, options)
- if (meet.returncode === 'FAILED' && meet.messageKey !== 'idNotUnique') {
- res.redirect('/b')
- return
+ //check if roomcreation was not succesful
+ if (meet.returncode === 'FAILED') {
+ //if room exists put warning message on page - else just go back
+ if (meet.messageKey === 'idNotUnique') {
+ // timeout as a very basic bruteforce prevention to prevent room search
+ setTimeout(function (){
+ res.redirect('/b' + `?roomName=${encodeURIComponent(roomName)}&roomBlocked=true`);
+ }, 1000);
+ return
+ } else {
+ res.redirect('/b');
+ return
+ }
}
- res.redirect('/b/' + room)
+ //slugify roomName because room contains prefix
+ res.redirect('/b/' + room )
})
app.get('/b/:room', async function (req, res){
- var room = slugify(req.params.room)
-
+ // added slugify lower to prevent error if accidental uppercase or special characters are in adress
+ var room = slugify(req.params.room, { lower: true })
var info = await getMeetingInfo(room)
+
+ //check if meeting info was not succesfully grabbed and in case redirect with error message (room not created)
if (info.returncode === 'FAILED') {
- res.redirect('/b')
+ // timeout as a very basic bruteforce prevention to prevent room search
+ setTimeout(function (){
+ res.redirect('/b' + `?roomName=${encodeURIComponent(req.params.room)}&roomMissing=true`)
+ }, 1000);
return
}
- res.render('join', { room: room, info: info })
+ // This variable decides whether we display a password dialogue.
+ // Normally, meetings require no user provided password...
+ var requiresPassword = false;
+ // ... unless one is set
+ if (info.attendeePW.startsWith('user-')) {
+ requiresPassword = true;
+ }
+ // ... except when the room is empty, then we'll become the moderator anyway.
+ if (info.hasUserJoined == false || info.participantCount == 0) {
+ requiresPassword = false;
+ }
+
+ res.render('join', {
+ room: room,
+ info: info,
+ requiresPassword: requiresPassword,
+ username: req.query.username,
+ wrongPw: req.query.wrongPw })
})
app.post('/b/:room', async function (req, res) {
@@ -111,10 +188,26 @@ app.post('/b/:room', async function (req, res) {
}
var password = info.attendeePW
+ // check if there is anybody in the meeting - if not give moderator rights
if (info.hasUserJoined == false || info.participantCount == 0) {
password = info.moderatorPW
+ // if there is somebody in the meeting get the attendee pw and check if it is manually set (starts wit user-) otherwise just join as attende
+ } else {
+ password = info.attendeePW;
+ if (password.startsWith('user-')) {
+ // check if provided login password matches required password if not redirect to login page with error
+ if (password != "user-" + req.body.room_password) {
+ password = info.moderatorPW;
+ if (password != req.body.room_password) {
+ // timeout as a very basic bruteforce prevention - double time for password try (2 seconds)
+ setTimeout(function (){
+ res.redirect('/b/' + info.meetingName + `?username=${encodeURIComponent(name)}&wrongPw=true`);
+ }, 2000);
+ return;
+ }
+ }
+ }
}
-
res.redirect(joinMeetingUrl(room, name, password))
})
diff --git a/docs/overview.png b/docs/overview.png
index 49faac2..48bebc9 100644
Binary files a/docs/overview.png and b/docs/overview.png differ
diff --git a/package-lock.json b/package-lock.json
index 2c1e2be..7465022 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,7 @@
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
@@ -21,7 +21,7 @@
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
- "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
@@ -38,12 +38,12 @@
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
- "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY="
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
- "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=",
"requires": {
"safe-buffer": "5.1.2"
}
@@ -51,12 +51,12 @@
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
- "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo="
},
"cookie-signature": {
"version": "1.0.6",
@@ -66,7 +66,7 @@
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"requires": {
"ms": "2.0.0"
}
@@ -84,7 +84,7 @@
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
- "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
+ "integrity": "sha1-l+YZJZradQ7qPk6j4mvO6lQksWo="
},
"ee-first": {
"version": "1.1.1",
@@ -114,7 +114,7 @@
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
- "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
@@ -151,12 +151,12 @@
"fast-xml-parser": {
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.16.0.tgz",
- "integrity": "sha512-U+bpScacfgnfNfIKlWHDu4u6rtOaCyxhblOLJ8sZPkhsjgGqdZmVPBhdOyvdMGCDt8CsAv+cssOP3NzQptNt2w=="
+ "integrity": "sha1-2QXn5rKPxGSMq+vLB0Njhn+1buI="
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
@@ -180,7 +180,7 @@
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
- "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
@@ -192,7 +192,7 @@
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
@@ -205,7 +205,7 @@
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM="
},
"media-typer": {
"version": "0.3.0",
@@ -225,7 +225,7 @@
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE="
},
"mime-db": {
"version": "1.43.0",
@@ -248,12 +248,12 @@
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs="
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
- "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
+ "integrity": "sha1-5jNFY4bUqlWGP2dqerDaqP3ssP0="
},
"on-finished": {
"version": "2.3.0",
@@ -266,7 +266,7 @@
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ="
},
"path-to-regexp": {
"version": "0.1.7",
@@ -276,7 +276,7 @@
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
- "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
@@ -285,17 +285,17 @@
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
- "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
- "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
@@ -306,17 +306,17 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
- "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
@@ -336,14 +336,14 @@
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
}
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
- "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
@@ -354,12 +354,12 @@
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM="
},
"slugify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz",
- "integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ=="
+ "integrity": "sha1-yVV8ZTxUsMf3qOeG7zQxrdZ20ss="
},
"statuses": {
"version": "1.5.0",
@@ -369,12 +369,12 @@
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM="
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
diff --git a/views/index.ejs b/views/index.ejs
index 3a488da..86e55fa 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -40,20 +40,35 @@
-
(Think about a short and unique meeting room name)
- - +Room <%= roomName %> does not exist (yet).
(or just create any room with a unique name)
+ <% } else { %> + <% if (roomBlocked) { %> +Room <%= roomName %> already exists.
+
+ Click here to join <%= roomName %>.
(think of a unique name for your room)
+ <% } %> + <% } %> +Wrong password