Changes to Authentication

- changed to password encryption on client side
- modified login page
- renamed webapi to weblib
pull/33/head
Trivernis 6 years ago
parent d095922926
commit d3e1106d70

@ -11,7 +11,7 @@ const Discord = require("discord.js"),
prefix = args.prefix || config.prefix || '~', prefix = args.prefix || config.prefix || '~',
gamepresence = args.game || config.presence; gamepresence = args.game || config.presence;
let webapi = null; let weblib = null;
class Bot { class Bot {
constructor(callback) { constructor(callback) {
@ -105,11 +105,11 @@ class Bot {
* initializes the api webserver * initializes the api webserver
*/ */
initializeWebserver() { initializeWebserver() {
logger.verbose('Importing webapi'); logger.verbose('Importing weblib');
webapi = require('./lib/webapi'); weblib = require('./lib/weblib');
webapi.setLogger(logger); weblib.setLogger(logger);
logger.verbose('Creating WebServer'); logger.verbose('Creating WebServer');
this.webServer = new webapi.WebServer(config.webservice.port || 8080); this.webServer = new weblib.WebServer(config.webservice.port || 8080);
logger.debug('Setting Reference Objects to webserver'); logger.debug('Setting Reference Objects to webserver');
this.webServer.setReferenceObjects({ this.webServer.setReferenceObjects({

@ -72,6 +72,7 @@ exports.DJ = class {
* Plays a file for the given filename. * Plays a file for the given filename.
* TODO: Implement queue * TODO: Implement queue
* @param filename * @param filename
* @todo
*/ */
playFile(filename) { playFile(filename) {
if (this.connected) { if (this.connected) {

@ -28,17 +28,14 @@ exports.WebServer = class {
this.setReferenceObjects(referenceObjects); this.setReferenceObjects(referenceObjects);
} }
/**
* TODO: Encrypt the password on client side.
*/
configureExpress() { configureExpress() {
this.app.set('view engine', 'pug'); this.app.set('view engine', 'pug');
this.app.set('trust proxy', 1); this.app.set('trust proxy', 1);
this.app.set('views', './web/http/'); this.app.set('views', './web/http/');
if (this.app.get('env') === 'devlopment') { if (this.app.get('env') === 'devlopment')
this.app.use(require('cors')()); this.app.use(require('cors')());
}
this.app.use(require('cors')()); this.app.use(require('cors')());
this.app.use(session({ this.app.use(session({
secret: config.webservice.sessionSecret, secret: config.webservice.sessionSecret,
@ -52,11 +49,11 @@ exports.WebServer = class {
this.app.use(compression({ this.app.use(compression({
filter: (req, res) => { filter: (req, res) => {
if (req.headers['x-no-compression']) { if (req.headers['x-no-compression'])
return false; return false;
} else { else
return compression.filter(req, res); return compression.filter(req, res);
}
} }
})); }));
this.app.use('/graphql', graphqlHTTP({ this.app.use('/graphql', graphqlHTTP({
@ -67,22 +64,11 @@ exports.WebServer = class {
this.app.use(compileSass({ this.app.use(compileSass({
root: './web/http/' root: './web/http/'
})); }));
this.app.get('/', (req, res, next) => {
if (req.session.user) {
next();
} else {
res.render('login');
}
}, (req, res) => {
res.render('index');
});
this.app.use('/scripts', express.static('./web/http/scripts'));
this.app.post('/', (req, res) => { this.app.post('/', (req, res) => {
if (!req.body.username || !req.body.password) { if (!req.body.username || !req.body.password)
res.render('login', {msg: 'Please enter username and password.'}); res.render('login', {msg: 'Please enter username and password.'});
} else { else
this.maindb.get('SELECT * FROM users WHERE username = ? AND password = ?', [req.body.username, sha512(req.body.password)], (err, user) => { this.maindb.get('SELECT * FROM users WHERE username = ? AND password = ?', [req.body.username, req.body.password], (err, user) => {
if (err || !user) { if (err || !user) {
if (err) if (err)
logger.warn(err.message); logger.warn(err.message);
@ -93,7 +79,15 @@ exports.WebServer = class {
res.render('index'); res.render('index');
} }
}); });
} });
this.app.use('/scripts', express.static('./web/http/scripts'));
this.app.use((req, res, next) => {
if (req.session.user)
next();
else
res.render('login');
}, (req, res) => {
res.render('index');
}); });
} }
@ -149,7 +143,7 @@ exports.WebServer = class {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let token = generateUUID(['TOKEN', username]); let token = generateUUID(['TOKEN', username]);
this.maindb.run('INSERT INTO users (username, password, token, scope) VALUES (?, ?, ?, ?)', this.maindb.run('INSERT INTO users (username, password, token, scope) VALUES (?, ?, ?, ?)',
[username, password,token, scope], (err) => { [username, password, token, scope], (err) => {
if (err) { if (err) {
logger.warn(err.message); logger.warn(err.message);
reject(err); reject(err);
@ -160,33 +154,6 @@ exports.WebServer = class {
}); });
} }
authenticateByToken(req, res, next) {
if (req.headers.authorization
&& req.headers.authorization.split(' ')[0] === 'Bearer') {
let bearer = req.headers.authorization.split(' ')[1];
this.maindb.get('SELECT * FROM users WHERE token = ?', [bearer], (err, user) => {
if (err) {
logger.warn(err.message);
logger.debug('Unauthorized access');
res.status(401);
res.end('Unauthorized Access');
} else {
if (!user) {
res.status(401);
res.end('Unauthorized Access');
} else {
req.user = user;
next();
}
}
});
} else {
logger.debug('Unauthorized access');
res.status(401);
res.end('Unauthorized Access');
}
}
/** /**
* Setting all objects that web can query * Setting all objects that web can query
* @param objects * @param objects
@ -200,19 +167,19 @@ exports.WebServer = class {
token VARCHAR(255) UNIQUE NOT NULL, token VARCHAR(255) UNIQUE NOT NULL,
scope INTEGER NOT NULL DEFAULT 0 scope INTEGER NOT NULL DEFAULT 0
)`, (err) => { )`, (err) => {
if (err) { if (err)
logger.error(err.message); logger.error(err.message);
}
}); });
this.root = { this.root = {
client: { client: {
guilds: (args) => { guilds: (args) => {
let dcGuilds = objects.client.guilds.values(); let dcGuilds = objects.client.guilds.values();
if (args.id) { if (args.id)
return [Array.from(dcGuilds) return [Array.from(dcGuilds)
.map((x) => new Guild(x, objects.getGuildHandler(x))) .map((x) => new Guild(x, objects.getGuildHandler(x)))
.find(x => (x.id === args.id))]; .find(x => (x.id === args.id))];
} else { else
try { try {
return Array.from(dcGuilds) return Array.from(dcGuilds)
.slice(args.offset, args.offset + args.first) .slice(args.offset, args.offset + args.first)
@ -221,7 +188,7 @@ exports.WebServer = class {
logger.error(err.stack); logger.error(err.stack);
return null; return null;
} }
}
}, },
guildCount: () => { guildCount: () => {
return Array.from(objects.client.guilds.values()).length; return Array.from(objects.client.guilds.values()).length;
@ -242,14 +209,14 @@ exports.WebServer = class {
let dcGuilds = Array.from(objects.client.guilds.values()); let dcGuilds = Array.from(objects.client.guilds.values());
return dcGuilds.filter((x) => { return dcGuilds.filter((x) => {
let gh = objects.guildHandlers[x.id]; let gh = objects.guildHandlers[x.id];
if (gh) { if (gh)
if (gh.dj) if (gh.dj)
return gh.dj.playing; return gh.dj.playing;
else else
return false; return false;
} else { else
return false; return false;
}
}).length; }).length;
} }
}, },
@ -270,18 +237,18 @@ exports.WebServer = class {
logEntries.push(new LogEntry(JSON.parse(line))); logEntries.push(new LogEntry(JSON.parse(line)));
}); });
lineReader.on('close', () => { lineReader.on('close', () => {
if (args.level) { if (args.level)
logEntries = logEntries logEntries = logEntries
.filter(x => (utils.logLevels[x.level] >= utils.logLevels[args.level])); .filter(x => (utils.logLevels[x.level] >= utils.logLevels[args.level]));
}
if (args.id) { if (args.id)
logEntries = [logEntries.find(x => (x.id === args.id))]; logEntries = [logEntries.find(x => (x.id === args.id))];
}
if (args.first) { if (args.first)
logEntries = logEntries.slice(args.offset, args.offset + args.first); logEntries = logEntries.slice(args.offset, args.offset + args.first);
} else { else
logEntries = logEntries.slice(logEntries.length - args.last); logEntries = logEntries.slice(logEntries.length - args.last);
}
resolve(logEntries); resolve(logEntries);
}); });
}); });
@ -291,7 +258,7 @@ exports.WebServer = class {
}; };
/** /**
* generating an unique id * generating an id
* @param valArr * @param valArr
* @returns {*} * @returns {*}
*/ */
@ -305,6 +272,11 @@ function generateID(valArr) {
return md5(b64); return md5(b64);
} }
/**
* generating an unique id
* @param input
* @returns {*}
*/
function generateUUID(input) { function generateUUID(input) {
return generateID([input, (new Date()).getMilliseconds()]) + Date.now(); return generateID([input, (new Date()).getMilliseconds()]) + Date.now();
} }
@ -327,11 +299,11 @@ class DJ {
thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(x.url) thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(x.url)
}; };
}); });
if (args.id) { if (args.id)
return [queue.find(x => (x.id === args.id))]; return [queue.find(x => (x.id === args.id))];
} else { else
return queue.slice(args.offset, args.offset + args.first); return queue.slice(args.offset, args.offset + args.first);
}
} }
get playing() { get playing() {
@ -377,6 +349,9 @@ class DJ {
} }
} }
/**
* Used for graphql access to the discord.js Guild and lib/guilding/GuildHandler
*/
class Guild { class Guild {
constructor(discordGuild, guildHandler) { constructor(discordGuild, guildHandler) {
this.id = generateID(['Guild', discordGuild.id]); this.id = generateID(['Guild', discordGuild.id]);
@ -405,14 +380,14 @@ class Guild {
logger.error(err.message); logger.error(err.message);
resolve(null); resolve(null);
} else { } else {
for (let row of rows) { for (let row of rows)
saved.push({ saved.push({
id: generateID(['Media', row.url]), id: generateID(['Media', row.url]),
name: row.name, name: row.name,
url: row.url, url: row.url,
thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(row.url) thumbnail: utils.YouTube.getVideoThumbnailUrlFromUrl(row.url)
}); });
}
resolve(saved); resolve(saved);
} }
}); });
@ -425,7 +400,7 @@ class Guild {
saved(args) { saved(args) {
return new Promise((resolve) => { return new Promise((resolve) => {
this.querySaved().then((result) => { this.querySaved().then((result) => {
if (result) { if (result)
if (args.id) { if (args.id) {
resolve([result.find(x => (x.id === args.id))]); resolve([result.find(x => (x.id === args.id))]);
} else if (args.name) { } else if (args.name) {
@ -433,31 +408,34 @@ class Guild {
} else { } else {
resolve(result.slice(args.offset, args.offset + args.first)); resolve(result.slice(args.offset, args.offset + args.first));
} }
} else { else
resolve(null); resolve(null);
}
}); });
}); });
} }
roles(args) { roles(args) {
if (args.id) { if (args.id)
return [this.prRoles.find(x => (x.id === args.id))]; return [this.prRoles.find(x => (x.id === args.id))];
} else { else
return this.prRoles.slice(args.offset, args.offset + args.first); return this.prRoles.slice(args.offset, args.offset + args.first);
}
} }
members(args) { members(args) {
if (args.id) { if (args.id)
return [this.prMembers.find(x => (x.id === args.id))]; return [this.prMembers.find(x => (x.id === args.id))];
} else { else
return this.prMembers.slice(args.offset, args.offset + args.first); return this.prMembers.slice(args.offset, args.offset + args.first);
}
} }
} }
/**
* Used for graphql access to the discord.js Role
*/
class Role { class Role {
constructor(discordRole) { constructor(discordRole) {
this.id = generateID(['Role', discordRole.id]); this.id = generateID(['Role', discordRole.id]);
@ -469,14 +447,17 @@ class Role {
} }
members(args) { members(args) {
if (args.id) { if (args.id)
return [this.prMembers.find(x => (x.id === args.id))]; return [this.prMembers.find(x => (x.id === args.id))];
} else { else
return this.prMembers.slice(args.offset, args.offset + args.first); return this.prMembers.slice(args.offset, args.offset + args.first);
}
} }
} }
/**
* Used for graphql access to the discord.js GuildMember
*/
class GuildMember { class GuildMember {
constructor(discordGuildMember) { constructor(discordGuildMember) {
this.id = generateID(['GuildMember', discordGuildMember.id]); this.id = generateID(['GuildMember', discordGuildMember.id]);
@ -489,14 +470,17 @@ class GuildMember {
} }
roles(args) { roles(args) {
if (args.id) { if (args.id)
return [this.prRoles.find(x => (x.id === args.id))]; return [this.prRoles.find(x => (x.id === args.id))];
} else { else
return this.prRoles.slice(args.offset, args.offset + args.first); return this.prRoles.slice(args.offset, args.offset + args.first);
}
} }
} }
/**
* Used for graphql access to the discord.js User
*/
class User { class User {
constructor(discordUser) { constructor(discordUser) {
this.id = generateID(['User', discordUser.id]); this.id = generateID(['User', discordUser.id]);
@ -513,6 +497,9 @@ class User {
} }
} }
/**
* Used for graphql access to log entries
*/
class LogEntry { class LogEntry {
constructor(entry) { constructor(entry) {
this.id = generateID(['LogEntry', entry.level, entry.timestamp]); this.id = generateID(['LogEntry', entry.level, entry.timestamp]);

@ -2,10 +2,12 @@ doctype html
html html
head head
link(type='text/css' rel='stylesheet' href='sass/style.sass') link(type='text/css' rel='stylesheet' href='sass/style.sass')
script(type='text/javascript' src='scripts/lib/sha512.min.js')
script(src='https://code.jquery.com/jquery-3.3.1.min.js')
script(type='text/javascript' src='scripts/login.js')
body body
h1 Login h1 Login
h3 #{message} h3 #{message}
form(action='/' method='POST') input(id='username' name='username' type='text' required placeholder='Username')
input(name='username' type='text' required placeholder='Username') input(id='password' name='password' type='password' required placeholder='Password')
input(name='password' type='password' required placeholder='Password') button(type='submit' onclick='login()') Log in
button(type='submit') Log in

File diff suppressed because one or more lines are too long

@ -0,0 +1,16 @@
/* eslint-disable */
function login() {
let username = document.querySelector('#username').value;
let password = sha512(document.querySelector('#password').value);
$.post({
url: "/",
data: JSON.stringify({
username: username,
password: password
}),
contentType: "application/json"
}).done((res) => {
document.write(res);
});
}

@ -1,3 +1,5 @@
/* eslint-disable */
let latestLogs = []; let latestLogs = [];
let status = { let status = {
@ -28,9 +30,6 @@ function postQuery(query) {
return new Promise((resolve) => { return new Promise((resolve) => {
$.post({ $.post({
url: "/graphql", url: "/graphql",
headers: {
Authorization: `Bearer ${localStorage.apiToken}`
},
data: JSON.stringify({ data: JSON.stringify({
query: query query: query
}), }),
@ -113,7 +112,6 @@ function queryGuild(guildId) {
} }
/** /**
* TODO: Play/Pause as status
* @param guildId * @param guildId
*/ */
function queryGuildStatus(guildId) { function queryGuildStatus(guildId) {
@ -278,9 +276,6 @@ function queryLogs(count) {
} }
function startUpdating() { function startUpdating() {
if (!localStorage.apiToken || localStorage.apiToken.length < 0)
localStorage.apiToken = prompt('Please provide an api token: ');
queryStatic(); queryStatic();
setInterval(queryStatic, 3600000); setInterval(queryStatic, 3600000);
queryStatus(); queryStatus();

Loading…
Cancel
Save