<commit_before>'use strict';

var sax = require('sax'),
    _ = require('lodash');

var common = require('./common'),
    Types = require('moddle').types,
    Stack = require('tiny-stack'),
    parseNameNs = require('moddle').ns.parseName,
    aliasToName = common.aliasToName;

function parseNodeAttributes(node) {
  var nodeAttrs = node.attributes;

  return _.reduce(nodeAttrs, function(result, v, k) {
    var name, ns;

    if (!v.local) {
      name = v.prefix;
    } else {
      ns = parseNameNs(v.name, v.prefix);
      name = ns.name;
    }

    result[name] = v.value;
    return result;
  }, {});
}

/**
 * Normalizes namespaces for a node given an optional default namespace and a
 * number of mappings from uris to default prefixes.
 *
 * @param  {XmlNode} node
 * @param  {Model} model the model containing all registered namespaces
 * @param  {Uri} defaultNsUri
 */
function normalizeNamespaces(node, model, defaultNsUri) {
  var uri, childUri, prefix;

  uri = node.uri || defaultNsUri;

  if (uri) {
    var pkg = model.getPackage(uri);

    if (pkg) {
      prefix = pkg.prefix;
    } else {
      prefix = node.prefix;
    }

    node.prefix = prefix;
    node.uri = uri;
  }

  _.forEach(node.attributes, function(attr) {
    normalizeNamespaces(attr, model, null);
  });
}

/**
 * A parse context.
 *
 * @class
 *
 * @param {ElementHandler} parseRoot the root handler for parsing a document
 */
function Context(parseRoot) {

  var elementsById = {};
  var references = [];

  var warnings = [];

  this.addReference = function(reference) {
    references.push(reference);
  };

  this.addElement = function(id, element) {

    if (!id || !element) {
      throw new Error('[xml-reader] id or ctx must not be null');
    }

    elementsById[id] = element;
  };

  this.addWarning = function (w) {
    warnings.push(w);
  };

  this.warnings = warnings;
  this.references = references;

  this.elementsById = elementsById;

  this.parseRoot = parseRoot;
}

function BaseHandler() {}

BaseHandler.prototype.handleEnd = function() {};
BaseHandler.prototype.handleText = function() {};
BaseHandler.prototype.handleNode = function() {};
BaseHandler.prototype.getElement = function() {
  return this.element;
};

function BodyHandler() {}

BodyHandler.prototype = new BaseHandler();

BodyHandler.prototype.handleText = function(text) {
  this.body = (this.body || '') + text;
};

function ReferenceHandler(property, context) {
  this.property = property;
  this.context = context;
}

ReferenceHandler.prototype = new BodyHandler();

ReferenceHandler.prototype.handleNode = function(node) {

  if (this.element) {
    throw new Error('expected no sub nodes');
  } else {
    this.element = this.createReference(node);
  }

  return this;
};

ReferenceHandler.prototype.handleEnd = function() {
  this.element.id = this.body;
};

ReferenceHandler.prototype.createReference = function() {
  return {
    property: this.property.ns.name,
    id: ''
  };
};

function ValueHandler(propertyDesc, element) {
  this.element = element;
  this.propertyDesc = propertyDesc;
}

ValueHandler.prototype = new BodyHandler();

ValueHandler.prototype.handleEnd = function() {

  var value = this.body,
      element = this.element,
      propertyDesc = this.propertyDesc;

  value = Types.coerceType(propertyDesc.type, value);

  if (propertyDesc.isMany) {
    element.get(propertyDesc.name).push(value);
  } else {
    element.set(propertyDesc.name, value);
  }
};

function BaseElementHandler() {}

BaseElementHandler.prototype = Object.create(BodyHandler.prototype);

BaseElementHandler.prototype.handleNode = function(node) {
  var parser = this;

  if (!this.element) {
    this.element = this.createElement(node);
    var id = this.element.id;

    if (id) {
      this.context.addElement(id, this.element);
    }
  } else {
    parser = this.handleChild(node);
  }

  return parser;
};

/**
 * @class XMLReader.ElementHandler
 *
 */
function ElementHandler(model, type, context) {
  this.model = model;
  this.type = model.getType(type);
  this.context = context;
}

ElementHandler.prototype = new BaseElementHandler();

ElementHandler.prototype.addReference = function(reference) {
  this.context.addReference(reference);
};

ElementHandler.prototype.handleEnd = function() {

  var value = this.body,
      element = this.element,
      descriptor = element.$descriptor,
      bodyProperty = descriptor.bodyProperty;

  if (bodyProperty && value !== undefined) {
    value = Types.coerceType(bodyProperty.type, value);
    element.set(bodyProperty.name, value);
  }
};

/**
 * Create an instance of the model from the given node.
 *
 * @param  {Element} node the xml node
 */
ElementHandler.prototype.createElement = function(node) {
  var attributes = parseNodeAttributes(node),
      Type = this.type,
      descriptor = Type.$descriptor,
      context = this.context,
      instance = new Type({});

  _.forEach(attributes, function(value, name) {

    var prop = descriptor.propertiesByName[name];

    if (prop && prop.isReference) {
      context.addReference({
        element: instance,
        property: prop.ns.name,
        id: value
      });
    } else {
      if (prop) {
        value = Types.coerceType(prop.type, value);
      }

      instance.set(name, value);
    }
  });

  return instance;
};

ElementHandler.prototype.getPropertyForElement = function(nameNs) {
  if (_.isString(nameNs)) {
    nameNs = parseNameNs(nameNs);
  }

  var type = this.type,
      model = this.model,
      descriptor = type.$descriptor;

  var propertyName = nameNs.name;

  var property = descriptor.propertiesByName[propertyName];

  // search for properties by name first
  if (property) {
    return property;
  }

  var pkg = model.getPackage(nameNs.prefix);

  if (pkg) {
    var typeName = nameNs.prefix + ':' + aliasToName(nameNs.localName, descriptor.$pkg),
        elementType = model.getType(typeName);

    // search for collection members later
    property = _.find(descriptor.properties, function(p) {
      return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
    });

    if (property) {
      return _.extend({}, property, { effectiveType: elementType.$descriptor.name });
    }
  } else {
    // parse unknown element (maybe extension)
    property = _.find(descriptor.properties, function(p) {
      return !p.isReference && !p.isAttribute && p.type === 'Element';
    });

    if (property) {
      return property;
    }
  }

  throw new Error('unrecognized element <' + nameNs.name + '>');
};

ElementHandler.prototype.toString = function() {
  return 'ElementDescriptor[' + this.type.$descriptor.name + ']';
};

ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
  return new ValueHandler(propertyDesc, element);
};

ElementHandler.prototype.referenceHandler = function(propertyDesc) {
  return new ReferenceHandler(propertyDesc, this.context);
};

ElementHandler.prototype.handler = function(type) {
  if (type === 'Element') {
    return new GenericElementHandler(this.model, type, this.context);
  } else {
    return new ElementHandler(this.model, type, this.context);
  }
};

/**
 * Handle the child element parsing
 *
 * @param  {Element} node the xml node
 */
ElementHandler.prototype.handleChild = function(node) {
  var nameNs = parseNameNs(node.local, node.prefix);

  var propertyDesc, type, element, childHandler;

  propertyDesc = this.getPropertyForElement(nameNs);
  element = this.element;

  type = propertyDesc.effectiveType || propertyDesc.type;

  if (Types.isSimple(propertyDesc.type)) {
    return this.valueHandler(propertyDesc, element);
  }

  if (propertyDesc.isReference) {
    childHandler = this.referenceHandler(propertyDesc).handleNode(node);
  } else {
    childHandler = this.handler(type).handleNode(node);
  }

  var newElement = childHandler.getElement();

  // child handles may decide to skip elements
  // by not returning anything
  if (newElement !== undefined) {

    if (propertyDesc.isMany) {
      element.get(propertyDesc.name).push(newElement);
    } else {
      element.set(propertyDesc.name, newElement);
    }

    if (propertyDesc.isReference) {
      _.extend(newElement, {
        element: element
      });

      this.context.addReference(newElement);
    } else {
      // establish child -> parent relationship
      newElement.$parent = element;
    }
  }

  return childHandler;
};

function GenericElementHandler(model, type, context) {
  this.model = model;
  this.context = context;
}

GenericElementHandler.prototype = new BaseElementHandler();

GenericElementHandler.prototype.createElement = function(node) {

  var name = node.name,
      prefix = node.prefix,
      uri = node.ns[prefix],
      attributes = node.attributes;

  return this.model.createAny(name, uri, attributes);
};

GenericElementHandler.prototype.handleChild = function(node) {

  var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
      element = this.element;

  var newElement = handler.getElement(),
      children;

  if (newElement !== undefined) {
    children = element.$children = element.$children || [];
    children.push(newElement);

    // establish child -> parent relationship
    newElement.$parent = element;
  }

  return handler;
};

GenericElementHandler.prototype.handleText = function(text) {
  this.body = this.body || '' + text;
};

GenericElementHandler.prototype.handleEnd = function() {
  if (this.body) {
    this.element.$body = this.body;
  }
};

/**
 * A reader for a meta-model
 *
 * @class XMLReader
 *
 * @param {Model} model used to read xml files
 */
function XMLReader(model) {

  function resolveReferences(context) {

    var elementsById = context.elementsById;
    var references = context.references;

    _.forEach(references, function(r) {
      var element = r.element;
      var reference = elementsById[r.id];
      var property = element.$descriptor.propertiesByName[r.property];

      if (!reference) {
        context.addWarning({
          message: 'unresolved reference <' + r.id + '>',
          element: r.element,
          property: r.property,
          value: r.id
        });
      }

      if (property.isMany) {
        var collection = element.get(property.name),
            idx = collection.indexOf(r);

        if (!reference) {
          // remove unresolvable reference
          collection.splice(idx, 1);
        } else {
          // update reference
          collection[idx] = reference;
        }
      } else {
        element.set(property.name, reference);
      }
    });
  }

  function fromXML(xml, rootHandler, done) {

    var context = new Context(rootHandler);

    var parser = sax.parser(true, { xmlns: true, trim: true }),
        stack = new Stack();

    rootHandler.context = context;

    // push root handler
    stack.push(rootHandler);

    // error handling
    parser.onerror = function (e) {
      // just throw
      throw e;
    };

    parser.onopentag = function(node) {
      var handler = stack.peek();

      normalizeNamespaces(node, model);

      try {
        stack.push(handler.handleNode(node));
      } catch (e) {

        var line = this.line,
            column = this.column;

        throw new Error(
          'unparsable content <' + node.name + '> detected\n\t' +
            'line: ' + line + '\n\t' +
            'column: ' + column + '\n\t' +
            'nested error: ' + e.message);
      }
    };

    parser.ontext = parser.oncdata = function(text) {
      var handler = stack.peek();
      handler.handleText(text);
    };

    parser.onclosetag = function(tagName) {
      var old = stack.pop();
      old.handleEnd();
    };

    parser.onend = function () {
      resolveReferences(context);
      done(null, rootHandler.getElement(), context);
    };

    try {
      parser.write(xml).close();
    } catch (e) {
      // handle errors
      done(e, undefined, context);
    }
  }

  return {
    fromXML: fromXML,

    handler: function(name) {
      return new ElementHandler(model, name);
    }
  };
}

module.exports = XMLReader;
module.exports.ElementHandler = ElementHandler;<commit_msg>feat(Reader): speedup XML parsing<commit_after>'use strict';

var sax = require('sax'),
    _ = require('lodash');

var common = require('./common'),
    Types = require('moddle').types,
    Stack = require('tiny-stack'),
    parseNameNs = require('moddle').ns.parseName,
    aliasToName = common.aliasToName;

function parseNodeAttributes(node) {
  var nodeAttrs = node.attributes;

  return _.reduce(nodeAttrs, function(result, v, k) {
    var name, ns;

    if (!v.local) {
      name = v.prefix;
    } else {
      ns = parseNameNs(v.name, v.prefix);
      name = ns.name;
    }

    result[name] = v.value;
    return result;
  }, {});
}

/**
 * Normalizes namespaces for a node given an optional default namespace and a
 * number of mappings from uris to default prefixes.
 *
 * @param  {XmlNode} node
 * @param  {Model} model the model containing all registered namespaces
 * @param  {Uri} defaultNsUri
 */
function normalizeNamespaces(node, model, defaultNsUri) {
  var uri, childUri, prefix;

  uri = node.uri || defaultNsUri;

  if (uri) {
    var pkg = model.getPackage(uri);

    if (pkg) {
      prefix = pkg.prefix;
    } else {
      prefix = node.prefix;
    }

    node.prefix = prefix;
    node.uri = uri;
  }

  _.forEach(node.attributes, function(attr) {
    normalizeNamespaces(attr, model, null);
  });
}

/**
 * A parse context.
 *
 * @class
 *
 * @param {ElementHandler} parseRoot the root handler for parsing a document
 */
function Context(parseRoot) {

  var elementsById = {};
  var references = [];

  var warnings = [];

  this.addReference = function(reference) {
    references.push(reference);
  };

  this.addElement = function(id, element) {

    if (!id || !element) {
      throw new Error('[xml-reader] id or ctx must not be null');
    }

    elementsById[id] = element;
  };

  this.addWarning = function (w) {
    warnings.push(w);
  };

  this.warnings = warnings;
  this.references = references;

  this.elementsById = elementsById;

  this.parseRoot = parseRoot;
}

function BaseHandler() {}

BaseHandler.prototype.handleEnd = function() {};
BaseHandler.prototype.handleText = function() {};
BaseHandler.prototype.handleNode = function() {};

function BodyHandler() {}

BodyHandler.prototype = new BaseHandler();

BodyHandler.prototype.handleText = function(text) {
  this.body = (this.body || '') + text;
};

function ReferenceHandler(property, context) {
  this.property = property;
  this.context = context;
}

ReferenceHandler.prototype = new BodyHandler();

ReferenceHandler.prototype.handleNode = function(node) {

  if (this.element) {
    throw new Error('expected no sub nodes');
  } else {
    this.element = this.createReference(node);
  }

  return this;
};

ReferenceHandler.prototype.handleEnd = function() {
  this.element.id = this.body;
};

ReferenceHandler.prototype.createReference = function() {
  return {
    property: this.property.ns.name,
    id: ''
  };
};

function ValueHandler(propertyDesc, element) {
  this.element = element;
  this.propertyDesc = propertyDesc;
}

ValueHandler.prototype = new BodyHandler();

ValueHandler.prototype.handleEnd = function() {

  var value = this.body,
      element = this.element,
      propertyDesc = this.propertyDesc;

  value = Types.coerceType(propertyDesc.type, value);

  if (propertyDesc.isMany) {
    element.get(propertyDesc.name).push(value);
  } else {
    element.set(propertyDesc.name, value);
  }
};

function BaseElementHandler() {}

BaseElementHandler.prototype = Object.create(BodyHandler.prototype);

BaseElementHandler.prototype.handleNode = function(node) {
  var parser = this;

  if (!this.element) {
    this.element = this.createElement(node);
    var id = this.element.id;

    if (id) {
      this.context.addElement(id, this.element);
    }
  } else {
    parser = this.handleChild(node);
  }

  return parser;
};

/**
 * @class XMLReader.ElementHandler
 *
 */
function ElementHandler(model, type, context) {
  this.model = model;
  this.type = model.getType(type);
  this.context = context;
}

ElementHandler.prototype = new BaseElementHandler();

ElementHandler.prototype.addReference = function(reference) {
  this.context.addReference(reference);
};

ElementHandler.prototype.handleEnd = function() {

  var value = this.body,
      element = this.element,
      descriptor = element.$descriptor,
      bodyProperty = descriptor.bodyProperty;

  if (bodyProperty && value !== undefined) {
    value = Types.coerceType(bodyProperty.type, value);
    element.set(bodyProperty.name, value);
  }
};

/**
 * Create an instance of the model from the given node.
 *
 * @param  {Element} node the xml node
 */
ElementHandler.prototype.createElement = function(node) {
  var attributes = parseNodeAttributes(node),
      Type = this.type,
      descriptor = Type.$descriptor,
      context = this.context,
      instance = new Type({});

  _.forEach(attributes, function(value, name) {

    var prop = descriptor.propertiesByName[name];

    if (prop && prop.isReference) {
      context.addReference({
        element: instance,
        property: prop.ns.name,
        id: value
      });
    } else {
      if (prop) {
        value = Types.coerceType(prop.type, value);
      }

      instance.set(name, value);
    }
  });

  return instance;
};

ElementHandler.prototype.getPropertyForElement = function(nameNs) {
  if (_.isString(nameNs)) {
    nameNs = parseNameNs(nameNs);
  }

  var type = this.type,
      model = this.model,
      descriptor = type.$descriptor;

  var propertyName = nameNs.name;

  var property = descriptor.propertiesByName[propertyName];

  // search for properties by name first
  if (property) {
    return property;
  }

  var pkg = model.getPackage(nameNs.prefix);

  if (pkg) {
    var typeName = nameNs.prefix + ':' + aliasToName(nameNs.localName, descriptor.$pkg),
        elementType = model.getType(typeName);

    // search for collection members later
    property = _.find(descriptor.properties, function(p) {
      return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
    });

    if (property) {
      return _.extend({}, property, { effectiveType: elementType.$descriptor.name });
    }
  } else {
    // parse unknown element (maybe extension)
    property = _.find(descriptor.properties, function(p) {
      return !p.isReference && !p.isAttribute && p.type === 'Element';
    });

    if (property) {
      return property;
    }
  }

  throw new Error('unrecognized element <' + nameNs.name + '>');
};

ElementHandler.prototype.toString = function() {
  return 'ElementDescriptor[' + this.type.$descriptor.name + ']';
};

ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
  return new ValueHandler(propertyDesc, element);
};

ElementHandler.prototype.referenceHandler = function(propertyDesc) {
  return new ReferenceHandler(propertyDesc, this.context);
};

ElementHandler.prototype.handler = function(type) {
  if (type === 'Element') {
    return new GenericElementHandler(this.model, type, this.context);
  } else {
    return new ElementHandler(this.model, type, this.context);
  }
};

/**
 * Handle the child element parsing
 *
 * @param  {Element} node the xml node
 */
ElementHandler.prototype.handleChild = function(node) {
  var nameNs = parseNameNs(node.local, node.prefix);

  var propertyDesc, type, element, childHandler;

  propertyDesc = this.getPropertyForElement(nameNs);
  element = this.element;

  type = propertyDesc.effectiveType || propertyDesc.type;

  if (Types.isSimple(propertyDesc.type)) {
    return this.valueHandler(propertyDesc, element);
  }

  if (propertyDesc.isReference) {
    childHandler = this.referenceHandler(propertyDesc).handleNode(node);
  } else {
    childHandler = this.handler(type).handleNode(node);
  }

  var newElement = childHandler.element;

  // child handles may decide to skip elements
  // by not returning anything
  if (newElement !== undefined) {

    if (propertyDesc.isMany) {
      element.get(propertyDesc.name).push(newElement);
    } else {
      element.set(propertyDesc.name, newElement);
    }

    if (propertyDesc.isReference) {
      _.extend(newElement, {
        element: element
      });

      this.context.addReference(newElement);
    } else {
      // establish child -> parent relationship
      newElement.$parent = element;
    }
  }

  return childHandler;
};

function GenericElementHandler(model, type, context) {
  this.model = model;
  this.context = context;
}

GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);

GenericElementHandler.prototype.createElement = function(node) {

  var name = node.name,
      prefix = node.prefix,
      uri = node.ns[prefix],
      attributes = node.attributes;

  return this.model.createAny(name, uri, attributes);
};

GenericElementHandler.prototype.handleChild = function(node) {

  var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
      element = this.element;

  var newElement = handler.element,
      children;

  if (newElement !== undefined) {
    children = element.$children = element.$children || [];
    children.push(newElement);

    // establish child -> parent relationship
    newElement.$parent = element;
  }

  return handler;
};

GenericElementHandler.prototype.handleText = function(text) {
  this.body = this.body || '' + text;
};

GenericElementHandler.prototype.handleEnd = function() {
  if (this.body) {
    this.element.$body = this.body;
  }
};

/**
 * A reader for a meta-model
 *
 * @class XMLReader
 *
 * @param {Model} model used to read xml files
 */
function XMLReader(model) {
  this.model = model;
}

XMLReader.prototype.fromXML = function(xml, rootHandler, done) {

  var context = new Context(rootHandler);

  var parser = sax.parser(true, { xmlns: true, trim: true }),
      stack = new Stack();

  var model = this.model,
      self = this;

  rootHandler.context = context;

  // push root handler
  stack.push(rootHandler);

  function resolveReferences() {

    var elementsById = context.elementsById;
    var references = context.references;

    var i, r;

    for (i = 0; !!(r = references[i]); i++) {
      var element = r.element;
      var reference = elementsById[r.id];
      var property = element.$descriptor.propertiesByName[r.property];

      if (!reference) {
        context.addWarning({
          message: 'unresolved reference <' + r.id + '>',
          element: r.element,
          property: r.property,
          value: r.id
        });
      }

      if (property.isMany) {
        var collection = element.get(property.name),
            idx = collection.indexOf(r);

        if (!reference) {
          // remove unresolvable reference
          collection.splice(idx, 1);
        } else {
          // update reference
          collection[idx] = reference;
        }
      } else {
        element.set(property.name, reference);
      }
    }
  }

  function handleClose(tagName) {
    stack.pop().handleEnd();
  }

  function handleOpen(node) {
    var handler = stack.peek();

    normalizeNamespaces(node, model);

    try {
      stack.push(handler.handleNode(node));
    } catch (e) {

      var line = this.line,
          column = this.column;

      throw new Error(
        'unparsable content <' + node.name + '> detected\n\t' +
          'line: ' + line + '\n\t' +
          'column: ' + column + '\n\t' +
          'nested error: ' + e.message);
    }
  }

  function handleText(text) {
    stack.peek().handleText(text);
  }

  parser.onopentag = handleOpen;
  parser.oncdata = parser.ontext = handleText;
  parser.onclosetag = handleClose;
  parser.onend = resolveReferences;

  try {
    parser.write(xml).close();
    done(null, rootHandler.element, context);
  } catch (e) {
    // handle errors
    done(e, undefined, context);
  }
};

XMLReader.prototype.handler = function(name) {
  return new ElementHandler(this.model, name);
};

module.exports = XMLReader;
module.exports.ElementHandler = ElementHandler;<|endoftext|>


<commit_before>'use strict';

const Promise = require('bluebird');
const Mime = require('mime');
const Fs = Promise.promisifyAll(require('fs'), {suffix: 'Promised'});
const Path = require('path');

const Tools = require('unifile-common-tools');

const NAME = 'fs';

const validatePath = Symbol('validatePath');

function statToFileInfos(filename, stat) {
	const isDir = stat.isDirectory();
	return {
		size: stat.size,
		modified: stat.mtime,
		name: filename,
		isDir: isDir,
		mime: isDir ? 'application/directory' : Mime.getType(filename)
	};
}

/**
 * Service connector for the local filesystem.
 */
class FsConnector {
	/**
   * @constructor
   * @param {Object} config - Configuration object
   * @param {string|Array<string>} [config.sandbox] - Restrict connector access to this path (if string)
   * or these paths (if array)
   * @param {string} [config.rootPath] - Path against all relative paths will be resolved.
   * Default to the first sandbox path if given or /.
   * @param {boolean} [config.showHiddenFiles=false] - Flag to show hidden files.
   * @param {ConnectorStaticInfos} [config.infos] - Connector infos to override
   * @throws {Error} Invalid sandbox path.
   */
	constructor(config) {
		const conf = config || {};
		this.showHiddenFile = conf.showHiddenFile;
		this.infos = Tools.mergeInfos(conf.infos, {
			name: NAME,
			displayName: 'Your Computer',
			icon: '',
			description: 'Edit files on your local drive.'
		});
		this.name = this.infos.name;

		if(!conf.sandbox) this.sandbox = [];
		else if(conf.sandbox.constructor === String) this.sandbox = [conf.sandbox];
		else if(Array.isArray(conf.sandbox)) this.sandbox = conf.sandbox;
		else throw new Error('Invalid sandbox path. Must be a string or an array');

		if(conf.rootPath) this.rootPath = conf.rootPath;
		else if(this.sandbox.length > 0) this.rootPath = this.sandbox[0];
		else this.rootPath = '/';
	}

	getInfos(session) {
		return Object.assign({
			isLoggedIn: true,
			isOAuth: false,
			username: process.env.USER
		}, this.infos);
	}

	// Auth methods are useless here

	getAuthorizeURL(session) {
		return Promise.resolve('');
	}

	setAccessToken(session, token) {
		return Promise.resolve(token);
	}

	clearAccessToken(session) {
		return Promise.resolve();
	}

	login(session, loginInfos) {
		return new Promise.resolve();
	}

	//Filesystem commands

	readdir(session, path) {
		try {
			const securePath = this[validatePath](path);
			return Fs.readdirPromised(securePath)
			.reduce((memo, entry) => {
				if(this.showHiddenFile || entry.charAt(0) != '.') {
					return Fs.statPromised(Path.resolve(securePath, entry))
					.then((stat) => {
						memo.push(statToFileInfos(entry, stat));
						return memo;
					});
				} else {
					return memo;
				}
			}, []);
		} catch (e) {
			return Promise.reject(e);
		}
	}

	stat(session, path) {
		try {
			const securePath = this[validatePath](path);
			return Fs.statPromised(securePath)
			.then((stat) => {
				return statToFileInfos(Path.basename(securePath), stat);
			});
		} catch (e) {
			return Promise.reject(e);
		}
	}

	mkdir(session, path) {
		try {
			return Fs.mkdirPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	writeFile(session, path, data) {
		try {
			return Fs.writeFilePromised(this[validatePath](path), data);
		} catch (e) {
			return Promise.reject(e);
		}
	}

	createWriteStream(session, path) {
		return Fs.createWriteStream(this[validatePath](path));
	}

	readFile(session, path) {
		try {
			return Fs.readFilePromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	createReadStream(session, path) {
		return Fs.createReadStream(this[validatePath](path), {encoding: 'utf8'});
	}

	rename(session, src, dest) {
		try {
			return Fs.renamePromised(this[validatePath](src), this[validatePath](dest));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	unlink(session, path) {
		try {
			return Fs.unlinkPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	rmdir(session, path) {
		try {
			return Fs.rmdirPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	batch(session, actions, message) {
		return Tools.simpleBatch(this, session, actions);
	}

	/**
   * Ensure the given path is in the user-defined sandbox
   * @private
   */
	[validatePath](path) {
		const absolutePath = Path.resolve(this.rootPath, path);
		if(this.sandbox.length !== 0 && !this.sandbox.some((sandboxPath) => absolutePath.startsWith(sandboxPath)))
			throw new Error(`Path is out of the sandbox: ${absolutePath}`);
		return absolutePath;
	}
}

module.exports = FsConnector;
<commit_msg>local file system supports symlinks<commit_after>'use strict';

const Promise = require('bluebird');
const Mime = require('mime');
const Fs = Promise.promisifyAll(require('fs'), {suffix: 'Promised'});
const Path = require('path');

const Tools = require('unifile-common-tools');

const NAME = 'fs';

const validatePath = Symbol('validatePath');

function statToFileInfos(filename, stat) {
	const isDir = stat.isDirectory();
	return {
		size: stat.size,
		modified: stat.mtime,
		name: filename,
		isDir: isDir,
		mime: isDir ? 'application/directory' : Mime.getType(filename)
	};
}

/**
 * Service connector for the local filesystem.
 */
class FsConnector {
	/**
   * @constructor
   * @param {Object} config - Configuration object
   * @param {string|Array<string>} [config.sandbox] - Restrict connector access to this path (if string)
   * or these paths (if array)
   * @param {string} [config.rootPath] - Path against all relative paths will be resolved.
   * Default to the first sandbox path if given or /.
   * @param {boolean} [config.showHiddenFiles=false] - Flag to show hidden files.
   * @param {ConnectorStaticInfos} [config.infos] - Connector infos to override
   * @throws {Error} Invalid sandbox path.
   */
	constructor(config) {
		const conf = config || {};
		this.showHiddenFile = conf.showHiddenFile;
		this.infos = Tools.mergeInfos(conf.infos, {
			name: NAME,
			displayName: 'Your Computer',
			icon: '',
			description: 'Edit files on your local drive.'
		});
		this.name = this.infos.name;

		if(!conf.sandbox) this.sandbox = [];
		else if(conf.sandbox.constructor === String) this.sandbox = [conf.sandbox];
		else if(Array.isArray(conf.sandbox)) this.sandbox = conf.sandbox;
		else throw new Error('Invalid sandbox path. Must be a string or an array');

		if(conf.rootPath) this.rootPath = conf.rootPath;
		else if(this.sandbox.length > 0) this.rootPath = this.sandbox[0];
		else this.rootPath = '/';
	}

	getInfos(session) {
		return Object.assign({
			isLoggedIn: true,
			isOAuth: false,
			username: process.env.USER
		}, this.infos);
	}

	// Auth methods are useless here

	getAuthorizeURL(session) {
		return Promise.resolve('');
	}

	setAccessToken(session, token) {
		return Promise.resolve(token);
	}

	clearAccessToken(session) {
		return Promise.resolve();
	}

	login(session, loginInfos) {
		return new Promise.resolve();
	}

	//Filesystem commands

	readdir(session, path) {
		try {
			const securePath = this[validatePath](path);
			return Fs.readdirPromised(securePath)
			.reduce((memo, entry) => {
				if(this.showHiddenFile || entry.charAt(0) != '.') {
					return Fs.lstatPromised(Path.resolve(securePath, entry))
					.then((stat) => {
						memo.push(statToFileInfos(entry, stat));
						return memo;
					});
				} else {
					return memo;
				}
			}, []);
		} catch (e) {
			return Promise.reject(e);
		}
	}

	stat(session, path) {
		try {
			const securePath = this[validatePath](path);
			return Fs.statPromised(securePath)
			.then((stat) => {
				return statToFileInfos(Path.basename(securePath), stat);
			});
		} catch (e) {
			return Promise.reject(e);
		}
	}

	mkdir(session, path) {
		try {
			return Fs.mkdirPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	writeFile(session, path, data) {
		try {
			return Fs.writeFilePromised(this[validatePath](path), data);
		} catch (e) {
			return Promise.reject(e);
		}
	}

	createWriteStream(session, path) {
		return Fs.createWriteStream(this[validatePath](path));
	}

	readFile(session, path) {
		try {
			return Fs.readFilePromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	createReadStream(session, path) {
		return Fs.createReadStream(this[validatePath](path), {encoding: 'utf8'});
	}

	rename(session, src, dest) {
		try {
			return Fs.renamePromised(this[validatePath](src), this[validatePath](dest));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	unlink(session, path) {
		try {
			return Fs.unlinkPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	rmdir(session, path) {
		try {
			return Fs.rmdirPromised(this[validatePath](path));
		} catch (e) {
			return Promise.reject(e);
		}
	}

	batch(session, actions, message) {
		return Tools.simpleBatch(this, session, actions);
	}

	/**
   * Ensure the given path is in the user-defined sandbox
   * @private
   */
	[validatePath](path) {
		const absolutePath = Path.resolve(this.rootPath, path);
		if(this.sandbox.length !== 0 && !this.sandbox.some((sandboxPath) => absolutePath.startsWith(sandboxPath)))
			throw new Error(`Path is out of the sandbox: ${absolutePath}`);
		return absolutePath;
	}
}

module.exports = FsConnector;
<|endoftext|>


<commit_before>/*  Copyright (C) 2016 Milan Pässler
    Copyright (C) 2016 HopGlass Server contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

'use strict'

var async = require('async')
var _ = require('lodash')

module.exports = function(receiver, config) {

  function isOnline(node) {
      if (node)
        return Math.abs((node.lastseen ? new Date(node.lastseen) : new Date()) - new Date()) < config.offlineTime * 1000
      else
      return true
  }

  function getNodesJson(stream, query) {
    var data = receiver.getData(query)
    var nJson = {}
    nJson.version = 2
    nJson.nodes = []
    nJson.timestamp = new Date().toISOString()
    var macTable = {}
    async.forEachOf(data, function(n, k, finished) {
      if (_.has(n, 'nodeinfo.network.mesh')) {
        for (let bat in n.nodeinfo.network.mesh) {
          for (let type in n.nodeinfo.network.mesh[bat].interfaces) {
            n.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(d) {
              macTable[d] = k
            })
          }
        }
      }
      finished()
    }, function() {
      async.forEachOf(data, function(n, k, finished) {
        if (n.nodeinfo) {
          var node = {}
          node.nodeinfo = _.get(n, 'nodeinfo', {})
          node.flags = {}
          node.flags.gateway = _.get(n, 'flags.gateway')
          node.flags.online = isOnline(n)
          node.statistics = {}
          if (node.flags.online) {
            node.statistics.uptime = _.get(n, 'statistics.uptime')
            node.statistics.gateway = _.get(n, 'statistics.gateway')
            if (node.statistics.gateway in macTable)
              node.statistics.gateway = macTable[node.statistics.gateway]
            node.statistics.gateway_nexthop = _.get(n, 'statistics.gateway_nexthop')
            if (node.statistics.gateway_nexthop in macTable)
              node.statistics.gateway_nexthop = macTable[node.statistics.gateway_nexthop]
            node.statistics.nexthop = _.get(n, 'statistics.nexthop')
            if (node.statistics.nexthop in macTable)
              node.statistics.nexthop = macTable[node.statistics.nexthop]
            if (_.has(n, 'statistics.wireless')) {
              node.statistics.wireless = {}
              if (Array.isArray(n.statistics.wireless)) {
                for (let freq in n.statistics.wireless)
                  if (freq.frequency && freq.busy && freq.rx && freq.tx) {
                    var newfreq = {}
                    newfreq.rx = freq.rx / freq.active
                    newfreq.tx = freq.tx / freq.active
                    newfreq.wait = (freq.busy - freq.rx - freq.tx) / freq.active
                    newfreq.free = (freq.active - freq.busy) / freq.active
                    node.statistics.wireless['airtime'+freq.frequency.substring(0, 1)] = newfreq
                  }
              } else {
                if (_.has(n, 'statistics.wireless.airtime2'))
                  node.statistics.wireless.airtime2 = _.get(n, 'statistics.wireless.airtime2')
                if (_.has(n, 'statistics.wireless.airtime5'))
                  node.statistics.wireless.airtime5 = _.get(n, 'statistics.wireless.airtime5')
              }
            }
            if (_.has(n, 'statistics.memory'))
              node.statistics.memory_usage =
                  (_.get(n, 'statistics.memory.total', 0)
                - _.get(n, 'statistics.memory.free', 0))
                / _.get(n, 'statistics.memory.total', 0)
            node.statistics.rootfs_usage = _.get(n, 'statistics.rootfs_usage')
            node.statistics.clients = _.get(n, 'statistics.clients.total', 0)
            node.statistics.loadavg = _.get(n, 'statistics.loadavg')
          }
          node.lastseen = _.get(n, 'lastseen', new Date().toISOString())
          node.firstseen = _.get(n, 'firstseen', new Date().toISOString())
          nJson.nodes.push(node)
        }
        finished()
      }, function() {
        stream.writeHead(200, { 'Content-Type': 'application/json' })
        stream.end(JSON.stringify(nJson))
      })
    })
  }

  function getGraphJson(stream, query) {
    var data = receiver.getData(query)
    var gJson = {}
    gJson.timestamp = new Date().toISOString()
    gJson.version = 1
    gJson.batadv = {}
    gJson.batadv.multigraph = false
    gJson.batadv.directed = true
    gJson.batadv.nodes = []
    gJson.batadv.links = []
    gJson.batadv.graph = null
    var nodeTable = {}
    var macTable = {}
    var typeTable = {}
    var counter = 0
    function createEntry(mac) {
      var nodeEntry = {}
      nodeEntry.id = mac
      nodeEntry.node_id = macTable[mac]
      nodeTable[mac] = counter
      var node = data[macTable[mac]]
      if (_.has(node, 'neighbours.batadv'))
        for (let m in _.get(node, 'neighbours.batadv')) {
          nodeTable[m] = counter
        }
      if (_.has(node, 'nodeinfo.network.mesh'))
        for (let bat in node.nodeinfo.network.mesh) {
          for (let type in node.nodeinfo.network.mesh[bat].interfaces) {
            if (typeof node.nodeinfo.network.mesh[bat].interfaces[type].forEach == 'function')
              node.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(m) {
                nodeTable[m] = counter
              })
          }
        }
      if (!isOnline(node))
        nodeEntry.unseen = true
      counter++
      gJson.batadv.nodes.push(nodeEntry)
    }
    async.forEachOf(data, function(n, k, finished1) {
      if (_.has(n, 'neighbours.batadv') && _.has(n, 'nodeinfo.network.mac'))
        for (let mac in n.neighbours.batadv) {
          macTable[mac] = k
        }
      if (_.has(n, 'nodeinfo.network.mesh'))
        for (let bat in n.nodeinfo.network.mesh) {
          for (let type in n.nodeinfo.network.mesh[bat].interfaces) {
            if (typeof n.nodeinfo.network.mesh[bat].interfaces[type].forEach == 'function')
              n.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(d) {
                typeTable[d] = type
                macTable[d] = k
              })
          }
        }
      finished1()
    }, function() {
      async.forEachOf(data, function(n, k, finished2) {
        if (_.has(n, 'neighbours.batadv') && isOnline(n)) {
          for (let dest in n.neighbours.batadv) {
            if (_.has(n.neighbours.batadv[dest], 'neighbours'))
              for (let src in n.neighbours.batadv[dest].neighbours) {
                var link = {}
                link.source = nodeTable[src]
                link.target = nodeTable[dest]
                var tq = _.get(n, ['neighbours', 'batadv', dest, 'neighbours', src, 'tq'])
                link.tq = 255 / (tq ? tq : 1)

                var ts = typeTable[src], td = typeTable[dest]
                if (ts === 'l2tp' || td === 'l2tp') {
                  link.type = 'l2tp'
                } else if (ts === 'fastd' || td === 'fastd') {
                  link.type = 'fastd'
                } else if (ts === 'tunnel' || td === 'tunnel') {
                  link.type = 'tunnel'

                  if (td === 'tunnel' && (ts == undefined || ts === 'tunnel')) {
                    var fds = 0, tds = 0, sis = 0
                    if (_.get(data[macTable[dest]], 'nodeinfo.software.fastd.enabled', false)) fds++
                    if (_.get(data[macTable[src]], 'nodeinfo.software.fastd.enabled', false)) fds++
                    if (_.get(data[macTable[dest]], 'nodeinfo.software.tunneldigger.enabled', false)) tds++
                    if (_.get(data[macTable[src]], 'nodeinfo.software.tunneldigger.enabled', false)) tds++
                    if (_.has(data[macTable[dest]], 'nodeinfo.software')) sis++
                    if (_.has(data[macTable[src]], 'nodeinfo.software')) sis++
                    if (sis == fds && fds > 0) link.type = 'fastd'
                    if (sis == tds && tds > 0) link.type = 'l2tp'
                  }
                } else
                  link.type = typeTable[dest]

                if (isNaN(link.source)) {
                  //unknown node (not in data) -> create nodeentry
                  createEntry(src)
                  link.source = nodeTable[src]
                }
                if (isNaN(link.target)) {
                  createEntry(dest)
                  link.target = nodeTable[dest]
                }
                gJson.batadv.links.push(link)
              }
          }
        }
        finished2()
      }, function() {
        stream.writeHead(200, { 'Content-Type': 'application/json' })
        stream.end(JSON.stringify(gJson))
      })
    })
  }

  var exports = {
    /* eslint-disable quotes */
    "nodes.json": getNodesJson,
    "graph.json": getGraphJson
  }
  return exports
}
<commit_msg>fix indentations for eslint<commit_after>/*  Copyright (C) 2016 Milan Pässler
    Copyright (C) 2016 HopGlass Server contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

'use strict'

var async = require('async')
var _ = require('lodash')

module.exports = function(receiver, config) {

  function isOnline(node) {
    if (node)
      return Math.abs((node.lastseen ? new Date(node.lastseen) : new Date()) - new Date()) < config.offlineTime * 1000

    return true
  }

  function getNodesJson(stream, query) {
    var data = receiver.getData(query)
    var nJson = {}
    nJson.version = 2
    nJson.nodes = []
    nJson.timestamp = new Date().toISOString()
    var macTable = {}
    async.forEachOf(data, function(n, k, finished) {
      if (_.has(n, 'nodeinfo.network.mesh')) {
        for (let bat in n.nodeinfo.network.mesh) {
          for (let type in n.nodeinfo.network.mesh[bat].interfaces) {
            n.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(d) {
              macTable[d] = k
            })
          }
        }
      }
      finished()
    }, function() {
      async.forEachOf(data, function(n, k, finished) {
        if (n.nodeinfo) {
          var node = {}
          node.nodeinfo = _.get(n, 'nodeinfo', {})
          node.flags = {}
          node.flags.gateway = _.get(n, 'flags.gateway')
          node.flags.online = isOnline(n)
          node.statistics = {}
          if (node.flags.online) {
            node.statistics.uptime = _.get(n, 'statistics.uptime')
            node.statistics.gateway = _.get(n, 'statistics.gateway')
            if (node.statistics.gateway in macTable)
              node.statistics.gateway = macTable[node.statistics.gateway]
            node.statistics.gateway_nexthop = _.get(n, 'statistics.gateway_nexthop')
            if (node.statistics.gateway_nexthop in macTable)
              node.statistics.gateway_nexthop = macTable[node.statistics.gateway_nexthop]
            node.statistics.nexthop = _.get(n, 'statistics.nexthop')
            if (node.statistics.nexthop in macTable)
              node.statistics.nexthop = macTable[node.statistics.nexthop]
            if (_.has(n, 'statistics.wireless')) {
              node.statistics.wireless = {}
              if (Array.isArray(n.statistics.wireless)) {
                for (let freq in n.statistics.wireless)
                  if (freq.frequency && freq.busy && freq.rx && freq.tx) {
                    var newfreq = {}
                    newfreq.rx = freq.rx / freq.active
                    newfreq.tx = freq.tx / freq.active
                    newfreq.wait = (freq.busy - freq.rx - freq.tx) / freq.active
                    newfreq.free = (freq.active - freq.busy) / freq.active
                    node.statistics.wireless['airtime'+freq.frequency.substring(0, 1)] = newfreq
                  }
              } else {
                if (_.has(n, 'statistics.wireless.airtime2'))
                  node.statistics.wireless.airtime2 = _.get(n, 'statistics.wireless.airtime2')
                if (_.has(n, 'statistics.wireless.airtime5'))
                  node.statistics.wireless.airtime5 = _.get(n, 'statistics.wireless.airtime5')
              }
            }
            if (_.has(n, 'statistics.memory'))
              node.statistics.memory_usage =
                  (_.get(n, 'statistics.memory.total', 0)
                - _.get(n, 'statistics.memory.free', 0))
                / _.get(n, 'statistics.memory.total', 0)
            node.statistics.rootfs_usage = _.get(n, 'statistics.rootfs_usage')
            node.statistics.clients = _.get(n, 'statistics.clients.total', 0)
            node.statistics.loadavg = _.get(n, 'statistics.loadavg')
          }
          node.lastseen = _.get(n, 'lastseen', new Date().toISOString())
          node.firstseen = _.get(n, 'firstseen', new Date().toISOString())
          nJson.nodes.push(node)
        }
        finished()
      }, function() {
        stream.writeHead(200, { 'Content-Type': 'application/json' })
        stream.end(JSON.stringify(nJson))
      })
    })
  }

  function getGraphJson(stream, query) {
    var data = receiver.getData(query)
    var gJson = {}
    gJson.timestamp = new Date().toISOString()
    gJson.version = 1
    gJson.batadv = {}
    gJson.batadv.multigraph = false
    gJson.batadv.directed = true
    gJson.batadv.nodes = []
    gJson.batadv.links = []
    gJson.batadv.graph = null
    var nodeTable = {}
    var macTable = {}
    var typeTable = {}
    var counter = 0
    function createEntry(mac) {
      var nodeEntry = {}
      nodeEntry.id = mac
      nodeEntry.node_id = macTable[mac]
      nodeTable[mac] = counter
      var node = data[macTable[mac]]
      if (_.has(node, 'neighbours.batadv'))
        for (let m in _.get(node, 'neighbours.batadv')) {
          nodeTable[m] = counter
        }
      if (_.has(node, 'nodeinfo.network.mesh'))
        for (let bat in node.nodeinfo.network.mesh) {
          for (let type in node.nodeinfo.network.mesh[bat].interfaces) {
            if (typeof node.nodeinfo.network.mesh[bat].interfaces[type].forEach == 'function')
              node.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(m) {
                nodeTable[m] = counter
              })
          }
        }
      if (!isOnline(node))
        nodeEntry.unseen = true
      counter++
      gJson.batadv.nodes.push(nodeEntry)
    }
    async.forEachOf(data, function(n, k, finished1) {
      if (_.has(n, 'neighbours.batadv') && _.has(n, 'nodeinfo.network.mac'))
        for (let mac in n.neighbours.batadv) {
          macTable[mac] = k
        }
      if (_.has(n, 'nodeinfo.network.mesh'))
        for (let bat in n.nodeinfo.network.mesh) {
          for (let type in n.nodeinfo.network.mesh[bat].interfaces) {
            if (typeof n.nodeinfo.network.mesh[bat].interfaces[type].forEach == 'function')
              n.nodeinfo.network.mesh[bat].interfaces[type].forEach(function(d) {
                typeTable[d] = type
                macTable[d] = k
              })
          }
        }
      finished1()
    }, function() {
      async.forEachOf(data, function(n, k, finished2) {
        if (_.has(n, 'neighbours.batadv') && isOnline(n)) {
          for (let dest in n.neighbours.batadv) {
            if (_.has(n.neighbours.batadv[dest], 'neighbours'))
              for (let src in n.neighbours.batadv[dest].neighbours) {
                var link = {}
                link.source = nodeTable[src]
                link.target = nodeTable[dest]
                var tq = _.get(n, ['neighbours', 'batadv', dest, 'neighbours', src, 'tq'])
                link.tq = 255 / (tq ? tq : 1)

                var ts = typeTable[src], td = typeTable[dest]
                if (ts === 'l2tp' || td === 'l2tp') {
                  link.type = 'l2tp'
                } else if (ts === 'fastd' || td === 'fastd') {
                  link.type = 'fastd'
                } else if (ts === 'tunnel' || td === 'tunnel') {
                  link.type = 'tunnel'

                  if (td === 'tunnel' && (ts == undefined || ts === 'tunnel')) {
                    var fds = 0, tds = 0, sis = 0
                    if (_.get(data[macTable[dest]], 'nodeinfo.software.fastd.enabled', false)) fds++
                    if (_.get(data[macTable[src]], 'nodeinfo.software.fastd.enabled', false)) fds++
                    if (_.get(data[macTable[dest]], 'nodeinfo.software.tunneldigger.enabled', false)) tds++
                    if (_.get(data[macTable[src]], 'nodeinfo.software.tunneldigger.enabled', false)) tds++
                    if (_.has(data[macTable[dest]], 'nodeinfo.software')) sis++
                    if (_.has(data[macTable[src]], 'nodeinfo.software')) sis++
                    if (sis == fds && fds > 0) link.type = 'fastd'
                    if (sis == tds && tds > 0) link.type = 'l2tp'
                  }
                } else
                  link.type = typeTable[dest]

                if (isNaN(link.source)) {
                  //unknown node (not in data) -> create nodeentry
                  createEntry(src)
                  link.source = nodeTable[src]
                }
                if (isNaN(link.target)) {
                  createEntry(dest)
                  link.target = nodeTable[dest]
                }
                gJson.batadv.links.push(link)
              }
          }
        }
        finished2()
      }, function() {
        stream.writeHead(200, { 'Content-Type': 'application/json' })
        stream.end(JSON.stringify(gJson))
      })
    })
  }

  var exports = {
    /* eslint-disable quotes */
    "nodes.json": getNodesJson,
    "graph.json": getGraphJson
  }
  return exports
}
<|endoftext|>


<commit_before>// https://developer.mozilla.org/en-US/docs/Web/API/URLUtils

var fuzzerURLObjects = (function() {

  var hostnames = ["mozilla.org", "www.mozilla.org", "ftp.mozilla.org"];
  var ports = [
    "80",  // http
    "443", // https
    "21",  // ftp
    "23",  // telnet - blocked - "This address uses a network port which is normally used for purposes other than Web browsing."
    "9310" // other
  ];

  var fields = [
    { field: "href",     values: fuzzValues.URIs },
    { field: "protocol", values: ["http:", "https:", "ftp:", "telnet:", "chrome:", "resource:"] },
    { field: "hostname", values: hostnames },
    { field: "origin",   values: "" }, // should be read-only
    { field: "port",     values: [ports, ""] },
    { field: "host",     values: function() { return Random.index(hostnames) + (rnd(2) ? ":"+Random.index(ports) : ""); } },
    { field: "pathname", values: ["/", "/index.html",        function() { return "/" + Random.pick(fuzzValues.texts) }] },
    { field: "search",   values: ["", "?", "?foo=bar",       function() { return "?" + Random.pick(fuzzValues.texts) }] },
    { field: "hash",     values: ["", "#", "#main-content",  function() { return "#" + Random.pick(fuzzValues.texts) }] },
    { field: "username", values: ["", fuzzValues.texts] },
    { field: "password", values: ["", fuzzValues.texts] },
  ];

  function makeCommand()
  {
    if (rnd(20) == 0) {
      return makeURLObject();
    }

    var obj = Things.instanceAny(["Location", "URL", "HTMLAnchorElement", "HTMLAreaElement"])
    if (!obj) {
      return makeURLObject();
    }

    var i = rnd(fields.length);
    if (rnd(10) == 0) {
      return obj + "." + fields[i].field; // just read the field
    }
    var j = rnd(10) ? i : rnd(fields.length); // generate a value, usually for the correct field
    return obj + "." + fields[i].field + " = " + simpleSource(Random.pick(fields[j].values)) + ";"
  }

  function makeURLObject()
  {
    switch(rnd(5)) {
      case 0:
        return Things.add('new URL(' + simpleSource(Random.pick(fuzzValues.URIs)) + ')')
      case 1:
        return Things.add('document.createElementNS("http://www.w3.org/1999/xhtml", "a")');
      case 2:
        return Things.add('document.createElementNS("http://www.w3.org/1999/xhtml", "area")');
      case 3:
        // It is safe to play with a frame's location.
        var frame = Things.instanceAny(["HTMLFrameElement", "HTMLIFrameElement"]);
        if (frame) {
          return Things.add(frame + ".location");
        }
      default:
        // It may be self-destructive to play with this document's location.
        if (rnd(100) == 0) {
          return "/*selfdestruct*/ " + Things.add("location");
        }
        return [];
    }
  }

  return { makeCommand: makeCommand };
})();
<commit_msg>Add a semicolon as required by the makeCommand protocol<commit_after>// https://developer.mozilla.org/en-US/docs/Web/API/URLUtils

var fuzzerURLObjects = (function() {

  var hostnames = ["mozilla.org", "www.mozilla.org", "ftp.mozilla.org"];
  var ports = [
    "80",  // http
    "443", // https
    "21",  // ftp
    "23",  // telnet - blocked - "This address uses a network port which is normally used for purposes other than Web browsing."
    "9310" // other
  ];

  var fields = [
    { field: "href",     values: fuzzValues.URIs },
    { field: "protocol", values: ["http:", "https:", "ftp:", "telnet:", "chrome:", "resource:"] },
    { field: "hostname", values: hostnames },
    { field: "origin",   values: "" }, // should be read-only
    { field: "port",     values: [ports, ""] },
    { field: "host",     values: function() { return Random.index(hostnames) + (rnd(2) ? ":"+Random.index(ports) : ""); } },
    { field: "pathname", values: ["/", "/index.html",        function() { return "/" + Random.pick(fuzzValues.texts) }] },
    { field: "search",   values: ["", "?", "?foo=bar",       function() { return "?" + Random.pick(fuzzValues.texts) }] },
    { field: "hash",     values: ["", "#", "#main-content",  function() { return "#" + Random.pick(fuzzValues.texts) }] },
    { field: "username", values: ["", fuzzValues.texts] },
    { field: "password", values: ["", fuzzValues.texts] },
  ];

  function makeCommand()
  {
    if (rnd(20) == 0) {
      return makeURLObject();
    }

    var obj = Things.instanceAny(["Location", "URL", "HTMLAnchorElement", "HTMLAreaElement"])
    if (!obj) {
      return makeURLObject();
    }

    var i = rnd(fields.length);
    if (rnd(10) == 0) {
      return obj + "." + fields[i].field + ";"; // just read the field
    }
    var j = rnd(10) ? i : rnd(fields.length); // generate a value, usually for the correct field
    return obj + "." + fields[i].field + " = " + simpleSource(Random.pick(fields[j].values)) + ";"
  }

  function makeURLObject()
  {
    switch(rnd(5)) {
      case 0:
        return Things.add('new URL(' + simpleSource(Random.pick(fuzzValues.URIs)) + ')')
      case 1:
        return Things.add('document.createElementNS("http://www.w3.org/1999/xhtml", "a")');
      case 2:
        return Things.add('document.createElementNS("http://www.w3.org/1999/xhtml", "area")');
      case 3:
        // It is safe to play with a frame's location.
        var frame = Things.instanceAny(["HTMLFrameElement", "HTMLIFrameElement"]);
        if (frame) {
          return Things.add(frame + ".location");
        }
      default:
        // It may be self-destructive to play with this document's location.
        if (rnd(100) == 0) {
          return "/*selfdestruct*/ " + Things.add("location");
        }
        return [];
    }
  }

  return { makeCommand: makeCommand };
})();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 Scott Bishop
 * BluJagu, LLC - www.blujagu.com
 * MIT License (MIT) - This header must remain intact.
 **/
define(['./eventHub'], function(eventHub) {
    'use strict';

    var _memory = {};

    _memory.__proto__ = {
        'create': function (dbName) {
            this[dbName] = eventHub.connect(new DB(dbName));

            return this[dbName];
        },
        'drop': function (dbName) {
            if (this[dbName]) {
                this[dbName] = null;
                delete this[dbName];

                return true;
            }

            return false;
        },
        'get': function (dbName) {
            return this[dbName];
        }
    };

    var DB = function (dbName) {
        this.__proto__._event = dbName;
    };

    DB.prototype = {
        'constructor': DB,
        '_event': '',
        'createTable': function (tableName, rows) {
            /**
             * create adds a new Table Object named tableName to the DB Object
             *        dispatches a 'tableName' event for any event listeners
             * @param tableName {String} Name to assign to the new table
             * @returns {TableObject} Returns a new Table(tableName)
             */
            var table = new Table(rows),
                path = this._event,
                detail;

            table._db = this;
            table.__proto__._event = path + '.' + tableName;
            this[tableName] = table;
            detail = {
                'target': this,
                'type': 'Create',
                'value': table
            };
            // todo: unlock dispatch
            //this.dispatch(path, detail);

            return table;
        },
        'drop': function (tableName) {
            if (this[tableName]) {
                this[tableName] = null;
                delete this[tableName];
                return true;
            }
        },
        'select': function (/*fields*/) {
            var fromFunc = function (tableName) {
                var table = this.db[tableName],
                    returnObj = {},
                    returnArray = [],
                    selects = this.selects,
                    select = selects.shift(),
                    selected = table[select],
                    selectedVal = undefined,
                    i = 0, j = 0,
                    iLen = selected.length,
                    jLen = selects.length;

                for (i; i < iLen; ++i) {
                    selectedVal = selected[i];
                    if (selectedVal !== null) { // skip holes, these are 'dead indices'
                        returnObj[select] = selectedVal;
                        for (j = 0; j < jLen; ++j) {
                            select = selects[j];
                            selected = table[select];
                            returnObj[select] = selected[i];
                        }
                        returnArray.push(returnObj);
                        returnObj = {};
                    }
                }

                return returnArray;
            }.bind({
                'db': this,
                'selects': Array.prototype.slice.call(arguments)
            });

            return {
                'from': fromFunc
            }
        },
        insertInto: function (tableName) {
            var table = this[tableName];

            return function (/*fields*/) {
                var insertValues = function (/*values*/) {
                    var table = this.table,
                        fields = this.fields,
                        values = Array.prototype.slice.call(arguments),
                        fillIndex = t[0].length,
                        targetIndex = -1,
                        prop = '',
                        i = 0;

                    for (prop in table) {
                        if (table.hasOwnProperty(prop)) {
                            targetIndex = fields.indexOf(prop);
                            if (targetIndex > -1) {
                                table[prop].push(values.splice(targetIndex, 1));
                                fields.splice(targetIndex, 1);
                            } else {
                                table[prop].push(undefined);
                            }
                        }
                    }

                    return table;
                }.bind({
                    'table': this,
                    'fields': Array.prototype.slice.call(arguments)
                });

                return {
                    'values': insertValues
                };
            }.bind(table);
        }
    };

    var Table = function (rows) {
        var row, rowName, i = 0, len;

        rows = rows !== undefined ? rows instanceof Array ? rows : [rows] : [];
        for (len = rows.length; i < len; ++i) {
            rowName = rows[i];
            row = new Row();
            row.__proto__._db = this._db;
            row.__proto__._event = this._event + '.' + rowName;
            this[rowName] = row;
            // todo: dispatch update
        }
    };

    Table.prototype = {
        'constructor': Table,
        '_event': '',
        '_db': undefined
    };

    var Row = function () {
        var __super = this.__proto__.__proto__;

        this.push = function (x) {
            // todo: dispatch update/add
            __super.push.call(this, x);
        };
    };

    Row.prototype = {
        'constructor': Row,
        '_event': '',
        '_db': undefined
    };

    Row.prototype.__proto__ = Array.prototype;

    return {
        'createDB': _memory.create,
        'dropDB'  : _memory.drop,
        'getDB'   : _memory.get
    };
});<commit_msg>Improved createTable<commit_after>/**
 * Copyright (c) 2015 Scott Bishop
 * BluJagu, LLC - www.blujagu.com
 * MIT License (MIT) - This header must remain intact.
 **/
define(['./eventHub'], function(eventHub) {
    'use strict';

    var _memory = {};

    _memory.__proto__ = {
        'create': function (dbName) {
            this[dbName] = eventHub.connect(new DB(dbName));

            return this[dbName];
        },
        'drop': function (dbName) {
            if (this[dbName]) {
                this[dbName] = null;
                delete this[dbName];

                return true;
            }

            return false;
        },
        'get': function (dbName) {
            return this[dbName];
        }
    };

    var DB = function (dbName) {
        this.__proto__._event = dbName;
    };

    DB.prototype = {
        'constructor': DB,
        '_event': '',
        'createTable': function (tableName) {
            /**
             * create adds a new Table Object named tableName to the DB Object
             *        dispatches a 'tableName' event for any event listeners
             * @param tableName {String} Name to assign to the new table
             * @returns {TableObject} Returns a new Table(tableName)
             */
            return function (/*rows*/) {
                var db = this.db,
                    rows = Array.prototype.slice.call(arguments),
                    path = db._event,
                    table = new Table(rows),
                    detail;

                table.__proto__._db = db;
                table.__proto__._event = path + '.' + this.tableName;
                db[tableName] = table;
                detail = {
                    'target': this,
                    'type': 'Create',
                    'value': table
                };
                // todo: unlock dispatch
                //this.dispatch(path, detail);
                return table;
            }.bind({
                'db': this,
                'tableName': tableName
            });
        },
        'drop': function (tableName) {
            if (this[tableName]) {
                this[tableName] = null;
                delete this[tableName];
                return true;
            }
        },
        'select': function (/*fields*/) {
            var fromFunc = function (tableName) {
                var table = this.db[tableName],
                    returnObj = {},
                    returnArray = [],
                    selects = this.selects,
                    select = selects.shift(),
                    selected = table[select],
                    selectedVal = undefined,
                    i = 0, j = 0,
                    iLen = selected.length,
                    jLen = selects.length;

                for (i; i < iLen; ++i) {
                    selectedVal = selected[i];
                    if (selectedVal !== null) { // skip holes, these are 'dead indices'
                        returnObj[select] = selectedVal;
                        for (j = 0; j < jLen; ++j) {
                            select = selects[j];
                            selected = table[select];
                            returnObj[select] = selected[i];
                        }
                        returnArray.push(returnObj);
                        returnObj = {};
                    }
                }

                return returnArray;
            }.bind({
                'db': this,
                'selects': Array.prototype.slice.call(arguments)
            });

            return {
                'from': fromFunc
            }
        },
        insertInto: function (tableName) {
            var table = this[tableName];

            return function (/*fields*/) {
                var insertValues = function (/*values*/) {
                    var table = this.table,
                        fields = this.fields,
                        values = Array.prototype.slice.call(arguments),
                        fillIndex = t[0].length,
                        targetIndex = -1,
                        prop = '',
                        i = 0;

                    for (prop in table) {
                        if (table.hasOwnProperty(prop)) {
                            targetIndex = fields.indexOf(prop);
                            if (targetIndex > -1) {
                                table[prop].push(values.splice(targetIndex, 1));
                                fields.splice(targetIndex, 1);
                            } else {
                                table[prop].push(undefined);
                            }
                        }
                    }

                    return table;
                }.bind({
                    'table': this,
                    'fields': Array.prototype.slice.call(arguments)
                });

                return {
                    'values': insertValues
                };
            }.bind(table);
        }
    };

    var Table = function (rows) {
        var row, rowName, i = 0, len;

        rows = rows !== undefined ? rows instanceof Array ? rows : [rows] : [];
        for (len = rows.length; i < len; ++i) {
            rowName = rows[i];
            row = new Row();
            row.__proto__._db = this._db;
            row.__proto__._event = this._event + '.' + rowName;
            this[rowName] = row;
            // todo: dispatch update
        }
    };

    Table.prototype = {
        'constructor': Table,
        '_event': '',
        '_db': undefined
    };

    var Row = function () {
        var __super = this.__proto__.__proto__;

        this.push = function (x) {
            // todo: dispatch update/add
            __super.push.call(this, x);
        };
    };

    Row.prototype = {
        'constructor': Row,
        '_event': '',
        '_db': undefined
    };

    Row.prototype.__proto__ = Array.prototype;

    return {
        'createDB': _memory.create,
        'dropDB'  : _memory.drop,
        'getDB'   : _memory.get
    };
});<|endoftext|>


<commit_before>"use strict";

var log = require("./Logger");
var uuid = require("node-uuid");

function padArray(obj) {
    var arr;
    if (Array.isArray(obj)) {
        arr = obj;
    }
    else {
        arr = [obj];
    }
    return arr;
}

/**
 * Returns a random id
 * @param prefix
 * @returns {string}
 */
function getUID(prefix) {
    var id = uuid.v4();
    return  prefix ? prefix + id : id;
}

function runCallBack(func, err, data, context) {
    try {
        if (typeof func === "function") {
            func.call(context || null, err, data);
        }
    }
    catch (exc) {
        log.error("[batchelor] Utils runCallBack Error executing callback");
    }
}

/**
 * check if the request if persistent
 * @param req
 * @returns {boolean}
 */
function isPersistentRequest(req) {
    return req && (req.isPersistentRequest === true || req.persistent === true);
}

module.exports = {
    padArray: padArray,
    getUID: getUID,
    runCallBack: runCallBack,
    isPersistentRequest: isPersistentRequest
};
<commit_msg>fixed log line<commit_after>"use strict";

var log = require("./Logger");
var uuid = require("node-uuid");

function padArray(obj) {
    var arr;
    if (Array.isArray(obj)) {
        arr = obj;
    }
    else {
        arr = [obj];
    }
    return arr;
}

/**
 * Returns a random id
 * @param prefix
 * @returns {string}
 */
function getUID(prefix) {
    var id = uuid.v4();
    return  prefix ? prefix + id : id;
}

function runCallBack(func, err, data, context) {
    try {
        if (typeof func === "function") {
            func.call(context || null, err, data);
        }
    }
    catch (exc) {
        log.error("[batchelor] Utils runCallBack Error executing callback err=" + exc.message);
    }
}

/**
 * check if the request if persistent
 * @param req
 * @returns {boolean}
 */
function isPersistentRequest(req) {
    return req && (req.isPersistentRequest === true || req.persistent === true);
}

module.exports = {
    padArray: padArray,
    getUID: getUID,
    runCallBack: runCallBack,
    isPersistentRequest: isPersistentRequest
};
<|endoftext|>


<commit_before>/*jslint node:true,bitwise:true*/
/*globals Uint8Array, beforeEach, afterEach, it, expect, jasmine */
var testUtil = require('../../util');

module.exports = function (provider, setup) {
  'use strict';
  var socket, dispatch;
  beforeEach(function () {
    setup();
    dispatch = testUtil.createTestPort('msgs');
    socket = new provider.provider(undefined, dispatch.onMessage.bind(dispatch));
  });

  function rawStringToBuffer(str) {
    var idx, len = str.length, arr = [];
    for (idx = 0; idx < len; idx += 1) {
      arr[idx] = str.charCodeAt(idx) & 0xFF;
    }
    return new Uint8Array(arr).buffer;
  }

  it("Works as a Client", function (done) {
    socket.connect('www.google.com', 80, function () {
      console.warn('connected');
      var written = false;
      socket.write(rawStringToBuffer('GET / HTTP/1.0\n\n'), function (okay) {
        console.warn('written');
        written = true;
      });
      setTimeout(function () {
        expect(written).toBe(true);
        expect(dispatch.gotMessage('onData', [])).not.toEqual(false);
        done();
        socket.close(function () {});
      }, 500);
    });
  });

  it("Gets info on client & server sockets", function (done) {
    var cspy = jasmine.createSpy('client'),
      client,
      onconnect = function () {
        client.getInfo(function (info) {
          expect(info.localPort).toBeGreaterThan(1023);
          client.close(function () {});
          socket.close(function () {});
          done();
        });
      };

    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        expect(info.localPort).toBeGreaterThan(1023);
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, onconnect);
      });
    });
  });

  it("Sends from Client to Server", function (done) {
    var cspy = jasmine.createSpy('client'),
      client,
      receiver,
      onDispatch,
      onconnect;

    onDispatch = function (evt, msg) {
      if (evt === 'onDisconnect') {
        return;
      }
      expect(evt).toEqual('onData');
      expect(msg.data.byteLength).toEqual(10);
      done();
      socket.close(function () {});
      client.close(function () {});
      receiver.close(function () {});
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      console.warn('connection');
      expect(msg.socket).toBeDefined();
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
      console.log('new socket id', msg);
    });
    onconnect = function () {
      console.warn('connected');
      var buf = new Uint8Array(10);
      client.write(buf.buffer, function () {});
    };
    socket.listen('127.0.0.1', 9981, function () {
      console.warn('listening');
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, onconnect);
    });
  });

  it("Gives error when connecting to invalid domain", function (done) {
    socket.connect('www.domainexistsbecausesomeonepaidmoneytobreakourtests.gov', 80,
      function (success, err) {
        expect(err.errcode).toBe('CONNECTION_FAILED');
        done();
      });
  });
  // TODO: add tests for tcpsocket.secure, accepting multiple.
};
<commit_msg>fix tcp integration to avoid tests clobbering each others connections<commit_after>/*jslint node:true,bitwise:true*/
/*globals Uint8Array, beforeEach, afterEach, it, expect, jasmine */
var testUtil = require('../../util');

module.exports = function (provider, setup) {
  'use strict';
  var socket, dispatch;
  beforeEach(function () {
    setup();
    dispatch = testUtil.createTestPort('msgs');
    socket = new provider.provider(undefined, dispatch.onMessage.bind(dispatch));
  });

  function rawStringToBuffer(str) {
    var idx, len = str.length, arr = [];
    for (idx = 0; idx < len; idx += 1) {
      arr[idx] = str.charCodeAt(idx) & 0xFF;
    }
    return new Uint8Array(arr).buffer;
  }

  it("Works as a Client", function (done) {
    socket.connect('www.google.com', 80, function () {
      console.warn('connected');
      var written = false;
      socket.write(rawStringToBuffer('GET / HTTP/1.0\n\n'), function (okay) {
        console.warn('written');
        written = true;
      });
      dispatch.gotMessageAsync('onData', [], function(msg) {
        console.warn('received onData');
        expect(written).toBe(true);
        expect(dispatch.gotMessage('onData', [])).not.toEqual(false);
        socket.close(function () { done(); });
      });
    });
  });

  it("Gets info on client & server sockets", function (done) {
    var cspy = jasmine.createSpy('client'),
      client,
      onconnect = function () {
        client.getInfo(function (info) {
          expect(info.localPort).toBeGreaterThan(1023);
          client.close(function () {});
          socket.close(function () {});
          done();
        });
      };

    socket.listen('127.0.0.1', 0, function () {
      socket.getInfo(function (info) {
        expect(info.localPort).toBeGreaterThan(1023);
        client = new provider.provider(undefined, cspy);
        client.connect('127.0.0.1', info.localPort, onconnect);
      });
    });
  });

  it("Sends from Client to Server", function (done) {
    var cspy = jasmine.createSpy('client'),
      client,
      receiver,
      onDispatch,
      onconnect;

    onDispatch = function (evt, msg) {
      if (evt === 'onDisconnect') {
        return;
      }
      expect(evt).toEqual('onData');
      expect(msg.data.byteLength).toEqual(10);
      socket.close(function () {});
      client.close(function () {});
      receiver.close(function () {});
      done();
    };
    dispatch.gotMessageAsync('onConnection', [], function (msg) {
      console.warn('connection');
      expect(msg.socket).toBeDefined();
      receiver = new provider.provider(undefined, onDispatch, msg.socket);
      console.log('new socket id', msg);
    });
    onconnect = function () {
      console.warn('connected');
      var buf = new Uint8Array(10);
      client.write(buf.buffer, function () {});
    };
    socket.listen('127.0.0.1', 9981, function () {
      console.warn('listening');
      client = new provider.provider(undefined, cspy);
      client.connect('127.0.0.1', 9981, onconnect);
    });
  });

  it("Gives error when connecting to invalid domain", function (done) {
    socket.connect('www.domainexistsbecausesomeonepaidmoneytobreakourtests.gov', 80,
      function (success, err) {
        expect(err.errcode).toBe('CONNECTION_FAILED');
        done();
      });
  });

  // TODO: add tests for tcpsocket.secure, accepting multiple.
};
<|endoftext|>


<commit_before>const EventEmitter = require('events').EventEmitter;
const Ws = require('ws');
const DeepExtend = require('deep-extend');

const ClientConnection = require('./ClientConnection.js');

class Server extends EventEmitter {

    constructor(wsOptions, guacdOptions, clientOptions, callbacks) {
        super();

        this.wsOptions = Object.assign({
            port: 8080
        }, wsOptions);

        this.guacdOptions = Object.assign({
            host: '127.0.0.1',
            port: 4822
        }, guacdOptions);

        this.clientOptions = {};
        DeepExtend(this.clientOptions, {
            log: {
                verbose: true
            },

            crypt: {
                cypher: 'AES-256-CBC',
            },

            connectionDefaultSettings: {
                rdp: {
                    'args': 'connect',
                    'port': '3389',
                    'width': 1024,
                    'height': 768,
                    'dpi': 96,
                }
            },

            allowedUnencryptedConnectionSettings: {
                rdp: [
                    'width',
                    'height',
                    'dpi'
                ]
            }

        }, clientOptions);

        this.callbacks = Object.assign({
            processConnectionSettings: (settings, callback) => callback(undefined, settings)
        }, callbacks);

        this.connectionsCount = 0;
        this.activeConnections = {};

        console.log('Starting websocket server on port ' + this.wsOptions.port);

        this.webSocketServer = new Ws.Server(this.wsOptions);
        this.webSocketServer.on('connection', this.newConnection.bind(this));

        process.on('SIGTERM', this.close.bind(this));
        process.on('SIGINT', this.close.bind(this));

    }

    close() {
        console.log('Closing all connections and exiting...');
        this.webSocketServer.close(() => {
            Object
                .keys(this.activeConnections)
                .forEach(key => this.activeConnections[key].close());
        });

    }

    newConnection(webSocketConnection) {
        this.connectionsCount++;
        this.activeConnections[this.connectionsCount] = new ClientConnection(this, this.connectionsCount, webSocketConnection)
    }
}

module.exports = Server;
<commit_msg>Added default connection parameters for VNC protocol<commit_after>const EventEmitter = require('events').EventEmitter;
const Ws = require('ws');
const DeepExtend = require('deep-extend');

const ClientConnection = require('./ClientConnection.js');

class Server extends EventEmitter {

    constructor(wsOptions, guacdOptions, clientOptions, callbacks) {
        super();

        this.wsOptions = Object.assign({
            port: 8080
        }, wsOptions);

        this.guacdOptions = Object.assign({
            host: '127.0.0.1',
            port: 4822
        }, guacdOptions);

        this.clientOptions = {};
        DeepExtend(this.clientOptions, {
            log: {
                verbose: true
            },

            crypt: {
                cypher: 'AES-256-CBC',
            },

            connectionDefaultSettings: {
                rdp: {
                    'args': 'connect',
                    'port': '3389',
                    'width': 1024,
                    'height': 768,
                    'dpi': 96,
                },
                vnc: {
                    'args': 'connect',
                    'port': '5900',
                    'width': 1024,
                    'height': 768,
                    'dpi': 96,
                }
            },

            allowedUnencryptedConnectionSettings: {
                rdp: [
                    'width',
                    'height',
                    'dpi'
                ],
                vnc: [
                    'width',
                    'height',
                    'dpi'
                ]
            }

        }, clientOptions);

        this.callbacks = Object.assign({
            processConnectionSettings: (settings, callback) => callback(undefined, settings)
        }, callbacks);

        this.connectionsCount = 0;
        this.activeConnections = {};

        console.log('Starting websocket server on port ' + this.wsOptions.port);

        this.webSocketServer = new Ws.Server(this.wsOptions);
        this.webSocketServer.on('connection', this.newConnection.bind(this));

        process.on('SIGTERM', this.close.bind(this));
        process.on('SIGINT', this.close.bind(this));

    }

    close() {
        console.log('Closing all connections and exiting...');
        this.webSocketServer.close(() => {
            Object
                .keys(this.activeConnections)
                .forEach(key => this.activeConnections[key].close());
        });

    }

    newConnection(webSocketConnection) {
        this.connectionsCount++;
        this.activeConnections[this.connectionsCount] = new ClientConnection(this, this.connectionsCount, webSocketConnection)
    }
}

module.exports = Server;
<|endoftext|>


<commit_before>const ExtendableFunction = require('../../internal/ExtendableFunction');
const Search = require('../Search');

const _names = require('../../internal/names');

/**
 * An api adapter for dealing with a single solar system, currently only
 * supporting fetching simple information.
 */
class SolarSystem {
  /**
   * Create a new SolarSystem for the given `api` provider and specific
   * `solarSystemId`.
   *
   * @param api {ApiProvider} The api provider used to generate web requests
   * @param solarSystemId {Number} The system id that is used for all requests
   * @constructor
   */
  constructor(api, solarSystemId) {
    this._api = api;
    this._id = solarSystemId;
  }

  /**
   * Get solar system public info from the ESI endpoint. This makes an HTTP GET
   * request to
   * [`/universe/systems/{id}/`](https://esi.tech.ccp.is/latest/#!/Universe/get_universe_systems_system_id).
   * The request is returned as an asynchronous Promise that resolves to an
   * object parsed from the response JSON model. An example value looks like:
   *
   * ```
   * {
   *   "solar_system_name": "Jita"
   * }
   * ```
   *
   * @return {Promise} A Promise that resolves to the response of the request
   * @esi_link UniverseApi.getUniverseSystemsSystemId
   */
  info() {
    return this._api.universe()
    .newRequest('getUniverseSystemsSystemId', [this._id]);
  }
}

/**
 * An api adapter that provides functions for accessing solar system information
 * via the
 * [universe](https://esi.tech.ccp.is/latest/#/Universe) and
 * [search](https://esi.tech.ccp.is/latest/#/Search) ESI end points.
 * You should not usually instantiate this directly as its constructor requires
 * an internal api instance.
 *
 * This is a function class so instances of `SolarSystems` are functions and can
 * be invoked directly, besides accessing its members. Its default function
 * action is equivalent to {@link SolarSystems#get get}.
 */
class SolarSystems extends ExtendableFunction {
  /**
   * Create a new SolarSystems instance using the given `api`.
   *
   * @param api {ApiProvider} The api provider
   * @constructor
   */
  constructor(api) {
    super(id => this.get(id));
    this._api = api;

    this._search = null;
  }

  /**
   * A Search module instance configured to search over the `'solarsystem'`
   * type.
   *
   * @returns {Search}
   */
  get search() {
    if (!this._search) {
      this._search = new Search(this._api, ['solarsystem']);
    }
    return this._search;
  }

  /**
   * Create a new SolarSystem end point targeting the particular system by `id`.
   *
   * @param id {Number} The solar system id
   * @returns {SolarSystem}
   */
  get(id) {
    return new SolarSystem(this._api, id);
  }

  /**
   * Get the names for a list of solar system ids from the ESI endpoint. This
   * makes an HTTP POST request to
   * [`universe/names/`](https://esi.tech.ccp.is/latest/#!/Universe/post_universe_names).
   * The request is returned as an asynchronous Promise that resolves to an
   * array parsed from the response JSON model. An example value looks like:
   *
   * ```
   * [
   *   {
   *     "id": 1000171,
   *     "name": "Republic University"
   *   }
   * ]
   * ```
   *
   * Note that this has the category field stripped from the response and will
   * only include matches with the solar system category.
   *
   * @param {Array.<Number>} ids The solar system ids to look up.
   * @return {Promise} A Promise that resolves to the response of
   *   the request
   * @esi_link UniverseApi.postUniverseNames
   */
  names(ids) {
    return _names(this._api, 'solar_system', ids);
  }
}

module.exports = SolarSystems;
<commit_msg>Add new and updated systems endpoints<commit_after>const ExtendableFunction = require('../../internal/ExtendableFunction');
const Search = require('../Search');

const _names = require('../../internal/names');

/**
 * An api adapter for dealing with a single solar system, currently only
 * supporting fetching simple information.
 */
class SolarSystem {
  /**
   * Create a new SolarSystem for the given `api` provider and specific
   * `solarSystemId`.
   *
   * @param api {ApiProvider} The api provider used to generate web requests
   * @param solarSystemId {Number} The system id that is used for all requests
   * @constructor
   */
  constructor(api, solarSystemId) {
    this._api = api;
    this._id = solarSystemId;
  }

  /**
   * Get solar system public info from the ESI endpoint. This makes an HTTP GET
   * request to
   * [`/universe/systems/{id}/`](https://esi.tech.ccp.is/latest/#!/Universe/get_universe_systems_system_id).
   * The request is returned as an asynchronous Promise that resolves to an
   * object parsed from the response JSON model. An example value looks like:
   *
   * ```
   * {
   *   "constellation_id": 20000001,
   *   "name": "Akpivem",
   *   "planets": [
   *     {
   *       "moons": [
   *         40000042
   *       ],
   *       "planet_id": 40000041
   *     },
   *     {
   *      "planet_id": 40000043
   *     }
   *   ],
   *   "position": {
   *     "x": -91174141133075340,
   *     "y": 43938227486247170,
   *     "z": -56482824383339900
   *   },
   *   "security_class": "B",
   *   "security_status": 0.8462923765182495,
   *   "stargates": [
   *     50000342
   *   ],
   *   "system_id": 30000003
   * }
   * ```
   *
   * @return {Promise} A Promise that resolves to the response of the request
   * @esi_link UniverseApi.getUniverseSystemsSystemId
   */
  info() {
    return this._api.universe()
    .newRequest('getUniverseSystemsSystemId', [this._id]);
  }
}

/**
 * An api adapter that provides functions for accessing solar system information
 * via the
 * [universe](https://esi.tech.ccp.is/latest/#/Universe) and
 * [search](https://esi.tech.ccp.is/latest/#/Search) ESI end points.
 * You should not usually instantiate this directly as its constructor requires
 * an internal api instance.
 *
 * This is a function class so instances of `SolarSystems` are functions and can
 * be invoked directly, besides accessing its members. Its default function
 * action is equivalent to {@link SolarSystems#get get} or {@link SolarSystems#all all}
 * if no id is provided.
 */
class SolarSystems extends ExtendableFunction {
  /**
   * Create a new SolarSystems instance using the given `api`.
   *
   * @param api {ApiProvider} The api provider
   * @constructor
   */
  constructor(api) {
    super(id => (id ? this.get(id) : this.all()));
    this._api = api;

    this._search = null;
  }

  /**
   * A Search module instance configured to search over the `'solarsystem'`
   * type.
   *
   * @returns {Search}
   */
  get search() {
    if (!this._search) {
      this._search = new Search(this._api, ['solarsystem']);
    }
    return this._search;
  }

  /**
   * Create a new SolarSystem end point targeting the particular system by `id`.
   *
   * @param id {Number} The solar system id
   * @returns {SolarSystem}
   */
  get(id) {
    return new SolarSystem(this._api, id);
  }

  /**
   * Get all solar system ids from the ESI endpoint. This makes an HTTP GET
   * request to
   * [`universe/systems/`](https://esi.tech.ccp.is/dev/?datasource=tranquility#!/Universe/get_universe_systems).
   * The request is returned as an asynchronous Promise that resolves to an
   * array parsed from the response JSON model. An example value looks like:
   *
   * ```
   * [
   *   30000001,
   *   30000002
   * ]
   * ```
   *
   * @returns {Promise}
   * @esi_link UniverseApi.getUniverseSystems
   */
  all() {
    return this._api.universe().newRequest('getUniverseSystems', []);
  }

  /**
   * Get the names for a list of solar system ids from the ESI endpoint. This
   * makes an HTTP POST request to
   * [`universe/names/`](https://esi.tech.ccp.is/latest/#!/Universe/post_universe_names).
   * The request is returned as an asynchronous Promise that resolves to an
   * array parsed from the response JSON model. An example value looks like:
   *
   * ```
   * [
   *   {
   *     "id": 30000003,
   *     "name": "Akpivem"
   *   }
   * ]
   * ```
   *
   * Note that this has the category field stripped from the response and will
   * only include matches with the solar system category.
   *
   * @param {Array.<Number>} ids  Optional; the solar system ids to look up. If
   *     not provided then the names of all systems will be returned.
   * @return {Promise} A Promise that resolves to the response of
   *     the request
   * @esi_link UniverseApi.postUniverseNames
   */
  names(ids = []) {
    if (!ids || ids.length == 0) {
      return this.all().then(allIds => this.names(allIds));
    } else {
      return _names(this._api, 'solar_system', ids);
    }
  }
}

module.exports = SolarSystems;
<|endoftext|>