Skip to content

Commit

Permalink
* Bump version to 0.0.5-alpha
Browse files Browse the repository at this point in the history
* Add email password reset support
  • Loading branch information
NuSkooler committed Feb 27, 2017
1 parent 97e1995 commit f5899bc
Show file tree
Hide file tree
Showing 18 changed files with 571 additions and 28 deletions.
4 changes: 4 additions & 0 deletions core/bbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ function initialize(cb) {
function readyFileAreaWeb(callback) {
return require('./file_area_web.js').startup(callback);
},
function readyPasswordReset(callback) {
const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset;
return WebPasswordReset.startup(callback);
},
function readyEventScheduler(callback) {
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
EventSchedulerModule.loadAndStart( (err, modInst) => {
Expand Down
15 changes: 13 additions & 2 deletions core/button_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,26 @@ function ButtonView(options) {

util.inherits(ButtonView, TextView);

ButtonView.prototype.onKeyPress = function(ch, key) {
if(this.isKeyMapped('accept', key.name) || ' ' === ch) {
this.submitData = 'accept';
this.emit('action', 'accept');
delete this.submitData;
} else {
ButtonView.super_.prototype.onKeyPress.call(this, ch, key);
}
};
/*
ButtonView.prototype.onKeyPress = function(ch, key) {
// allow space = submit
if(' ' === ch) {
if(' ' === ch) {
this.emit('action', 'accept');
}
ButtonView.super_.prototype.onKeyPress.call(this, ch, key);
};
*/

ButtonView.prototype.getData = function() {
return null;
return this.submitData || null;
};
27 changes: 26 additions & 1 deletion core/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,26 @@ function getDefaultConfig() {
domain : 'another-fine-enigma-bbs.org',

staticRoot : paths.join(__dirname, './../www'),


resetPassword : {
//
// The following templates have these variables available to them:
//
// * %BOARDNAME% : Name of BBS
// * %USERNAME% : Username of whom to reset password
// * %TOKEN% : Reset token
// * %RESET_URL% : In case of email, the link to follow for reset. In case of landing page,
// URL to POST submit reset form.

// templates for pw reset *email*
resetPassEmailText : paths.join(__dirname, '../misc/reset_password_email.template.txt'), // plain text version
resetPassEmailHtml : paths.join(__dirname, '../misc/reset_password_email.template.html'), // HTML version

// tempalte for pw reset *landing page*
//
resetPageTemplate : paths.join(__dirname, './../www/reset_password.template.html'),
},

http : {
enabled : false,
port : 8080,
Expand Down Expand Up @@ -563,6 +582,12 @@ function getDefaultConfig() {
// - @execute:/path/to/something/executable.sh
//
action : '@method:core/message_area.js:trimMessageAreasScheduledEvent',
},

forgotPasswordMaintenance : {
schedule : 'every 24 hours',
action : '@method:core/web_password_reset.js:performMaintenanceTask',
args : [ '24 hours' ] // items older than this will be removed
}
}
},
Expand Down
31 changes: 31 additions & 0 deletions core/email.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* jslint node: true */
'use strict';

// ENiGMA½
const Config = require('./config.js').config;
const Errors = require('./enig_error.js').Errors;
const Log = require('./logger.js').log;

// deps
const _ = require('lodash');
const nodeMailer = require('nodemailer');

exports.sendMail = sendMail;

function sendMail(message, cb) {
if(!_.has(Config, 'email.transport')) {
return cb(Errors.MissingConfig('Email "email::transport" configuration missing'));
}

message.from = message.from || Config.email.defaultFrom;

const transportOptions = Object.assign( {}, Config.email.transport, {
logger : Log,
});

const transport = nodeMailer.createTransport(transportOptions);

transport.sendMail(message, (err, info) => {
return cb(err, info);
});
}
1 change: 1 addition & 0 deletions core/enig_error.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ exports.Errors = {
ExternalProcess : (reason, reasonCode) => new EnigError('External process error', -32005, reason, reasonCode),
MissingConfig : (reason, reasonCode) => new EnigError('Missing configuration', -32006, reason, reasonCode),
UnexpectedState : (reason, reasonCode) => new EnigError('Unexpected state', -32007, reason, reasonCode),
MissingParam : (reason, reasonCode) => new EnigError('Missing paramater(s)', -32008, reason, reasonCode),
};

exports.ErrorReasons = {
Expand Down
13 changes: 8 additions & 5 deletions core/file_area_web.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const StatLog = require('./stat_log.js');
const User = require('./user.js');
const Log = require('./logger.js').log;
const getConnectionByUserId = require('./client_connections.js').getConnectionByUserId;
const webServerPackageName = require('./servers/content/web.js').moduleInfo.packageName;

// deps
const hashids = require('hashids');
Expand All @@ -23,8 +24,6 @@ const fs = require('fs');
const mimeTypes = require('mime-types');
const _ = require('lodash');

const WEB_SERVER_PACKAGE_NAME = 'codes.l33t.enigma.web.server';

/*
:TODO:
* Load temp download URLs @ startup & set expire timers via scheduler.
Expand All @@ -51,9 +50,9 @@ class FileAreaWebAccess {
return self.load(callback);
},
function addWebRoute(callback) {
self.webServer = getServer(WEB_SERVER_PACKAGE_NAME);
self.webServer = getServer(webServerPackageName);
if(!self.webServer) {
return callback(Errors.DoesNotExist(`Server with package name "${WEB_SERVER_PACKAGE_NAME}" does not exist`));
return callback(Errors.DoesNotExist(`Server with package name "${webServerPackageName}" does not exist`));
}

if(self.isEnabled()) {
Expand Down Expand Up @@ -173,6 +172,9 @@ class FileAreaWebAccess {

buildTempDownloadLink(client, fileEntry, hashId) {
hashId = hashId || this.getHashId(client, fileEntry);

return this.webServer.instance.buildUrl(`${Config.fileBase.web.path}${hashId}`);
/*
//
// Create a URL such as
Expand Down Expand Up @@ -200,6 +202,7 @@ class FileAreaWebAccess {
return `${schema}${Config.contentServers.web.domain}${port}${Config.fileBase.web.path}${hashId}`;
}
*/
}

getExistingTempDownloadServeItem(client, fileEntry, cb) {
Expand Down Expand Up @@ -246,7 +249,7 @@ class FileAreaWebAccess {
}

fileNotFound(resp) {
this.webServer.instance.respondWithError(resp, 404, 'File not found.', 'File Not Found');
return this.webServer.instance.fileNotFound(resp);
}

routeWebRequestForFile(req, resp) {
Expand Down
9 changes: 4 additions & 5 deletions core/ftn_mail_packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ class PacketHeader {
point : 0,
};

this.packetVersion = version || '2+';

this.version = version || '2+';
this.origAddress = origAddr || EMPTY_ADDRESS;
this.destAddress = destAddr || EMPTY_ADDRESS;
this.created = createdMoment || moment();
Expand Down Expand Up @@ -234,7 +233,7 @@ function Packet(options) {
//
// :TODO: adjust values based on version discovered
if(FTN_PACKET_BAUD_TYPE_2_2 === packetHeader.baud) {
packetHeader.packetVersion = '2.2';
packetHeader.version = '2.2';

// See FSC-0045
packetHeader.origPoint = packetHeader.year;
Expand All @@ -254,14 +253,14 @@ function Packet(options) {
0 != packetHeader.capWord &&
packetHeader.capWord & 0x0001)
{
packetHeader.packetVersion = '2+';
packetHeader.version = '2+';

// See FSC-0048
if(-1 === packetHeader.origNet) {
packetHeader.origNet = packetHeader.auxNet;
}
} else {
packetHeader.packetVersion = '2';
packetHeader.version = '2';

// :TODO: should fill bytes be 0?
}
Expand Down
65 changes: 62 additions & 3 deletions core/servers/content/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class Route {
);
}

matchesRequest(req) { return req.method === this.method && this.pathRegExp.test(req.url); }
matchesRequest(req) {
return req.method === this.method && this.pathRegExp.test(req.url);
}

getRouteKey() { return `${this.method}:${this.path}`; }
}
Expand All @@ -67,6 +69,35 @@ exports.getModule = class WebServerModule extends ServerModule {
}
}

buildUrl(pathAndQuery) {
//
// Create a URL such as
// https://l33t.codes:44512/ + |pathAndQuery|
//
// Prefer HTTPS over HTTP. Be explicit about the port
// only if non-standard. Allow users to override full prefix in config.
//
if(_.isString(Config.contentServers.web.overrideUrlPrefix)) {
return `${Config.contentServers.web.overrideUrlPrefix}${pathAndQuery}`;
}

let schema;
let port;
if(Config.contentServers.web.https.enabled) {
schema = 'https://';
port = (443 === Config.contentServers.web.https.port) ?
'' :
`:${Config.contentServers.web.https.port}`;
} else {
schema = 'http://';
port = (80 === Config.contentServers.web.http.port) ?
'' :
`:${Config.contentServers.web.http.port}`;
}

return `${schema}${Config.contentServers.web.domain}${port}${pathAndQuery}`;
}

isEnabled() {
return this.enableHttp || this.enableHttps;
}
Expand Down Expand Up @@ -126,7 +157,7 @@ exports.getModule = class WebServerModule extends ServerModule {
}

routeRequest(req, resp) {
const route = _.find(this.routes, r => r.matchesRequest(req) );
const route = _.find(this.routes, r => r.matchesRequest(req) );
return route ? route.handler(req, resp) : this.accessDenied(resp);
}

Expand Down Expand Up @@ -161,14 +192,18 @@ exports.getModule = class WebServerModule extends ServerModule {
return this.respondWithError(resp, 401, 'Access denied.', 'Access Denied');
}

fileNotFound(resp) {
return this.respondWithError(resp, 404, 'File not found.', 'File Not Found');
}

routeStaticFile(req, resp) {
const fileName = req.url.substr(req.url.indexOf('/', 1));
const filePath = paths.join(Config.contentServers.web.staticRoot, fileName);
const self = this;

fs.stat(filePath, (err, stats) => {
if(err) {
return self.respondWithError(resp, 404, 'File not found.', 'File Not Found');
return self.fileNotFound(resp);
}

const headers = {
Expand All @@ -181,4 +216,28 @@ exports.getModule = class WebServerModule extends ServerModule {
return readStream.pipe(resp);
});
}

routeTemplateFilePage(templatePath, preprocessCallback, resp) {
const self = this;

fs.readFile(templatePath, 'utf8', (err, templateData) => {
if(err) {
return self.fileNotFound(resp);
}

preprocessCallback(templateData, (err, finalPage, contentType) => {
if(err || !finalPage) {
return self.respondWithError(resp, 500, 'Internal Server Error.', 'Internal Server Error');
}

const headers = {
'Content-Type' : contentType || mimeTypes.contentType('.html'),
'Content-Length' : finalPage.length,
};

resp.writeHead(200, headers);
return resp.end(finalPage);
});
});
}
};
37 changes: 28 additions & 9 deletions core/system_menu_method.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
const removeClient = require('./client_connections.js').removeClient;
const ansiNormal = require('./ansi_term.js').normal;
const userLogin = require('./user_login.js').userLogin;
const messageArea = require('./message_area.js');
const messageArea = require('./message_area.js');

// deps
const _ = require('lodash');
const iconv = require('iconv-lite');

exports.login = login;
exports.logoff = logoff;
exports.prevMenu = prevMenu;
exports.nextMenu = nextMenu;
exports.prevConf = prevConf;
exports.nextConf = nextConf;
exports.prevArea = prevArea;
exports.nextArea = nextArea;
exports.login = login;
exports.logoff = logoff;
exports.prevMenu = prevMenu;
exports.nextMenu = nextMenu;
exports.prevConf = prevConf;
exports.nextConf = nextConf;
exports.prevArea = prevArea;
exports.nextArea = nextArea;
exports.sendForgotPasswordEmail = sendForgotPasswordEmail;

function login(callingMenu, formData, extraArgs, cb) {

Expand Down Expand Up @@ -152,3 +153,21 @@ function nextArea(callingMenu, formData, extraArgs, cb) {
return reloadMenu(callingMenu, cb);
});
}

function sendForgotPasswordEmail(callingMenu, formData, extraArgs, cb) {
const username = formData.value.username || callingMenu.client.user.username;

const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset;

WebPasswordReset.sendForgotPasswordEmail(username, err => {
if(err) {
callingMenu.client.log.warn( { err : err.message }, 'Failed sending forgot password email');
}

if(extraArgs.next) {
return callingMenu.gotoMenu(extraArgs.next, cb);
}

return logoff(callingMenu, formData, extraArgs, cb);
});
}
Loading

0 comments on commit f5899bc

Please sign in to comment.