* Start work on database & users

This commit is contained in:
NuSkooler 2014-10-19 23:30:44 -06:00
parent eab6da2b0a
commit 7a3e375f5d
7 changed files with 196 additions and 41 deletions

View File

@ -6,6 +6,7 @@ var conf = require('./config.js');
var modules = require('./modules.js'); var modules = require('./modules.js');
var logger = require('./logger.js'); var logger = require('./logger.js');
var miscUtil = require('./misc_util.js'); var miscUtil = require('./misc_util.js');
var database = require('./database.js');
var iconv = require('iconv-lite'); var iconv = require('iconv-lite');
var paths = require('path'); var paths = require('path');
@ -49,10 +50,6 @@ exports.bbsMain = function() {
logger.init(); logger.init();
preServingInit();
startListening();
process.on('SIGINT', function onSigInt() { process.on('SIGINT', function onSigInt() {
// :TODO: for any client in |clientConnections|, if 'ready', send a "Server Disconnecting" + semi-gracefull hangup // :TODO: for any client in |clientConnections|, if 'ready', send a "Server Disconnecting" + semi-gracefull hangup
// e.g. client.disconnectNow() // e.g. client.disconnectNow()
@ -60,6 +57,12 @@ exports.bbsMain = function() {
logger.log.info('Process interrupted, shutting down'); logger.log.info('Process interrupted, shutting down');
process.exit(); process.exit();
}); });
database.initializeDatabases();
preServingInit();
startListening();
}; };
function parseArgs() { function parseArgs() {

View File

@ -6,6 +6,7 @@ var paths = require('path');
var miscUtil = require('./misc_util.js'); var miscUtil = require('./misc_util.js');
module.exports = { module.exports = {
// :TODO: remove this ... anti-pattern!
config : undefined, config : undefined,
defaultPath : function() { defaultPath : function() {
@ -31,6 +32,7 @@ module.exports = {
servers : paths.join(__dirname, './servers/'), servers : paths.join(__dirname, './servers/'),
art : paths.join(__dirname, './../mods/art/'), art : paths.join(__dirname, './../mods/art/'),
logs : paths.join(__dirname, './../logs/'), // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such logs : paths.join(__dirname, './../logs/'), // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such
db : paths.join(__dirname, './../db/'),
}, },
servers : { servers : {

44
core/database.js Normal file
View File

@ -0,0 +1,44 @@
/* jslint node: true */
'use strict';
var conf = require('./config.js');
var sqlite3 = require('sqlite3');
var paths = require('path');
exports.initializeDatabases = initializeDatabases;
exports.user = user;
// db handles
var user;
function getDatabasePath(name) {
return paths.join(conf.config.paths.db, name + '.sqlite3');
}
function initializeDatabases() {
// :TODO: this will need to change if more DB's are added
user = new sqlite3.Database(getDatabasePath('user'));
user.serialize(function onSerialized() {
createUserTables();
});
}
function createUserTables() {
user.run(
'CREATE TABLE IF NOT EXISTS user (' +
' id INTEGER PRIMARY KEY,' +
' user_name VARCHAR NOT NULL,' +
' UNIQUE(user_name)' +
');'
);
user.run(
'CREATE TABLE IF NOT EXISTS user_property (' +
' user_id INTEGER NOT NULL,' +
' prop_name VARCHAR NOT NULL,' +
' prop_value VARCHAR,' +
' UNIQUE(user_id, prop_name)' +
');'
);
}

View File

@ -30,6 +30,10 @@ function stylizeString(s, style) {
var stylized = ''; var stylized = '';
switch(style) { switch(style) {
// None/normal
case 'normal' :
case 'N' : return s;
// UPPERCASE // UPPERCASE
case 'upper' : case 'upper' :
case 'U' : return s.toUpperCase(); case 'U' : return s.toUpperCase();
@ -38,9 +42,9 @@ function stylizeString(s, style) {
case 'lower' : case 'lower' :
case 'l' : return s.toLowerCase(); case 'l' : return s.toLowerCase();
// Proper Case // Title Case
case 'proper' : case 'title' :
case 'P' : case 'T' :
return s.replace(/\w\S*/g, function onProperCaseChar(t) { return s.replace(/\w\S*/g, function onProperCaseChar(t) {
return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase(); return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase();
}); });

93
core/user.js Normal file
View File

@ -0,0 +1,93 @@
/* jslint node: true */
'use strict';
var crypto = require('crypto');
var database = require('./database.js');
exports.User = User;
var PBKDF2_OPTIONS = {
iterations : 1000,
keyLen : 128,
saltLen : 32,
};
function User() {
var self = this;
this.id = 0;
this.userName = '';
this.groups = [];
this.permissions = [];
this.properties = {};
/*
this.load = function(userName, cb) {
database.user.get('SELECT id FROM user WHERE user_name = $un LIMIT 1;', { un : userName }, function onUser(err, row) {
if(err) {
cb(err);
return;
}
var user = new User();
user.id = row.id;
// :TODO: load the rest.
database.user.serialize(function loadUserSerialized() {
database.user.each('SELECT prop_name, prop_value FROM user_property WHERE user_id = $uid;', { uid : user.id }, function onUserPropRow(err, propRow) {
user.properties[propRow.prop_name] = propRow.prop_value;
});
});
cb(null, user);
});
};*/
}
User.load = function(userName, cb) {
database.user.get('SELECT id FROM user WHERE user_name = $un LIMIT 1;', { un : userName }, function onUser(err, row) {
if(err) {
cb(err);
return;
}
var user = new User();
user.id = row.id;
// :TODO: load the rest.
database.user.serialize(function loadUserSerialized() {
database.user.each('SELECT prop_name, prop_value FROM user_property WHERE user_id = $uid;', { uid : user.id }, function onUserPropRow(err, propRow) {
user.properties[propRow.prop_name] = propRow.prop_value;
});
});
cb(null, user);
});
};
User.prototype.setPassword = function(password, cb) {
// :TODO: validate min len, etc. here?
crypto.randomBytes(PBKDF2_OPTIONS.saltLen, function onRandomSalt(err, salt) {
if(err) {
cb(err);
return;
}
password = Buffer.isBuffer(password) ? password : new Buffer(password, 'base64');
crypto.pbkdf2(password, salt, PBKDF2_OPTIONS.iterations, PBKDF2_OPTIONS.keyLen, function onPbkdf2Generated(err, dk) {
if(err) {
cb(err);
return;
}
cb(null, dk);
this.properties['pw.pbkdf2.salt'] = salt;
this.properties['pw.pbkdf2.dk'] = dk;
});
});
};

View File

@ -140,11 +140,10 @@ InteractiveView.prototype.setNextView = function(id) {
var TEXT_EDIT_INPUT_TYPES = [ var TEXT_EDIT_INPUT_TYPES = [
'none', // :TODO: TextEditView -> TextView (optional focus/editable) 'normal', 'N',
'text', 'password', 'P',
'password', 'upper', 'U',
'upper', 'lower', 'l',
'lower',
]; ];
@ -155,14 +154,16 @@ function TextEditView(client, options) {
this.options.multiLine = false; this.options.multiLine = false;
} }
this.options.inputType = miscUtil.valueWithDefault(this.options.inputType, 'text'); this.options.inputType = miscUtil.valueWithDefault(this.options.inputType, 'normal');
assert(TEXT_EDIT_INPUT_TYPES.indexOf(this.options.inputType) > -1); assert(TEXT_EDIT_INPUT_TYPES.indexOf(this.options.inputType) > -1);
if('password' === this.options.inputType) { if('password' === this.options.inputType || 'P' === this.options.inputType) {
this.options.inputMaskChar = miscUtil.valueWithDefault(this.options.inputMaskChar, '*').substr(0,1); this.options.inputMaskChar = miscUtil.valueWithDefault(this.options.inputMaskChar, '*').substr(0,1);
} }
this.value = miscUtil.valueWithDefault(options.defaultValue, ''); this.value = miscUtil.valueWithDefault(options.defaultValue, '');
// :TODO: hilight, text, etc., should come from options or default for theme if not provided // :TODO: hilight, text, etc., should come from options or default for theme if not provided
// focus=fg + bg // focus=fg + bg
@ -211,7 +212,7 @@ TextEditView.prototype.onKeyPressed = function(k, isSpecial) {
this.value += k; this.value += k;
if('password' === this.options.inputType) { if('P' === this.options.inputType.charAt(0).toUpperCase()) {
this.client.term.write(this.options.inputMaskChar); this.client.term.write(this.options.inputMaskChar);
} else { } else {
this.client.term.write(k); this.client.term.write(k);
@ -272,14 +273,16 @@ function ViewsController(client) {
}); });
this.onViewAction = function(action) { this.onViewAction = function(action) {
console.log(action + '@ ' + this.id); console.log(action + ' @ ' + this.id);
self.emit('action', { id : this.id, action : action }); if(self.submitViewId == this.id) {
self.emit('action', { view : this, action : 'submit' });
} else {
self.emit('action', { view : this, action : action });
if('accepted' === action) { if('accepted' === action || 'next' === action) {
self.nextFocus(); self.nextFocus();
} else if('next' === action) { }
self.nextFocus();
} }
}; };
@ -335,6 +338,10 @@ ViewsController.prototype.nextFocus = function() {
} }
}; };
ViewsController.prototype.setSubmitView = function(id) {
this.submitViewId = id;
};
ViewsController.prototype.loadFromMCIMap = function(mciMap) { ViewsController.prototype.loadFromMCIMap = function(mciMap) {
var factory = new MCIViewFactory(this.client); var factory = new MCIViewFactory(this.client);
var view; var view;
@ -399,7 +406,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
} }
if(mci.args.length > 1) { if(mci.args.length > 1) {
options.inputType = mci.args[1];
} }
options.color = mci.color; options.color = mci.color;

View File

@ -5,6 +5,7 @@
var ansi = require('../core/ansi_term.js'); var ansi = require('../core/ansi_term.js');
var lineEditor = require('../core/line_editor.js'); var lineEditor = require('../core/line_editor.js');
var art = require('../core/art.js'); var art = require('../core/art.js');
var user = require('../core/user.js');
var view = require('../core/view.js'); var view = require('../core/view.js');
@ -21,22 +22,6 @@ function entryPoint(client) {
term.write(ansi.resetScreen()); term.write(ansi.resetScreen());
//-------------
/*
client.on('position', function onPos(pos) {
console.log(pos);
});
term.write('Hello, world!');
term.write(ansi.queryPos());
term.write(ansi.goto(5,5));
term.write('Yehawww a bunch of text incoming.... maybe that is what breaks it... hrm... who knows.\nHave to do more testing ;(\n');
term.write(ansi.queryPos());
return;
*/
//-------------
// :TODO: types, random, and others? could come from conf.mods.matrix or such // :TODO: types, random, and others? could come from conf.mods.matrix or such
//art.getArt('SO-CC1.ANS'/* 'MATRIX'*/, { types: ['.ans'], random: true}, function onArt(err, theArt) { //art.getArt('SO-CC1.ANS'/* 'MATRIX'*/, { types: ['.ans'], random: true}, function onArt(err, theArt) {
@ -52,6 +37,23 @@ function entryPoint(client) {
vc.loadFromMCIMap(mci); vc.loadFromMCIMap(mci);
vc.setViewOrder(); vc.setViewOrder();
vc.switchFocus(1); vc.switchFocus(1);
vc.setSubmitView(2);
vc.on('action', function onAction(act) {
if('submit' === act.action) {
console.log('userName=' + vc.getView(1).value);
console.log('password: ' + act.view.value);
user.User.load(vc.getView(1).value, function onUser(err, user) {
if(err) {
console.log(err);
return;
}
console.log(user.id);
});
}
});
}); });
} }
}); });