<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, vars: true, white: true, plusplus: true */
/*global require, window, exports, Backbone, $, arangoHelper, templateEngine */
(function() {
  "use strict";
  window.collectionView = Backbone.View.extend({
    el: '#modalPlaceholder',
    initialize: function () {
    },

    template: templateEngine.createTemplate("collectionView.ejs"),

    render: function() {
      var self = this;
      $(this.el).html(this.template.text);
      $('#change-collection').modal('show');
      $('#change-collection').on('hidden', function () {
      });
      $('#change-collection').on('shown', function () {
        $('#change-collection-name').focus();
      });
      this.fillModal();

      $('.modalTooltips, .glyphicon-info-sign').tooltip({
        placement: "left"
      });

      return this;
    },
    events: {
      "click #save-modified-collection"       :    "saveModifiedCollection",
      "hidden #change-collection"             :    "hidden",
      "click #delete-modified-collection"     :    "deleteCollection",
      "click #load-modified-collection"       :    "loadCollection",
      "click #unload-modified-collection"     :    "unloadCollection",
      "click #confirmDeleteCollection"        :    "confirmDeleteCollection",
      "click #abortDeleteCollection"          :    "abortDeleteCollection",
      "keydown #change-collection-name"       :    "listenKey",
      "keydown #change-collection-size"       :    "listenKey"
    },
    listenKey: function(e) {
      if (e.keyCode === 13) {
        this.saveModifiedCollection();
      }
    },
    hidden: function () {
      window.App.navigate("#collections", {trigger: true});
    },
    fillModal: function() {
      try {
        this.myCollection = window.arangoCollectionsStore.get(this.options.colId).attributes;
      }
      catch (e) {
        // in case the collection cannot be found or something is not present (e.g. after a reload)
        window.App.navigate("#");
        return;
      }

      $('#change-collection-name').val(this.myCollection.name);
      $('#change-collection-id').text(this.myCollection.id);
      $('#change-collection-type').text(this.myCollection.type);
      $('#change-collection-status').text(this.myCollection.status);

      if (this.myCollection.status === 'unloaded') {
        $('#colFooter').prepend(
          '<button id="load-modified-collection" class="btn btn-notification">Load</button>'
        );
        $('#collectionSizeBox').hide();
        $('#collectionSyncBox').hide();
        $('#tab-content-collection-edit tab-pane').css("border-top",0);
      }
      else if (this.myCollection.status === 'loaded') {
        $('#colFooter').prepend(
          '<button id="unload-modified-collection"'+
          'class="btn btn-notification">Unload</button>'
        );
        var data = window.arangoCollectionsStore.getProperties(this.options.colId, true);
        this.fillLoadedModal(data);
      }
    },

    fillLoadedModal: function (data) {

      //show tabs & render figures tab-view
      $('#change-collection .nav-tabs').css("visibility","visible");

      $('#collectionSizeBox').show();
      $('#collectionSyncBox').show();
      if (data.waitForSync === false) {
        $('#change-collection-sync').val('false');
      }
      else {
        $('#change-collection-sync').val('true');
      }
      var calculatedSize = data.journalSize / 1024 / 1024;
      $('#change-collection-size').val(calculatedSize);
      $('#change-collection').modal('show');
    },
    saveModifiedCollection: function() {
      var newname = $('#change-collection-name').val();
      if (newname === '') {
        arangoHelper.arangoError('No collection name entered!');
        return 0;
      }

      var collid = this.getCollectionId();
      var status = this.getCollectionStatus();

      if (status === 'loaded') {
        var result;
        if (this.myCollection.name !== newname) {
          result = window.arangoCollectionsStore.renameCollection(collid, newname);
        }

        var wfs = $('#change-collection-sync').val();
        var journalSize;
        try {
          journalSize = JSON.parse($('#change-collection-size').val() * 1024 * 1024);
        }
        catch (e) {
          arangoHelper.arangoError('Please enter a valid number');
          return 0;
        }
        var changeResult = window.arangoCollectionsStore.changeCollection(collid, wfs, journalSize);

        if (result === true) {
          arangoHelper.arangoNotification("Collection renamed");
        }

        if (result !== true) {
          if (result !== undefined) {
            arangoHelper.arangoError("Collection error: " + result);
            return 0;
          }
        }

        if (changeResult !== true) {
          arangoHelper.arangoNotification("Collection error: " + changeResult);
          return 0;
        }

        if (changeResult === true) {
          arangoHelper.arangoNotification("Saved collection properties");
            window.arangoCollectionsStore.fetch({
              success: function () {
                window.collectionsView.render();
              }
            });
            this.hideModal();
        }
      }
      else if (status === 'unloaded') {
        if (this.myCollection.name !== newname) {
          var result2 = window.arangoCollectionsStore.renameCollection(collid, newname);
          if (result2 === true) {

            window.arangoCollectionsStore.fetch({
              success: function () {
                window.collectionsView.render();
              }
            });
            this.hideModal();
            arangoHelper.arangoNotification("Collection renamed");
          }
          else {
            arangoHelper.arangoError("Collection error: " + result2);
          }
        }
        else {
          //arangoHelper.arangoNotification("No changes.");
          this.hideModal();
        }
      }
    },
    getCollectionId: function () {
      return this.myCollection.id;
    },
    getCollectionStatus: function () {
      return this.myCollection.status;
    },
    unloadCollection: function () {
      var collid = this.getCollectionId();
      window.arangoCollectionsStore.unloadCollection(collid);
      this.hideModal();
    },
    loadCollection: function () {
      var collid = this.getCollectionId();
      window.arangoCollectionsStore.loadCollection(collid);
      this.hideModal();
    },
    hideModal: function () {
      $('#change-collection').modal('hide');
    },
    deleteCollection: function () {
      $('#reallyDeleteColDiv').show();
    },
    abortDeleteCollection: function() {
      $('#reallyDeleteColDiv').hide();
    },
    confirmDeleteCollection: function () {
      var self = this;
      var collName = self.myCollection.name;
      var returnval = window.arangoCollectionsStore.deleteCollection(collName);
      if (returnval === true) {
        arangoHelper.arangoNotification('Collection deleted successfully.');
      }
      else {
        arangoHelper.arangoError('Could not delete collection.');
      }
      self.hideModal();
    }

  });
}());
<commit_msg>Fixed jslint warning for sync, (we are nt syncing but JSLint matches sync in parameternames<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, vars: true, white: true, plusplus: true, stupid: true */
/*global require, window, exports, Backbone, $, arangoHelper, templateEngine */
(function() {
  "use strict";
  window.collectionView = Backbone.View.extend({
    el: '#modalPlaceholder',
    initialize: function () {
    },

    template: templateEngine.createTemplate("collectionView.ejs"),

    render: function() {
      var self = this;
      $(this.el).html(this.template.text);
      $('#change-collection').modal('show');
      $('#change-collection').on('hidden', function () {
      });
      $('#change-collection').on('shown', function () {
        $('#change-collection-name').focus();
      });
      this.fillModal();

      $('.modalTooltips, .glyphicon-info-sign').tooltip({
        placement: "left"
      });

      return this;
    },
    events: {
      "click #save-modified-collection"       :    "saveModifiedCollection",
      "hidden #change-collection"             :    "hidden",
      "click #delete-modified-collection"     :    "deleteCollection",
      "click #load-modified-collection"       :    "loadCollection",
      "click #unload-modified-collection"     :    "unloadCollection",
      "click #confirmDeleteCollection"        :    "confirmDeleteCollection",
      "click #abortDeleteCollection"          :    "abortDeleteCollection",
      "keydown #change-collection-name"       :    "listenKey",
      "keydown #change-collection-size"       :    "listenKey"
    },
    listenKey: function(e) {
      if (e.keyCode === 13) {
        this.saveModifiedCollection();
      }
    },
    hidden: function () {
      window.App.navigate("#collections", {trigger: true});
    },
    fillModal: function() {
      try {
        this.myCollection = window.arangoCollectionsStore.get(this.options.colId).attributes;
      }
      catch (e) {
        // in case the collection cannot be found or something is not present (e.g. after a reload)
        window.App.navigate("#");
        return;
      }

      $('#change-collection-name').val(this.myCollection.name);
      $('#change-collection-id').text(this.myCollection.id);
      $('#change-collection-type').text(this.myCollection.type);
      $('#change-collection-status').text(this.myCollection.status);

      if (this.myCollection.status === 'unloaded') {
        $('#colFooter').prepend(
          '<button id="load-modified-collection" class="btn btn-notification">Load</button>'
        );
        $('#collectionSizeBox').hide();
        $('#collectionSyncBox').hide();
        $('#tab-content-collection-edit tab-pane').css("border-top",0);
      }
      else if (this.myCollection.status === 'loaded') {
        $('#colFooter').prepend(
          '<button id="unload-modified-collection"'+
          'class="btn btn-notification">Unload</button>'
        );
        var data = window.arangoCollectionsStore.getProperties(this.options.colId, true);
        this.fillLoadedModal(data);
      }
    },

    fillLoadedModal: function (data) {

      //show tabs & render figures tab-view
      $('#change-collection .nav-tabs').css("visibility","visible");

      $('#collectionSizeBox').show();
      $('#collectionSyncBox').show();
      if (data.waitForSync === false) {
        $('#change-collection-sync').val('false');
      }
      else {
        $('#change-collection-sync').val('true');
      }
      var calculatedSize = data.journalSize / 1024 / 1024;
      $('#change-collection-size').val(calculatedSize);
      $('#change-collection').modal('show');
    },
    saveModifiedCollection: function() {
      var newname = $('#change-collection-name').val();
      if (newname === '') {
        arangoHelper.arangoError('No collection name entered!');
        return 0;
      }

      var collid = this.getCollectionId();
      var status = this.getCollectionStatus();

      if (status === 'loaded') {
        var result;
        if (this.myCollection.name !== newname) {
          result = window.arangoCollectionsStore.renameCollection(collid, newname);
        }

        var wfs = $('#change-collection-sync').val();
        var journalSize;
        try {
          journalSize = JSON.parse($('#change-collection-size').val() * 1024 * 1024);
        }
        catch (e) {
          arangoHelper.arangoError('Please enter a valid number');
          return 0;
        }
        var changeResult = window.arangoCollectionsStore.changeCollection(collid, wfs, journalSize);

        if (result === true) {
          arangoHelper.arangoNotification("Collection renamed");
        }

        if (result !== true) {
          if (result !== undefined) {
            arangoHelper.arangoError("Collection error: " + result);
            return 0;
          }
        }

        if (changeResult !== true) {
          arangoHelper.arangoNotification("Collection error: " + changeResult);
          return 0;
        }

        if (changeResult === true) {
          arangoHelper.arangoNotification("Saved collection properties");
            window.arangoCollectionsStore.fetch({
              success: function () {
                window.collectionsView.render();
              }
            });
            this.hideModal();
        }
      }
      else if (status === 'unloaded') {
        if (this.myCollection.name !== newname) {
          var result2 = window.arangoCollectionsStore.renameCollection(collid, newname);
          if (result2 === true) {

            window.arangoCollectionsStore.fetch({
              success: function () {
                window.collectionsView.render();
              }
            });
            this.hideModal();
            arangoHelper.arangoNotification("Collection renamed");
          }
          else {
            arangoHelper.arangoError("Collection error: " + result2);
          }
        }
        else {
          //arangoHelper.arangoNotification("No changes.");
          this.hideModal();
        }
      }
    },
    getCollectionId: function () {
      return this.myCollection.id;
    },
    getCollectionStatus: function () {
      return this.myCollection.status;
    },
    unloadCollection: function () {
      var collid = this.getCollectionId();
      window.arangoCollectionsStore.unloadCollection(collid);
      this.hideModal();
    },
    loadCollection: function () {
      var collid = this.getCollectionId();
      window.arangoCollectionsStore.loadCollection(collid);
      this.hideModal();
    },
    hideModal: function () {
      $('#change-collection').modal('hide');
    },
    deleteCollection: function () {
      $('#reallyDeleteColDiv').show();
    },
    abortDeleteCollection: function() {
      $('#reallyDeleteColDiv').hide();
    },
    confirmDeleteCollection: function () {
      var self = this;
      var collName = self.myCollection.name;
      var returnval = window.arangoCollectionsStore.deleteCollection(collName);
      if (returnval === true) {
        arangoHelper.arangoNotification('Collection deleted successfully.');
      }
      else {
        arangoHelper.arangoError('Could not delete collection.');
      }
      self.hideModal();
    }

  });
}());
<|endoftext|>


<commit_before>var Step     = require('step');
var xmpp     = require('node-xmpp');

var _campfire = require('../vendor/node-campfire/lib/campfire');
var Campfire  = _campfire.Campfire;
var Room      = _campfire.Room;

var ERROR_NS    = 'urn:ietf:params:xml:ns:xmpp-stanzas';
var MUC_NS      = 'http://jabber.org/protocol/muc';
var MUC_USER_NS = MUC_NS + '#user';

var TWITTER_STATUS_PREFIX = 'http://twitter.com/twitter/status/';

var XmppCampfireRoom = function(client, room_jid) {
  if (typeof(room_jid) === 'string') {
    room_jid = new xmpp.JID(room_jid);
  }

  this.client = client;
  this.jid = room_jid.bare();
  this.present = false;

  this.campfire = null;
  this.campfire_user = {};
  this.campfire_room = null;
  this.campfire_roster = [];
  this.campfire_users = {};

  // JID "buffer"
  this._jid = room_jid;
};

XmppCampfireRoom.prototype = {

  handle_stanza: function(stanza) {
    this.log('>>>', stanza.name);

    if (stanza.is('presence')) {
      if (stanza.attrs.type === 'unavailable') {
        if (this.present) {
          this.handle_exit(stanza);
        }
      } else {
        this.handle_enter(stanza);
      }
    } else if (!this.present) {
      this.send_stanza(
        null, this.build_xmpp_error(
          stanza, 'modify', 'not-acceptable', 'Not in room'));
    } else if (stanza.is('message') && stanza.attrs.type === 'groupchat') {
      this.handle_xmpp_message(stanza);
    } else if (!stanza.is('iq')) {
      this.log('unhandled stanza:', stanza.toString());
    }
  },

  handle_enter: function(stanza) {
    var self = this;
    var options = {ssl: true};
    var room_name;

    Step(
      function auth() {
        if (stanza.attrs.id && stanza.attrs.id === self._prev_id) {
          self.log('duplicate presence received');
          return;
        }
        self._prev_id = stanza.attrs.id;

        var i = self.jid.user.indexOf('+');
        if (i > -1) {
          options.account = self.jid.user.substr(0, i).trim();
          room_name = self.jid.user.substr(i + 1).trim();
        } else {
          throw 302;
        }

        var x = stanza.getChild('x', MUC_NS);
        options.token = x ? x.getChildText('password') : null;
        if (!options.token) {
          throw 401;
        }

        self.campfire = new Campfire(options);

        if (options.token.length != 40) {
          var username = stanza.attrs.to.split('/')[1];
          self.campfire.authorization = 'Basic ' + new Buffer(
            username + ':' + options.token).toString('base64');
        }

        self.campfire.me(this);
      },

      function get_rooms(err, response) {
        if (err) throw err;

        self.campfire_user = response.user;
        self.campfire_users[response.user.id] = response.user;

        // Reset token in case we used username/password
        if (response.user.api_auth_token) {
          options.token = response.user.api_auth_token;
          self.campfire = new Campfire(options);
        }

        self.campfire.rooms(this);
      },

      function find_room(err, rooms) {
        if (err) throw err;

        // .some() to emulate for loop with break
        var found_room = null;
        rooms.some(function(room) {
          if (room.id == room_name ||
              room.name.trim().toLowerCase() == room_name.toLowerCase()) {
            found_room = room;
            return true;
          }
          return false;
        });

        if (found_room) {
          self.campfire_room = found_room;
          self.campfire_room.join(this);
        } else {
          throw 302;
        }
      },

      function join_room(err, room) {
        if (err == 302) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'cancel', 'item-not-found', 'Room not found'));
          self.log('not found');
          return;
        } else if (err == 401) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'auth', 'not-authorized', 'Auth failed'));
          self.log('not authorized');
          return;
        } else if (err) {
          throw err;
        }

        self.present = true;

        self.refresh_room(this);
        // TODO parallelize next steps?
      },

      function finish_join(err) {
        if (err) throw err;

        // Send user self presence
        self.send_stanza(
          self.campfire_user.name, build_xmpp_presence(
            {status_codes: [110, 170, 210]}));

        self.campfire_room.messages(this);
      },

      function send_room_state(err, messages) {
        if (err) {
          self.log('messages', err);
        };

        if (messages) {
          // Filter types for history
          messages = messages.filter(function(msg) {
            return ['TextMessage', 'PasteMessage', 'TweetMessage',
                    'SystemMessage', 'TopicChangeMessage'
                   ].indexOf(msg.type) > -1;
          });

          // Obey (some) client history limits
          try {
            var history = stanza.getChild('x', MUC_NS).getChild('history');
          } catch (e) {}
          if (history && history.attrs.maxstanzas) {
            messages.splice(0, messages.length - history.attrs.maxstanzas);
          }

          // Send messages through normal handler
          messages.forEach(function(msg) {
            self.handle_campfire_message(msg, true);
          });
        }

        if (self.campfire_room.topic) {
          self.send_stanza(
            null, build_xmpp_message(
              self.campfire_room.topic, 'subject'));
        }

        self.campfire_start_listen();
      },

      function errors(err) {
        self.send_stanza(
          null, build_xmpp_error(
            stanza, 'wait', 'internal-server-error', err));
        self.log('join_error', err);
      }
    );
  },

  handle_exit: function(stanza, status_code) {
    this.campfire_stop_listen();

    if (this.present) {
      var self = this;
      this.campfire_room.leave(function() {
        self.send_stanza(
          self.campfire_user.name, build_xmpp_presence(
            {type: 'unavailable', status_codes: [status_code || 110]}));
      });
    }

    this.present = false;
  },

  handle_xmpp_message: function(stanza) {
    var body = stanza.getChildText('body');
    if (body) {
      var self = this;
      this.campfire_room.message(body, undefined, function(err) {
        if (err) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'wait', 'internal-server-error', err));
        }
      });
    }
    // TODO handle other messages (subject change)
  },

  refresh_room: function(callback) {
    var self = this;

    self.campfire.get(self.campfire_room.path, function(err, response) {
      if (!err) {
        try {
          // Build current roster
          var roster = response.room.users.map(function(user) {
            if (user.id != self.campfire_user.id) {
              self.send_stanza(
                user.name, build_xmpp_presence());
            }
            self.campfire_users[user.id] = user;
            return user.id;
          });

          // Send exit notifications
          self.campfire_roster.forEach(function(user_id) {
            if (roster.indexOf(user_id) < 0 && self.campfire_users[user_id]) {
              self.send_stanza(
                self.campfire_users[user_id].name, build_xmpp_presence(
                  {type: 'unavailable'}));
            }
          });

          self.campfire_roster = roster;

        } catch (e) {
          err = e;
        }
      }

      if (callback) {
        callback(err);
      } else if (err) {
        self.log('refresh_room:', err);
      }
    });
  },

  send_stanza: function(from_resource, stanza) {
    stanza = stanza.root();
    this._jid.setResource(from_resource);
    stanza.attrs.from = this._jid.toString();
    this.client.send_stanza(stanza);
    this.log('<<<', stanza.name);
  },

  campfire_start_listen: function() {
    this.campfire_stop_listen();

    if (this.present) {
      this._listen_req = this.campfire_room.listen(
        this.handle_campfire_message.bind(this));

      var self = this;
      this._listen_req.on('error', function(err) {
        self.log('listen', err);
        setTimeout(function() {
          self.campfire_start_listen();
        }, 1000);
      });
    }
  },

  campfire_stop_listen: function() {
    if (this._listen_req) {
      this._listen_req.abort();
    }
  },

  handle_campfire_message: function(msg, history) {
    var self = this;
    Step(
      function lookup_name() {
        if (msg.userId && self.campfire_users[msg.userId] === undefined) {
          self.campfire.user(msg.userId, this);
        } else {
          return null;
        }
      },

      function translate_message(err, response) {
        if (err == 404) {
          self.campfire_users[msg.userId] = null;
        } else if (err) {
          self.log('user', msg.userId, err);
        } else {
          // Cache user name if retrieved
          var _user = response && response.user;
          if (_user && _user.id) {
            self.campfire_users[_user.id] = _user;
          }
        }

        var user = self.campfire_users[msg.userId];

        var stanza = null;
        if (['TextMessage', 'PasteMessage', 'SystemMessage']
            .indexOf(msg.type) > -1) {
          stanza = build_xmpp_message(msg.body);

        } else if (msg.type === 'TweetMessage') {
          var body = msg.body;
          if (msg.tweet) {
            body = msg.tweet.message + ' -- @' + msg.tweet.author_username +
              ', ' + TWITTER_STATUS_PREFIX + msg.tweet.id;
          } else if (body.indexOf('---\n') === 0) {
            self.log('YAML tweet body without .tweet data');
          }
          stanza = build_xmpp_message(body);
        } else if (msg.type === 'TopicChangeMessage') {
          stanza = build_xmpp_message(msg.body, 'subject');

        } else if (msg.type === 'EnterMessage') {
          self.refresh_room();

        } else if (msg.type === 'LeaveMessage') {
          var i = self.campfire_roster.indexOf(msg.userId);
          if (i > -1 && user) {
            stanza = build_xmpp_presence({type: 'unavailable'});
          } else {
            self.refresh_room();
          }

        } else {
          self.log('unhandled campfire message', msg.type);
        }

        if (stanza) {
          if (history) {
            stanza.root()
              .c('delay', {xmlns: 'urn:xmpp:delay',
                           stamp: msg.createdAt.toISOString()});
          }

          self.send_stanza(
            user && user.name || 'User ' + msg.userId, stanza);
        }
      },

      function errors(err) {
        self.log('campfire_message error', err);
      }
    );
  },

  log: function() {
    Array.prototype.unshift.call(arguments, '-', this.jid.toString());
    this.client.log.apply(this.client, arguments);
  }
};

exports.XmppCampfireRoom = XmppCampfireRoom;

// XMPP Helpers

function build_xmpp_presence(options) {
  options = options || {};
  options.role = options.role || (
    options.type === 'unavailable' ? 'none' : 'participant');

  var stanza = new xmpp.Element('presence', {type: options.type})
        .c('x', {xmlns: MUC_USER_NS})
          .c('item', {role: options.role, affiliation: 'member'}).up();

  (options.status_codes || []).forEach(function(status_code) {
    stanza.c('status', {code: status_code});
  });

  return stanza;
}

function build_xmpp_message(body, body_type) {
  body_type = body_type || 'body';
  return new xmpp.Element('message', {type: 'groupchat'})
    .c(body_type)
      .t(body);
}

function build_xmpp_error(stanza, error_type, error, text) {
  if (typeof(stanza) === 'string') {
    stanza = {name: stanza, attrs: {}};
  }
  return new xmpp.Element(stanza.name, {type: 'error', id: stanza.attrs.id})
    .c('x', {xmlns: MUC_NS}).up()
    .c('error', {type: error_type})
      .c(error, {xmlns: ERROR_NS}).up()
      .c('text', {xmlns: ERROR_NS})
        .t(text);
}
<commit_msg>Handle <iq> stanzas better<commit_after>var Step     = require('step');
var xmpp     = require('node-xmpp');

var _campfire = require('../vendor/node-campfire/lib/campfire');
var Campfire  = _campfire.Campfire;
var Room      = _campfire.Room;

var ERROR_NS    = 'urn:ietf:params:xml:ns:xmpp-stanzas';
var MUC_NS      = 'http://jabber.org/protocol/muc';
var MUC_USER_NS = MUC_NS + '#user';

var TWITTER_STATUS_PREFIX = 'http://twitter.com/twitter/status/';

var XmppCampfireRoom = function(client, room_jid) {
  if (typeof(room_jid) === 'string') {
    room_jid = new xmpp.JID(room_jid);
  }

  this.client = client;
  this.jid = room_jid.bare();
  this.present = false;

  this.campfire = null;
  this.campfire_user = {};
  this.campfire_room = null;
  this.campfire_roster = [];
  this.campfire_users = {};

  // JID "buffer"
  this._jid = room_jid;
};

XmppCampfireRoom.prototype = {

  handle_stanza: function(stanza) {
    this.log('>>>', stanza.name);

    if (stanza.is('presence')) {
      if (stanza.attrs.type === 'unavailable') {
        if (this.present) {
          this.handle_exit(stanza);
        }
      } else {
        this.handle_enter(stanza);
      }
    } else if (!this.present) {
      this.send_stanza(
        null, this.build_xmpp_error(
          stanza, 'modify', 'not-acceptable', 'Not in room'));
    } else if (stanza.is('message') && stanza.attrs.type === 'groupchat') {
      this.handle_xmpp_message(stanza);
    } else if (stanza.is('iq')) {
      if (stanza.attrs.type === 'get' && stanza.getChild('vCard', 'vcard-temp')) {
        this.handle_xmpp_vcard(stanza);
      }
      this.send_stanza(
        stanza.attrs.from.split('/')[1], build_xmpp_error(
          stanza, 'cancel', 'service-unavailable'));
    } else {
      this.log('unhandled stanza:', stanza.toString());
    }
  },

  handle_enter: function(stanza) {
    var self = this;
    var options = {ssl: true};
    var room_name;

    Step(
      function auth() {
        if (stanza.attrs.id && stanza.attrs.id === self._prev_id) {
          self.log('duplicate presence received');
          return;
        }
        self._prev_id = stanza.attrs.id;

        var i = self.jid.user.indexOf('+');
        if (i > -1) {
          options.account = self.jid.user.substr(0, i).trim();
          room_name = self.jid.user.substr(i + 1).trim();
        } else {
          throw 302;
        }

        var x = stanza.getChild('x', MUC_NS);
        options.token = x ? x.getChildText('password') : null;
        if (!options.token) {
          throw 401;
        }

        self.campfire = new Campfire(options);

        if (options.token.length != 40) {
          var username = stanza.attrs.to.split('/')[1];
          self.campfire.authorization = 'Basic ' + new Buffer(
            username + ':' + options.token).toString('base64');
        }

        self.campfire.me(this);
      },

      function get_rooms(err, response) {
        if (err) throw err;

        self.campfire_user = response.user;
        self.campfire_users[response.user.id] = response.user;

        // Reset token in case we used username/password
        if (response.user.api_auth_token) {
          options.token = response.user.api_auth_token;
          self.campfire = new Campfire(options);
        }

        self.campfire.rooms(this);
      },

      function find_room(err, rooms) {
        if (err) throw err;

        // .some() to emulate for loop with break
        var found_room = null;
        rooms.some(function(room) {
          if (room.id == room_name ||
              room.name.trim().toLowerCase() == room_name.toLowerCase()) {
            found_room = room;
            return true;
          }
          return false;
        });

        if (found_room) {
          self.campfire_room = found_room;
          self.campfire_room.join(this);
        } else {
          throw 302;
        }
      },

      function join_room(err, room) {
        if (err == 302) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'cancel', 'item-not-found', 'Room not found'));
          self.log('not found');
          return;
        } else if (err == 401) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'auth', 'not-authorized', 'Auth failed'));
          self.log('not authorized');
          return;
        } else if (err) {
          throw err;
        }

        self.present = true;

        self.refresh_room(this);
        // TODO parallelize next steps?
      },

      function finish_join(err) {
        if (err) throw err;

        // Send user self presence
        self.send_stanza(
          self.campfire_user.name, build_xmpp_presence(
            {status_codes: [110, 170, 210]}));

        self.campfire_room.messages(this);
      },

      function send_room_state(err, messages) {
        if (err) {
          self.log('messages', err);
        };

        if (messages) {
          // Filter types for history
          messages = messages.filter(function(msg) {
            return ['TextMessage', 'PasteMessage', 'TweetMessage',
                    'SystemMessage', 'TopicChangeMessage'
                   ].indexOf(msg.type) > -1;
          });

          // Obey (some) client history limits
          try {
            var history = stanza.getChild('x', MUC_NS).getChild('history');
          } catch (e) {}
          if (history && history.attrs.maxstanzas) {
            messages.splice(0, messages.length - history.attrs.maxstanzas);
          }

          // Send messages through normal handler
          messages.forEach(function(msg) {
            self.handle_campfire_message(msg, true);
          });
        }

        if (self.campfire_room.topic) {
          self.send_stanza(
            null, build_xmpp_message(
              self.campfire_room.topic, 'subject'));
        }

        self.campfire_start_listen();
      },

      function errors(err) {
        self.send_stanza(
          null, build_xmpp_error(
            stanza, 'wait', 'internal-server-error', err));
        self.log('join_error', err);
      }
    );
  },

  handle_exit: function(stanza, status_code) {
    this.campfire_stop_listen();

    if (this.present) {
      var self = this;
      this.campfire_room.leave(function() {
        self.send_stanza(
          self.campfire_user.name, build_xmpp_presence(
            {type: 'unavailable', status_codes: [status_code || 110]}));
      });
    }

    this.present = false;
  },

  handle_xmpp_message: function(stanza) {
    var body = stanza.getChildText('body');
    if (body) {
      var self = this;
      this.campfire_room.message(body, undefined, function(err) {
        if (err) {
          self.send_stanza(
            null, build_xmpp_error(
              stanza, 'wait', 'internal-server-error', err));
        }
      });
    }
    // TODO handle other messages (subject change)
  },

  handle_xmpp_vcard: function(stanza) {
    var name = stanza.attrs.to.split('/')[1];
    for (var user_id in this.campfire_users) {
      var user = this.campfire_users[user_id];
      if (user && user.name === name) {
        var vcard = new xmpp.Element('iq', {type: 'result', id: stanza.attrs.id})
            .c('vCard', {xmlns: 'vcard-temp'})
              .c('FN').t(name).up();

        if (user.email_address) {
          vcard.c('EMAIL').c('USERID').t(user.email_address);
        }

        if (user.avatar_url) {
          vcard.c('PHOTO').c('EXTVAL').t(user.avatar_url);
        }

        this.send_stanza(name, vcard);
        return;
      }
    }
    this.send_stanza(
      name, build_xmpp_error(
        stanza, 'cancel', 'item-not-found'));
  },

  refresh_room: function(callback) {
    var self = this;

    self.campfire.get(self.campfire_room.path, function(err, response) {
      if (!err) {
        try {
          // Build current roster
          var roster = response.room.users.map(function(user) {
            if (user.id != self.campfire_user.id) {
              self.send_stanza(
                user.name, build_xmpp_presence());
            }
            self.campfire_users[user.id] = user;
            return user.id;
          });

          // Send exit notifications
          self.campfire_roster.forEach(function(user_id) {
            if (roster.indexOf(user_id) < 0 && self.campfire_users[user_id]) {
              self.send_stanza(
                self.campfire_users[user_id].name, build_xmpp_presence(
                  {type: 'unavailable'}));
            }
          });

          self.campfire_roster = roster;

        } catch (e) {
          err = e;
        }
      }

      if (callback) {
        callback(err);
      } else if (err) {
        self.log('refresh_room:', err);
      }
    });
  },

  send_stanza: function(from_resource, stanza) {
    stanza = stanza.root();
    this._jid.setResource(from_resource);
    stanza.attrs.from = this._jid.toString();
    this.client.send_stanza(stanza);
    this.log('<<<', stanza.name);
  },

  campfire_start_listen: function() {
    this.campfire_stop_listen();

    if (this.present) {
      this._listen_req = this.campfire_room.listen(
        this.handle_campfire_message.bind(this));

      var self = this;
      this._listen_req.on('error', function(err) {
        self.log('listen', err);
        setTimeout(function() {
          self.campfire_start_listen();
        }, 1000);
      });
    }
  },

  campfire_stop_listen: function() {
    if (this._listen_req) {
      this._listen_req.abort();
    }
  },

  handle_campfire_message: function(msg, history) {
    var self = this;
    Step(
      function lookup_name() {
        if (msg.userId && self.campfire_users[msg.userId] === undefined) {
          self.campfire.user(msg.userId, this);
        } else {
          return null;
        }
      },

      function translate_message(err, response) {
        if (err == 404) {
          self.campfire_users[msg.userId] = null;
        } else if (err) {
          self.log('user', msg.userId, err);
        } else {
          // Cache user name if retrieved
          var _user = response && response.user;
          if (_user && _user.id) {
            self.campfire_users[_user.id] = _user;
          }
        }

        var user = self.campfire_users[msg.userId];

        var stanza = null;
        if (['TextMessage', 'PasteMessage', 'SystemMessage']
            .indexOf(msg.type) > -1) {
          stanza = build_xmpp_message(msg.body);

        } else if (msg.type === 'TweetMessage') {
          var body = msg.body;
          if (msg.tweet) {
            body = msg.tweet.message + ' -- @' + msg.tweet.author_username +
              ', ' + TWITTER_STATUS_PREFIX + msg.tweet.id;
          } else if (body.indexOf('---\n') === 0) {
            self.log('YAML tweet body without .tweet data');
          }
          stanza = build_xmpp_message(body);
        } else if (msg.type === 'TopicChangeMessage') {
          stanza = build_xmpp_message(msg.body, 'subject');

        } else if (msg.type === 'EnterMessage') {
          self.refresh_room();

        } else if (msg.type === 'LeaveMessage') {
          var i = self.campfire_roster.indexOf(msg.userId);
          if (i > -1 && user) {
            stanza = build_xmpp_presence({type: 'unavailable'});
          } else {
            self.refresh_room();
          }

        } else {
          self.log('unhandled campfire message', msg.type);
        }

        if (stanza) {
          if (history) {
            stanza.root()
              .c('delay', {xmlns: 'urn:xmpp:delay',
                           stamp: msg.createdAt.toISOString()});
          }

          self.send_stanza(
            user && user.name || 'User ' + msg.userId, stanza);
        }
      },

      function errors(err) {
        self.log('campfire_message error', err);
      }
    );
  },

  log: function() {
    Array.prototype.unshift.call(arguments, '-', this.jid.toString());
    this.client.log.apply(this.client, arguments);
  }
};

exports.XmppCampfireRoom = XmppCampfireRoom;

// XMPP Helpers

function build_xmpp_presence(options) {
  options = options || {};
  options.role = options.role || (
    options.type === 'unavailable' ? 'none' : 'participant');

  var stanza = new xmpp.Element('presence', {type: options.type})
        .c('x', {xmlns: MUC_USER_NS})
          .c('item', {role: options.role, affiliation: 'member'}).up();

  (options.status_codes || []).forEach(function(status_code) {
    stanza.c('status', {code: status_code});
  });

  return stanza;
}

function build_xmpp_message(body, body_type) {
  body_type = body_type || 'body';
  return new xmpp.Element('message', {type: 'groupchat'})
    .c(body_type)
      .t(body);
}

function build_xmpp_error(stanza, error_type, error, text) {
  if (typeof(stanza) === 'string') {
    stanza = {name: stanza, attrs: {}};
  }
  return new xmpp.Element(stanza.name, {type: 'error', id: stanza.attrs.id})
    .c('x', {xmlns: MUC_NS}).up()
    .c('error', {type: error_type})
      .c(error, {xmlns: ERROR_NS}).up()
      .c('text', {xmlns: ERROR_NS})
        .t(text || '');
}
<|endoftext|>


<commit_before>'use strict';

// ----------------------------------------------------------------------------

const assert = require ('assert');

//  ---------------------------------------------------------------------------

function testOHLCV (exchange, ohlcv, symbol, now) {
    assert (ohlcv);
    assert (Array.isArray (ohlcv));
    const length = ohlcv.length;
    assert (length >= 6);
    for (let i = 0; i < ohlcv.length; i++) {
        assert ((ohlcv[i] === undefined) || (typeof ohlcv[i] === 'number'));
    }

    assert (ohlcv[0] > 1230940800000); // 03 Jan 2009 - first block
    assert (ohlcv[0] < 2147483648000); // 19 Jan 2038 - int32 overflows

    assert ((ohlcv[1] === undefined) || (ohlcv[2] === undefined) || (ohlcv[1] <= ohlcv[2]), 'open > high! ' + ohlcv[1] + ' > ' + ohlcv[2]); // open <= high
    assert ((ohlcv[3] === undefined) || (ohlcv[2] === undefined) || (ohlcv[3] <= ohlcv[2]), 'low > high! ' + ohlcv[3] + ' > ' + ohlcv[2]); // low <= high
    assert ((ohlcv[3] === undefined) || (ohlcv[4] === undefined) || (ohlcv[3] <= ohlcv[4]), 'low > close! ' + ohlcv[3] + ' > ' + ohlcv[4]); // low <= close
}

module.exports = testOHLCV;
<commit_msg>js/test/Exchange/test.ohlcv.js<commit_after>'use strict';

// ----------------------------------------------------------------------------

const assert = require ('assert');

//  ---------------------------------------------------------------------------

function testOHLCV (exchange, ohlcv, symbol, now) {
    assert (ohlcv);
    assert (Array.isArray (ohlcv));
    const length = ohlcv.length;
    assert (length >= 6);
    for (let i = 0; i < ohlcv.length; i++) {
        assert ((ohlcv[i] === undefined) || (typeof ohlcv[i] === 'number'));
    }

    assert (ohlcv[0] > 1230940800000); // 03 Jan 2009 - first block
    assert (ohlcv[0] < 2147483648000); // 19 Jan 2038 - int32 overflows

    assert ((ohlcv[1] === undefined) || (ohlcv[2] === undefined) || (ohlcv[1] <= ohlcv[2]), 'open > high, ' + ohlcv[1] + ' > ' + ohlcv[2]); // open <= high
    assert ((ohlcv[3] === undefined) || (ohlcv[2] === undefined) || (ohlcv[3] <= ohlcv[2]), 'low > high, ' + ohlcv[3] + ' > ' + ohlcv[2]); // low <= high
    assert ((ohlcv[3] === undefined) || (ohlcv[4] === undefined) || (ohlcv[3] <= ohlcv[4]), 'low > close, ' + ohlcv[3] + ' > ' + ohlcv[4]); // low <= close
}

module.exports = testOHLCV;
<|endoftext|>


<commit_before>var Test = require('./test.js')

var tap = new Test()
module.exports = tap

if (tap._timer && tap._timer.unref) {
  tap._timer.unref()
}

tap._name = 'TAP'

// No sense continuing after bailout!
// allow 1 tick for any other bailout handlers to run first.
tap.on('bailout', function () {
  process.nextTick(function () {
    process.exit(1)
  })
})

// need to autoend if a teardown is added.
// otherwise we may never see process.on('exit')!
tap.tearDown = function (fn) {
  var ret = Test.prototype.tearDown.apply(tap, arguments)
  tap.autoend()
  return ret
}

var didPipe = false

process.on('exit', function (code) {
  if (didPipe) {
    tap.endAll()
  }

  if (!tap._ok && code === 0) {
    process.exit(1)
  }
})

tap.pipe = function () {
  didPipe = true
  tap.push = Test.prototype.push
  tap.pipe = Test.prototype.pipe
  process.on('uncaughtException', onUncaught)
  return Test.prototype.pipe.apply(tap, arguments)
}

function pipe () {
  if (didPipe) {
    return
  }

  tap.pipe(process.stdout)
}

tap.push = function push () {
  pipe()
  return tap.push.apply(tap, arguments)
}

tap.mocha = require('./mocha.js')
tap.mochaGlobals = tap.mocha.global
tap.Test = Test
tap.synonyms = require('./synonyms.js')

function onUncaught (er) {
  var child = tap
  while (child._currentChild && child._currentChild instanceof Test) {
    child = child._currentChild
  }
  child.threw(er)
  child._tryResumeEnd()
}

tap.on('end', function () {
  process.removeListener('uncaughtException', onUncaught)
})

// SIGTERM means being forcibly killed, almost always by timeout
var onExit = require('signal-exit')
onExit(function (code, signal) {
  if (signal !== 'SIGTERM' || !didPipe) {
    return
  }

  var handles = process._getActiveHandles().filter(function (h) {
    return h !== process.stdout &&
    h !== process.stdin &&
    h !== process.stderr
  })
  var requests = process._getActiveRequests()

  // Ignore this because it's really hard to test cover in a way
  // that isn't inconsistent and unpredictable.
  /* istanbul ignore next */
  var extra = {
    at: null,
    signal: signal
  }
  if (requests.length) {
    extra.requests = requests.map(function (r) {
      var ret = { type: r.constructor.name }
      if (r.context) {
        ret.context = r.context
      }
      return ret
    })
  }
  if (handles.length) {
    extra.handles = handles.map(function (h) {
      var ret = { type: h.constructor.name }
      if (h.msecs) {
        ret.msecs = h.msecs
      }
      if (h._events) {
        ret.events = Object.keys(h._events)
      }
      if (h._sockname) {
        ret.sockname = h._sockname
      }
      if (h._connectionKey) {
        ret.connectionKey = h._connectionKey
      }
      return ret
    })
  }

  tap._onTimeout(extra)
})
<commit_msg>Don't nextTick root bailout exit<commit_after>var Test = require('./test.js')

var tap = new Test()
module.exports = tap

if (tap._timer && tap._timer.unref) {
  tap._timer.unref()
}

tap._name = 'TAP'

// No sense continuing after bailout!
// allow 1 tick for any other bailout handlers to run first.
tap.bailout = function (reason) {
  Test.prototype.bailout.apply(tap, arguments)
  process.exit(1)
}

// need to autoend if a teardown is added.
// otherwise we may never see process.on('exit')!
tap.tearDown = function (fn) {
  var ret = Test.prototype.tearDown.apply(tap, arguments)
  tap.autoend()
  return ret
}

var didPipe = false

process.on('exit', function (code) {
  if (didPipe) {
    tap.endAll()
  }

  if (!tap._ok && code === 0) {
    process.exit(1)
  }
})

tap.pipe = function () {
  didPipe = true
  tap.push = Test.prototype.push
  tap.pipe = Test.prototype.pipe
  process.on('uncaughtException', onUncaught)
  return Test.prototype.pipe.apply(tap, arguments)
}

function pipe () {
  if (didPipe) {
    return
  }

  tap.pipe(process.stdout)
}

tap.push = function push () {
  pipe()
  return tap.push.apply(tap, arguments)
}

tap.mocha = require('./mocha.js')
tap.mochaGlobals = tap.mocha.global
tap.Test = Test
tap.synonyms = require('./synonyms.js')

function onUncaught (er) {
  var child = tap
  while (child._currentChild && child._currentChild instanceof Test) {
    child = child._currentChild
  }
  child.threw(er)
  child._tryResumeEnd()
}

tap.on('end', function () {
  process.removeListener('uncaughtException', onUncaught)
})

// SIGTERM means being forcibly killed, almost always by timeout
var onExit = require('signal-exit')
onExit(function (code, signal) {
  if (signal !== 'SIGTERM' || !didPipe) {
    return
  }

  var handles = process._getActiveHandles().filter(function (h) {
    return h !== process.stdout &&
    h !== process.stdin &&
    h !== process.stderr
  })
  var requests = process._getActiveRequests()

  // Ignore this because it's really hard to test cover in a way
  // that isn't inconsistent and unpredictable.
  /* istanbul ignore next */
  var extra = {
    at: null,
    signal: signal
  }
  if (requests.length) {
    extra.requests = requests.map(function (r) {
      var ret = { type: r.constructor.name }
      if (r.context) {
        ret.context = r.context
      }
      return ret
    })
  }
  if (handles.length) {
    extra.handles = handles.map(function (h) {
      var ret = { type: h.constructor.name }
      if (h.msecs) {
        ret.msecs = h.msecs
      }
      if (h._events) {
        ret.events = Object.keys(h._events)
      }
      if (h._sockname) {
        ret.sockname = h._sockname
      }
      if (h._connectionKey) {
        ret.connectionKey = h._connectionKey
      }
      return ret
    })
  }

  tap._onTimeout(extra)
})
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const fs = require('fs-extra')
const chalk = require('chalk')

const utils = require('./utils')

const isValidPublisherName = (function () {
  // MakeCert looks like it accepts RFC1779 / X.500 distinguished names
  // See https://msdn.microsoft.com/en-us/library/windows/apps/br211441.aspx
  //     https://msdn.microsoft.com/en-us/library/aa366101
  //     http://www.itu.int/rec/T-REC-X.520-198811-S/en
  //
  // However, in practice there seem to be some discepencies, such as not supported comma/space escaping,
  // so we adapt this to match the observed behavior of makecert.exe.
  const validKeyPatterns = [
    'CN', // commonName
    'OU', // organizationalUnitName
    'O', // organizationName
    'STREET', // streetAddress
    'L', // localityName
    'ST', // stateOrProvinceName
    'C', // countryName
    'DC', // domainComponent
    'SN', // surname
    'GN', // given name
    'E', // email
    'S', // (non-standard) "State" used by MS Identity objects
    'T', // ?? Title / telephone
    'G', // ?? generationQualifier
    'I', // ?? IP Address
    'SERIALNUMBER', // serialNumber
    '(?:OID\\.(0|[1-9][0-9]*)(?:\\.(0|[1-9][0-9]*))+)' // Object IDentifier by explicit numeric code
  ]
  const validKeyPattern = validKeyPatterns.join('|')
  const doubleQuotedPatternWithoutEmbeddedDoubleQuote = '"[^"\\\\]*(?:[^"][^"\\\\]*)*"'
  const validKeyValuePairPattern = `(${validKeyPattern})=((?:${doubleQuotedPatternWithoutEmbeddedDoubleQuote})|[^,"]*)`
  const validSequencePattern = `${validKeyValuePairPattern}(:?\\s*[,;]\\s*${validKeyValuePairPattern})*,?`
  const validDNRegex = new RegExp(`^${validSequencePattern}$`, 'i')

  return function isValidPublisherName (publisherName) {
    return typeof publisherName === 'string' &&
      (publisherName.length === 0 || validDNRegex.test(publisherName))
  }
}())

function makeCert (parametersOrPublisherName, certFilePath, program) {
  let publisherName
  let certFileName
  let install = true

  // We accept both an object and a string here - a string was used
  // in the first release of electron-windows-store, while the object
  // was added later to allow additional flexibility for consuming apps.
  if (typeof parametersOrPublisherName === 'string') {
    publisherName = parametersOrPublisherName
  } else {
    publisherName = parametersOrPublisherName.publisherName
    certFilePath = parametersOrPublisherName.certFilePath
    certFileName = parametersOrPublisherName.certFileName || publisherName
    program = parametersOrPublisherName.program
    if (typeof parametersOrPublisherName.install === 'boolean') {
      install = parametersOrPublisherName.install
    }
  }

  if (typeof publisherName !== 'string') {
    throw new Error('publisherName must be a string')
  }

  if (!isValidPublisherName(publisherName)) {
    publisherName = `CN=${publisherName}`
  }

  certFilePath = certFilePath || ''
  const cer = path.join(certFilePath, `${certFileName}.cer`)
  const pvk = path.join(certFilePath, `${certFileName}.pvk`)
  const pfx = path.join(certFilePath, `${certFileName}.pfx`)

  const makecertExe = path.join(program.windowsKit, 'makecert.exe')
  const makecertArgs = ['-r', '-h', '0', '-n', publisherName, '-eku', '1.3.6.1.5.5.7.3.3', '-pe', '-sv', pvk, cer]

  const pk2pfx = path.join(program.windowsKit, 'pvk2pfx.exe')
  const pk2pfxArgs = ['-pvk', pvk, '-spc', cer, '-pfx', pfx]
  const installPfxArgs = ['Import-PfxCertificate', '-FilePath', pfx, '-CertStoreLocation', '"Cert:\\LocalMachine\\TrustedPeople"']

  // Ensure the target directory exists
  fs.ensureDirSync(certFilePath)

  // If the private key file doesn't exist, makecert.exe will generate one and prompt user to set password
  if (!fs.existsSync(pvk)) {
    utils.log(chalk.green.bold('When asked to enter a password, please select "None".'))
  }

  return utils.executeChildProcess(makecertExe, makecertArgs)
    .then(() => utils.executeChildProcess(pk2pfx, pk2pfxArgs))
    .then(() => {
      if (install) {
        utils.executeChildProcess('powershell.exe', installPfxArgs)
      }
    })
    .then(() => {
      program.devCert = pfx
      return pfx
    })
}

function signAppx (program) {
  return new Promise((resolve, reject) => {
    if (!program.devCert) {
      utils.debug(`Error: Tried to call signAppx, but program.devCert was undefined`)
      reject(new Error('No developer certificate specified!'))
    }

    const pfxFile = program.devCert
    const appxFile = path.join(program.outputDirectory, `${program.packageName}.appx`)
    let params = ['sign', '-f', pfxFile, '-fd', 'SHA256', '-v']
    if (program.certPass) {
      params.push('-p', program.certPass)
    }

    params = params.concat(program.signtoolParams || [])

    utils.debug(`Using PFX certificate from: ${pfxFile}`)
    utils.debug(`Signing appx package: ${appxFile}`)
    utils.debug(`Using the following parameters for signtool.exe: ${JSON.stringify(params)}`)

    params.push(appxFile)

    utils.executeChildProcess(path.join(program.windowsKit, 'signtool.exe'), params)
      .then(() => resolve())
      .catch((err) => reject(err))
  })
}

module.exports = {
  isValidPublisherName,
  makeCert,
  signAppx
}
<commit_msg>Return from signAppx after rejecting, if no devCert.<commit_after>'use strict'

const path = require('path')
const fs = require('fs-extra')
const chalk = require('chalk')

const utils = require('./utils')

const isValidPublisherName = (function () {
  // MakeCert looks like it accepts RFC1779 / X.500 distinguished names
  // See https://msdn.microsoft.com/en-us/library/windows/apps/br211441.aspx
  //     https://msdn.microsoft.com/en-us/library/aa366101
  //     http://www.itu.int/rec/T-REC-X.520-198811-S/en
  //
  // However, in practice there seem to be some discepencies, such as not supported comma/space escaping,
  // so we adapt this to match the observed behavior of makecert.exe.
  const validKeyPatterns = [
    'CN', // commonName
    'OU', // organizationalUnitName
    'O', // organizationName
    'STREET', // streetAddress
    'L', // localityName
    'ST', // stateOrProvinceName
    'C', // countryName
    'DC', // domainComponent
    'SN', // surname
    'GN', // given name
    'E', // email
    'S', // (non-standard) "State" used by MS Identity objects
    'T', // ?? Title / telephone
    'G', // ?? generationQualifier
    'I', // ?? IP Address
    'SERIALNUMBER', // serialNumber
    '(?:OID\\.(0|[1-9][0-9]*)(?:\\.(0|[1-9][0-9]*))+)' // Object IDentifier by explicit numeric code
  ]
  const validKeyPattern = validKeyPatterns.join('|')
  const doubleQuotedPatternWithoutEmbeddedDoubleQuote = '"[^"\\\\]*(?:[^"][^"\\\\]*)*"'
  const validKeyValuePairPattern = `(${validKeyPattern})=((?:${doubleQuotedPatternWithoutEmbeddedDoubleQuote})|[^,"]*)`
  const validSequencePattern = `${validKeyValuePairPattern}(:?\\s*[,;]\\s*${validKeyValuePairPattern})*,?`
  const validDNRegex = new RegExp(`^${validSequencePattern}$`, 'i')

  return function isValidPublisherName (publisherName) {
    return typeof publisherName === 'string' &&
      (publisherName.length === 0 || validDNRegex.test(publisherName))
  }
}())

function makeCert (parametersOrPublisherName, certFilePath, program) {
  let publisherName
  let certFileName
  let install = true

  // We accept both an object and a string here - a string was used
  // in the first release of electron-windows-store, while the object
  // was added later to allow additional flexibility for consuming apps.
  if (typeof parametersOrPublisherName === 'string') {
    publisherName = parametersOrPublisherName
  } else {
    publisherName = parametersOrPublisherName.publisherName
    certFilePath = parametersOrPublisherName.certFilePath
    certFileName = parametersOrPublisherName.certFileName || publisherName
    program = parametersOrPublisherName.program
    if (typeof parametersOrPublisherName.install === 'boolean') {
      install = parametersOrPublisherName.install
    }
  }

  if (typeof publisherName !== 'string') {
    throw new Error('publisherName must be a string')
  }

  if (!isValidPublisherName(publisherName)) {
    publisherName = `CN=${publisherName}`
  }

  certFilePath = certFilePath || ''
  const cer = path.join(certFilePath, `${certFileName}.cer`)
  const pvk = path.join(certFilePath, `${certFileName}.pvk`)
  const pfx = path.join(certFilePath, `${certFileName}.pfx`)

  const makecertExe = path.join(program.windowsKit, 'makecert.exe')
  const makecertArgs = ['-r', '-h', '0', '-n', publisherName, '-eku', '1.3.6.1.5.5.7.3.3', '-pe', '-sv', pvk, cer]

  const pk2pfx = path.join(program.windowsKit, 'pvk2pfx.exe')
  const pk2pfxArgs = ['-pvk', pvk, '-spc', cer, '-pfx', pfx]
  const installPfxArgs = ['Import-PfxCertificate', '-FilePath', pfx, '-CertStoreLocation', '"Cert:\\LocalMachine\\TrustedPeople"']

  // Ensure the target directory exists
  fs.ensureDirSync(certFilePath)

  // If the private key file doesn't exist, makecert.exe will generate one and prompt user to set password
  if (!fs.existsSync(pvk)) {
    utils.log(chalk.green.bold('When asked to enter a password, please select "None".'))
  }

  return utils.executeChildProcess(makecertExe, makecertArgs)
    .then(() => utils.executeChildProcess(pk2pfx, pk2pfxArgs))
    .then(() => {
      if (install) {
        utils.executeChildProcess('powershell.exe', installPfxArgs)
      }
    })
    .then(() => {
      program.devCert = pfx
      return pfx
    })
}

function signAppx (program) {
  return new Promise((resolve, reject) => {
    if (!program.devCert) {
      utils.debug(`Error: Tried to call signAppx, but program.devCert was undefined`)
      return reject(new Error('No developer certificate specified!'))
    }

    const pfxFile = program.devCert
    const appxFile = path.join(program.outputDirectory, `${program.packageName}.appx`)
    let params = ['sign', '-f', pfxFile, '-fd', 'SHA256', '-v']
    if (program.certPass) {
      params.push('-p', program.certPass)
    }

    params = params.concat(program.signtoolParams || [])

    utils.debug(`Using PFX certificate from: ${pfxFile}`)
    utils.debug(`Signing appx package: ${appxFile}`)
    utils.debug(`Using the following parameters for signtool.exe: ${JSON.stringify(params)}`)

    params.push(appxFile)

    utils.executeChildProcess(path.join(program.windowsKit, 'signtool.exe'), params)
      .then(() => resolve())
      .catch((err) => reject(err))
  })
}

module.exports = {
  isValidPublisherName,
  makeCert,
  signAppx
}
<|endoftext|>


<commit_before>/* jshint esversion: 6 */
/* jslint node: true */
'use strict';

const cbor = require('cbor');
const EC = require('elliptic').ec;
const crypto = require('crypto');
const common = require('./common');
const Promise = require('any-promise');
const EMPTY_BUFFER = common.EMPTY_BUFFER;
const Tagged = cbor.Tagged;

const SignTag = exports.SignTag = 98;
const Sign1Tag = exports.Sign1Tag = 18;

const AlgFromTags = {};
AlgFromTags[-7] = { 'sign': 'ES256', 'digest': 'SHA-256' };
AlgFromTags[-35] = { 'sign': 'ES384', 'digest': 'SHA-384' };
AlgFromTags[-36] = { 'sign': 'ES512', 'digest': 'SHA-512' };
AlgFromTags[-257] = { 'sign': 'RS256', 'digest': 'SHA-256' };
AlgFromTags[-258] = { 'sign': 'RS384', 'digest': 'SHA-384' };
AlgFromTags[-259] = { 'sign': 'RS512', 'digest': 'SHA-512' };

const COSEAlgToNodeAlg = {
  'ES256': { 'sign': 'p256', 'digest': 'sha256' },
  'ES384': { 'sign': 'p384', 'digest': 'sha384' },
  'ES512': { 'sign': 'p521', 'digest': 'sha512' },
  'RS256': { 'sign': 'RSA-SHA256' },
  'RS384': { 'sign': 'RSA-SHA384' },
  'RS512': { 'sign': 'RSA-SHA512' },
};

function doSign (SigStructure, signer, alg) {
  return new Promise((resolve, reject) => {
    if (!AlgFromTags[alg]) {
      throw new Error('Unknown algorithm, ' + alg);
    }
    if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) {
      throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
    }

    let ToBeSigned = cbor.encode(SigStructure);

    let sig;
    if (AlgFromTags[alg].sign.startsWith('ES')) {
      const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest);
      hash.update(ToBeSigned);
      ToBeSigned = hash.digest();
      const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      const key = ec.keyFromPrivate(signer.key.d);
      const signature = key.sign(ToBeSigned);
      const bitLength = Math.ceil(ec.curve._bitLength / 8);
      sig = Buffer.concat([signature.r.toArrayLike(Buffer, undefined, bitLength), signature.s.toArrayLike(Buffer, undefined, bitLength)]);
    } else {
      const key = crypto.createPrivateKey(signer.key);
      const sign = crypto.createSign(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      sign.update(ToBeSigned);
      sign.end();
      sig = sign.sign(key);
    }

    resolve(sig);
  });
}

exports.create = function (headers, payload, signers, options) {
  options = options || {};
  let u = headers.u || {};
  let p = headers.p || {};

  p = common.TranslateHeaders(p);
  u = common.TranslateHeaders(u);
  let bodyP = p || {};
  bodyP = (bodyP.size === 0) ? EMPTY_BUFFER : cbor.encode(bodyP);
  if (Array.isArray(signers)) {
    if (signers.length === 0) {
      throw new Error('There has to be at least one signer');
    }
    if (signers.length > 1) {
      throw new Error('Only one signer is supported');
    }
    // TODO handle multiple signers
    const signer = signers[0];
    const externalAAD = signer.externalAAD || EMPTY_BUFFER;
    let signerP = signer.p || {};
    let signerU = signer.u || {};

    signerP = common.TranslateHeaders(signerP);
    signerU = common.TranslateHeaders(signerU);
    const alg = signerP.get(common.HeaderParameters.alg);
    signerP = (signerP.size === 0) ? EMPTY_BUFFER : cbor.encode(signerP);

    const SigStructure = [
      'Signature',
      bodyP,
      signerP,
      externalAAD,
      payload
    ];
    return doSign(SigStructure, signer, alg).then((sig) => {
      if (p.size === 0 && options.encodep === 'empty') {
        p = EMPTY_BUFFER;
      } else {
        p = cbor.encode(p);
      }
      const signed = [p, u, payload, [[signerP, signerU, sig]]];
      return cbor.encode(options.excludetag ? signed : new Tagged(SignTag, signed));
    });
  } else {
    const signer = signers;
    const externalAAD = signer.externalAAD || EMPTY_BUFFER;
    const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
    const SigStructure = [
      'Signature1',
      bodyP,
      externalAAD,
      payload
    ];
    return doSign(SigStructure, signer, alg).then((sig) => {
      if (p.size === 0 && options.encodep === 'empty') {
        p = EMPTY_BUFFER;
      } else {
        p = cbor.encode(p);
      }
      const signed = [p, u, payload, sig];
      return cbor.encodeCanonical(options.excludetag ? signed : new Tagged(Sign1Tag, signed));
    });
  }
};

function doVerify (SigStructure, verifier, alg, sig) {
  return new Promise((resolve, reject) => {
    if (!AlgFromTags[alg]) {
      throw new Error('Unknown algorithm, ' + alg);
    }
    if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) {
      throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
    }
    let msgHash = cbor.encode(SigStructure);
    const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest);
    hash.update(msgHash);
    msgHash = hash.digest();

    const pub = { 'x': verifier.key.x, 'y': verifier.key.y };
    const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
    const key = ec.keyFromPublic(pub);
    sig = { 'r': sig.slice(0, sig.length / 2), 's': sig.slice(sig.length / 2) };
    if (key.verify(msgHash, sig)) {
      resolve();
    } else {
      throw new Error('Signature missmatch');
    }
  });
}

function getSigner (signers, verifier) {
  for (let i = 0; i < signers.length; i++) {
    const kid = signers[i][1].get(common.HeaderParameters.kid); // TODO create constant for header locations
    if (kid.equals(Buffer.from(verifier.key.kid, 'utf8'))) {
      return signers[i];
    }
  }
}

function getCommonParameter (first, second, parameter) {
  let result;
  if (first.get) {
    result = first.get(parameter);
  }
  if (!result && second.get) {
    result = second.get(parameter);
  }
  return result;
}

exports.verify = function (payload, verifier, options) {
  options = options || {};
  return cbor.decodeFirst(payload)
    .then((obj) => {
      let type = options.defaultType ? options.defaultType : SignTag;
      if (obj instanceof Tagged) {
        if (obj.tag !== SignTag && obj.tag !== Sign1Tag) {
          throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
        }
        type = obj.tag;
        obj = obj.value;
      }

      if (!Array.isArray(obj)) {
        throw new Error('Expecting Array');
      }

      if (obj.length !== 4) {
        throw new Error('Expecting Array of lenght 4');
      }

      let [p, u, plaintext, signers] = obj;

      if (type === SignTag && !Array.isArray(signers)) {
        throw new Error('Expecting signature Array');
      }

      p = (!p.length) ? EMPTY_BUFFER : cbor.decodeFirstSync(p);
      u = (!u.size) ? EMPTY_BUFFER : u;

      let signer = (type === SignTag ? getSigner(signers, verifier) : signers);

      if (!signer) {
        throw new Error('Failed to find signer with kid' + verifier.key.kid);
      }

      if (type === SignTag) {
        const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
        let [signerP, , sig] = signer;
        signerP = (!signerP.length) ? EMPTY_BUFFER : signerP;
        p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
        const signerPMap = cbor.decode(signerP);
        const alg = signerPMap.get(common.HeaderParameters.alg);
        const SigStructure = [
          'Signature',
          p,
          signerP,
          externalAAD,
          plaintext
        ];
        return doVerify(SigStructure, verifier, alg, sig)
          .then(() => {
            return plaintext;
          });
      } else {
        const externalAAD = verifier.externalAAD || EMPTY_BUFFER;

        const alg = getCommonParameter(p, u, common.HeaderParameters.alg);
        p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
        const SigStructure = [
          'Signature1',
          p,
          externalAAD,
          plaintext
        ];
        return doVerify(SigStructure, verifier, alg, signer)
          .then(() => {
            return plaintext;
          });
      }
    });
};
<commit_msg>add RS* verify support<commit_after>/* jshint esversion: 6 */
/* jslint node: true */
'use strict';

const cbor = require('cbor');
const EC = require('elliptic').ec;
const crypto = require('crypto');
const common = require('./common');
const Promise = require('any-promise');
const EMPTY_BUFFER = common.EMPTY_BUFFER;
const Tagged = cbor.Tagged;

const SignTag = exports.SignTag = 98;
const Sign1Tag = exports.Sign1Tag = 18;

const AlgFromTags = {};
AlgFromTags[-7] = { 'sign': 'ES256', 'digest': 'SHA-256' };
AlgFromTags[-35] = { 'sign': 'ES384', 'digest': 'SHA-384' };
AlgFromTags[-36] = { 'sign': 'ES512', 'digest': 'SHA-512' };
AlgFromTags[-257] = { 'sign': 'RS256', 'digest': 'SHA-256' };
AlgFromTags[-258] = { 'sign': 'RS384', 'digest': 'SHA-384' };
AlgFromTags[-259] = { 'sign': 'RS512', 'digest': 'SHA-512' };

const COSEAlgToNodeAlg = {
  'ES256': { 'sign': 'p256', 'digest': 'sha256' },
  'ES384': { 'sign': 'p384', 'digest': 'sha384' },
  'ES512': { 'sign': 'p521', 'digest': 'sha512' },
  'RS256': { 'sign': 'RSA-SHA256' },
  'RS384': { 'sign': 'RSA-SHA384' },
  'RS512': { 'sign': 'RSA-SHA512' },
};

function doSign (SigStructure, signer, alg) {
  return new Promise((resolve, reject) => {
    if (!AlgFromTags[alg]) {
      throw new Error('Unknown algorithm, ' + alg);
    }
    if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) {
      throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
    }

    let ToBeSigned = cbor.encode(SigStructure);

    let sig;
    if (AlgFromTags[alg].sign.startsWith('ES')) {
      const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest);
      hash.update(ToBeSigned);
      ToBeSigned = hash.digest();
      const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      const key = ec.keyFromPrivate(signer.key.d);
      const signature = key.sign(ToBeSigned);
      const bitLength = Math.ceil(ec.curve._bitLength / 8);
      sig = Buffer.concat([signature.r.toArrayLike(Buffer, undefined, bitLength), signature.s.toArrayLike(Buffer, undefined, bitLength)]);
    } else {
      const key = crypto.createPrivateKey(signer.key);
      const sign = crypto.createSign(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      sign.update(ToBeSigned);
      sign.end();
      sig = sign.sign(key);
    }

    resolve(sig);
  });
}

exports.create = function (headers, payload, signers, options) {
  options = options || {};
  let u = headers.u || {};
  let p = headers.p || {};

  p = common.TranslateHeaders(p);
  u = common.TranslateHeaders(u);
  let bodyP = p || {};
  bodyP = (bodyP.size === 0) ? EMPTY_BUFFER : cbor.encode(bodyP);
  if (Array.isArray(signers)) {
    if (signers.length === 0) {
      throw new Error('There has to be at least one signer');
    }
    if (signers.length > 1) {
      throw new Error('Only one signer is supported');
    }
    // TODO handle multiple signers
    const signer = signers[0];
    const externalAAD = signer.externalAAD || EMPTY_BUFFER;
    let signerP = signer.p || {};
    let signerU = signer.u || {};

    signerP = common.TranslateHeaders(signerP);
    signerU = common.TranslateHeaders(signerU);
    const alg = signerP.get(common.HeaderParameters.alg);
    signerP = (signerP.size === 0) ? EMPTY_BUFFER : cbor.encode(signerP);

    const SigStructure = [
      'Signature',
      bodyP,
      signerP,
      externalAAD,
      payload
    ];
    return doSign(SigStructure, signer, alg).then((sig) => {
      if (p.size === 0 && options.encodep === 'empty') {
        p = EMPTY_BUFFER;
      } else {
        p = cbor.encode(p);
      }
      const signed = [p, u, payload, [[signerP, signerU, sig]]];
      return cbor.encode(options.excludetag ? signed : new Tagged(SignTag, signed));
    });
  } else {
    const signer = signers;
    const externalAAD = signer.externalAAD || EMPTY_BUFFER;
    const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
    const SigStructure = [
      'Signature1',
      bodyP,
      externalAAD,
      payload
    ];
    return doSign(SigStructure, signer, alg).then((sig) => {
      if (p.size === 0 && options.encodep === 'empty') {
        p = EMPTY_BUFFER;
      } else {
        p = cbor.encode(p);
      }
      const signed = [p, u, payload, sig];
      return cbor.encodeCanonical(options.excludetag ? signed : new Tagged(Sign1Tag, signed));
    });
  }
};

function doVerify (SigStructure, verifier, alg, sig) {
  return new Promise((resolve, reject) => {
    if (!AlgFromTags[alg]) {
      throw new Error('Unknown algorithm, ' + alg);
    }
    if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) {
      throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
    }
    const ToBeSigned = cbor.encode(SigStructure);

    if (AlgFromTags[alg].sign.startsWith('ES')) {
      const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest);
      hash.update(ToBeSigned);
      const msgHash = hash.digest();

      const pub = { 'x': verifier.key.x, 'y': verifier.key.y };
      const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      const key = ec.keyFromPublic(pub);
      sig = { 'r': sig.slice(0, sig.length / 2), 's': sig.slice(sig.length / 2) };
      if (key.verify(msgHash, sig)) {
        resolve();
      } else {
        throw new Error('Signature mismatch');
      }
    } else {
      const key = crypto.createPublicKey(verifier.key);
      const verify = crypto.createVerify(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
      verify.update(ToBeSigned);
      if (verify.verify(key, sig)) {
        resolve();
      } else {
        throw new Error('Signature mismatch');
      }
    }
  });
}

function getSigner (signers, verifier) {
  for (let i = 0; i < signers.length; i++) {
    const kid = signers[i][1].get(common.HeaderParameters.kid); // TODO create constant for header locations
    if (kid.equals(Buffer.from(verifier.key.kid, 'utf8'))) {
      return signers[i];
    }
  }
}

function getCommonParameter (first, second, parameter) {
  let result;
  if (first.get) {
    result = first.get(parameter);
  }
  if (!result && second.get) {
    result = second.get(parameter);
  }
  return result;
}

exports.verify = function (payload, verifier, options) {
  options = options || {};
  return cbor.decodeFirst(payload)
    .then((obj) => {
      let type = options.defaultType ? options.defaultType : SignTag;
      if (obj instanceof Tagged) {
        if (obj.tag !== SignTag && obj.tag !== Sign1Tag) {
          throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
        }
        type = obj.tag;
        obj = obj.value;
      }

      if (!Array.isArray(obj)) {
        throw new Error('Expecting Array');
      }

      if (obj.length !== 4) {
        throw new Error('Expecting Array of lenght 4');
      }

      let [p, u, plaintext, signers] = obj;

      if (type === SignTag && !Array.isArray(signers)) {
        throw new Error('Expecting signature Array');
      }

      p = (!p.length) ? EMPTY_BUFFER : cbor.decodeFirstSync(p);
      u = (!u.size) ? EMPTY_BUFFER : u;

      let signer = (type === SignTag ? getSigner(signers, verifier) : signers);

      if (!signer) {
        throw new Error('Failed to find signer with kid' + verifier.key.kid);
      }

      if (type === SignTag) {
        const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
        let [signerP, , sig] = signer;
        signerP = (!signerP.length) ? EMPTY_BUFFER : signerP;
        p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
        const signerPMap = cbor.decode(signerP);
        const alg = signerPMap.get(common.HeaderParameters.alg);
        const SigStructure = [
          'Signature',
          p,
          signerP,
          externalAAD,
          plaintext
        ];
        return doVerify(SigStructure, verifier, alg, sig)
          .then(() => {
            return plaintext;
          });
      } else {
        const externalAAD = verifier.externalAAD || EMPTY_BUFFER;

        const alg = getCommonParameter(p, u, common.HeaderParameters.alg);
        p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
        const SigStructure = [
          'Signature1',
          p,
          externalAAD,
          plaintext
        ];
        return doVerify(SigStructure, verifier, alg, signer)
          .then(() => {
            return plaintext;
          });
      }
    });
};
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Post = require('./post');
var Media = require('./media');
var debug = require('debug')('wpcom:site');

/**
 * Resources array
 */

var resources = [
  'categories',
  'comments',
  'follows',
  'media',
  'posts',
  [ 'stats', 'stats' ],
  [ 'statsVisits', 'stats/visits' ],
  [ 'statsReferrers', 'stats/referrers' ],
  [ 'statsTopPosts', 'stats/top-posts' ],
  [ 'statsCountryViews', 'stats/country-views' ],
  [ 'statsClicks', 'stats/clicks' ],
  [ 'statsSearchTerms', 'stats/search-terms' ],
  'tags',
  'users'
];

/**
 * Create a Site instance
 *
 * @param {WPCOM} wpcom
 * @api public
 */

function Site(id, wpcom){
  if (!(this instanceof Site)) return new Site(id, wpcom);
  this.wpcom = wpcom;

  debug('set `%s` site id', id);
  this._id = id;
}

/**
 * Require site information
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

Site.prototype.get = function(query, fn){
  this.wpcom.sendRequest('/sites/' + this._id, query, null, fn);
};

/**
 * List method builder
 *
 * @param {String} subpath
 * @param {Function}
 * @api private
 */

var list = function(subpath) {

  /**
   * Return the <names>List method
   *
   * @param {Object} [query]
   * @param {Function} fn
   * @api public
   */

  return function (query, fn){
    this.wpcom.sendRequest('/sites/' + this._id + '/' + subpath, query, null, fn);
  };
};

// walk for each resource and create <resources>List method
for (var i = 0; i < resources.length; i++) {
  var res = resources[i];
  var isarr = Array.isArray(res);

  var name =  isarr ? res[0] : res + 'List';
  var subpath = isarr ? res[1] : res;

  debug('adding `site.%s()` method in `%s` sub-path', name, subpath);
  Site.prototype[name] = list.call(this, subpath);
}

/**
 * :POST:
 * Create a `Post` instance
 *
 * @param {String} id
 * @api public
 */

Site.prototype.post = function(id){
  return Post(id, this._id, this.wpcom);
};

/**
 * :POST:
 * Add a new blog post
 *
 * @param {Object} body
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addPost = function(body, fn){
  var post = Post(null, this._id, this.wpcom);
  post.add(body, fn);
  return post;
};

/**
 * :POST:
 * Delete a blog post
 *
 * @param {String} id
 * @param {Function} fn
 * @return {Post} remove Post instance
 */

Site.prototype.deletePost = function(id, fn){
  var post = Post(id, this._id, this.wpcom);
  post.delete(fn);
  return post;
};

/**
 * :MEDIA:
 * Create a `Media` instance
 *
 * @param {String} id
 * @api public
 */

Site.prototype.media = function(id){
  return Media(id, this._id, this.wpcom);
};

/**
 * :MEDIA:
 * Add a media from a file
 *
 * @param {Array|String} files
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addMediaFiles = function(files, fn){
  var media = Media(null, this._id, this.wpcom);
  media.addFiles(files, fn);
  return media;
};

/**
 * :MEDIA:
 * Add a new media from url
 *
 * @param {Array|String} files
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addMediaUrls = function(files, fn){
  var media = Media(null, this._id, this.wpcom);
  media.addUrls(files, fn);
  return media;
};

/**
 * :MEDIA:
 * Delete a blog media
 *
 * @param {String} id
 * @param {Function} fn
 * @return {Post} removed Media instance
 */

Site.prototype.deleteMedia = function(id, fn){
  var media = Media(id, this._id, this.wpcom);
  media.del(fn);
  return media;
};

/**
 * Expose `Site` module
 */

module.exports = Site;
<commit_msg>site: add site.comment() method<commit_after>
/**
 * Module dependencies.
 */

var Post = require('./post');
var Media = require('./media');
var Comment = require('./comment');
var debug = require('debug')('wpcom:site');

/**
 * Resources array
 * A list of endpoints with the same structure
 */

var resources = [
  'categories',
  'comments',
  'follows',
  'media',
  'posts',
  [ 'stats', 'stats' ],
  [ 'statsVisits', 'stats/visits' ],
  [ 'statsReferrers', 'stats/referrers' ],
  [ 'statsTopPosts', 'stats/top-posts' ],
  [ 'statsCountryViews', 'stats/country-views' ],
  [ 'statsClicks', 'stats/clicks' ],
  [ 'statsSearchTerms', 'stats/search-terms' ],
  'tags',
  'users'
];

/**
 * Create a Site instance
 *
 * @param {WPCOM} wpcom
 * @api public
 */

function Site(id, wpcom){
  if (!(this instanceof Site)) return new Site(id, wpcom);
  this.wpcom = wpcom;

  debug('set `%s` site id', id);
  this._id = id;
}

/**
 * Require site information
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

Site.prototype.get = function(query, fn){
  this.wpcom.sendRequest('/sites/' + this._id, query, null, fn);
};

/**
 * List method builder
 *
 * @param {String} subpath
 * @param {Function}
 * @api private
 */

var list = function(subpath) {

  /**
   * Return the <names>List method
   *
   * @param {Object} [query]
   * @param {Function} fn
   * @api public
   */

  return function (query, fn){
    this.wpcom.sendRequest('/sites/' + this._id + '/' + subpath, query, null, fn);
  };
};

// walk for each resource and create related method
for (var i = 0; i < resources.length; i++) {
  var res = resources[i];
  var isarr = Array.isArray(res);

  var name =  isarr ? res[0] : res + 'List';
  var subpath = isarr ? res[1] : res;

  debug('adding `site.%s()` method in `%s` sub-path', name, subpath);
  Site.prototype[name] = list.call(this, subpath);
}

/**
 * :POST:
 * Create a `Post` instance
 *
 * @param {String} id
 * @api public
 */

Site.prototype.post = function(id){
  return Post(id, this._id, this.wpcom);
};

/**
 * :POST:
 * Add a new blog post
 *
 * @param {Object} body
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addPost = function(body, fn){
  var post = Post(null, this._id, this.wpcom);
  post.add(body, fn);
  return post;
};

/**
 * :POST:
 * Delete a blog post
 *
 * @param {String} id
 * @param {Function} fn
 * @return {Post} remove Post instance
 */

Site.prototype.deletePost = function(id, fn){
  var post = Post(id, this._id, this.wpcom);
  post.delete(fn);
  return post;
};

/**
 * :MEDIA:
 * Create a `Media` instance
 *
 * @param {String} id
 * @api public
 */

Site.prototype.media = function(id){
  return Media(id, this._id, this.wpcom);
};

/**
 * :MEDIA:
 * Add a media from a file
 *
 * @param {Array|String} files
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addMediaFiles = function(files, fn){
  var media = Media(null, this._id, this.wpcom);
  media.addFiles(files, fn);
  return media;
};

/**
 * :MEDIA:
 * Add a new media from url
 *
 * @param {Array|String} files
 * @param {Function} fn
 * @return {Post} new Post instance
 */

Site.prototype.addMediaUrls = function(files, fn){
  var media = Media(null, this._id, this.wpcom);
  media.addUrls(files, fn);
  return media;
};

/**
 * :MEDIA:
 * Delete a blog media
 *
 * @param {String} id
 * @param {Function} fn
 * @return {Post} removed Media instance
 */

Site.prototype.deleteMedia = function(id, fn){
  var media = Media(id, this._id, this.wpcom);
  media.del(fn);
  return media;
};

/**
 * :COMMENT:
 * Create a `Comment` instance
 *
 * @param {String} id
 * @api public
 */

Site.prototype.comment = function(id){
  return Comment(id, null, this._id, this.wpcom);
};

/**
 * Expose `Site` module
 */

module.exports = Site;
<|endoftext|>


<commit_before>// Basic structures of the ECLib library

// We will not require anything right now.
//

var addon = require('bindings')('Release/node-eclib.node')
var ECLibUtil = require("./eclib-util.js");
var enums = require("./eclib-enum.js");

function ECLib(){
	this.eclibUtil = new ECLibUtil();
}

ECLib.prototype.create = function ( ec_backend_id, k, m, w, hd, ct, backend_args,callback) {

	var instance_descriptor_id = -1;
	var err = {};

	if ( this.eclibUtil.validateInstanceCreateParams(ec_backend_id, k, m, w, hd, ct)  ){

		instance_descriptor_id = addon.create(ec_backend_id, k, m, w, hd, ct);

		if (instance_descriptor_id <=0 ){
			err.errorcode =  instance_descriptor_id ;
			err.message = this.eclibUtil.getErrorMessage(instance_descriptor_id);
		}

	} else {
		err.errorcode =  enums.ErrorCode.EBACKENDNOTAVAIL ;
		err.message = this.eclibUtil.getErrorMessage(err.errorcode);
		instance_descriptor_id = err.errorcode ;
	}

	if (!callback){

		return instance_descriptor_id;
	}

	callback.call(this,instance_descriptor_id, err);

};

ECLib.prototype.destroy = function(instance_descriptor_id,callback){

	var resultcode = enums.ErrorCode.EBACKENDNOTSUPP;
	var err = {};

	if (!instance_descriptor_id){

		resultcode = addon.destroy(instance_descriptor_id);
		if ( instance_descriptor_id !== 0){
			err.errorcode = resultcode;
			err.message = this.eclibUtil.getErrorMessage(resultcode);
		}

	} else {

		err.errorcode = resultcode;
		err.message = this.eclibUtil.getErrorMessage(resultcode);

	}

	if (!callback){
		return resultcode;
	}

	callback.call(this,resultcode,err);
};

ECLib.prototype.encode = function(instance_descriptor_id, orig_data, orig_data_size,callback){

	console.log("JS encode ");
	console.log(addon.encode());

	//result.resultcode = 1//2/3/4/5
	//result.encoded_data = "" ,result.encoded_parity ="", result.fragment_len =12312312312312;
	//callback.call(result,err)
};

ECLib.prototype.encodeCleanup = function(instance_descriptor_id, encoded_data,encoded_parity,callback){

	console.log("JS encodeCleanup ");
	console.log(addon.encodeCleanup());
	//callback.call(resultcode,err)
};

ECLib.prototype.decode = function(instance_descriptor_id, available_fragments
							 , num_fragments, fragment_len, callback){

	console.log("JS decode #");
	console.log(addon.decode());
	//result.resultcode = 1//2/3/4/5
	//result.out_data = "" ,result.out_data_len =""
	//callback.call(result,err)
};

ECLib.prototype.decodeCleanup = function(instance_descriptor_id, data,callback){

	console.log("JS decode_cleanup #");
	console.log(addon.decodeCleanup());
	//callback.call(resultcode,err)
};

ECLib.prototype.reconstructFragment = function(instance_descriptor_id, available_fragments
	, num_fragments, fragment_len,destination_idx, callback) {

	console.log("JS reconstructFragment #");
	console.log(addon.reconstructFragment());

	//result.resultcode = 1//2/3/4/5
	//result.out_fragment = ""
	//callback.call(result,err)

};

ECLib.prototype.fragmentsNeeded = function (instance_descriptor_id,fragments_to_reconstruct
					,fragments_to_exclude,fragments_needed,callback){

	console.log("from fragmentsNeeded method");
	//callback.call(resultcode,err)
}

ECLib.prototype.getFragmentMetadata = function(fragment, fragment_metadata, callback){

	console.log("from getFragmentMetadata method");
	//callback.call(resultcode,err)

};

ECLib.prototype.isInvalidFragment = function(instance_descriptor_id, fragment, callback){

	console.log("from isInvalidFragment method");
	//callback.call(resultcode,err)
};

ECLib.prototype.verifyStripeMetadata = function (instance_descriptor_id, fragments
					, num_fragments, callback){

	console.log("from verifyStripeMetadata method");
	//callback.call(resultcode,err)
};

ECLib.prototype.getAlignedDataSize = function(instance_descriptor_id, data_len, callback){

	console.log("from getAlignedDataSize method");
	//callback.call(resultlength, err)
};

ECLib.prototype.getMinimumEncodeSize = function (instance_descriptor_id, callback){

	console.log("from getMinimumEncodeSize method");
	//callback.call(resultminimumlength, err)
};

ECLib.prototype.getFragmentSize = function(instance_descriptor_id, data_len ,callback){

	console.log("from getFragmentSize method");
	//callback.call(resultfragmentsize, err)

};

module.exports = ECLib <commit_msg>New structure of the EClib library's JS file<commit_after>// Basic structures of the ECLib library

// We will not require anything right now.
//

var addon = require('bindings')('Release/node-eclib.node')
var ECLibUtil = require("./eclib-util.js");
var enums = require("./eclib-enum.js");
var __ = require('underscore');

function ECLib(opts){
	var d_options = {"bc_id":0,"k":8,"m":4,"w":0,"hd":0,"ct":0 };

	this.opt = {};
	__.extend(this.opt,d_options);

	if (__.size(opts) > 1){
		__.extend(this.opt, opts );
	}

	this.ins_id = null;
	this.eclibUtil = new ECLibUtil();
	this.isValidInstance = function(){

		return ( __.isUndefined(this.ins_id));

	};

	this.resetOptions = function(){
		this.opt = null;
		__.extend(this.opt,d_options);
	};
}

ECLib.prototype = {

	init: function(callback){
		//This will be the  create method of the ECLIB
		var instance_descriptor_id = -1;
		var err = {};
		var o= this.opt;

		if ( this.eclibUtil.validateInstanceCreateParams(o.ec_id, o.k, o.m, o.w, o.hd, o.ct)  ){

			instance_descriptor_id = addon.create(o.ec_id, o.k, o.m, o.w, o.hd, o.ct);

			if (instance_descriptor_id <=0 ){
				err.errorcode =  instance_descriptor_id ;
				err.message = this.eclibUtil.getErrorMessage(instance_descriptor_id);
			}else {
				this.ins_id =instance_descriptor_id;
			}

		} else {
			err.errorcode =  enums.ErrorCode.EINVALIDPARAMS ;
			err.message = this.eclibUtil.getErrorMessage(err.errorcode);
			instance_descriptor_id = err.errorcode ;
		}

		if (!callback){

			return instance_descriptor_id;
		}

		callback.call(this,instance_descriptor_id, err);

	},
	destroy: function(callback){

		var resultcode = enums.ErrorCode.EBACKENDNOTAVAIL;
		var err = {};

		if (this.isValidInstance()){
			resultcode = addon.destroy(instance_descriptor_id);
			if ( resultcode !== 0){
				err.errorcode = resultcode;
				err.message = this.eclibUtil.getErrorMessage(resultcode);
			}

		} else {

			err.errorcode = resultcode;
			err.message = this.eclibUtil.getErrorMessage(resultcode);

		}

		if (!callback){
			return resultcode;
		}

		callback.call(this,resultcode,err);

	},

	encode: function(o_data,callback){

	},
	encodeCleanup: function(callback){

	},

	decode:function(d_data,callback){

	},

	decodeCleanup:function(callback){

	},

	getFragmentMetadata: function(fragment, fragment_metadata, callback){

	},

	setOptions: function(opts){
		__.extend(this.opt,opts);
	}
}

/*

ECLib.prototype.create = function ( ec_backend_id, k, m, w, hd, ct, backend_args,callback) {

	var instance_descriptor_id = -1;
	var err = {};

	if ( this.eclibUtil.validateInstanceCreateParams(ec_backend_id, k, m, w, hd, ct)  ){

		instance_descriptor_id = addon.create(ec_backend_id, k, m, w, hd, ct);

		if (instance_descriptor_id <=0 ){
			err.errorcode =  instance_descriptor_id ;
			err.message = this.eclibUtil.getErrorMessage(instance_descriptor_id);
		}

	} else {
		err.errorcode =  enums.ErrorCode.EINVALIDPARAMS ;
		err.message = this.eclibUtil.getErrorMessage(err.errorcode);
		instance_descriptor_id = err.errorcode ;
	}

	if (!callback){

		return instance_descriptor_id;
	}

	callback.call(this,instance_descriptor_id, err);

};

ECLib.prototype.destroy = function(instance_descriptor_id,callback){

	var resultcode = enums.ErrorCode.EINVALIDPARAMS;
	var err = {};

	if (!instance_descriptor_id){

		resultcode = addon.destroy(instance_descriptor_id);
		if ( resultcode !== 0){
			err.errorcode = resultcode;
			err.message = this.eclibUtil.getErrorMessage(resultcode);
		}

	} else {

		err.errorcode = resultcode;
		err.message = this.eclibUtil.getErrorMessage(resultcode);

	}

	if (!callback){
		return resultcode;
	}

	callback.call(this,resultcode,err);
};

ECLib.prototype.encode = function(instance_descriptor_id, orig_data, orig_data_size,callback){

	//console.log(addon.encode());

	var resultcode = enums.ErrorCode.EINVALIDPARAMS;
	var err = {};
	var result = {};

	if (this.eclibUtil.validateEncodeParams(instance_descriptor_id, orig_data, orig_data_size, callback)){

		console.log("++++++++++++++++++++++");

		addon.encode(instance_descriptor_id,orig_data,orig_data_size
			,function(r_code,encoded_data,encoded_parity,f_len){

				if (r_code ==0) {

					result.resultcode = r_code;
					result.encoded_data = encoded_data;
					result.encoded_parity = encoded_parity;
					result.fragment_len =f_len;

					//callback.call(this,result,err,self);

				} else {

					//Error occured in Server side
					err.errorcode = r_code;
					err.message = this.eclibUtil.getErrorMessage(r_code);
					//we will see what happens here
					//callback.call(this,result,err);

				}
		});

	} else {

		if (!callback){
			return resultcode;
		} else {

			err.errorcode = resultcode;
			err.message = this.eclibUtil.getErrorMessage(resultcode);

			callback.call(this,result,err);
		}

		//
	}

	//result.resultcode = 1//2/3/4/5
	//result.encoded_data = "" ,result.encoded_parity ="", result.fragment_len =12312312312312;
	//callback.call(result,err)
};

ECLib.prototype.encodeCleanup = function(instance_descriptor_id, encoded_data,encoded_parity,callback){

	console.log("JS encodeCleanup ");
	console.log(addon.encodeCleanup());
	//callback.call(resultcode,err)
};

ECLib.prototype.decode = function(instance_descriptor_id, available_fragments
							 , num_fragments, fragment_len, callback){

	console.log("JS decode #");
	console.log(addon.decode());
	//result.resultcode = 1//2/3/4/5
	//result.out_data = "" ,result.out_data_len =""
	//callback.call(result,err)
};

ECLib.prototype.decodeCleanup = function(instance_descriptor_id, data,callback){

	console.log("JS decode_cleanup #");
	console.log(addon.decodeCleanup());
	//callback.call(resultcode,err)
};

ECLib.prototype.reconstructFragment = function(instance_descriptor_id, available_fragments
	, num_fragments, fragment_len,destination_idx, callback) {

	console.log("JS reconstructFragment #");
	console.log(addon.reconstructFragment());

	//result.resultcode = 1//2/3/4/5
	//result.out_fragment = ""
	//callback.call(result,err)

};

ECLib.prototype.fragmentsNeeded = function (instance_descriptor_id,fragments_to_reconstruct
					,fragments_to_exclude,fragments_needed,callback){

	console.log("from fragmentsNeeded method");
	//callback.call(resultcode,err)
}

ECLib.prototype.getFragmentMetadata = function(fragment, fragment_metadata, callback){

	console.log("from getFragmentMetadata method");
	//callback.call(resultcode,err)

};

ECLib.prototype.isInvalidFragment = function(instance_descriptor_id, fragment, callback){

	console.log("from isInvalidFragment method");
	//callback.call(resultcode,err)
};

ECLib.prototype.verifyStripeMetadata = function (instance_descriptor_id, fragments
					, num_fragments, callback){

	console.log("from verifyStripeMetadata method");
	//callback.call(resultcode,err)
};

ECLib.prototype.getAlignedDataSize = function(instance_descriptor_id, data_len, callback){

	console.log("from getAlignedDataSize method");
	//callback.call(resultlength, err)
};

ECLib.prototype.getMinimumEncodeSize = function (instance_descriptor_id, callback){

	console.log("from getMinimumEncodeSize method");
	//callback.call(resultminimumlength, err)
};

ECLib.prototype.getFragmentSize = function(instance_descriptor_id, data_len ,callback){

	console.log("from getFragmentSize method");
	//callback.call(resultfragmentsize, err)

}; */

module.exports = ECLib <|endoftext|>