Skip to content

Commit

Permalink
Fixed a lot of security issues
Browse files Browse the repository at this point in the history
- Now using bcrypt to hash passwords

- Switched from md5ed timestamps to JWT's (Login) and true random strings (Email confirmation / Password resets) for tokens.

- Now using helmet for xss and iframe protection

- Updated dependencys

- Added Dependency badge

Signed-off-by: Henry Gressmann <[email protected]>
  • Loading branch information
explodingcamera committed Jul 24, 2016
1 parent 77f8a08 commit c0b6996
Show file tree
Hide file tree
Showing 22 changed files with 352 additions and 536 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
language: node_js

node_js:
- '6'
- '5'
- '5.1'
- '4'
- '4.1'

env:
- CXX=g++-4.8
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# mqp-server [![Version npm](https://img.shields.io/npm/v/mqp-server.svg?style=flat-square)](https://www.npmjs.com/package/mqp-server) [![npm Downloads](https://img.shields.io/npm/dm/mqp-server.svg?style=flat-square)](https://www.npmjs.com/package/mqp-server) [![Build Status](https://img.shields.io/travis/musiqpad/mqp-server/master.svg?style=flat-square)](https://travis-ci.org/musiqpad/mqp-server)
# mqp-server [![Version npm](https://img.shields.io/npm/v/mqp-server.svg?style=flat-square)](https://www.npmjs.com/package/mqp-server) [![npm Downloads](https://img.shields.io/npm/dm/mqp-server.svg?style=flat-square)](https://www.npmjs.com/package/mqp-server) [![Build Status](https://img.shields.io/travis/musiqpad/mqp-server/master.svg?style=flat-square)](https://travis-ci.org/musiqpad/mqp-server) [![devDependency Status](https://david-dm.org/musiqpad/mqp-server/dev-status.svg?style=flat-square)](https://david-dm.org/musiqpad/mqp-server#info=devDependencies)

[![NPM](https://nodei.co/npm/mqp-server.png)](https://npmjs.org/package/mqp-server)

Expand Down
39 changes: 33 additions & 6 deletions config.example.hjson
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
{
/*
/* _ _
_ __ ___ _ _ ___(_) __ _ _ __ __ _ __| |
| '_ ` _ \| | | / __| |/ _` | '_ \ / _` |/ _` |
| | | | | | |_| \__ \ | (_| | |_) | (_| | (_| |
|_| |_| |_|\__,_|___/_|\__, | .__/ \__,_|\__,_|
|_|_|

More infos about the config syntax: https://hjson.org/

Set this flag to false to disable web server hosting or true to enable web server hosting.
This is useful if you want to host static files in another web server such as nginx.

Expand Down Expand Up @@ -101,7 +109,7 @@
twitter: "@musiqpad"
description: // A one to two sentence description for search engines & co
'''

Real time music streaming and chat with friends. Musiqpad is a place where people can discover new music.
'''
themeColor: "" // a hex color for the theme on chrome for android
favicon: "/pads/lib/img/icon.png"
Expand Down Expand Up @@ -129,9 +137,8 @@
}
}

// The amount of time users stay logged in for before having to login again in days.
// 0 = login every time
loginExpire: 7
// The amount of time users stay logged in for before having to login again, eg "2 days", "10h", "7d"
loginExpire: "5d",
db: {
dbType: "level" // Values "level" for LevelDB, "mysql" for MySQL and "mongo" for MongoDB
dbDir: "./socketserver/db" // Only used for LevelDB. Directory to save databases. Default is ./socketserver/db
Expand Down Expand Up @@ -413,17 +420,36 @@
color: "#964B74"
}
permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
"djqueue.skip.self"
"djqueue.skip.other"
"djqueue.lock"
"djqueue.cycle"
"djqueue.limit"
"djqueue.move"
"djqueue.playLiveVideos"
"djqueue.limit.bypass"
"djqueue.lock.bypass"
"chat.send"
"chat.private"
"chat.delete"
"chat.specialMention"
"chat.broadcast"
"chat.staff"
"playlist.create"
"playlist.delete"
"playlist.rename"
"playlist.import"
"playlist.shuffle"
"room.grantroles"
"room.restrict.ban"
"room.restrict.mute"
"room.restrict.mute_silent"
"room.ratelimit.bypass"
"room.whois"
"room.whois.iphistory"
]
canGrantRoles: [
]
Expand Down Expand Up @@ -470,4 +496,5 @@
]
}
}
}
tokenSecret: "" // This should be a random string that needs to be kept private. Automatically generated if empty.
}
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"dependencies": {
"basic-logger": "^0.4.4",
"bcrypt-nodejs": "0.0.3",
"chalk": "^1.0.0",
"clean-css": "^3.4.9",
"compression": "^1.6.2",
Expand All @@ -37,27 +38,28 @@
"file-tail": "^0.3.0",
"forever": "^0.15.1",
"fs-extra": "^0.30.0",
"helmet": "^2.1.1",
"hjson": "^1.8.4",
"jsonwebtoken": "^7.1.6",
"leveldown": "1.4.4",
"levelup": "^1.3.1",
"mongodb": "^2.1.16",
"mongodb": "^2.2.4",
"mysql": "^2.10.2",
"nconf": "^0.8.4",
"nodemailer": "^2.1.0",
"path": "^0.12.7",
"ps-tree": "^1.0.1",
"request": "^2.67.0",
"update-notifier": "^0.7.0",
"ws": "^1.0.1",
"request": "^2.74.0",
"update-notifier": "^1.0.2",
"ws": "^1.1.1",
"xoauth2": "^1.1.0",
"yesno": "0.0.1"
},
"devDependencies": {
"ava": "^0.15.2",
"eslint": "^2.13.1",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-import": "^1.9.2",
"eslint-plugin-jsx-a11y": "^1.5.3",
"eslint-plugin-import": "^1.11.1",
"eslint-plugin-jsx-a11y": "^1.5.5",
"eslint-plugin-react": "^5.2.2"
},
"ava": {
Expand Down
10 changes: 5 additions & 5 deletions socketserver/YT.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
var https = require('https');
var util = require('util');
var log = new (require('basic-logger'))({showTimestamp: true, prefix: "YT"});
var querystring = require('querystring');
var Duration = require("durationjs");
const https = require('https');
const util = require('util');
const log = new (require('basic-logger'))({showTimestamp: true, prefix: "YT"});
const querystring = require('querystring');
const Duration = require("durationjs");
const nconf = require('nconf');
const key = nconf.get('apis:YT:key');

Expand Down
111 changes: 96 additions & 15 deletions socketserver/database.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,100 @@
'use strict';
const nconf = require('nconf');
const LevelDB = require('./db_level');
const MySQL = require('./db_mysql');
const MongoDB = require('./db_mongo');
const utils = require('./utils');
let Database;

function Database() {
nconf.defaults({
'db:dbType': 'level'
});
switch (nconf.get('db:dbType')) {
case 'level':
return require('./db_level');
case 'mysql':
return require('./db_mysql');
case 'mongo':
return require('./db_mongo');
default:
return require('./db_level');
}
var util = require('util');

switch (nconf.get('db:dbType')) {
case 'level':
Database = LevelDB;
break;
case 'mysql':
Database = MySQL;
break;
case 'mongo':
Database = MongoDB;
break;
default:
Database = LevelDB;
}

function loginCallback(callback) {
return function (err, user, email) {
if (email) {
callback(null, user, utils.token.createToken({ email }, nconf.get('tokenSecret'), nconf.get('loginExpire')));
return;
}
callback(err);
};
}

class DB extends Database {
loginUser(obj, callback) {
if (obj.token) {
try {
obj.email = utils.token.verify(obj.token, nconf.get('tokenSecret')).email;
} catch (e) {
if (e) {
callback('InvalidToken');
return;
}
}
}

this.getUser(obj.email, (err, user) => {
if ((err && err.notFound) || user == null) {
callback('UserNotFound');
return;
}

if (err) {
callback(err);
return;
}
// If the user has an old md5 password saved in the db
if (typeof user.data.pw === 'string' && utils.hash.isMD5(user.data.pw) && !obj.token) {
// And if that md5 password matches with the supplied pw
if (utils.db.makePassMD5(obj.pw, user.data.salt) !== user.data.pw) {
callback('IncorrectPassword');
return;
}
// Update the pw to a new bcrypt password
user.pw = obj.pw;
super.loginUser(obj.email, loginCallback(callback));
// If user has an md5 password and only supplied a token
} else if (utils.hash.isMD5(user.data.pw) && obj.token) {
// Say token is invalid so we get the password instead of the token next time
callback('InvalidToken');
} else if (obj.token) {
// Check if the token is correct
utils.token.verify(obj.token, nconf.get('tokenSecret'), (err, decoded) => {
if (err) {
callback('InvalidToken');
return;
}
const email = decoded.email;
super.loginUser(email, loginCallback(callback));
});
} else if (obj.pw && utils.hash.compareBcrypt(obj.pw, user.data.pw)) {
super.loginUser(obj.email, loginCallback(callback));
} else {
callback('IncorrectPassword');
}
});
}
createUser(obj, callback) {
if (obj.pw) {
obj.pw = utils.hash.bcrypt(obj.pw);
super.createUser(obj, loginCallback(callback));
} else {
callback('InvalidPassword');
}
}
}

module.exports = new Database();
const db = new DB();
module.exports = db;
17 changes: 0 additions & 17 deletions socketserver/database_util.js

This file was deleted.

Loading

0 comments on commit c0b6996

Please sign in to comment.