<commit_before><commit_msg>fix list deletion on pages other than the homepage.<commit_after><|endoftext|>


<commit_before>var vm = require('vm');
var fs = require('fs');

// compute freedom.js source.
var src = fs.readFileSync(__dirname + '/moduleentry.js'),
    fileInfo = require('freedom'),
    glob = require('glob'),
    freedomPrefix = require.resolve('freedom').substr(0,
        require.resolve('freedom').lastIndexOf('freedom') + 8);

src += fs.readFileSync(require.resolve('es6-promise/dist/promise-1.0.0'));

fileInfo.FILES.srcCore.concat(
    fileInfo.FILES.srcPlatform).forEach(function(dir) {
  glob.sync(freedomPrefix + '/' +  dir).forEach(function(file) {
    src += fs.readFileSync(file);
  });
});
glob.sync(__dirname + '/../providers/*.js').forEach(function(file) {
  src += fs.readFileSync(file);
});

// Create Minimal Context.
var context = {
  // setTimeout - for delaying async / implementing promises.
  setTimeout: function(cb, time) {
    setTimeout(cb, time);
  },
  // postMessage - sending messages out of the module.
  postMessage: function(msg) {
    process.send(msg);
  },
  // onMessage - sending messages into the module.
  _om: null,
  onMessage: function(cb) {
    context._om = cb;
  },
  ArrayBuffer: ArrayBuffer,
  Uint8Array: Uint8Array,
  Uint16Array: Uint16Array,
  Buffer: Buffer,
  // importScripts - Loading code into the module.
  importScripts: function(script) {
    try {
      var file = fs.readFileSync(script.substr(7));
      vm.runInContext(file, freedomVM, script.substr(7));
    } catch(e) {
      console.error(e);
      process.exit(1);
    }
  }
};

var freedomVM = vm.createContext(context);
//console.log('Starting VM Context');
try {
  vm.runInContext(src, freedomVM, 'freedom.js.vm');
} catch(e) {
  // Report Syntax error.
  process.send(e);
  console.error(e);
  process.exit(1);
}

process.on('message', function(msg) {
  if (context._om) {
    context._om(msg);
  } else {
    console.warn('Message dropped - VM not ready');
  }
});
<commit_msg>Add DataView to context<commit_after>var vm = require('vm');
var fs = require('fs');

// compute freedom.js source.
var src = fs.readFileSync(__dirname + '/moduleentry.js'),
    fileInfo = require('freedom'),
    glob = require('glob'),
    freedomPrefix = require.resolve('freedom').substr(0,
        require.resolve('freedom').lastIndexOf('freedom') + 8);

src += fs.readFileSync(require.resolve('es6-promise/dist/promise-1.0.0'));

fileInfo.FILES.srcCore.concat(
    fileInfo.FILES.srcPlatform).forEach(function(dir) {
  glob.sync(freedomPrefix + '/' +  dir).forEach(function(file) {
    src += fs.readFileSync(file);
  });
});
glob.sync(__dirname + '/../providers/*.js').forEach(function(file) {
  src += fs.readFileSync(file);
});

// Create Minimal Context.
var context = {
  // setTimeout - for delaying async / implementing promises.
  setTimeout: function(cb, time) {
    setTimeout(cb, time);
  },
  // postMessage - sending messages out of the module.
  postMessage: function(msg) {
    process.send(msg);
  },
  // onMessage - sending messages into the module.
  _om: null,
  onMessage: function(cb) {
    context._om = cb;
  },
  ArrayBuffer: ArrayBuffer,
  DataView: DataView,
  Uint8Array: Uint8Array,
  Uint16Array: Uint16Array,
  Buffer: Buffer,
  // importScripts - Loading code into the module.
  importScripts: function(script) {
    try {
      var file = fs.readFileSync(script.substr(7));
      vm.runInContext(file, freedomVM, script.substr(7));
    } catch(e) {
      console.error(e);
      process.exit(1);
    }
  }
};

var freedomVM = vm.createContext(context);
//console.log('Starting VM Context');
try {
  vm.runInContext(src, freedomVM, 'freedom.js.vm');
} catch(e) {
  // Report Syntax error.
  process.send(e);
  console.error(e);
  process.exit(1);
}

process.on('message', function(msg) {
  if (context._om) {
    context._om(msg);
  } else {
    console.warn('Message dropped - VM not ready');
  }
});
<|endoftext|>


<commit_before><commit_msg>minified js; added randomly generated string to class name to support multiple elements<commit_after><|endoftext|>


<commit_before>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (this.isTypeCastExpression()) {
    return this.get("expression").resolve(dangerous, resolved);
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(path, name, types = []) {
  var binding = this.scope.getBinding(name);

  this.typeAnnotation = t.unionTypeAnnotation(types);

  var functions = [];
  var constantViolations = getConstantViolationsBefore(binding, path, functions);

  var testType = getTypeAnnotationBasedOnConditional(path, name);
  if (testType) {
    var testConstantViolations = getConstantViolationsBefore(binding, testType.ifStatement);

    // remove constant violations observed before the IfStatement
    constantViolations = constantViolations.filter((path) => testConstantViolations.indexOf(path) < 0);

    // add back on functions which would have been removed by the last filter
    constantViolations = constantViolations.concat(functions);

    // clear current types and add in observed test type
    types = [testType.typeAnnotation];
  }

  for (var constantViolation of (constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

function getConstantViolationsBefore(binding, path, functions) {
  var violations = binding.constantViolations.slice();
  violations.push(binding.path);
  return violations.filter((violation) => {
    violation = violation.resolve();
    var status = violation._guessExecutionStatusRelativeTo(path);
    if (functions && status === "function") functions.push(violation);
    return status !== "after";
  });
}

function checkBinary(path, name) {
  var right = path.get("right").resolve();
  var left = path.get("left").resolve();
  if (left.isIdentifier({ name })) {
    return right.getTypeAnnotation();
  } else if (right.isIdentifier({ name })) {
    return left.getTypeAnnotation();
  } else {
    return;
  }
}

function getParentConditional(path) {
  var parentPath;
  while (parentPath = path.parentPath) {
    if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) {
      if (path.key === "test") {
        return;
      } else {
        return parentPath;
      }
    } else {
      path = parentPath;
    }
  }
}

function getTypeAnnotationBasedOnConditional(path, name) {
  var ifStatement = getParentConditional(path);
  if (!ifStatement) return;

  var test  = ifStatement.get("test");
  var paths = [test];
  var types = [];

  do {
    var path = paths.shift().resolve();

    if (path.isLogicalExpression()) {
      paths.push(path.get("left"), path.get("right"));
    } else if (path.isBinaryExpression({ operator: "===" })) {
      // todo: add in cases where operators imply a number
      var type = checkBinary(path, name);
      if (type) types.push(type);
    }
  } while(paths.length);

  var typeAnnotation;
  if (types.length) {
    return {
      typeAnnotation: t.createUnionTypeAnnotation(types),
      ifStatement
    };
  } else {
    return getTypeAnnotationBasedOnConditional(ifStatement, name);
  }
}

/**
 * todo: split up this method
 */

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      var init = this.get("init").getTypeAnnotation();

      // just because we're inferring a VariableDeclarator doesn't mean that it's the same
      // binding path as it may have been shadowed
      if (this.scope.getBinding(id.node.name).path === this) {
        return this._getTypeAnnotationBindingConstantViolations(this, id.node.name, [init]);
      } else {
        return init;
      }
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(this, node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (value === null) return t.voidTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<commit_msg>fix duplicate declaration<commit_after>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (this.isTypeCastExpression()) {
    return this.get("expression").resolve(dangerous, resolved);
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(path, name, types = []) {
  var binding = this.scope.getBinding(name);

  this.typeAnnotation = t.unionTypeAnnotation(types);

  var functions = [];
  var constantViolations = getConstantViolationsBefore(binding, path, functions);

  var testType = getTypeAnnotationBasedOnConditional(path, name);
  if (testType) {
    var testConstantViolations = getConstantViolationsBefore(binding, testType.ifStatement);

    // remove constant violations observed before the IfStatement
    constantViolations = constantViolations.filter((path) => testConstantViolations.indexOf(path) < 0);

    // add back on functions which would have been removed by the last filter
    constantViolations = constantViolations.concat(functions);

    // clear current types and add in observed test type
    types = [testType.typeAnnotation];
  }

  for (var constantViolation of (constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

function getConstantViolationsBefore(binding, path, functions) {
  var violations = binding.constantViolations.slice();
  violations.push(binding.path);
  return violations.filter((violation) => {
    violation = violation.resolve();
    var status = violation._guessExecutionStatusRelativeTo(path);
    if (functions && status === "function") functions.push(violation);
    return status !== "after";
  });
}

function checkBinary(path, name) {
  var right = path.get("right").resolve();
  var left = path.get("left").resolve();
  if (left.isIdentifier({ name })) {
    return right.getTypeAnnotation();
  } else if (right.isIdentifier({ name })) {
    return left.getTypeAnnotation();
  } else {
    return;
  }
}

function getParentConditional(path) {
  var parentPath;
  while (parentPath = path.parentPath) {
    if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) {
      if (path.key === "test") {
        return;
      } else {
        return parentPath;
      }
    } else {
      path = parentPath;
    }
  }
}

function getTypeAnnotationBasedOnConditional(path, name) {
  var ifStatement = getParentConditional(path);
  if (!ifStatement) return;

  var test  = ifStatement.get("test");
  var paths = [test];
  var types = [];

  do {
    let path = paths.shift().resolve();

    if (path.isLogicalExpression()) {
      paths.push(path.get("left"), path.get("right"));
    } else if (path.isBinaryExpression({ operator: "===" })) {
      // todo: add in cases where operators imply a number
      var type = checkBinary(path, name);
      if (type) types.push(type);
    }
  } while(paths.length);

  var typeAnnotation;
  if (types.length) {
    return {
      typeAnnotation: t.createUnionTypeAnnotation(types),
      ifStatement
    };
  } else {
    return getTypeAnnotationBasedOnConditional(ifStatement, name);
  }
}

/**
 * todo: split up this method
 */

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      var init = this.get("init").getTypeAnnotation();

      // just because we're inferring a VariableDeclarator doesn't mean that it's the same
      // binding path as it may have been shadowed
      if (this.scope.getBinding(id.node.name).path === this) {
        return this._getTypeAnnotationBindingConstantViolations(this, id.node.name, [init]);
      } else {
        return init;
      }
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(this, node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (value === null) return t.voidTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<|endoftext|>


<commit_before>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 *
 * NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
  var binding = this.scope.getBinding(name);

  for (var constantViolation of (binding.constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      return this._getTypeAnnotationBindingConstantViolations(id.node.name, [
        this.get("init").getTypeAnnotation()
      ]);
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"), t.typeParameterInstantiation([t.anyTypeAnnotation()]));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<commit_msg>save union type in _getTypeAnnotationBindingConstantViolations to prevent infinite recursion<commit_after>import type NodePath from "./index";
import * as t from "../../types";

/**
 * Resolve a "pointer" `NodePath` to it's absolute path.
 */

export function resolve(dangerous, resolved) {
  return this._resolve(dangerous, resolved) || this;
}

export function _resolve(dangerous?, resolved?): ?NodePath {
  // detect infinite recursion
  // todo: possibly have a max length on this just to be safe
  if (resolved && resolved.indexOf(this) >= 0) return;

  // we store all the paths we've "resolved" in this array to prevent infinite recursion
  resolved = resolved || [];
  resolved.push(this);

  if (this.isVariableDeclarator()) {
    if (this.get("id").isIdentifier()) {
      return this.get("init").resolve(dangerous, resolved);
    } else {
      // otherwise it's a request for a pattern and that's a bit more tricky
    }
  } else if (this.isReferencedIdentifier()) {
    var binding = this.scope.getBinding(this.node.name);
    if (!binding) return;

    // reassigned so we can't really resolve it
    if (!binding.constant) return;

    // todo - lookup module in dependency graph
    if (binding.kind === "module") return;

    if (binding.path !== this) {
      return binding.path.resolve(dangerous, resolved);
    }
  } else if (dangerous && this.isMemberExpression()) {
    // this is dangerous, as non-direct target assignments will mutate it's state
    // making this resolution inaccurate

    var targetKey = this.toComputedKey();
    if (!t.isLiteral(targetKey)) return;

    var targetName = targetKey.value;

    var target = this.get("object").resolve(dangerous, resolved);

    if (target.isObjectExpression()) {
      var props = target.get("properties");
      for (var prop of (props: Array)) {
        if (!prop.isProperty()) continue;

        var key = prop.get("key");

        // { foo: obj }
        var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });

        // { "foo": "obj" } or { ["foo"]: "obj" }
        match = match || key.isLiteral({ value: targetName });

        if (match) return prop.get("value").resolve(dangerous, resolved);
      }
    } else if (target.isArrayExpression() && !isNaN(+targetName)) {
      var elems = target.get("elements");
      var elem = elems[targetName];
      if (elem) return elem.resolve(dangerous, resolved);
    }
  }
}

/**
 * Infer the type of the current `NodePath`.
 *
 * NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
 */

export function getTypeAnnotation(force) {
  if (this.typeAnnotation) return this.typeAnnotation;

  var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
  if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
  return this.typeAnnotation = type;
}

export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
  var binding = this.scope.getBinding(name);

  var types = [];
  this.typeAnnotation = t.unionTypeAnnotation(types);

  for (var constantViolation of (binding.constantViolations: Array)) {
    types.push(constantViolation.getTypeAnnotation());
  }

  if (types.length) {
    return t.createUnionTypeAnnotation(types);
  }
}

export function _getTypeAnnotation(force?: boolean): ?Object {
  var node = this.node;

  if (!node) {
    // handle initializerless variables, add in checks for loop initializers too
    if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
      var declar       = this.parentPath.parentPath;
      var declarParent = declar.parentPath;

      // for (var NODE in bar) {}
      if (declar.key === "left" && declarParent.isForInStatement()) {
        return t.stringTypeAnnotation();
      }

      // for (var NODE of bar) {}
      if (declar.key === "left" && declarParent.isForOfStatement()) {
        return t.anyTypeAnnotation();
      }

      return t.voidTypeAnnotation();
    } else {
      return;
    }
  }

  if (node.typeAnnotation) {
    return node.typeAnnotation;
  }

  //
  if (this.isVariableDeclarator()) {
    var id = this.get("id");

    if (id.isIdentifier()) {
      var init = this.get("init").getTypeAnnotation();

      // just because we're inferring a VariableDeclarator doesn't mean that it's the same
      // binding path as it may have been shadowed
      if (this.scope.getBinding(id.node.name).path === this) {
        return this._getTypeAnnotationBindingConstantViolations(id.node.name, [init]);
      } else {
        return init;
      }
    } else {
      return;
    }
  }

  //
  if (this.parentPath.isTypeCastExpression()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isTypeCastExpression()) {
    return node.typeAnnotation;
  }

  //
  if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
    return t.genericTypeAnnotation(t.identifier("Array"), t.typeParameterInstantiation([t.anyTypeAnnotation()]));
  }

  //
  if (!force && this.parentPath.isReturnStatement()) {
    return this.parentPath.getTypeAnnotation();
  }

  if (this.isReturnStatement()) {
    var funcPath = this.findParent((path) => path.isFunction());
    if (!funcPath) return;

    var returnType = funcPath.node.returnType;
    if (returnType) {
      return returnType;
    } else {
      return this.get("argument").getTypeAnnotation(true);
    }
  }

  //
  if (this.isNewExpression() && this.get("callee").isIdentifier()) {
    // only resolve identifier callee
    return t.genericTypeAnnotation(node.callee);
  }

  //
  if (this.isReferencedIdentifier()) {
    // check if a binding exists of this value and if so then return a union type of all
    // possible types that the binding could be
    var binding = this.scope.getBinding(node.name);
    if (binding) {
      if (binding.identifier.typeAnnotation) {
        return binding.identifier.typeAnnotation;
      } else {
        return this._getTypeAnnotationBindingConstantViolations(node.name, [
          binding.path.getTypeAnnotation()
        ]);
      }
    }

    // built-in values
    if (node.name === "undefined") {
      return t.voidTypeAnnotation();
    } else if (node.name === "NaN" || node.name === "Infinity") {
      return t.numberTypeAnnotation();
    } else if (node.name === "arguments") {
      // todo
    }
  }

  //
  if (this.isObjectExpression()) {
    return t.genericTypeAnnotation(t.identifier("Object"));
  }

  //
  if (this.isFunction() || this.isClass()) {
    return t.genericTypeAnnotation(t.identifier("Function"));
  }

  //
  if (this.isTemplateLiteral()) {
    return t.stringTypeAnnotation();
  }

  //
  if (this.isUnaryExpression()) {
    let operator = node.operator;

    if (operator === "void") {
      return t.voidTypeAnnotation();
    } else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.stringTypeAnnotation();
    } else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    }
  }

  //
  if (this.isBinaryExpression()) {
    let operator = node.operator;

    if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.numberTypeAnnotation();
    } else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
      return t.booleanTypeAnnotation();
    } else if (operator === "+") {
      var right = this.get("right");
      var left  = this.get("left");

      if (left.isGenericType("Number") && right.isGenericType("Number")) {
        // both numbers so this will be a number
        return t.numberTypeAnnotation();
      } else if (left.isGenericType("String") || right.isGenericType("String")) {
        // one is a string so the result will be a string
        return t.stringTypeAnnotation();
      }

      // unsure if left and right are strings or numbers so stay on the safe side
      return t.unionTypeAnnotation([
        t.stringTypeAnnotation(),
        t.numberTypeAnnotation()
      ]);
    }
  }

  //
  if (this.isLogicalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("left").getTypeAnnotation(),
      this.get("right").getTypeAnnotation()
    ]);
  }

  //
  if (this.isConditionalExpression()) {
    return t.createUnionTypeAnnotation([
      this.get("consequent").getTypeAnnotation(),
      this.get("alternate").getTypeAnnotation()
    ]);
  }

  //
  if (this.isSequenceExpression()) {
    return this.get("expressions").pop().getTypeAnnotation(force);
  }

  //
  if (this.isAssignmentExpression()) {
    return this.get("right").getTypeAnnotation(force);
  }

  //
  if (this.isUpdateExpression()) {
    let operator = node.operator;
    if (operator === "++" || operator === "--") {
      return t.numberTypeAnnotation();
    }
  }

  //
  if (this.isLiteral()) {
    var value = node.value;
    if (typeof value === "string") return t.stringTypeAnnotation();
    if (typeof value === "number") return t.numberTypeAnnotation();
    if (typeof value === "boolean") return t.booleanTypeAnnotation();
    if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
  }

  //
  var callPath;
  if (this.isCallExpression()) callPath = this.get("callee");
  if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
  if (callPath) {
    var callee = callPath.resolve();
    // todo: read typescript/flow interfaces

    if (callee.isFunction()) {
      if (callee.is("async")) {
        if (callee.is("generator")) {
          return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
        } else {
          return t.genericTypeAnnotation(t.identifier("Promise"));
        }
      } else {
        if (callee.node.returnType) {
          return callee.node.returnType;
        } else {
          // todo: get union type of all return arguments
        }
      }
    }
  }
}

/**
 * Description
 */

export function isGenericType(genericName: string): boolean {
  var type = this.getTypeAnnotation();

  if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
    return true;
  }

  if (genericName === "String") {
    return t.isStringTypeAnnotation(type);
  } else if (genericName === "Number") {
    return t.isNumberTypeAnnotation(type);
  } else if (genericName === "Boolean") {
    return t.isBooleanTypeAnnotation(type);
  }

  return false;
}
<|endoftext|>


<commit_before>define(function (require, exports, module) {
    "use strict";

    Algo.authBitLength = 16;
    Algo.offerBitLength = 128;
    Algo.dhPrivBitLength = 160;

    var tools = require("../tools");
    var SHA1 = require("../cryptography/sha1-crypto-js");
    var DiffieHellman = require("../cryptography/diffie-hellman-leemon");
    var Hex = require("../multivalue/hex");
    var BitArray = require("../multivalue/bitArray");
    var Bytes = require("../multivalue/bytes");
    var Aes = require("../cryptography/aes-sjcl");

    var eventEmitter = require("../events/eventEmitter");
    var invariant = require("../invariant");
    var Multivalue = require("../multivalue/multivalue");

    var serializable = require("../serialization/serializable");

    var extend = tools.extend;
    var isFunction = tools.isFunction;

    function hash(value) {
        return SHA1(value).as(BitArray).bitSlice(0, 128);
    }

// __________________________________________________________________________ //

    function Algo(random) {
        this.random = random;

        this._dhAesKey = null;
        this.dhk = null;
        this.dh = null;
        this.auth = null;
        this.check = null;
        this.authData = null;
    }

    Algo.prototype._getRandomBytes = function (bitLength) {
        invariant(isFunction(this.random.bitArray), "random must implement IRandom");
        return this.random.bitArray(bitLength);
    }

    Algo.prototype._encrypt = function (bytes, customKey) {
        var iv = this._getRandomBytes(128);
        var aes = new Aes(customKey || this._dhAesKey);
        var encryptedData = aes.encryptCbc(bytes, iv);
        return iv.as(Bytes).concat(encryptedData);
    }

    Algo.prototype._decrypt = function (bytes, customKey) {
        var dataBitArray = bytes.as(BitArray);
        var iv = dataBitArray.bitSlice(0, 128);
        var encryptedData = dataBitArray.bitSlice(128, dataBitArray.bitLength());
        var aes = new Aes(customKey || this._dhAesKey);
        return aes.decryptCbc(encryptedData, iv);
    }

    // Alice 1.1 (instantiation)
    Algo.prototype._generateOffer = function () {
        this.dh = DiffieHellman.generate(Algo.dhPrivBitLength, this.random);
        var dhAes = this._getRandomBytes(Algo.offerBitLength);
        this._dhAesKey = dhAes;
        var outId = dhAes.bitSlice(0, 16);
        var inId = dhAes.bitSlice(16, 32);
        return {inId: inId, outId: outId};
    }

    // Bob 2.1 (instantiation) offer is from getOffer (via IM)
    Algo.prototype._acceptOffer = function (offer) {
        this.dh = DiffieHellman.generate(Algo.dhPrivBitLength, this.random);
        var dhAes = offer.as(Hex).as(BitArray);
        this._dhAesKey = dhAes;
        var inId = dhAes.bitSlice(0, 16);
        var outId = dhAes.bitSlice(16, 32);
        return {inId: inId, outId: outId};
    }

    Algo.prototype._getOfferData = function () {
        var dhData = new Hex(this.dh.createKeyExchange());
        return this._encrypt(dhData);
    }

    // Bob 2.2.
    Algo.prototype._acceptOfferData = function (bytes) {
        var dhData;
        try {
            dhData = this._decrypt(bytes);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            return;
        }
        var dhDataHex = dhData.as(Hex).value;
        var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
        this.dhk = new Hex(dhkHex);
    }

    Algo.prototype._getOfferResponse = function () {
        var dhData = new Hex(this.dh.createKeyExchange());
        return this._encrypt(dhData);
    }

    // Alice 3.1
    Algo.prototype._acceptOfferResponse = function (data) {
        var dhDataHex;
        try {
            dhDataHex = this._decrypt(data).as(Hex).value;
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            return;
        }
        var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
        this.dhk = new Hex(dhkHex);

        this.auth = this._getRandomBytes(Tlke.authBitLength);
        this.check = this._getRandomBytes(128);
    }

    Algo.prototype._getAuthData = function () {
        return this._encrypt(this.check, this._getVerifiedDhk());
    }

    Algo.prototype._getVerifiedDhk = function () {
        var dhk = this.dhk.as(Bytes);
        var auth = this.auth.as(Bytes);
        return hash(dhk.concat(auth));
    }

    // Bob 4.2
    Algo.prototype._acceptAuthData = function (bytes) {
        this.authData = bytes;
    }

    // Bob 4.1
    Algo.prototype._acceptAuth = function (auth) {
        this.auth = auth;
    }

    Algo.prototype.hasAuth = function () {
        return !!this.auth;
    }

    Algo.prototype.hasAuthData = function () {
        return !!this.authData;
    }

    // Bob 4.3 (4.1 + 4.2)
    Algo.prototype._acceptAuthAndData = function () {
        var bytes = this.authData;
        // todo check's checksum and ACHTUNG if not match
        var verified = this._getVerifiedDhk();
        try {
            this.check = this._decrypt(bytes, verified);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            return;
        }
        return {
            inId: hCheck.bitSlice(0, 16),
            outId: hCheck.bitSlice(16, 32),
            key: hash(this.check.as(Bytes).concat(verified))
        };
    }

    Algo.prototype._getAuthResponse = function () {
        var hCheck = hash(this.check);
        return this._encrypt(hCheck, this._getVerifiedDhk());
    }

    // Alice 5
    Algo.prototype._acceptAuthResponse = function (bytes) {
        var verified = this._getVerifiedDhk(), hCheck;
        try {
            hCheck = this._decrypt(bytes, verified);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            return;
        }
        if (hash(this.check).as(Hex).value !== hCheck.as(Hex).value) {
            return;
        }
        return {
            inId: hCheck.bitSlice(16, 32),
            outId: hCheck.bitSlice(0, 16),
            key: hash(this.check.as(Bytes).concat(verified))
        };
    }

    Algo.prototype.deserialize = function (data) {
        this._dhAesKey = data.dhAesKey ? Hex.deserialize(data.dhAesKey) : null;
        this.dhk = data.dhk ? Hex.deserialize(data.dhk) : null;
        this.dh = data.dh ? DiffieHellman.deserialize(data.dh) : null;
        this.auth = data.auth ? Hex.deserialize(data.auth) : null;
        this.check = data.check ? Hex.deserialize(data.check) : null;
        this.authData = data.authData ? Hex.deserialize(data.authData) : null;
    },

    Algo.prototype.serialize = function (packet, context) {
        return {
            state: this.state,
            dhAesKey: this._dhAesKey ? this._dhAesKey.as(Hex).serialize() : null,
            dhk: this.dhk ? this.dhk.as(Hex).serialize() : null,
            dh: this.dh ? this.dh.serialize() : null,
            auth: this.auth ? this.auth.as(Hex).serialize() : null,
            check: this.check ? this.check.as(Hex).serialize() : null,
            authData: this.authData ? this.authData.as(Hex).serialize() : null
        };
    }

// __________________________________________________________________________ //

    // tl channel that is used during key exchange (while channel is being set up)
    function Tlke(factory) {
        invariant(factory, "Can be constructed only with factory");
        invariant(isFunction(factory.createRandom), "factory must have createRandom() method");

        this._defineEvent("changed");
        this._defineEvent("offer");
        this._defineEvent("auth");
        this._defineEvent("addr");
        this._defineEvent("packet");
        this._defineEvent("keyReady");

        // use the rng without serialization (assume singleton)
        this.random = factory.createRandom();

        this._algo = new Algo(this.random);

        this.state = null;
    }

    extend(Tlke.prototype, eventEmitter, serializable, {
        init: function () {
            this.state = Tlke.STATE_NOT_STARTED;
        },
        generate: function () {
            this.checkEventHandlers();
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't generate offer being in a state %s", this.state);
            this._generateOffer();
        },
        enterOffer: function (offer) {
            this.checkEventHandlers();
            invariant(offer instanceof Multivalue, "offer must be multivalue");
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't accept offer being in a state %s", this.state);
            invariant(offer, "Received an empty offer");
            this._acceptOffer(offer);
        },
        enterAuth: function (auth) {
            invariant(auth instanceof Multivalue, "offer must be multivalue");
            invariant(auth, "Received an empty auth");
            this._acceptAuth(auth);
        },

        processPacket: function (bytes) {
            invariant(bytes instanceof Multivalue, "bytes must be multivalue");
            switch (this.state) {
            case Algo.STATE_AWAITING_OFFER_RESPONSE:
                this._acceptOfferResponse(bytes);
                break;
            case Algo.STATE_AWAITING_AUTH_RESPONSE:
                this._acceptAuthResponse(bytes);
                break;
            case Algo.STATE_AWAITING_OFFERDATA:
                this._acceptOfferData(bytes);
                break;
            case Algo.STATE_AWAITING_AUTH:
            case Algo.STATE_AWAITING_AUTHDATA:
                this._acceptAuthData(bytes);
                break;
            default:
                console.warn("packet ignored: not the right state");
                break;
            }
            this._onChanged();
        },

        // Alice 1.1 (instantiation)
        _generateOffer: function () {
            var ids = this._algo._generateOffer();
            // emit this event before any "packet" event call to configure the appropriate transport behavior
            this.fire("addr", ids);
            this.fire("offer", this._algo._dhAesKey);
            this.state = Tlke.STATE_AWAITING_OFFER_RESPONSE;
            this.fire("packet", this._algo._getOfferData());
            this._onChanged();
        },

        // Bob 2.1 (instantiation) offer is from getOffer (via IM)
        _acceptOffer: function (offer) {
            var ids = this._algo._acceptOffer(offer);
            this.state = Tlke.STATE_AWAITING_OFFERDATA;
            this.fire("addr", ids);
            this._onChanged();
        },

        // Bob 2.2.
        _acceptOfferData: function (bytes) {
            this._algo._acceptOfferData(bytes);
            this.state = Tlke.STATE_AWAITING_AUTH;
            this.fire("packet", this._algo._getOfferResponse());
            this.fire("auth", null);
        },

        // Alice 3.1
        _acceptOfferResponse: function (data) {
            this._algo._acceptOfferResponse(data);
            this.state = Tlke.STATE_AWAITING_AUTH_RESPONSE;
            this.fire("packet", this._algo._getAuthData());
            this.fire("auth", this.auth);
        },

        // Bob 4.2
        _acceptAuthData: function (bytes) {
            this._algo._acceptAuthData(bytes);
            if (this._algo.hasAuth()) {
                this._acceptAuthAndData();
            } else {
                this.state = Tlke.STATE_AWAITING_AUTH;
            }
        },

        // Bob 4.1
        _acceptAuth: function (auth) {
            this._algo._acceptAuth(auth)
            if (this._algo.hasAuthData()) {
                this._acceptAuthAndData();
            } else {
                this.state = Tlke.STATE_AWAITING_AUTHDATA;
            }
            this._onChanged();
        },

        // Bob 4.3 (4.1 + 4.2)
        _acceptAuthAndData: function () {
            var keyAndCids = this._algo._acceptAuthAndData();
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this.fire("packet", this._getAuthResponse());
            this.fire("keyReady", keyAndCids);
            this._onChanged();
        },

        // Alice 5
        _acceptAuthResponse: function (bytes) {
            var keyAndCids = this._algo._acceptAuthResponse();

            if (!keyAndCids) {
                this.state = Tlke.STATE_CONNECTION_FAILED;
                return;
            }
            this.state = Algo.STATE_CONNECTION_ESTABLISHED;

            this.fire("keyReady", keyAndCids);
        },

        _onChanged: function () {
            this.fire("changed", this);
        },

        deserialize: function (packet, context) {
            var dto = packet.getData();
            this.state = dto.state;
            this._algo.deserialize(dto);
        },

        serialize: function (packet, context) {
            var data = this._algo.serialize();
            data.state = this.state;
            packet.setData(data);
            return packet;
        }

    });

    // A. NOT_STARTED
    //    generate() -> packet + offer
    //    AWAITING_OFFER_RESPONSE
    //    _acceptOfferResponse() -> packet + auth
    //    AWAITING_AUTH_RESPONSE
    //    _acceptAuthResponse() -> keyReady | authError

    // B. NOT_STARTED
    //    acceptOffer(offer) -> packet
    //    AWAITING_OFFERDATA
    //    _acceptOfferData
    //    STATE_AWAITING_AUTHDATA   |
    //    _acceptAuthData           |--> packet + keyReady
    //    STATE_AWAITING_AUTH       |
    //    acceptAuth(auth)          |

    Tlke.STATE_NOT_STARTED = Algo.STATE_NOT_STARTED;
    Tlke.STATE_AWAITING_OFFERDATA = Algo.STATE_AWAITING_OFFERDATA;
    Tlke.STATE_AWAITING_OFFER_RESPONSE = Algo.STATE_AWAITING_OFFER_RESPONSE;
    Tlke.STATE_AWAITING_AUTH = Algo.STATE_AWAITING_AUTH;
    Tlke.STATE_AWAITING_AUTHDATA = Algo.STATE_AWAITING_AUTHDATA;
    Tlke.STATE_AWAITING_AUTH_RESPONSE = Algo.STATE_AWAITING_AUTH_RESPONSE;
    Tlke.STATE_CONNECTION_ESTABLISHED = Algo.STATE_CONNECTION_ESTABLISHED;
    Tlke.STATE_CONNECTION_SYNCED = Algo.STATE_CONNECTION_SYNCED;
    Tlke.STATE_CONNECTION_FAILED = Algo.STATE_CONNECTION_FAILED;

    module.exports = Tlke;
});<commit_msg>made Algo's fields private<commit_after>define(function (require, exports, module) {
    "use strict";

    Algo.authBitLength = 16;
    Algo.offerBitLength = 128;
    Algo.dhPrivBitLength = 160;

    var tools = require("../tools");
    var SHA1 = require("../cryptography/sha1-crypto-js");
    var DiffieHellman = require("../cryptography/diffie-hellman-leemon");
    var Hex = require("../multivalue/hex");
    var BitArray = require("../multivalue/bitArray");
    var Bytes = require("../multivalue/bytes");
    var Aes = require("../cryptography/aes-sjcl");

    var eventEmitter = require("../events/eventEmitter");
    var invariant = require("../invariant");
    var Multivalue = require("../multivalue/multivalue");

    var serializable = require("../serialization/serializable");

    var extend = tools.extend;
    var isFunction = tools.isFunction;

    function hash(value) {
        return SHA1(value).as(BitArray).bitSlice(0, 128);
    }

// __________________________________________________________________________ //

    function Algo(random) {
        this._random = random;

        this._dhAesKey = null;
        this._dhk = null;
        this._dh = null;
        this._auth = null;
        this._check = null;
        this._authData = null;
    }

    Algo.prototype._getRandomBytes = function (bitLength) {
        invariant(isFunction(this._random.bitArray), "random must implement IRandom");
        return this._random.bitArray(bitLength);
    }

    Algo.prototype._encrypt = function (bytes, customKey) {
        var iv = this._getRandomBytes(128);
        var aes = new Aes(customKey || this._dhAesKey);
        var encryptedData = aes.encryptCbc(bytes, iv);
        return iv.as(Bytes).concat(encryptedData);
    }

    Algo.prototype._decrypt = function (bytes, customKey) {
        var dataBitArray = bytes.as(BitArray);
        var iv = dataBitArray.bitSlice(0, 128);
        var encryptedData = dataBitArray.bitSlice(128, dataBitArray.bitLength());
        var aes = new Aes(customKey || this._dhAesKey);
        return aes.decryptCbc(encryptedData, iv);
    }

    // Alice 1.1 (instantiation)
    Algo.prototype._generateOffer = function () {
        this._dh = DiffieHellman.generate(Algo.dhPrivBitLength, this._random);
        var dhAes = this._getRandomBytes(Algo.offerBitLength);
        this._dhAesKey = dhAes;
        var outId = dhAes.bitSlice(0, 16);
        var inId = dhAes.bitSlice(16, 32);
        return {inId: inId, outId: outId};
    }

    // Bob 2.1 (instantiation) offer is from getOffer (via IM)
    Algo.prototype._acceptOffer = function (offer) {
        this._dh = DiffieHellman.generate(Algo.dhPrivBitLength, this._random);
        var dhAes = offer.as(Hex).as(BitArray);
        this._dhAesKey = dhAes;
        var inId = dhAes.bitSlice(0, 16);
        var outId = dhAes.bitSlice(16, 32);
        return {inId: inId, outId: outId};
    }

    Algo.prototype._getOfferData = function () {
        var dhData = new Hex(this._dh.createKeyExchange());
        return this._encrypt(dhData);
    }

    // Bob 2.2.
    Algo.prototype._acceptOfferData = function (bytes) {
        var dhData;
        try {
            dhData = this._decrypt(bytes);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            //todo
            return;
        }
        var dhDataHex = dhData.as(Hex).value;
        var dhkHex = this._dh.decryptKeyExchange(dhDataHex);
        this._dhk = new Hex(dhkHex);
    }

    Algo.prototype._getOfferResponse = function () {
        var dhData = new Hex(this._dh.createKeyExchange());
        return this._encrypt(dhData);
    }

    // Alice 3.1
    Algo.prototype._acceptOfferResponse = function (data) {
        var dhDataHex;
        try {
            dhDataHex = this._decrypt(data).as(Hex).value;
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            //todo
            return;
        }
        var dhkHex = this._dh.decryptKeyExchange(dhDataHex);
        this._dhk = new Hex(dhkHex);

        this._auth = this._getRandomBytes(Tlke.authBitLength);
        this._check = this._getRandomBytes(128);
        return this._auth;
    }

    Algo.prototype._getAuthData = function () {
        return this._encrypt(this._check, this._getVerifiedDhk());
    }

    Algo.prototype._getVerifiedDhk = function () {
        var dhk = this._dhk.as(Bytes);
        var auth = this._auth.as(Bytes);
        return hash(dhk.concat(auth));
    }

    // Bob 4.2
    Algo.prototype._acceptAuthData = function (bytes) {
        this._authData = bytes;
    }

    // Bob 4.1
    Algo.prototype._acceptAuth = function (auth) {
        this._auth = auth;
    }

    Algo.prototype.hasAuth = function () {
        return !!this._auth;
    }

    Algo.prototype.hasAuthData = function () {
        return !!this._authData;
    }

    // Bob 4.3 (4.1 + 4.2)
    Algo.prototype._acceptAuthAndData = function () {
        var bytes = this._authData;
        // todo check's checksum and ACHTUNG if not match
        var verified = this._getVerifiedDhk();
        try {
            this._check = this._decrypt(bytes, verified);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            //todo
            return;
        }
        return {
            inId: hCheck.bitSlice(0, 16),
            outId: hCheck.bitSlice(16, 32),
            key: hash(this._check.as(Bytes).concat(verified))
        };
    }

    Algo.prototype._getAuthResponse = function () {
        var hCheck = hash(this._check);
        return this._encrypt(hCheck, this._getVerifiedDhk());
    }

    // Alice 5
    Algo.prototype._acceptAuthResponse = function (bytes) {
        var verified = this._getVerifiedDhk(), hCheck;
        try {
            hCheck = this._decrypt(bytes, verified);
        } catch (ex) {
            console.warn("Received bad bytes.  " + ex.message);
            //todo
            return;
        }
        if (hash(this._check).as(Hex).value !== hCheck.as(Hex).value) {
            return;
        }
        return {
            inId: hCheck.bitSlice(16, 32),
            outId: hCheck.bitSlice(0, 16),
            key: hash(this._check.as(Bytes).concat(verified))
        };
    }

    Algo.prototype.deserialize = function (data) {
        this._dhAesKey = data.dhAesKey ? Hex.deserialize(data.dhAesKey) : null;
        this._dhk = data.dhk ? Hex.deserialize(data.dhk) : null;
        this._dh = data.dh ? DiffieHellman.deserialize(data.dh) : null;
        this._auth = data.auth ? Hex.deserialize(data.auth) : null;
        this._check = data.check ? Hex.deserialize(data.check) : null;
        this._authData = data.authData ? Hex.deserialize(data.authData) : null;
    },

    Algo.prototype.serialize = function (packet, context) {
        return {
            state: this.state,
            dhAesKey: this._dhAesKey ? this._dhAesKey.as(Hex).serialize() : null,
            dhk: this._dhk ? this._dhk.as(Hex).serialize() : null,
            dh: this._dh ? this._dh.serialize() : null,
            auth: this._auth ? this._auth.as(Hex).serialize() : null,
            check: this._check ? this._check.as(Hex).serialize() : null,
            authData: this._authData ? this._authData.as(Hex).serialize() : null
        };
    }

// __________________________________________________________________________ //

    // tl channel that is used during key exchange (while channel is being set up)
    function Tlke(factory) {
        invariant(factory, "Can be constructed only with factory");
        invariant(isFunction(factory.createRandom), "factory must have createRandom() method");

        this._defineEvent("changed");
        this._defineEvent("offer");
        this._defineEvent("auth");
        this._defineEvent("addr");
        this._defineEvent("packet");
        this._defineEvent("keyReady");

        // use the rng without serialization (assume singleton)
        this.random = factory.createRandom();

        this._algo = new Algo(this.random);

        this.state = null;
    }

    extend(Tlke.prototype, eventEmitter, serializable, {
        init: function () {
            this.state = Tlke.STATE_NOT_STARTED;
        },
        generate: function () {
            this.checkEventHandlers();
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't generate offer being in a state %s", this.state);
            this._generateOffer();
        },
        enterOffer: function (offer) {
            this.checkEventHandlers();
            invariant(offer instanceof Multivalue, "offer must be multivalue");
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't accept offer being in a state %s", this.state);
            invariant(offer, "Received an empty offer");
            this._acceptOffer(offer);
        },
        enterAuth: function (auth) {
            invariant(auth instanceof Multivalue, "offer must be multivalue");
            invariant(auth, "Received an empty auth");
            this._acceptAuth(auth);
        },

        processPacket: function (bytes) {
            invariant(bytes instanceof Multivalue, "bytes must be multivalue");
            switch (this.state) {
            case Algo.STATE_AWAITING_OFFER_RESPONSE:
                this._acceptOfferResponse(bytes);
                break;
            case Algo.STATE_AWAITING_AUTH_RESPONSE:
                this._acceptAuthResponse(bytes);
                break;
            case Algo.STATE_AWAITING_OFFERDATA:
                this._acceptOfferData(bytes);
                break;
            case Algo.STATE_AWAITING_AUTH:
            case Algo.STATE_AWAITING_AUTHDATA:
                this._acceptAuthData(bytes);
                break;
            default:
                console.warn("packet ignored: not the right state");
                break;
            }
            this._onChanged();
        },

        // Alice 1.1 (instantiation)
        _generateOffer: function () {
            var ids = this._algo._generateOffer();
            // emit this event before any "packet" event call to configure the appropriate transport behavior
            this.fire("addr", ids);
            this.fire("offer", this._algo._dhAesKey);
            this.state = Tlke.STATE_AWAITING_OFFER_RESPONSE;
            this.fire("packet", this._algo._getOfferData());
            this._onChanged();
        },

        // Bob 2.1 (instantiation) offer is from getOffer (via IM)
        _acceptOffer: function (offer) {
            var ids = this._algo._acceptOffer(offer);
            this.state = Tlke.STATE_AWAITING_OFFERDATA;
            this.fire("addr", ids);
            this._onChanged();
        },

        // Bob 2.2.
        _acceptOfferData: function (bytes) {
            this._algo._acceptOfferData(bytes);
            this.state = Tlke.STATE_AWAITING_AUTH;
            this.fire("packet", this._algo._getOfferResponse());
            this.fire("auth", null);
        },

        // Alice 3.1
        _acceptOfferResponse: function (data) {
            var auth = this._algo._acceptOfferResponse(data);
            this.state = Tlke.STATE_AWAITING_AUTH_RESPONSE;
            this.fire("packet", this._algo._getAuthData());
            this.fire("auth", auth);
        },

        // Bob 4.2
        _acceptAuthData: function (bytes) {
            this._algo._acceptAuthData(bytes);
            if (this._algo.hasAuth()) {
                this._acceptAuthAndData();
            } else {
                this.state = Tlke.STATE_AWAITING_AUTH;
            }
        },

        // Bob 4.1
        _acceptAuth: function (auth) {
            this._algo._acceptAuth(auth)
            if (this._algo.hasAuthData()) {
                this._acceptAuthAndData();
            } else {
                this.state = Tlke.STATE_AWAITING_AUTHDATA;
            }
            this._onChanged();
        },

        // Bob 4.3 (4.1 + 4.2)
        _acceptAuthAndData: function () {
            var keyAndCids = this._algo._acceptAuthAndData();
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this.fire("packet", this._getAuthResponse());
            this.fire("keyReady", keyAndCids);
            this._onChanged();
        },

        // Alice 5
        _acceptAuthResponse: function (bytes) {
            var keyAndCids = this._algo._acceptAuthResponse();

            if (!keyAndCids) {
                this.state = Tlke.STATE_CONNECTION_FAILED;
                return;
            }
            this.state = Algo.STATE_CONNECTION_ESTABLISHED;

            this.fire("keyReady", keyAndCids);
        },

        _onChanged: function () {
            this.fire("changed", this);
        },

        deserialize: function (packet, context) {
            var dto = packet.getData();
            this.state = dto.state;
            this._algo.deserialize(dto);
        },

        serialize: function (packet, context) {
            var data = this._algo.serialize();
            data.state = this.state;
            packet.setData(data);
            return packet;
        }

    });

    // A. NOT_STARTED
    //    generate() -> packet + offer
    //    AWAITING_OFFER_RESPONSE
    //    _acceptOfferResponse() -> packet + auth
    //    AWAITING_AUTH_RESPONSE
    //    _acceptAuthResponse() -> keyReady | authError

    // B. NOT_STARTED
    //    acceptOffer(offer) -> packet
    //    AWAITING_OFFERDATA
    //    _acceptOfferData
    //    STATE_AWAITING_AUTHDATA   |
    //    _acceptAuthData           |--> packet + keyReady
    //    STATE_AWAITING_AUTH       |
    //    acceptAuth(auth)          |

    Tlke.STATE_NOT_STARTED = Algo.STATE_NOT_STARTED;
    Tlke.STATE_AWAITING_OFFERDATA = Algo.STATE_AWAITING_OFFERDATA;
    Tlke.STATE_AWAITING_OFFER_RESPONSE = Algo.STATE_AWAITING_OFFER_RESPONSE;
    Tlke.STATE_AWAITING_AUTH = Algo.STATE_AWAITING_AUTH;
    Tlke.STATE_AWAITING_AUTHDATA = Algo.STATE_AWAITING_AUTHDATA;
    Tlke.STATE_AWAITING_AUTH_RESPONSE = Algo.STATE_AWAITING_AUTH_RESPONSE;
    Tlke.STATE_CONNECTION_ESTABLISHED = Algo.STATE_CONNECTION_ESTABLISHED;
    Tlke.STATE_CONNECTION_SYNCED = Algo.STATE_CONNECTION_SYNCED;
    Tlke.STATE_CONNECTION_FAILED = Algo.STATE_CONNECTION_FAILED;

    module.exports = Tlke;
});<|endoftext|>


<commit_before>/*
Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

    http://aws.amazon.com/apache2.0/

or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

*/

// Define our dependencies
var express        = require('express');
var session        = require('express-session');
var passport       = require('passport');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var request        = require('request');
var handlebars     = require('handlebars');

// Define our constants, you will change these with your own
const TWITCH_CLIENT_ID = '<YOUR CLIENT ID HERE>';
const TWITCH_SECRET    = '<YOUR CLIENT SECRET HERE>';
const SESSION_SECRET   = '<SOME SECRET HERE>';
const CALLBACK_URL     = '<YOUR REDIRECT URL HERE>';  // You can run locally with - http://localhost:3000/auth/twitch/callback

// Initialize Express and middlewares
var app = express();
app.use(session({secret: SESSION_SECRET, resave: false, saveUninitialized: false}));
app.use(express.static('public'));
app.use(passport.initialize());
app.use(passport.session());

// Override passport profile function to get user profile from Twitch API
OAuth2Strategy.prototype.userProfile = function(accessToken, done) {
  var options = {
    url: 'https://api.twitch.tv/kraken/user',
    method: 'GET',
    headers: {
      'Client-ID': TWITCH_CLIENT_ID,
      'Accept': 'application/vnd.twitchtv.v5+json',
      'Authorization': 'OAuth ' + accessToken
    }
  };

  request(options, function (error, response, body) {
    if (response && response.statusCode == 200) {
      done(null, JSON.parse(body));
    } else {
      done(JSON.parse(body));
    }
  });
}

passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(user, done) {
    done(null, user);
});

passport.use('twitch', new OAuth2Strategy({
    authorizationURL: 'https://api.twitch.tv/kraken/oauth2/authorize',
    tokenURL: 'https://api.twitch.tv/kraken/oauth2/token',
    clientID: TWITCH_CLIENT_ID,
    clientSecret: TWITCH_SECRET,
    callbackURL: CALLBACK_URL,
    state: true
  },
  function(accessToken, refreshToken, profile, done) {
    profile.accessToken = accessToken;
    profile.refreshToken = refreshToken;

    // Securely store user profile in your DB
    //User.findOrCreate(..., function(err, user) {
    //  done(err, user);
    //});

    done(null, profile);
  }
));

// Set route to start OAuth link, this is where you define scopes to request
app.get('/auth/twitch', passport.authenticate('twitch', { scope: 'user_read' }));

// Set route for OAuth redirect
app.get('/auth/twitch/callback', passport.authenticate('twitch', { successRedirect: '/', failureRedirect: '/' }));

// Define a simple template to safely generate HTML with values from user's profile
var template = handlebars.compile(`
<title>My First Twitch App</title>

Access Token	{{accessToken}}

Refresh Token	{{refreshToken}}

Display Name	{{display_name}}

Bio	{{bio}}

Image	{{logo}}

`);

// If user has an authenticated session, display it, otherwise display link to authenticate
app.get('/', function (req, res) {
  if(req.session && req.session.passport && req.session.passport.user) {
    res.send(template(req.session.passport.user));
  } else {
    res.send('<title>My First Twitch App</title>');
  }
});

app.listen(3000, function () {
  console.log('Twitch auth sample listening on port 3000!')
});
<commit_msg>Chnaged Listening port<commit_after>/*
Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

    http://aws.amazon.com/apache2.0/

or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

*/

// Define our dependencies
var express        = require('express');
var session        = require('express-session');
var passport       = require('passport');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var request        = require('request');
var handlebars     = require('handlebars');

// Define our constants, you will change these with your own
const TWITCH_CLIENT_ID = '<YOUR CLIENT ID HERE>';
const TWITCH_SECRET    = '<YOUR CLIENT SECRET HERE>';
const SESSION_SECRET   = '<SOME SECRET HERE>';
const CALLBACK_URL     = '<YOUR REDIRECT URL HERE>';  // You can run locally with - http://localhost:3000/auth/twitch/callback

// Initialize Express and middlewares
var app = express();
app.use(session({secret: SESSION_SECRET, resave: false, saveUninitialized: false}));
app.use(express.static('public'));
app.use(passport.initialize());
app.use(passport.session());

// Override passport profile function to get user profile from Twitch API
OAuth2Strategy.prototype.userProfile = function(accessToken, done) {
  var options = {
    url: 'https://api.twitch.tv/kraken/user',
    method: 'GET',
    headers: {
      'Client-ID': TWITCH_CLIENT_ID,
      'Accept': 'application/vnd.twitchtv.v5+json',
      'Authorization': 'OAuth ' + accessToken
    }
  };

  request(options, function (error, response, body) {
    if (response && response.statusCode == 200) {
      done(null, JSON.parse(body));
    } else {
      done(JSON.parse(body));
    }
  });
}

passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(user, done) {
    done(null, user);
});

passport.use('twitch', new OAuth2Strategy({
    authorizationURL: 'https://api.twitch.tv/kraken/oauth2/authorize',
    tokenURL: 'https://api.twitch.tv/kraken/oauth2/token',
    clientID: TWITCH_CLIENT_ID,
    clientSecret: TWITCH_SECRET,
    callbackURL: CALLBACK_URL,
    state: true
  },
  function(accessToken, refreshToken, profile, done) {
    profile.accessToken = accessToken;
    profile.refreshToken = refreshToken;

    // Securely store user profile in your DB
    //User.findOrCreate(..., function(err, user) {
    //  done(err, user);
    //});

    done(null, profile);
  }
));

// Set route to start OAuth link, this is where you define scopes to request
app.get('/auth/twitch', passport.authenticate('twitch', { scope: 'user_read' }));

// Set route for OAuth redirect
app.get('/auth/twitch/callback', passport.authenticate('twitch', { successRedirect: '/', failureRedirect: '/' }));

// Define a simple template to safely generate HTML with values from user's profile
var template = handlebars.compile(`
<title>My First Twitch App</title>

Access Token	{{accessToken}}

Refresh Token	{{refreshToken}}

Display Name	{{display_name}}

Bio	{{bio}}

Image	{{logo}}

`);

// If user has an authenticated session, display it, otherwise display link to authenticate
app.get('/', function (req, res) {
  if(req.session && req.session.passport && req.session.passport.user) {
    res.send(template(req.session.passport.user));
  } else {
    res.send('<title>My First Twitch App</title>');
  }
});

app.listen(1080, function () {
  console.log('Twitch auth sample listening on port 3000!')
});
<|endoftext|>


<commit_before>const
	bodyParser = require('body-parser');
    fs = require('fs'),
    path = require('path'),
    spawn = require('child_process').spawn,
    express = require('express'),
    pod = require('../lib/api'),
    ghURL = require('parse-github-url'),
    app = express(),
   // favicon = require('serve-favicon'),
    statics = require('serve-static'),
    basicAuth = require('basic-auth');

// late def, wait until pod is ready
var conf = pod.reloadConfig()

// middlewares
var reloadConf = function (req, res, next) {
    conf = pod.reloadConfig()
    next()
}
var auth = function(username, password) {
	return function(req, res, next) {
		var user = basicAuth(req);
		if (!user || user.name !== username || user.pass !== password)
		{
			res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
			return res.send(401);
		}
		next();
	};
};
var aauth = ()=>{
	return auth((conf.web.username || 'admin'),(conf.web.password || 'admin'));
}

app.set('views', __dirname + '/views')
app.set('view engine', 'ejs')
//app.use(favicon())
app.use(reloadConf)
app.use(bodyParser.json())
app.use(statics(path.join(__dirname, 'static')))

app.get('/', aauth, function (req, res) {
    pod.listApps(function (err, list) {
        if (err) return res.end(err)
        res.render('index', {
            apps: list
        })
    })
})

app.get('/json', aauth, function (req, res) {
    pod.listApps(function (err, list) {
        if (err) return res.end(err)
        res.json(list)
    })
})

app.post('/hooks/:appid', function (req, res) {
    var appid = req.params.appid,
        payload = JSON.stringify(req.body),
        app = conf.apps[appid]

    try {
        payload = JSON.parse(payload)
    } catch (e) {
        return res.end(e.toString())
    }

    if (req.get('X-GitHub-Event') === 'ping') {
        if (ghURL(payload.repository.git_url).repopath === ghURL(app.remote).repopath) {
            return res.status(200).end()
        } else {
            return res.status(500).end()
        }
    }

    if (app && verify(req, app, payload)) {
        executeHook(appid, app, payload, function () {
            res.end()
        })
    } else {
        res.end()
    }
})

// listen when API is ready
pod.once('ready', function () {
    // load config first
    conf = pod.getConfig()
    // conditional open up jsonp based on config
    if (conf.web.jsonp === true) {
        app.get('/jsonp', function (req, res) {
            pod.listApps(function (err, list) {
                if (err) return res.end(err)
                res.jsonp(list)
            })
        })
    }
    app.listen(process.env.PORT || 19999)
})

// Helpers
function verify(req, app, payload) {
    // not even a remote app
    if (!app.remote) return
    // check repo match

    var repo = payload.repository
    var repoURL

    if (repo.links && /bitbucket\.org/.test(repo.links.html.href)) {
        console.log('\nreceived webhook request from: ' + repo.links.html.href)

        repoURL = repo.links.html.href
    } else {
        console.log('\nreceived webhook request from: ' + repo.url)

        repoURL = repo.url
    }

    if (!repoURL) return

    if (ghURL(repoURL).repopath !== ghURL(app.remote).repopath) {
        console.log('aborted.')
        return
    }

    var commit

    // support bitbucket webhooks payload structure
    if (/bitbucket\.org/.test(repoURL)) {
        commit = payload.push.changes[0].new

        commit.message = commit.target.message
    } else {
        // use gitlab's payload structure if detected
        commit = payload.head_commit ? payload.head_commit :
            payload.commits[payload.commits.length - 1];
    }

    if (!commit) return

    // skip it with [pod skip] message
    console.log('commit message: ' + commit.message)
    if (/\[pod skip\]/.test(commit.message)) {
        console.log('aborted.')
        return
    }
    // check branch match
    var ref = commit.name ? commit.name : payload.ref

    if (!ref) return

    var branch = ref.replace('refs/heads/', ''),
        expected = app.branch || 'master'
    console.log('expected branch: ' + expected + ', got branch: ' + branch)
    if (branch !== expected) {
        console.log('aborted.')
        return
    }
    return true
}

function executeHook(appid, app, payload, cb) {

    // set a response timeout to avoid GitHub webhooks
    // hanging up due to long build times
    var responded = false
    function respond(err) {
        if (!responded) {
            responded = true
            cb(err)
        }
    }
    setTimeout(respond, 3000)

    fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function (err, template) {
        if (err) return respond(err)
        var hookPath = conf.root + '/temphook.sh',
            hook = template
                .replace(/\{\{pod_dir\}\}/g, conf.root)
                .replace(/\{\{app\}\}/g, appid)
        if (app.branch) {
            hook = hook.replace('origin/master', 'origin/' + app.branch)
        }
        fs.writeFile(hookPath, hook, function (err) {
            if (err) return respond(err)
            fs.chmod(hookPath, '0777', function (err) {
                if (err) return respond(err)
                console.log('excuting github webhook for ' + appid + '...')
                var child = spawn('bash', [hookPath])
                child.stdout.pipe(process.stdout)
                child.stderr.pipe(process.stderr)
                child.on('exit', function (code) {
                    fs.unlink(hookPath, respond)
                })
            })
        })
    })
}

<commit_msg>fix basic auth<commit_after>const
    bodyParser = require('body-parser');
fs = require('fs'),
    path = require('path'),
    spawn = require('child_process').spawn,
    express = require('express'),
    pod = require('../lib/api'),
    ghURL = require('parse-github-url'),
    app = express(),
    // favicon = require('serve-favicon'),
    statics = require('serve-static'),
    basicAuth = require('basic-auth');

// late def, wait until pod is ready
var conf = pod.reloadConfig()

// middlewares
var reloadConf = function (req, res, next) {
    conf = pod.reloadConfig()
    next()
}
var auth = function (req, res, next) {
    var user = basicAuth(req);
    const username = (conf.web.username || 'admin');
    const password = (conf.web.password || 'admin');
    console.log(JSON.stringify(user))
    if (!user || user.name !== username || user.pass !== password) {
        res.setHeader('WWW-Authenticate', 'Basic realm=Authorization Required');
        return res.sendStatus(401);
    }
    next();
};

app.set('views', __dirname + '/views')
app.set('view engine', 'ejs')
//app.use(favicon())
app.use(reloadConf)
app.use(bodyParser.json())
app.use(statics(path.join(__dirname, 'static')))

app.get('/', auth, function (req, res) {
    pod.listApps(function (err, list) {
        if (err) return res.end(err)
        return res.render('index', {
            apps: list
        })
    })
})

app.get('/json', auth, function (req, res) {
    pod.listApps(function (err, list) {
        if (err) return res.end(err)
        res.json(list)
        res.end();
    })
})

app.post('/hooks/:appid', function (req, res) {
    var appid = req.params.appid,
        payload = JSON.stringify(req.body),
        app = conf.apps[appid]

    try {
        payload = JSON.parse(payload)
    } catch (e) {
        return res.end(e.toString())
    }

    if (req.get('X-GitHub-Event') === 'ping') {
        if (ghURL(payload.repository.git_url).repopath === ghURL(app.remote).repopath) {
            return res.status(200).end()
        } else {
            return res.status(500).end()
        }
    }

    if (app && verify(req, app, payload)) {
        executeHook(appid, app, payload, function () {
            res.end()
        })
    } else {
        res.end()
    }
})

// listen when API is ready
pod.once('ready', function () {
    // load config first
    conf = pod.getConfig()
    // conditional open up jsonp based on config
    if (conf.web.jsonp === true) {
        app.get('/jsonp', function (req, res) {
            pod.listApps(function (err, list) {
                if (err) return res.end(err)
                res.jsonp(list)
            })
        })
    }
    app.listen(process.env.PORT || 19999)
})

// Helpers
function verify(req, app, payload) {
    // not even a remote app
    if (!app.remote) return
    // check repo match

    var repo = payload.repository
    var repoURL

    if (repo.links && /bitbucket\.org/.test(repo.links.html.href)) {
        console.log('\nreceived webhook request from: ' + repo.links.html.href)

        repoURL = repo.links.html.href
    } else {
        console.log('\nreceived webhook request from: ' + repo.url)

        repoURL = repo.url
    }

    if (!repoURL) return

    if (ghURL(repoURL).repopath !== ghURL(app.remote).repopath) {
        console.log('aborted.')
        return
    }

    var commit

    // support bitbucket webhooks payload structure
    if (/bitbucket\.org/.test(repoURL)) {
        commit = payload.push.changes[0].new

        commit.message = commit.target.message
    } else {
        // use gitlab's payload structure if detected
        commit = payload.head_commit ? payload.head_commit :
            payload.commits[payload.commits.length - 1];
    }

    if (!commit) return

    // skip it with [pod skip] message
    console.log('commit message: ' + commit.message)
    if (/\[pod skip\]/.test(commit.message)) {
        console.log('aborted.')
        return
    }
    // check branch match
    var ref = commit.name ? commit.name : payload.ref

    if (!ref) return

    var branch = ref.replace('refs/heads/', ''),
        expected = app.branch || 'master'
    console.log('expected branch: ' + expected + ', got branch: ' + branch)
    if (branch !== expected) {
        console.log('aborted.')
        return
    }
    return true
}

function executeHook(appid, app, payload, cb) {

    // set a response timeout to avoid GitHub webhooks
    // hanging up due to long build times
    var responded = false
    function respond(err) {
        if (!responded) {
            responded = true
            cb(err)
        }
    }
    setTimeout(respond, 3000)

    fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function (err, template) {
        if (err) return respond(err)
        var hookPath = conf.root + '/temphook.sh',
            hook = template
                .replace(/\{\{pod_dir\}\}/g, conf.root)
                .replace(/\{\{app\}\}/g, appid)
        if (app.branch) {
            hook = hook.replace('origin/master', 'origin/' + app.branch)
        }
        fs.writeFile(hookPath, hook, function (err) {
            if (err) return respond(err)
            fs.chmod(hookPath, '0777', function (err) {
                if (err) return respond(err)
                console.log('excuting github webhook for ' + appid + '...')
                var child = spawn('bash', [hookPath])
                child.stdout.pipe(process.stdout)
                child.stderr.pipe(process.stderr)
                child.on('exit', function (code) {
                    fs.unlink(hookPath, respond)
                })
            })
        })
    })
}

<|endoftext|>