Implemented username reserve feature

This commit is contained in:
2021-03-03 04:27:48 +11:00
parent 34a5444705
commit 9a7e9313d8
13 changed files with 190 additions and 2 deletions
+2
View File
@@ -13,5 +13,7 @@ DB_USERNAME=template
DB_PASSWORD=pikachu
DB_TIMEZONE=Australia/Sydney
CHAT_URI=http://example.com:3200/chat
SESSION_SECRET=secret
SESSION_ADMIN=adminsecret
+1
View File
@@ -43,6 +43,7 @@ const App = props => {
<LazyRoute path='/signup' component={() => import('./pages/signup')} />
<LazyRoute path='/login' component={() => import('./pages/login')} />
<LazyRoute path='/account' component={() => import('./pages/account')} />
<LazyRoute path='/chat' component={() => import('./pages/chat')} />
<LazyRoute path='/admin' component={() => import('./pages/admin')} />
+23
View File
@@ -0,0 +1,23 @@
import React from 'react';
import { Redirect } from 'react-router-dom';
import { useCookies } from 'react-cookie';
import Chat from '../panels/chat';
//Temporary chat page
const ChatPage = props => {
const [cookies, setCookie] = useCookies();
//check for logged in redirect
if (!cookies['loggedin']) {
return <Redirect to='/' />;
}
return (
<div className='page'>
<Chat uri={process.env.CHAT_URI} />
</div>
);
};
export default ChatPage;
-1
View File
@@ -3,7 +3,6 @@ import React from 'react';
import NewsFeed from '../panels/news-feed';
const HomePage = props => {
//TODO: move the URIs into the config files
return (
<div className='page'>
<p>This is the MERN template homepage.</p>
+32
View File
@@ -0,0 +1,32 @@
import React from 'react';
import { useCookies } from 'react-cookie';
const Chat = props => {
requestPseudonym();
return (
<div className='chat'>
<p>Chat URI: {props.uri}</p>
<p>Chat Paragraph TODO</p>
</div>
);
};
const requestPseudonym = () => {
const [cookies, setCookie] = useCookies();
//if your username hasn't been reserved
if (!cookies['pseudonym']) {
fetch('/api/chat/reserve', { method: 'POST' })
.then(msg => msg.json())
.then(json => {
if (!json.ok) { //I don't like doing this
console.error(json.error);
}
})
.catch(e => console.error(e))
;
}
};
export default Chat;
+14 -1
View File
@@ -39,7 +39,12 @@ const question = (prompt, def) => {
const newsDBPass = await question('News Database Password', 'charizard');
const newsKey = await question('News Query Key', uuid());
//TODO: chat configuration
//chat configuration
const chatName = await question('Chat Name', 'chat');
const chatWebAddress = await question('Chat Web Address', 'chat.example.com');
const chatDBUser = await question('Chat Database Username', chatName);
const chatDBPass = await question('Chat Database Password', 'blastoise');
const chatKey = await question('Chat Reservation Key', uuid());
//database configuration
const databaseRootPassword = await question('Database Root Password', 'password');
@@ -52,6 +57,8 @@ const question = (prompt, def) => {
const sessionSecret = uuid(); //for session randomness
const sessionAdmin = uuid(128); //for checking if user is admin
//TODO: Implement chat-server as a docker container
const yml = `
version: "3.6"
services:
@@ -83,6 +90,8 @@ services:
- SESSION_ADMIN=${sessionAdmin}
- NEWS_URI=https://${newsWebAddress}/news
- NEWS_KEY=${newsKey}
- CHAT_URI=https://${chatWebAddress}/chat
- CHAT_KEY=${chatKey}
networks:
- app-network
depends_on:
@@ -180,6 +189,10 @@ CREATE DATABASE IF NOT EXISTS ${newsName};
CREATE USER IF NOT EXISTS '${newsDBUser}'@'%' IDENTIFIED BY '${newsDBPass}';
GRANT ALL PRIVILEGES ON ${newsName}.* TO '${newsDBUser}'@'%';
CREATE DATABASE IF NOT EXISTS ${chatName};
CREATE USER IF NOT EXISTS '${chatDBUser}'@'%' IDENTIFIED BY '${chatDBPass}';
GRANT ALL PRIVILEGES ON ${chatName}.* TO '${chatDBUser}'@'%';
FLUSH PRIVILEGES;
`;
+80
View File
@@ -18,8 +18,10 @@
"express": "^4.17.1",
"express-formidable": "^1.2.0",
"express-session": "^1.17.1",
"form-data": "^4.0.0",
"mariadb": "^2.5.2",
"node-cron": "^2.0.3",
"node-fetch": "^2.6.1",
"nodemailer": "^6.4.17",
"react-cookie": "^4.0.3",
"react-dropdown-select": "^4.7.3",
@@ -1949,6 +1951,11 @@
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"dev": true
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"node_modules/atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -2670,6 +2677,17 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -3376,6 +3394,14 @@
"node": ">=6"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
@@ -4319,6 +4345,19 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/formidable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
@@ -6547,6 +6586,14 @@
"node": ">=6.0.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"engines": {
"node": "4.x || >=6.0.0"
}
},
"node_modules/node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@@ -12384,6 +12431,11 @@
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -12983,6 +13035,14 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -13555,6 +13615,11 @@
"rimraf": "^2.6.3"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"denque": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
@@ -14354,6 +14419,16 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"formidable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
@@ -16100,6 +16175,11 @@
"tz-offset": "0.0.1"
}
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
+2
View File
@@ -35,8 +35,10 @@
"express": "^4.17.1",
"express-formidable": "^1.2.0",
"express-session": "^1.17.1",
"form-data": "^4.0.0",
"mariadb": "^2.5.2",
"node-cron": "^2.0.3",
"node-fetch": "^2.6.1",
"nodemailer": "^6.4.17",
"react-cookie": "^4.0.3",
"react-dropdown-select": "^4.7.3",
+1
View File
@@ -3,6 +3,7 @@ const route = (req, res) => {
req.session.account = null;
res.clearCookie('loggedin');
res.clearCookie('admin');
res.clearCookie('pseudonym');
return res.status(200).end();
};
+7
View File
@@ -0,0 +1,7 @@
const express = require('express');
const router = express.Router();
//reserve the name on the chat server (then get out of the way)
router.post('/reserve', require('./reserve'));
module.exports = router;
+23
View File
@@ -0,0 +1,23 @@
const fetch = require('node-fetch');
const FormData = require('form-data');
const route = async (req, res) => {
//build the fake form data object
let form = new FormData();
form.append('username', req.session?.account?.username);
try {
//reserve the UUID with the chat server (hop 1)
const result = await fetch(`http://${process.env.CHAT_URI}/reserve`, { method: 'POST', body: form });
const json = await result.json();
res.cookie('pseudonym', json.pseudonym);
res.status(200).send({ ok: true });
} catch(e) {
console.error('Chat server not found');
res.cookie('pseudonym', '.null');
res.status(200).send({ ok: false, error: 'Chat server not found' });
}
};
module.exports = route;
+3
View File
@@ -31,6 +31,9 @@ app.use(session({
//account management
app.use('/api/accounts', require('./accounts'));
//chat management
app.use('/api/chat', require('./chat'));
//administration
app.use('/api/admin', require('./admin'));
require('./admin/bookkeeper')(); //BUGFIX
+2
View File
@@ -51,7 +51,9 @@ module.exports = ({ production, analyzer }) => {
new DefinePlugin({
'process.env': {
'NEWS_URI': production ? `"${process.env.NEWS_URI}"` : '"http://dev-news.eggtrainer.com:3100/news"',
/* TODO: (1) NEWS_KEY needs to be set in the server, and auth'd via admin accounts, NOT embedded in the client */
'NEWS_KEY': production ? `"${process.env.NEWS_KEY}"` : '"key"',
'CHAT_URI': production ? `"${process.env.NEWS_URI}"` : '"http://dev-chat.eggtrainer.com:3200/chat"',
}
}),
new CleanWebpackPlugin({