From 4fc859bcbeceda8e1579be7526ef948a7a355722 Mon Sep 17 00:00:00 2001 From: hydrabolt Date: Tue, 18 Aug 2015 19:01:45 +0100 Subject: [PATCH] Added Token Caching, v2.6.1 --- .gitignore | 1 + index.js | 31 ++++++++++++++----- lib/TokenManager.js | 72 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 ++-- 4 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 lib/TokenManager.js diff --git a/.gitignore b/.gitignore index 9394ea652..661f8f613 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ hydrabot/config.json hydrabot/authority.json +hydrabot/tokencache.json ### Node ### # Logs diff --git a/index.js b/index.js index 2901b5fd5..5a0f91832 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ var Invite = require( "./lib/invite.js" ).Invite; var PMChannel = require( "./lib/PMChannel.js" ).PMChannel; var WebSocket = require( 'ws' ); var Internal = require( "./lib/internal.js" ).Internal; +var TokenManager = require( "./lib/TokenManager.js" ).TokenManager; var serverCreateRequests = []; @@ -46,6 +47,7 @@ exports.Client = function( options ) { */ this.options = options || {}; this.options.maxmessage = 5000; + this.tokenManager = new TokenManager( "./", "tokencache.json" ); /** * Contains the token used to authorise HTTP requests and WebSocket connection. Received when login was successful. * @attribute token @@ -258,16 +260,24 @@ exports.Client.prototype.cacheServer = function( id, cb, members ) { * @param {Object} callback.error.error The raw XHR error. * @param {String} callback.token The token received when logging in */ -exports.Client.prototype.login = function( email, password, callback ) { +exports.Client.prototype.login = function( email, password, callback, noCache ) { var self = this; callback = callback || function() {}; + if ( noCache == undefined || noCache == null ) { + noCache = false; + } + self.connectWebsocket(); + if ( this.tokenManager.exists( email ) && !noCache ) { + done( this.tokenManager.getToken( email, password ) ); + return; + } + var time = Date.now(); Internal.XHR.login( email, password, function( err, token ) { - console.log( Date.now() - time ); if ( err ) { self.triggerEvent( "disconnected", [ { reason: "failed to log in", @@ -275,13 +285,20 @@ exports.Client.prototype.login = function( email, password, callback ) { } ] ); self.websocket.close(); } else { - self.token = token; - self.websocket.sendData(); - self.loggedIn = true; - callback( null, token ); + if ( !noCache ) { + self.tokenManager.addToken( email, token, password ); + } + done( token ); } } ); + + function done( token ) { + self.token = token; + self.websocket.sendData(); + self.loggedIn = true; + callback( null, token ); + } } /** @@ -898,7 +915,7 @@ exports.Client.prototype.joinServer = function( invite, callback ) { if ( err ) { callback( err ); } else { - serverCreateRequests[inviteData.guild.id] = callback; + serverCreateRequests[ inviteData.guild.id ] = callback; } } ); diff --git a/lib/TokenManager.js b/lib/TokenManager.js new file mode 100644 index 000000000..7b2853390 --- /dev/null +++ b/lib/TokenManager.js @@ -0,0 +1,72 @@ +var fs = require( "fs" ); +var crypto = require( "crypto" ); +var md5 = require( "md5" ); + +var tokens = {}; + +exports.TokenManager = function( folder, file ) { + + this.path = folder + file; + + var self = this; + + try { + var fd = fs.openSync( self.path, "wx" ); + self.writeTokens(); + } catch ( e ) { + if ( e.errno !== -4075 ) { + throw e; + } else { + self.readTokens(); + } + } + +} + +exports.TokenManager.prototype.addToken = function( id, token, pass ) { + tokens[ md5( id ) ] = encrypt( token, pass ); + this.writeTokens(); +} + +exports.TokenManager.prototype.readTokens = function() { + tokens = JSON.parse( fs.readFileSync( this.path, "utf8" ) ); + for ( tkn in tokens ) { + tokens[ tkn ] = decrypt( tokens[ tkn ], tkn ); + } +} + +exports.TokenManager.prototype.writeTokens = function() { + var tkn = {}; + for ( token in tokens ) { + tkn[ token ] = encrypt( tokens[ token ], token ); + } + fs.writeFile( this.path, JSON.stringify( tkn ), function( err ) { + + } ); +} + +exports.TokenManager.prototype.exists = function( id ) { + return tokens[ md5( id ) ]; +} + +exports.TokenManager.prototype.getToken = function( id, pass ) { + try{ + return decrypt( tokens[ md5( id ) ], pass ); + }catch(e){ + return false; + } +} + +function encrypt( string, password ) { + var cipher = crypto.createCipher( "aes-256-ctr", password ) + var crypted = cipher.update( string, 'utf8', 'hex' ) + crypted += cipher.final( 'hex' ); + return crypted; +} + +function decrypt( string, password ) { + var decipher = crypto.createDecipher( "aes-256-ctr", password ) + var dec = decipher.update( string, 'hex', 'utf8' ) + dec += decipher.final( 'utf8' ); + return dec; +} diff --git a/package.json b/package.json index 2c275f233..e980442b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.js", - "version": "2.6.0", + "version": "2.6.1", "description": "A way to interface with the Discord API", "main": "index.js", "scripts": { @@ -15,7 +15,8 @@ "api", "bot", "client", - "node" + "node", + "discordapp" ], "author": "Amish Shah ", "license": "Apache-2.0", @@ -24,6 +25,7 @@ }, "homepage": "https://github.com/discord-js/discord.js#readme", "dependencies": { + "md5": "^2.0.0", "superagent": "^1.3.0", "ws": "^0.7.2" }