UNPKG

ftpd.js

Version:
272 lines (252 loc) 7.37 kB
//Imports var net = require( "net" ), tls = require( "tls" ), fs = require( "fs" ), util = require( "util" ), EventEmitter = require( "events" ).EventEmitter, path = require( "path" ), User = require( path.join( "..", "user", "index.js" ) ); /** * * @access public * @constructor * @param {Server} server the server utilizing the interface * @param {Object} options the interface options * @since 0.6.0 */ function Interface( server, options ) { this.server = server; this.options = options; this.issetup = false; this.connections = []; EventEmitter.call( this ); } util.inherits( Interface, EventEmitter ); /** * * This callback is used when the interface have finished setting up * * @callback Interface~didSetup * @param {Interface} the interface that finished setting up * @since 0.6.0 */ /** * * This function is used to setup the interface in this order: * - Check for tls certificate * - Read certificate into memory * - Create socket * - Setup listeners * * @access public * @param {Interface~didSetup} callback the callback to invoke when finished * @since 0.6.0 */ Interface.prototype.setup = function ( callback ) { var that = this, createServerOptions = this.getOptions().createServer || {}, parent = net; this.getServer().getFtpdjs().log( this.getBaseMessage() + ": Setting up" ); if ( (undefined !== createServerOptions.key) || (undefined !== this.getOptions().key) ) { parent = tls; } if ( undefined !== this.getOptions().key ) { //Read the SSL Certificate from storage createServerOptions.key = fs.readFileSync( this.getOptions().key ); createServerOptions.cert = fs.readFileSync( this.getOptions().cert ); if ( undefined !== this.getOptions().ca ) { createServerOptions.ca = [ fs.readFileSync( this.getOptions().ca ) ]; } } this.socket = parent.createServer( createServerOptions, function ( connection ) { that.onConnection( connection ); } ); this.getSocket().on( "error", function ( error ) { that.onError( error ); } ); this.issetup = true; try { this.getServer().getFtpdjs().log( this.getBaseMessage() + ": Finished setting up" ); callback( this ); } catch ( e ) { } }; /** * * This callback is used to when the interface have successfully bound to the provided address and is now accepting * connections * * @callback Interface~didListen * @since 0.6.0 */ /** * * This function is used to tell the interface to bind to the address it's been provided and start to liten for * connections The function will setup the interface if it haven't been done at the time of execution * * @access public * @param {Interface~didListen} callback the callback to invoke when bound and accepting clients * @since 0.6.0 */ Interface.prototype.listen = function ( callback ) { var that = this; //Check if the interface have been setup if ( !this.isSetup() ) { this.setup( function () { that.listen( callback ); } ); return; } this.getSocket().listen( this.getOptions().listen, function () { var formattedListen = that.getFormattedListen(); that.getServer().getFtpdjs().log( that.getBaseMessage() + ": Listening " + ("/" === formattedListen.charAt( 0 ) ? "at" : "on") + " " + formattedListen ); callback(); } ); }; /** * * This function gets invoked when an error occurs with the interface. Usually this is FATAL * * @access public * @param {Error} error the error * @since 0.6.0 */ Interface.prototype.onError = function ( error ) { this.emit( "error", error ); }; /** * * This function gets invoked when a new connection have been made to the interface * * @access public * @param {net.Socket} connection the connection object * @since 0.6.0 */ Interface.prototype.onConnection = function ( connection ) { connection = new User( this, connection ); this.emit( "connection", connection ); this.getConnections().push( connection ); }; /** * * This callback is used when the interface have closed and finished disconnecting all connections * * @callback Interface~finishedClose * @since 0.6.0 */ /** * * This function is used to close the interface and disconnect all active connections * * @access public * @param {Interface~finishedClose} done the callback to invoke when finished closing * @since 0.6.0 */ Interface.prototype.close = function ( done ) { var that = this; this.getSocket().close( function () { that.getServer().getFtpdjs().log( that.getBaseMessage() + ": Closed" ); done(); } ); for ( var i = 0; i < this.getConnections().length; i++ ) { this.getConnections()[ i ].destroy(); } }; /** * * This function is used to get the interface's ID * * @access public * @returns {int} the interface's id * @since 0.6.0 */ Interface.prototype.getID = function () { return this.getOptions().id; }; /** * * This function is used to get the server utilizing the interface * * @access public * @returns {Server} the server utilizing the interface * @since 0.6.0 */ Interface.prototype.getServer = function () { return this.server; }; /** * * This function is used to get the interface's options * * @access public * @returns {Object} the interface's options * @since 0.6.0 */ Interface.prototype.getOptions = function () { return this.options; }; /** * * This function is used to get the socket the interface is listening for connections on * * @access public * @returns {net.Server} the socket the server is listening on * @since 0.6.0 */ Interface.prototype.getSocket = function () { return this.socket; }; /** * * This function is used to get all of the connections connected to the interface * * @access public * @returns {Array} the connected connections * @since 0.6.0 */ Interface.prototype.getConnections = function () { return this.connections; }; /** * * This function is used to tell wether or not the interface have been setup * * @access public * @returns {boolean} true if the server have been setup, false if not * @since 0.6.0 */ Interface.prototype.isSetup = function () { return this.issetup; }; /** * * This function is used to get the base message for interface logging * * @access public * @returns {string} the base logging message * @since 0.6.o */ Interface.prototype.getBaseMessage = function () { return this.getServer().getBaseMessage() + " [Interface " + this.getID() + "]"; }; /** * * This function is used to get the formatted interface address * * @access public * @returns {string} the formatted address the interface *should* be listening on * @since 0.6.0 */ Interface.prototype.getFormattedListen = function () { //Check that it's not a unix socket/windows pipe if ( undefined !== this.getOptions().listen.path ) { return this.getOptions().listen.path; } return (undefined !== this.getOptions().key ? "tls://" : "") + this.getOptions().listen.host + ":" + this.getOptions().listen.port; }; /** * @access public * @type {Interface} * @since 0.6.0 */ module.exports = Interface;