From d7cfe02c170dc533e5f7328146ebb0a0d14a47fc Mon Sep 17 00:00:00 2001 From: zekro Date: Fri, 19 Oct 2018 12:55:16 +0200 Subject: [PATCH 1/2] Update websocket.js --- src/core/websocket.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/websocket.js b/src/core/websocket.js index 2967901..289ed6b 100644 --- a/src/core/websocket.js +++ b/src/core/websocket.js @@ -15,7 +15,7 @@ const querystring = require('querystring') const WEBINTERFACE_VERSION = '1.10.0' const SESSION_TIMEOUT = 1800 * 1000 -const EXPOSE_PORT = 1337 +const EXPOSE_PORT = 6612 const STATUS = { ERROR: 'ERROR', @@ -656,4 +656,4 @@ class Websocket { -module.exports = Websocket \ No newline at end of file +module.exports = Websocket From b09cad437b58fabff7731b85c7db838ed72e67e2 Mon Sep 17 00:00:00 2001 From: zekro Date: Sat, 20 Oct 2018 01:54:24 +0200 Subject: [PATCH 2/2] updated some stuff --- .gitignore | 1 + src/core/webinterface/login.hbs | 4 +- src/core/websocket.js | 109 +++++++++++++++----------------- src/util/discordOAuth.js | 78 +++++++++++++++++++++++ 4 files changed, 132 insertions(+), 60 deletions(-) create mode 100644 src/util/discordOAuth.js diff --git a/.gitignore b/.gitignore index a68efb9..cc837cd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ WebApiClient/YuriClient/obj/* */packages/* WebApiClient/.vs/* config.json +expose/* \ No newline at end of file diff --git a/src/core/webinterface/login.hbs b/src/core/webinterface/login.hbs index 7831019..b920c55 100644 --- a/src/core/webinterface/login.hbs +++ b/src/core/webinterface/login.hbs @@ -64,7 +64,9 @@ function saveToken() { if (cbsavetoken.checked) { - document.cookie = `logintoken=${tbtoken.value};`; + let d = new Date(); + d.setTime(d.getTime() + (90 * 24 * 3600 * 1000)) + document.cookie = `logintoken=${tbtoken.value};expires=${d.toUTCString()};`; } } \ No newline at end of file diff --git a/src/core/websocket.js b/src/core/websocket.js index 289ed6b..3e95525 100644 --- a/src/core/websocket.js +++ b/src/core/websocket.js @@ -4,18 +4,18 @@ const { players, guildLog, Player } = require('../core/player') const { info, error } = require('../util/msgs') const path = require('path') const EventEmitter = require('events'); +const DicordOAuth = require('../util/discordOAuth') const express = require('express') const hbs = require('express-handlebars') const socketio = require('socket.io') const http = require('http') -const request = require('request') -const querystring = require('querystring') const WEBINTERFACE_VERSION = '1.10.0' -const SESSION_TIMEOUT = 1800 * 1000 -const EXPOSE_PORT = 6612 +const SESSION_TIMEOUT = 1800 * 1000 // 30 Minutes +const LOGIN_TIMEOUT = 30 * 1000 // 30 Seconds +const EXPOSE_PORT = process.argv.includes("--1337") ? 1337 : 6612 const STATUS = { ERROR: 'ERROR', @@ -30,7 +30,8 @@ const ERRCODE = { PLAYER_ERROR: 4, INVALID_LOGIN: 5, SESSION_NOT_LOGGED_IN: 6, - NO_VC: 7 + NO_VC: 7, + LOGIN_TIMED_OUT: 8 } class Session { @@ -87,11 +88,23 @@ class SessionTimer extends EventEmitter { } +function removeFromArrayIfExists(array, element) { + let i = array.indexOf(element) + if (i > -1) + array.splice(i, 1) +} + class Websocket { constructor() { this.sessions = {} this.ipregister = {} + this.authorizedids = [] + this.oauth = new DicordOAuth({ + clientid: Main.config.client.id, + clientsecret: Main.config.client.secret, + serveraddr: Main.config.serveraddr + }) this.app = express() this.app.engine('hbs', hbs({ extname: 'hbs', @@ -110,12 +123,15 @@ class Websocket { return } + /////////////////////// + //// WEB INTERFACE //// + /////////////////////// + // WEBINTERFACE this.app.get('/', (req, res) => { - var authRedirect = () => res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${Main.config.client.id}&redirect_uri=${encodeURIComponent(Main.config.serveraddr + '/authorize')}&response_type=code&scope=identify`) var user = req.query.user ? req.query.user : this.ipregister[req.connection.remoteAddress] if (!user) { - authRedirect() + this.oauth.redirectToAuth('authorize', res) return } var session = this.sessions[user] @@ -142,7 +158,7 @@ class Websocket { WEBINTERFACE_VERSION }) } else { - authRedirect() + this.oauth.redirectToAuth('authorize', res) } }) @@ -160,6 +176,14 @@ class Websocket { return } + if (!this.authorizedids.includes(user)) { + res.render('error', { + code: ERRCODE.LOGIN_TIMED_OUT, + reason: 'Login timed out.' + }) + return + } + if (!this._checkToken(token)) { if (passedByToken == '1') { res.render('resetTokenCookie', { @@ -447,61 +471,28 @@ class Websocket { let user = req.query.user res.render('login', { user, resetToken }) } - - let data = { - 'client_id': Main.config.client.id, - 'client_secret': Main.config.client.secret, - 'grant_type': 'authorization_code', - 'code': code, - 'redirect_uri': Main.config.serveraddr + '/authorize', - 'scope': 'identify' - } - request({ - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - uri: 'https://discordapp.com/api/oauth2/token', - body: querystring.stringify(data), - method: 'POST' - }, (err, _, body) => { - let bobj = JSON.parse(body) - if (err || bobj.error) { - console.log(bobj) + this.oauth.getId(req, (err, user) => { + if (err) { this._sendStatus(res, STATUS.ERROR, ERRCODE.INVALID_LOGIN) return } - request({ - headers: { - 'Authorization': 'Bearer ' + bobj.access_token - }, - uri: 'https://discordapp.com/api/users/@me', - method: 'GET' - }, (err, _, body) => { - let bobj = JSON.parse(body) - if (err || bobj.error) { - this._sendStatus(res, STATUS.ERROR, ERRCODE.INVALID_LOGIN) - return - } - let user = bobj.id - - var sortbydate = (req.query.sortbydate == 1) - - var session = this.sessions[user] - - if (!session) { - res.render('login', { user }) - return - } - - if (!session.vc) { - this.sessions[user] = null - res.render('login', { user }) - return - } - - res.redirect('/?user=' + user) - }) + var sortbydate = (req.query.sortbydate == 1) + var session = this.sessions[user] + this.authorizedids.push(user) + setTimeout(() => { + removeFromArrayIfExists(this.authorizedids, user) + }, LOGIN_TIMEOUT) + if (!session) { + res.render('login', { user }) + return + } + if (!session.vc) { + this.sessions[user] = null + res.render('login', { user }) + return + } + res.redirect('/?user=' + user) }) }) diff --git a/src/util/discordOAuth.js b/src/util/discordOAuth.js new file mode 100644 index 0000000..92c6323 --- /dev/null +++ b/src/util/discordOAuth.js @@ -0,0 +1,78 @@ +const request = require('request'); +const querystring = require('querystring'); + +/** + * + */ +class DiscordOAuth { + + /** + * Create new instance of DiscordOAuth. + * @param {string} options.clientid ID of the Discord API APP (NOT the ID of the bot's account!) + * @param {string} options.clientsecret Secret of the Discord API APP (NOT the token of the bot!) + * @param {string} options.serveraddr The address of the server (including protocol (http:// or https://) port, + * if not accessed over 443 or 80) + */ + constructor(options) { + this.options = options; + } + + /** + * Redirect the request to the OAuth Authorization Endpoint + * @param {string} authRoot The name of the GET endpoint where the redirect should end + * @param {express.Response} response The response passed by express app callback + */ + redirectToAuth(authRoot, response) { + response.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${this.options.clientid}&redirect_uri=${encodeURIComponent(this.options.serveraddr + '/' + authRoot)}&response_type=code&scope=identify`); + } + + /** + * Get the Users ID by response code from 'DiscordOAuth#redirectToAuth' redirect. + * @param {express.Request} req The request passed by express app callback + * @param {function} cb Callback function(error, userID) + */ + getId(req, cb) { + let code = req.query.code; + + let data = { + 'client_id': this.options.clientid, + 'client_secret': this.options.clientsecret, + 'grant_type': 'authorization_code', + 'code': code, + 'redirect_uri': this.options.serveraddr + '/authorize', + 'scope': 'identify' + }; + + request({ + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + uri: 'https://discordapp.com/api/oauth2/token', + body: querystring.stringify(data), + method: 'POST' + }, (err, _, body) => { + let bobj = JSON.parse(body); + if (err || bobj.error) { + cb(err); + return; + } + request({ + headers: { + 'Authorization': 'Bearer ' + bobj.access_token + }, + uri: 'https://discordapp.com/api/users/@me', + method: 'GET' + }, (err, _, body) => { + let bobj = JSON.parse(body); + if (err || bobj.error) { + cb(err); + return; + } + + cb(null, bobj.id); + }); + }); + } +}; + +module.exports = DiscordOAuth; \ No newline at end of file