<commit_before>const _ = require('lodash');
const qs = require('querystring');
const crypto = require('crypto');
const os = require('os');
const properties = require('properties');
const got = require('got');
const semver = require('semver');
const spawn = require('child_process').spawn;

const pkg = require('../package.json');
const ua = 'logdna-cli/' + pkg.version;

const ERROR_LEVEL_TEST = /[Ee]rr(?:or)?|ERR(?:OR)?|[Cc]rit(?:ical)?|CRIT(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?/;
const WARN_LEVEL_TEST = /[Ww]arn(?:ing)?|WARN(?:ING)?/;

const log = function(msg) {
    console.log(msg || '');
};

const saveConfig = function(config, callback) {
    properties.stringify(config, {
        path: config.DEFAULT_CONF_FILE
    }, function(err) {
        if (err) {
            console.error('Error while saving to: ' + (config.DEFAULT_CONF_FILE) + ': ' + err);
        } else {
            return callback && callback();
        }
    });
};

function generateHmac(payload, secret) {
    var msg = qs.stringify(payload);
    return crypto.createHmac('sha256', secret.toString()).update(msg).digest('hex');
};

const authParams = function(config) {
    if (!config.token) {
        log('Please login first. Type \'logdna login\' or \'logdna --help\' for more info.');
        return process.exit();
    }

    var hmacParams = {
        email: config.email
        , id: config.account
        , ts: Date.now()
    };

    hmacParams.hmac = generateHmac(hmacParams, config.token);
    return hmacParams;
};

function apiCall(config, endpoint, method, params, callback) {
    if (typeof params === 'function') {
        callback = params;
        params = null;
    }

    var opts = {
        headers: {
            'user-agent': ua
        }
    };

    if (params && params.auth !== undefined) {
        if (params.auth) opts.auth = params.auth;
        delete params.auth;
        opts.query = params;

    } else {
        var hmacParams = authParams(config);
        params = _.extend(params || {}, hmacParams);
        opts.query = params;
    }

    if (method === 'post') opts.method = 'post';

    got((config.LOGDNA_APISSL ? 'https://' : 'http://') + config.LOGDNA_APIHOST + '/' + endpoint, opts)
        .then(function(res) {
            if (res.body && res.body.substring(0, 1) === '{') {
                try {
                    return callback(JSON.parse(res.body));
                } catch (err) {
                    // procedure for jsonl format
                    return callback(res.body);
                }
            }
            callback(res.body);
        })
        .catch(function(err) {
            if (err.statusCode === '403') {
                return log('Access token invalid. If you created or changed your password recently, please \'logdna login\' again. Type \'logdna --help\' for more info.');
            } else {
                return log('Error ' + err.statusCode + ': ' + err.response.body);
            }
        });
};

function levelColor(config, level) {
    if (ERROR_LEVEL_TEST.test(level)) return '\x1b[38;5;255;48;5;203m';
    if (WARN_LEVEL_TEST.test(level)) return '\x1b[38;5;255;48;5;208m';
    return '\x1b[38;5;247;48;5;239m';
};

const apiGet = function(config, endpoint, params, callback) {
    apiCall(config, endpoint, 'get', params, callback);
};

const apiPost = function(config, endpoint, params, callback) {
    apiCall(config, endpoint, 'post', params, callback);
};

const renderLine = function(config, line, params) {

    var t = new Date(line._ts);
    params = params || {};

    if (params.json) return log(JSON.stringify(line));

    if (config.SUPPORTS_COLORS) {
        log('\x1b[38;5;240m' + t.toString().substring(4, 11) + t.toString().substring(16, 24) +
            ' \x1b[38;5;166m' + line._host +
            ' \x1b[38;5;74m' + line._app +
            ' ' + (line.level ? levelColor(config, line.level) + ' ' + line.level + ' \x1b[0m ' : '') +
            '\x1b[38;5;246m' + (line.message || line._line) +
            '\x1b[0m');
    } else {
        log(t.toString().substring(4, 11) + t.toString().substring(16, 24) +
            ' ' + line._host +
            ' ' + line._app +
            ' ' + (line.level ? '[' + line.level + '] ' : '') +
            (line.message || line._line));
    };
};

const performUpgrade = function(config, force, callback) {
    if (typeof force === 'function') {
        callback = force;
        force = null;
    }
    if (force || Date.now() - (config.updatecheck || 0) > config.UPDATE_CHECK_INTERVAL) {
        if (os.platform() === 'darwin') {
            config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace('PLATFORM', 'mac');
            config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace('PLATFORM', 'mac');

        } else if (os.platform() === 'linux') {
            config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace('PLATFORM', 'linux');
            config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace('PLATFORM', 'linux');

        } else if (os.platform() === 'win32') {
            // config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace("PLATFORM", "windows");
            // config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace("PLATFORM", "windows");
            return callback && callback(); // ignore for now until this works
        }

        if (force) log('Checking for updates...');
        var force_timeout_ms = 30000;
        var default_timeout_ms = 2500;
        got(config.VERSION_CHECK_URL, { timeout: (force ? force_timeout_ms : default_timeout_ms) })
            .then(function(res) {
                if (res.body) res.body = res.body.replace(/\r/g, '').replace(/\n/g, '');
                if (!semver.valid(res.body)) {
                    // error during update check, set to check again in a day
                    config.updatecheck = Date.now() - config.UPDATE_CHECK_INTERVAL + 86400000;
                    saveConfig(config);
                    return callback && callback();
                }

                config.updatecheck = Date.now();
                saveConfig(config);

                if (semver.gt(res.body, pkg.version)) {
                    // update needed
                    log('Performing upgrade from ' + pkg.version + ' to ' + res.body + '...');
                    var shell = spawn('/bin/bash', ['-c'
                        , 'if [[ ! -z $(which curl) ]]; then curl -so /tmp/logdna.gz ' + config.UPDATE_CHECK_URL + '; elif [[ ! -z $(which wget) ]]; then wget -qO /tmp/logdna.gz ' + config.UPDATE_CHECK_URL + '; fi; gunzip -f /tmp/logdna.gz; cp -f /tmp/logdna /usr/local/logdna/bin/logdna; chmod 777 /usr/local/logdna/bin/logdna 2> /dev/null; echo -n "Successfully upgraded logdna-cli to "; /usr/local/bin/logdna -v'
                    ], {
                        stdio: 'inherit'
                    });
                    shell.on('close', function() {
                        if (!force && process.argv[process.argv.length - 1].toLowerCase() !== 'update') log('Please run your command again');
                    });
                    return;

                } else {
                    return callback && callback(); // no update necessary, run rest of program
                }
            })
            .catch(function(err) {
                return log('Error ' + err.statusCode + ': ' + err.response.body);
            });

    } else {
        return callback && callback(); // no check necessary, run rest of program
    }
};

exports.saveConfig = saveConfig;
exports.log = log;
exports.apiGet = apiGet;
exports.apiPost = apiPost;
exports.renderLine = renderLine;
exports.authParams = authParams;
exports.performUpgrade = performUpgrade;
<commit_msg>Some Changes<commit_after>const _ = require('lodash');
const qs = require('querystring');
const crypto = require('crypto');
const os = require('os');
const properties = require('properties');
const got = require('got');
const semver = require('semver');
const spawn = require('child_process').spawn;

const pkg = require('../package.json');
const ua = 'logdna-cli/' + pkg.version;

const ERROR_LEVEL_TEST = /[Ee]rr(?:or)?|ERR(?:OR)?|[Cc]rit(?:ical)?|CRIT(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?/;
const WARN_LEVEL_TEST = /[Ww]arn(?:ing)?|WARN(?:ING)?/;

const log = function(msg) {
    console.log(msg || '');
};

const saveConfig = function(config, callback) {
    properties.stringify(config, {
        path: config.DEFAULT_CONF_FILE
    }, function(err) {
        if (err) {
            console.error('Error while saving to: ' + (config.DEFAULT_CONF_FILE) + ': ' + err);
        } else {
            return callback && callback();
        }
    });
};

function generateHmac(payload, secret) {
    var msg = qs.stringify(payload);
    return crypto.createHmac('sha256', secret.toString()).update(msg).digest('hex');
};

const authParams = function(config) {
    if (!config.token) {
        log('Please login first. Type \'logdna login\' or \'logdna --help\' for more info.');
        return process.exit();
    }

    var hmacParams = {
        email: config.email
        , id: config.account
        , ts: Date.now()
    };

    hmacParams.hmac = generateHmac(hmacParams, config.token);
    return hmacParams;
};

function apiCall(config, endpoint, method, params, callback) {
    if (typeof params === 'function') {
        callback = params;
        params = null;
    }

    var opts = {
        headers: {
            'user-agent': ua
        }
    };

    if (params && params.auth !== undefined) {
        if (params.auth) opts.auth = params.auth;
        delete params.auth;
        opts.query = params;

    } else {
        var hmacParams = authParams(config);
        params = _.extend(params || {}, hmacParams);
        opts.query = params;
    }

    if (method === 'post') opts.method = 'post';

    got((config.LOGDNA_APISSL ? 'https://' : 'http://') + config.LOGDNA_APIHOST + '/' + endpoint, opts)
        .then((res) => {
            if (res.body && res.body.substring(0, 1) === '{') {
                try {
                    return callback(JSON.parse(res.body));
                } catch (err) {
                    // procedure for jsonl format
                    return callback(res.body);
                }
            }
            callback(res.body);
        })
        .catch((err) => {
            if (err.statusCode === '403') {
                return log('Access token invalid. If you created or changed your password recently, please \'logdna login\' again. Type \'logdna --help\' for more info.');
            } else {
                return log('Error ' + err.statusCode + ': ' + (err.response && err.response.body ? err.response.body : err));
            }
        });
};

function levelColor(config, level) {
    if (ERROR_LEVEL_TEST.test(level)) return '\x1b[38;5;255;48;5;203m';
    if (WARN_LEVEL_TEST.test(level)) return '\x1b[38;5;255;48;5;208m';
    return '\x1b[38;5;247;48;5;239m';
};

const apiGet = function(config, endpoint, params, callback) {
    apiCall(config, endpoint, 'get', params, callback);
};

const apiPost = function(config, endpoint, params, callback) {
    apiCall(config, endpoint, 'post', params, callback);
};

const renderLine = function(config, line, params) {

    var t = new Date(line._ts);
    params = params || {};

    if (params.json) return log(JSON.stringify(line));

    if (config.SUPPORTS_COLORS) {
        log('\x1b[38;5;240m' + t.toString().substring(4, 11) + t.toString().substring(16, 24) +
            ' \x1b[38;5;166m' + line._host +
            ' \x1b[38;5;74m' + line._app +
            ' ' + (line.level ? levelColor(config, line.level) + ' ' + line.level + ' \x1b[0m ' : '') +
            '\x1b[38;5;246m' + (line.message || line._line) +
            '\x1b[0m');
    } else {
        log(t.toString().substring(4, 11) + t.toString().substring(16, 24) +
            ' ' + line._host +
            ' ' + line._app +
            ' ' + (line.level ? '[' + line.level + '] ' : '') +
            (line.message || line._line));
    };
};

const performUpgrade = function(config, force, callback) {
    if (typeof force === 'function') {
        callback = force;
        force = null;
    }
    if (force || Date.now() - (config.updatecheck || 0) > config.UPDATE_CHECK_INTERVAL) {
        if (os.platform() === 'darwin') {
            config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace('PLATFORM', 'mac');
            config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace('PLATFORM', 'mac');

        } else if (os.platform() === 'linux') {
            config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace('PLATFORM', 'linux');
            config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace('PLATFORM', 'linux');

        } else if (os.platform() === 'win32') {
            // config.VERSION_CHECK_URL = config.VERSION_CHECK_URL.replace("PLATFORM", "windows");
            // config.UPDATE_CHECK_URL = config.UPDATE_CHECK_URL.replace("PLATFORM", "windows");
            return callback && callback(); // ignore for now until this works
        }

        if (force) log('Checking for updates...');
        var force_timeout_ms = 30000;
        var default_timeout_ms = 2500;
        got(config.VERSION_CHECK_URL, { timeout: (force ? force_timeout_ms : default_timeout_ms) })
            .then(function(res) {
                if (res.body) res.body = res.body.replace(/\r/g, '').replace(/\n/g, '');
                if (!semver.valid(res.body)) {
                    // error during update check, set to check again in a day
                    config.updatecheck = Date.now() - config.UPDATE_CHECK_INTERVAL + 86400000;
                    saveConfig(config);
                    return callback && callback();
                }

                config.updatecheck = Date.now();
                saveConfig(config);

                if (semver.gt(res.body, pkg.version)) {
                    // update needed
                    log('Performing upgrade from ' + pkg.version + ' to ' + res.body + '...');
                    var shell = spawn('/bin/bash', ['-c'
                        , 'if [[ ! -z $(which curl) ]]; then curl -so /tmp/logdna.gz ' + config.UPDATE_CHECK_URL + '; elif [[ ! -z $(which wget) ]]; then wget -qO /tmp/logdna.gz ' + config.UPDATE_CHECK_URL + '; fi; gunzip -f /tmp/logdna.gz; cp -f /tmp/logdna /usr/local/logdna/bin/logdna; chmod 777 /usr/local/logdna/bin/logdna 2> /dev/null; echo -n "Successfully upgraded logdna-cli to "; /usr/local/bin/logdna -v'
                    ], {
                        stdio: 'inherit'
                    });
                    shell.on('close', function() {
                        if (!force && process.argv[process.argv.length - 1].toLowerCase() !== 'update') log('Please run your command again');
                    });
                    return;

                } else {
                    return callback && callback(); // no update necessary, run rest of program
                }
            })
            .catch(function(err) {
                return log('Error ' + err.statusCode + ': ' + err.response.body);
            });

    } else {
        return callback && callback(); // no check necessary, run rest of program
    }
};

exports.saveConfig = saveConfig;
exports.log = log;
exports.apiGet = apiGet;
exports.apiPost = apiPost;
exports.renderLine = renderLine;
exports.authParams = authParams;
exports.performUpgrade = performUpgrade;
<|endoftext|>


<commit_before>var crypto = require('crypto');

var _timer = null;  // holds the timeout timer

/*
 * blends two objects together, with second overriding the first
 * @param first {Object}
 * @param second {Object}
 */
function blend(first, second) {
    var mix = {};

    for(var key in first)
        mix[key] = first[key];
    for(var key in second)
        mix[key] = second[key];

    return mix;
}

/*
 * matches a criteria object with a message header
 * @param criteria {Object}
 * @param header {Object}
 * @return {Boolean}: true if they match, false otherwise
 */
function match(criteria, header) {
    var matches_source = (criteria.from === header.from || criteria.from === -1);
    var matches_subject = (criteria.subject === header.subject || criteria.subject === "-1");

    return matches_source && matches_subject;
}

/*
 * starts a timeout timer
 * @param callback {Function}
 */
function startTimeout(callback) {
    _timer = setTimeout(callback, 2000);
};

/*
 * stops a running timeout timer
 */
function stopTimeout() {
    clearTimeout(_timer);
}

/*
 * encrypts a message and signs it with HMAC
 * @param msg {Object}: the message to be secured
 * @param key {String}: the secret key to be used
 * @return {Object}: the secured message
 */
function secure(msg, key) {
    var cipher = crypto.createCipher('aes-256-ctr', key);
    var hmac = crypto.createHmac('sha256', key);

    var ciphertext = cipher.update(JSON.stringify(msg), 'utf8', 'base64') + cipher.final('base64');

    hmac.update(ciphertext);
    var mac = hmac.digest('base64');

    return {payload: ciphertext, mac: mac};
}

/* verifies an encrypted message and decryptes it if verified
 * @param msg {Object}: the encrypted message
 * @param key {String}: the secret key to be used
 * @return {Object|Boolean}: the decrypted message if verified, false otherwise
 */
function verify(msg, key) {
    var hmac = crypto.createHmac('sha256', key);

    hmac.update(msg.payload);
    var mac = hmac.digest('base64');

    if(mac === msg.mac) {
        var decipher = crypto.createDecipher('aes-256-ctr', key);
        var plaintext = decipher.update(msg.payload, 'base64', 'utf8') + decipher.final('utf8');

        // attempt to parse as json
        try {
            return JSON.parse(plaintext);
        }
        catch(err) {
            // if failed, return plaintext directly
            return plaintext;
        }
    }

    return false;
}

/*
 * returns a wrapper over crypto.DiffieHellman
 * @param prime {String}: a prime number to initialize with (optional)
 * @return {Object}
 */
function diffieHellman(prime) {
    var dhObj = null;
    var wrapper = {};

    if(!!prime)
        dhObj = crypto.createDiffieHellman(prime, 'base64');
    else
        dhObj = crypto.createDiffieHellman(512);

    wrapper.prime = dhObj.getPrime('base64');
    wrapper.publicKey = dhObj.generateKeys('base64');

    wrapper.computeSecret = function(remotePublicKey) {
        return dhObj.computeSecret(remotePublicKey, 'base64', 'base64');
    };

    return wrapper;
}

module.exports = {
    blend: blend,
    match: match,
    startTimeout: startTimeout,
    stopTimeout: stopTimeout,
    secure: secure,
    verify: verify,
    diffieHellman: diffieHellman
};
<commit_msg>updated secure function to handle non-json messages<commit_after>var crypto = require('crypto');

var _timer = null;  // holds the timeout timer

/*
 * blends two objects together, with second overriding the first
 * @param first {Object}
 * @param second {Object}
 */
function blend(first, second) {
    var mix = {};

    for(var key in first)
        mix[key] = first[key];
    for(var key in second)
        mix[key] = second[key];

    return mix;
}

/*
 * matches a criteria object with a message header
 * @param criteria {Object}
 * @param header {Object}
 * @return {Boolean}: true if they match, false otherwise
 */
function match(criteria, header) {
    var matches_source = (criteria.from === header.from || criteria.from === -1);
    var matches_subject = (criteria.subject === header.subject || criteria.subject === "-1");

    return matches_source && matches_subject;
}

/*
 * starts a timeout timer
 * @param callback {Function}
 */
function startTimeout(callback) {
    _timer = setTimeout(callback, 2000);
};

/*
 * stops a running timeout timer
 */
function stopTimeout() {
    clearTimeout(_timer);
}

/*
 * encrypts a message and signs it with HMAC
 * @param msg {Object}: the message to be secured
 * @param key {String}: the secret key to be used
 * @return {Object}: the secured message
 */
function secure(msg, key) {
    var cipher = crypto.createCipher('aes-256-ctr', key);
    var hmac = crypto.createHmac('sha256', key);
    var plaintext = (typeof msg === "object") ? JSON.stringify(msg) : msg.toString();

    var ciphertext = cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');

    hmac.update(ciphertext);
    var mac = hmac.digest('base64');

    return {payload: ciphertext, mac: mac};
}

/* verifies an encrypted message and decryptes it if verified
 * @param msg {Object}: the encrypted message
 * @param key {String}: the secret key to be used
 * @return {Object|Boolean}: the decrypted message if verified, false otherwise
 */
function verify(msg, key) {
    var hmac = crypto.createHmac('sha256', key);

    hmac.update(msg.payload);
    var mac = hmac.digest('base64');

    if(mac === msg.mac) {
        var decipher = crypto.createDecipher('aes-256-ctr', key);
        var plaintext = decipher.update(msg.payload, 'base64', 'utf8') + decipher.final('utf8');

        // attempt to parse as json
        try {
            return JSON.parse(plaintext);
        }
        catch(err) {
            // if failed, return plaintext directly
            return plaintext;
        }
    }

    return false;
}

/*
 * returns a wrapper over crypto.DiffieHellman
 * @param prime {String}: a prime number to initialize with (optional)
 * @return {Object}
 */
function diffieHellman(prime) {
    var dhObj = null;
    var wrapper = {};

    if(!!prime)
        dhObj = crypto.createDiffieHellman(prime, 'base64');
    else
        dhObj = crypto.createDiffieHellman(512);

    wrapper.prime = dhObj.getPrime('base64');
    wrapper.publicKey = dhObj.generateKeys('base64');

    wrapper.computeSecret = function(remotePublicKey) {
        return dhObj.computeSecret(remotePublicKey, 'base64', 'base64');
    };

    return wrapper;
}

module.exports = {
    blend: blend,
    match: match,
    startTimeout: startTimeout,
    stopTimeout: stopTimeout,
    secure: secure,
    verify: verify,
    diffieHellman: diffieHellman
};
<|endoftext|>


<commit_before>/**
 * @module utils
 */

'use strict';

const dnode = require('dnode');
const net = require('net');
const fs = require('fs');
const storj = require('storj-lib');
const {bitcore} = storj.deps;
const du = require('du');          // Get amount used
const disk = require('diskusage'); // Get amount free
const assert = require('assert');
const bytes = require('bytes');

/**
 * Validate the given payout address
 * @param {String} address
 */
exports._isValidPayoutAddress = function(address) {
  return bitcore.Address.isValid(address) ||
         bitcore.Address.isValid(address, bitcore.Networks.testnet) ||
         this.isValidEthereumAddress(address);
};

/**
 * Validate the given payout address is an Ethereum address
 * @param {String} address
 */
exports.isValidEthereumAddress = function(address) {
  //Disallow contract and contract owner addresses
  //Stops users from accidentally copying the wrong address
  const disallowAddresses = [
    '0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac',
    '0x00f6bf3c5033e944feddb3dc8ffb4d47af17ef0b'
  ];
  if (typeof address !== 'string') {
    return false;
  } else if (disallowAddresses.indexOf(address.toLowerCase()) >= 0) {
    return false;
  }
  return /^0x([0-9A-Fa-f]{2}){20}$/.test(address);
};

/**
 * Validate the given dataserv directory
 * @param {String} directory
 */
exports._isValidDirectory = function(directory) {
  return this.existsSync(directory);
};

/**
 * Validate the given size
 * @param {String} size
 */
exports._isValidSize = function(size) {
  return typeof size === 'number'
    && size >= 0
    && size <= 8e+12; // 8TB
};

/**
 * Validates a given tab config
 * @param {Object} config
 */
exports.validate = function(config) {
  assert(this._isValidPayoutAddress(config.paymentAddress),
         'Invalid payout address');
  assert(this._isValidDirectory(config.storagePath), 'Invalid directory');
  assert(this._isValidSize(bytes.parse(config.storageAllocation)),
         'Invalid storage size');
  assert(this._isValidDirectory(config.storagePath),
         'Could not create Shard Directory');
};

/**
 * Attempts to apply common fixes to a config
 * @param {Object} config
 */
exports.repairConfig = function(config) {
  // Check to see if the size is not using a storage unit
  if(!isNaN(parseInt(config.storageAllocation))
    && this._isValidSize(config.storageAllocation)) {
      config.storageAllocation = config.storageAllocation.toString() + 'B';
  }
    return config;
};

/**
 * Validates the space being allocated exists
 * @param {Object} config
 */
exports.validateAllocation = function(conf, callback) {
  const self = this;

  if (!self._isValidStorageAllocationFormat(conf.storageAllocation)) {
    if (isNaN(conf.storageAllocation)) {
      return callback(
        new Error('Invalid storage size specified: '+ conf.storageAllocation)
      );
    }

    conf.storageAllocation = conf.storageAllocation.toString() + 'B';
  }

  self.getFreeSpace(conf.storagePath, function(err, free) {
    var allocatedSpace = bytes.parse(conf.storageAllocation);
    if (err) {
      callback(err);
    }

    self.getDirectorySize(conf.storagePath, function(err, usedSpaceBytes) {
      if (err) {
        return callback(err);
      }

      if (allocatedSpace > free + usedSpaceBytes) {
        return callback(new Error('Invalid storage size: '+
          -(free + usedSpaceBytes - allocatedSpace) +' bytes missing'));
      }

      return callback(null);
    });
  });
};

/**
 * Check if file exists
 * @param {String} file - Path to file
 */
exports.existsSync = function(file) {
  try {
    fs.statSync(file);
  } catch(err) {
    return !(err);
  }

  return true;
};

/**
 * Check if StorageAllocation is formatted properly (Size + Unit)
 * @param {String} storage - storage Allocation from config
 */
exports._isValidStorageAllocationFormat = function(storageAllocation) {
    if (!storageAllocation.toString().match(
          /[0-9]+([Tt]|[Mm]|[Gg]|[Kk])?[Bb]/g)
    ) {
      return false;
    }

    return true;
};

/**
 * Recursively determines the size of a directory
 * @param {String} dir - Directory to traverse
 * @param {Function} callback
 */
exports.getDirectorySize = function(dir, callback) {
  /* istanbul ignore next */
  du(dir, {
    filter: function(f) {
      return f.indexOf('contracts.db') !== -1 ||
             f.indexOf('sharddata.kfs') !== -1;
    }
  }, callback);
};

/**
 * Get free space on disk of path
 * @param {String} path
 */
/* istanbul ignore next */
exports.getFreeSpace = function(path, callback) {
  if (!exports.existsSync(path)) {
    return callback(null, 0);
  }

  disk.check(path, function(err, info) {
    if (err) {
      return callback(err);
    }

    return callback(null, info.available);
  });
};

/**
 * Checks whether a port is currently in use or open
 * Callback is of form (err, result)
 * @param {Number} port
 * @param {Function} callback
 */
exports.portIsAvailable = function(port, callback) {
  if(typeof port !== 'number' || port < 0 || port > 65535) {
    return callback('Invalid port');
  } else if (port <= 1024) {
    return callback(
      'Using a port in the well-known range is strongly discouraged');
  }
  let testServer = net.createServer()
  .once('error', function() {
    testServer.once('close', function() {
      callback(null, false);
    })
    .close();
  })
  .once('listening', function() {
    testServer.once('close', function() {
      callback(null, true);
    })
    .close();
  })
  .listen(port);
};

/**
 * Checks the status of the daemon RPC server
 * @param {Number} port
 * @param {Function} callback
 * @param {String} hostname - optional
 */
exports.checkDaemonRpcStatus = function(port, callback, hostname = null) {
  if (!hostname) {
    hostname = '127.0.0.1';
  }
  const sock = net.connect(port, hostname);

  sock.once('error', function() {
    callback(false);
  });

  sock.once('connect', () => {
    sock.end();
    callback(true);
  });
};

/**
 * Connects to the daemon and callback with rpc
 * @param {Number} port
 * @param {Function} callback
 * @param {String} hostname - optional
 */
exports.connectToDaemon = function(port, callback, hostname = null) {
  if (!hostname) {
    hostname = '127.0.0.1';
  }
  const sock = dnode.connect(hostname, port);

  sock.on('error', function() {
    process.exitCode = 1;
    console.error('\n  daemon is not running, try: storjshare daemon');
  });

  sock.on('remote', (rpc) => callback(rpc, sock));
};

/**
 * Get node Id by Private Key
 * @param {String} privateKey
 */
 exports.getNodeID = function(privateKey) {
  let nodeId = null;
  try {
    nodeId = storj.KeyPair(privateKey).getNodeID();
  } catch (err) {
    return null;
  }

  return nodeId;
};
<commit_msg>Allow nodes with an allocated space size of up to 8TiB.<commit_after>/**
 * @module utils
 */

'use strict';

const dnode = require('dnode');
const net = require('net');
const fs = require('fs');
const storj = require('storj-lib');
const {bitcore} = storj.deps;
const du = require('du');          // Get amount used
const disk = require('diskusage'); // Get amount free
const assert = require('assert');
const bytes = require('bytes');

/**
 * Validate the given payout address
 * @param {String} address
 */
exports._isValidPayoutAddress = function(address) {
  return bitcore.Address.isValid(address) ||
         bitcore.Address.isValid(address, bitcore.Networks.testnet) ||
         this.isValidEthereumAddress(address);
};

/**
 * Validate the given payout address is an Ethereum address
 * @param {String} address
 */
exports.isValidEthereumAddress = function(address) {
  //Disallow contract and contract owner addresses
  //Stops users from accidentally copying the wrong address
  const disallowAddresses = [
    '0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac',
    '0x00f6bf3c5033e944feddb3dc8ffb4d47af17ef0b'
  ];
  if (typeof address !== 'string') {
    return false;
  } else if (disallowAddresses.indexOf(address.toLowerCase()) >= 0) {
    return false;
  }
  return /^0x([0-9A-Fa-f]{2}){20}$/.test(address);
};

/**
 * Validate the given dataserv directory
 * @param {String} directory
 */
exports._isValidDirectory = function(directory) {
  return this.existsSync(directory);
};

/**
 * Validate the given size
 * @param {String} size
 */
exports._isValidSize = function(size) {
  return typeof size === 'number'
    && size >= 0
    && size <= 8 * Math.pow(2, 30); // 8TiB
};

/**
 * Validates a given tab config
 * @param {Object} config
 */
exports.validate = function(config) {
  assert(this._isValidPayoutAddress(config.paymentAddress),
         'Invalid payout address');
  assert(this._isValidDirectory(config.storagePath), 'Invalid directory');
  assert(this._isValidSize(bytes.parse(config.storageAllocation)),
         'Invalid storage size');
  assert(this._isValidDirectory(config.storagePath),
         'Could not create Shard Directory');
};

/**
 * Attempts to apply common fixes to a config
 * @param {Object} config
 */
exports.repairConfig = function(config) {
  // Check to see if the size is not using a storage unit
  if(!isNaN(parseInt(config.storageAllocation))
    && this._isValidSize(config.storageAllocation)) {
      config.storageAllocation = config.storageAllocation.toString() + 'B';
  }
    return config;
};

/**
 * Validates the space being allocated exists
 * @param {Object} config
 */
exports.validateAllocation = function(conf, callback) {
  const self = this;

  if (!self._isValidStorageAllocationFormat(conf.storageAllocation)) {
    if (isNaN(conf.storageAllocation)) {
      return callback(
        new Error('Invalid storage size specified: '+ conf.storageAllocation)
      );
    }

    conf.storageAllocation = conf.storageAllocation.toString() + 'B';
  }

  self.getFreeSpace(conf.storagePath, function(err, free) {
    var allocatedSpace = bytes.parse(conf.storageAllocation);
    if (err) {
      callback(err);
    }

    self.getDirectorySize(conf.storagePath, function(err, usedSpaceBytes) {
      if (err) {
        return callback(err);
      }

      if (allocatedSpace > free + usedSpaceBytes) {
        return callback(new Error('Invalid storage size: '+
          -(free + usedSpaceBytes - allocatedSpace) +' bytes missing'));
      }

      return callback(null);
    });
  });
};

/**
 * Check if file exists
 * @param {String} file - Path to file
 */
exports.existsSync = function(file) {
  try {
    fs.statSync(file);
  } catch(err) {
    return !(err);
  }

  return true;
};

/**
 * Check if StorageAllocation is formatted properly (Size + Unit)
 * @param {String} storage - storage Allocation from config
 */
exports._isValidStorageAllocationFormat = function(storageAllocation) {
    if (!storageAllocation.toString().match(
          /[0-9]+([Tt]|[Mm]|[Gg]|[Kk])?[Bb]/g)
    ) {
      return false;
    }

    return true;
};

/**
 * Recursively determines the size of a directory
 * @param {String} dir - Directory to traverse
 * @param {Function} callback
 */
exports.getDirectorySize = function(dir, callback) {
  /* istanbul ignore next */
  du(dir, {
    filter: function(f) {
      return f.indexOf('contracts.db') !== -1 ||
             f.indexOf('sharddata.kfs') !== -1;
    }
  }, callback);
};

/**
 * Get free space on disk of path
 * @param {String} path
 */
/* istanbul ignore next */
exports.getFreeSpace = function(path, callback) {
  if (!exports.existsSync(path)) {
    return callback(null, 0);
  }

  disk.check(path, function(err, info) {
    if (err) {
      return callback(err);
    }

    return callback(null, info.available);
  });
};

/**
 * Checks whether a port is currently in use or open
 * Callback is of form (err, result)
 * @param {Number} port
 * @param {Function} callback
 */
exports.portIsAvailable = function(port, callback) {
  if(typeof port !== 'number' || port < 0 || port > 65535) {
    return callback('Invalid port');
  } else if (port <= 1024) {
    return callback(
      'Using a port in the well-known range is strongly discouraged');
  }
  let testServer = net.createServer()
  .once('error', function() {
    testServer.once('close', function() {
      callback(null, false);
    })
    .close();
  })
  .once('listening', function() {
    testServer.once('close', function() {
      callback(null, true);
    })
    .close();
  })
  .listen(port);
};

/**
 * Checks the status of the daemon RPC server
 * @param {Number} port
 * @param {Function} callback
 * @param {String} hostname - optional
 */
exports.checkDaemonRpcStatus = function(port, callback, hostname = null) {
  if (!hostname) {
    hostname = '127.0.0.1';
  }
  const sock = net.connect(port, hostname);

  sock.once('error', function() {
    callback(false);
  });

  sock.once('connect', () => {
    sock.end();
    callback(true);
  });
};

/**
 * Connects to the daemon and callback with rpc
 * @param {Number} port
 * @param {Function} callback
 * @param {String} hostname - optional
 */
exports.connectToDaemon = function(port, callback, hostname = null) {
  if (!hostname) {
    hostname = '127.0.0.1';
  }
  const sock = dnode.connect(hostname, port);

  sock.on('error', function() {
    process.exitCode = 1;
    console.error('\n  daemon is not running, try: storjshare daemon');
  });

  sock.on('remote', (rpc) => callback(rpc, sock));
};

/**
 * Get node Id by Private Key
 * @param {String} privateKey
 */
 exports.getNodeID = function(privateKey) {
  let nodeId = null;
  try {
    nodeId = storj.KeyPair(privateKey).getNodeID();
  } catch (err) {
    return null;
  }

  return nodeId;
};
<|endoftext|>


<commit_before>module.exports.uriToFilename = uriToFilename
module.exports.uriToRelativeFilename = uriToRelativeFilename
module.exports.getBaseUri = getBaseUri
module.exports.pathBasename = pathBasename
module.exports.getFullUri = getFullUri
module.exports.hasSuffix = hasSuffix
module.exports.parse = parse
module.exports.serialize = serialize
module.exports.translate = translate
module.exports.stringToStream = stringToStream
module.exports.reqToPath = reqToPath
module.exports.debrack = debrack
module.exports.stripLineEndings = stripLineEndings
module.exports.fullUrlForReq = fullUrlForReq
module.exports.routeResolvedFile = routeResolvedFile
module.exports.getQuota = getQuota
module.exports.overQuota = overQuota

const fs = require('fs-extra')
const path = require('path')
const util = require('util')
const $rdf = require('rdflib')
const from = require('from2')
const url = require('url')
const debug = require('./debug').other
const getSize = require('get-folder-size')
var ns = require('solid-namespace')($rdf)

/**
 * Returns a fully qualified URL from an Express.js Request object.
 * (It's insane that Express does not provide this natively.)
 *
 * Usage:
 *
 *   ```
 *   console.log(util.fullUrlForReq(req))
 *   // -> https://example.com/path/to/resource?q1=v1
 *   ```
 *
 * @param req {IncomingRequest}
 *
 * @return {string}
 */
function fullUrlForReq (req) {
  let fullUrl = url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: url.resolve(req.baseUrl, req.path),
    query: req.query
  })

  return fullUrl
}

/**
 * Removes the `<` and `>` brackets around a string and returns it.
 * Used by the `allow` handler in `verifyDelegator()` logic.
 * @method debrack
 *
 * @param s {string}
 *
 * @return {string}
 */
function debrack (s) {
  if (!s || s.length < 2) {
    return s
  }
  if (s[0] !== '<') {
    return s
  }
  if (s[s.length - 1] !== '>') {
    return s
  }
  return s.substring(1, s.length - 1)
}

function uriToFilename (uri, base) {
  const decoded = uri.split('/').map(decodeURIComponent).join('/')
  let filename = path.join(base, decoded)
  // Make sure filename ends with '/'  if filename exists and is a directory.
  // TODO this sync operation can be avoided and can be left
  // to do, to other components, see `ldp.get`
  try {
    const fileStats = fs.statSync(filename)
    if (fileStats.isDirectory() && !filename.endsWith('/')) {
      filename += '/'
    } else if (fileStats.isFile() && filename.endsWith('/')) {
      filename = filename.substr(0, filename.length - 1)
    }
  } catch (err) {}
  return filename
}

function uriToRelativeFilename (uri, base) {
  const filename = uriToFilename(uri, base)
  const relative = path.relative(base, filename)
  return relative
}

function getBaseUri (req) {
  // Obtain the protocol from the configured server URI
  // (in case the server is running behind a reverse proxy)
  const locals = req.app.locals
  const serverUri = locals.host.serverUri
  const protocol = serverUri.replace(/:.*/, '')

  return `${protocol || req.protocol}://${req.get('host')}`
}

/**
 * Composes and returns the fully-qualified URI for the request, to be used
 * as a base URI for RDF parsing or serialization. For example, if a request
 * is to `Host: example.com`, `GET /files/` using the `https:` protocol,
 * then:
 *
 *   ```
 *   getFullUri(req)  // -> 'https://example.com/files/'
 *   ```
 *
 * @param req {IncomingMessage}
 *
 * @return {string}
 */
function getFullUri (req) {
  return getBaseUri(req) + url.resolve(req.baseUrl, req.path)
}

function pathBasename (fullpath) {
  let bname = ''
  if (fullpath) {
    bname = (fullpath.lastIndexOf('/') === fullpath.length - 1)
      ? ''
      : path.basename(fullpath)
  }
  return bname
}

function hasSuffix (path, suffixes) {
  for (let i in suffixes) {
    if (path.indexOf(suffixes[i], path.length - suffixes[i].length) !== -1) {
      return true
    }
  }
  return false
}

function parse (data, baseUri, contentType, callback) {
  const graph = $rdf.graph()
  try {
    return $rdf.parse(data, graph, baseUri, contentType, callback)
  } catch (err) {
    return callback(err)
  }
}

function serialize (graph, baseUri, contentType, callback) {
  try {
    // target, kb, base, contentType, callback
    $rdf.serialize(null, graph, baseUri, contentType, function (err, result) {
      if (err) {
        console.log(err)
        return callback(err)
      }
      if (result === undefined) {
        return callback(new Error('Error serializing the graph to ' +
          contentType))
      }

      return callback(null, result)
    })
  } catch (err) {
    console.log(err)
    callback(err)
  }
}

function translate (stream, baseUri, from, to, callback) {
  // Handle Turtle Accept header
  if (to === 'text/turtle' ||
    to === 'text/n3' ||
    to === 'application/turtle' ||
    to === 'application/n3') {
    to = 'text/turtle'
  }

  let data = ''
  stream
    .on('data', function (chunk) {
      data += chunk
    })
    .on('end', function () {
      parse(data, baseUri, from, function (err, graph) {
        if (err) return callback(err)
        serialize(graph, baseUri, to, function (err, data) {
          if (err) return callback(err)
          callback(null, data)
        })
      })
    })
}

function stringToStream (string) {
  return from(function (size, next) {
    // if there's no more content
    // left in the string, close the stream.
    if (!string || string.length <= 0) {
      return next(null, null)
    }

    // Pull in a new chunk of text,
    // removing it from the string.
    const chunk = string.slice(0, size)
    string = string.slice(size)

    // Emit "chunk" from the stream.
    next(null, chunk)
  })
}

/**
 * Removes line endings from a given string. Used for WebID TLS Certificate
 * generation.
 *
 * @param obj {string}
 *
 * @return {string}
 */
function stripLineEndings (obj) {
  if (!obj) { return obj }

  return obj.replace(/(\r\n|\n|\r)/gm, '')
}

function reqToPath (req) {
  const ldp = req.app.locals.ldp
  const root = ldp.multiuser ? ldp.root + req.hostname + '/' : ldp.root
  return uriToFilename(req.path, root)
}

/**
 * Adds a route that serves a static file from another Node module
 */
function routeResolvedFile (router, path, file, appendFileName = true) {
  const fullPath = appendFileName ? path + file.match(/[^/]+$/) : path
  const fullFile = require.resolve(file)
  router.get(fullPath, (req, res) => res.sendFile(fullFile))
}

/**
 * Returns the number of bytes that the user owning the requested POD
 * may store or Infinity if no limit
 */

async function getQuota (root, serverUri) {
  const filename = path.join(root, 'settings/serverSide.ttl')
  var quota = Infinity
  var prefs
  try {
    prefs = await _asyncReadfile(filename)
  } catch (error) {
    debug('Setting no quota. While reading serverSide.ttl, got ' + error)
    return Infinity
  }
  var graph = $rdf.graph()
  const storageUri = serverUri + '/'
  try {
    $rdf.parse(prefs, graph, storageUri, 'text/turtle')
  } catch (error) {
    throw new Error('Failed to parse serverSide.ttl, got ' + error)
  }
  const lit = graph.each($rdf.sym(storageUri), ns.solid('storageQuota'), undefined)[0]
  if (lit) {
    quota = lit.value
    const unitUri = 'http://www.w3.invalid/ns#'
    // The following should be encoded in the ontology
    switch (lit.datatype.value) {
      case unitUri + 'kilobyte':
        quota *= 1000
        break
      case unitUri + 'megabyte':
        quota *= 1000000
        break
      case unitUri + 'gigabyte':
        quota *= 1000000000
        break
    }
  }
  return quota
}

/**
 * Returns true of the user has exceeded their quota
 */

async function overQuota (root, serverUri) {
  let quota = await getQuota(root, serverUri)
  if (quota === Infinity) {
    return false
  }
  var size = await actualSize(root)
  return (size > quota)
}

/**
 * Returns the number of bytes that is occupied by the actual files in
 * the file system. IMPORTANT NOTE: Since it traverses the directory
 * to find the actual file sizes, this does a costly operation, but
 * neglible for the small quotas we currently allow. If the quotas
 * grow bigger, this will significantly reduce write performance, and
 * so it needs to be rewritten.
 */

function actualSize (root) {
  return util.promisify(getSize)(root)
}

function _asyncReadfile (filename) {
  return util.promisify(fs.readFile)(filename, 'utf-8')
}
<commit_msg>add cache TODO<commit_after>module.exports.uriToFilename = uriToFilename
module.exports.uriToRelativeFilename = uriToRelativeFilename
module.exports.getBaseUri = getBaseUri
module.exports.pathBasename = pathBasename
module.exports.getFullUri = getFullUri
module.exports.hasSuffix = hasSuffix
module.exports.parse = parse
module.exports.serialize = serialize
module.exports.translate = translate
module.exports.stringToStream = stringToStream
module.exports.reqToPath = reqToPath
module.exports.debrack = debrack
module.exports.stripLineEndings = stripLineEndings
module.exports.fullUrlForReq = fullUrlForReq
module.exports.routeResolvedFile = routeResolvedFile
module.exports.getQuota = getQuota
module.exports.overQuota = overQuota

const fs = require('fs-extra')
const path = require('path')
const util = require('util')
const $rdf = require('rdflib')
const from = require('from2')
const url = require('url')
const debug = require('./debug').other
const getSize = require('get-folder-size')
var ns = require('solid-namespace')($rdf)

/**
 * Returns a fully qualified URL from an Express.js Request object.
 * (It's insane that Express does not provide this natively.)
 *
 * Usage:
 *
 *   ```
 *   console.log(util.fullUrlForReq(req))
 *   // -> https://example.com/path/to/resource?q1=v1
 *   ```
 *
 * @param req {IncomingRequest}
 *
 * @return {string}
 */
function fullUrlForReq (req) {
  let fullUrl = url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: url.resolve(req.baseUrl, req.path),
    query: req.query
  })

  return fullUrl
}

/**
 * Removes the `<` and `>` brackets around a string and returns it.
 * Used by the `allow` handler in `verifyDelegator()` logic.
 * @method debrack
 *
 * @param s {string}
 *
 * @return {string}
 */
function debrack (s) {
  if (!s || s.length < 2) {
    return s
  }
  if (s[0] !== '<') {
    return s
  }
  if (s[s.length - 1] !== '>') {
    return s
  }
  return s.substring(1, s.length - 1)
}

function uriToFilename (uri, base) {
  const decoded = uri.split('/').map(decodeURIComponent).join('/')
  let filename = path.join(base, decoded)
  // Make sure filename ends with '/'  if filename exists and is a directory.
  // TODO this sync operation can be avoided and can be left
  // to do, to other components, see `ldp.get`
  try {
    const fileStats = fs.statSync(filename)
    if (fileStats.isDirectory() && !filename.endsWith('/')) {
      filename += '/'
    } else if (fileStats.isFile() && filename.endsWith('/')) {
      filename = filename.substr(0, filename.length - 1)
    }
  } catch (err) {}
  return filename
}

function uriToRelativeFilename (uri, base) {
  const filename = uriToFilename(uri, base)
  const relative = path.relative(base, filename)
  return relative
}

function getBaseUri (req) {
  // Obtain the protocol from the configured server URI
  // (in case the server is running behind a reverse proxy)
  const locals = req.app.locals
  const serverUri = locals.host.serverUri
  const protocol = serverUri.replace(/:.*/, '')

  return `${protocol || req.protocol}://${req.get('host')}`
}

/**
 * Composes and returns the fully-qualified URI for the request, to be used
 * as a base URI for RDF parsing or serialization. For example, if a request
 * is to `Host: example.com`, `GET /files/` using the `https:` protocol,
 * then:
 *
 *   ```
 *   getFullUri(req)  // -> 'https://example.com/files/'
 *   ```
 *
 * @param req {IncomingMessage}
 *
 * @return {string}
 */
function getFullUri (req) {
  return getBaseUri(req) + url.resolve(req.baseUrl, req.path)
}

function pathBasename (fullpath) {
  let bname = ''
  if (fullpath) {
    bname = (fullpath.lastIndexOf('/') === fullpath.length - 1)
      ? ''
      : path.basename(fullpath)
  }
  return bname
}

function hasSuffix (path, suffixes) {
  for (let i in suffixes) {
    if (path.indexOf(suffixes[i], path.length - suffixes[i].length) !== -1) {
      return true
    }
  }
  return false
}

function parse (data, baseUri, contentType, callback) {
  const graph = $rdf.graph()
  try {
    return $rdf.parse(data, graph, baseUri, contentType, callback)
  } catch (err) {
    return callback(err)
  }
}

function serialize (graph, baseUri, contentType, callback) {
  try {
    // target, kb, base, contentType, callback
    $rdf.serialize(null, graph, baseUri, contentType, function (err, result) {
      if (err) {
        console.log(err)
        return callback(err)
      }
      if (result === undefined) {
        return callback(new Error('Error serializing the graph to ' +
          contentType))
      }

      return callback(null, result)
    })
  } catch (err) {
    console.log(err)
    callback(err)
  }
}

function translate (stream, baseUri, from, to, callback) {
  // Handle Turtle Accept header
  if (to === 'text/turtle' ||
    to === 'text/n3' ||
    to === 'application/turtle' ||
    to === 'application/n3') {
    to = 'text/turtle'
  }

  let data = ''
  stream
    .on('data', function (chunk) {
      data += chunk
    })
    .on('end', function () {
      parse(data, baseUri, from, function (err, graph) {
        if (err) return callback(err)
        serialize(graph, baseUri, to, function (err, data) {
          if (err) return callback(err)
          callback(null, data)
        })
      })
    })
}

function stringToStream (string) {
  return from(function (size, next) {
    // if there's no more content
    // left in the string, close the stream.
    if (!string || string.length <= 0) {
      return next(null, null)
    }

    // Pull in a new chunk of text,
    // removing it from the string.
    const chunk = string.slice(0, size)
    string = string.slice(size)

    // Emit "chunk" from the stream.
    next(null, chunk)
  })
}

/**
 * Removes line endings from a given string. Used for WebID TLS Certificate
 * generation.
 *
 * @param obj {string}
 *
 * @return {string}
 */
function stripLineEndings (obj) {
  if (!obj) { return obj }

  return obj.replace(/(\r\n|\n|\r)/gm, '')
}

function reqToPath (req) {
  const ldp = req.app.locals.ldp
  const root = ldp.multiuser ? ldp.root + req.hostname + '/' : ldp.root
  return uriToFilename(req.path, root)
}

/**
 * Adds a route that serves a static file from another Node module
 */
function routeResolvedFile (router, path, file, appendFileName = true) {
  const fullPath = appendFileName ? path + file.match(/[^/]+$/) : path
  const fullFile = require.resolve(file)
  router.get(fullPath, (req, res) => res.sendFile(fullFile))
}

/**
 * Returns the number of bytes that the user owning the requested POD
 * may store or Infinity if no limit
 */

async function getQuota (root, serverUri) {
  const filename = path.join(root, 'settings/serverSide.ttl')
  var quota = Infinity
  var prefs
  try {
    prefs = await _asyncReadfile(filename)
  } catch (error) {
    debug('Setting no quota. While reading serverSide.ttl, got ' + error)
    return Infinity
  }
  var graph = $rdf.graph()
  const storageUri = serverUri + '/'
  try {
    $rdf.parse(prefs, graph, storageUri, 'text/turtle')
  } catch (error) {
    throw new Error('Failed to parse serverSide.ttl, got ' + error)
  }
  const lit = graph.each($rdf.sym(storageUri), ns.solid('storageQuota'), undefined)[0]
  if (lit) {
    quota = lit.value
    const unitUri = 'http://www.w3.invalid/ns#'
    // The following should be encoded in the ontology
    switch (lit.datatype.value) {
      case unitUri + 'kilobyte':
        quota *= 1000
        break
      case unitUri + 'megabyte':
        quota *= 1000000
        break
      case unitUri + 'gigabyte':
        quota *= 1000000000
        break
    }
  }
  return quota
}

/**
 * Returns true of the user has exceeded their quota
 */

async function overQuota (root, serverUri) {
  let quota = await getQuota(root, serverUri)
  if (quota === Infinity) {
    return false
  }
  // TODO: cache this value?
  var size = await actualSize(root)
  return (size > quota)
}

/**
 * Returns the number of bytes that is occupied by the actual files in
 * the file system. IMPORTANT NOTE: Since it traverses the directory
 * to find the actual file sizes, this does a costly operation, but
 * neglible for the small quotas we currently allow. If the quotas
 * grow bigger, this will significantly reduce write performance, and
 * so it needs to be rewritten.
 */

function actualSize (root) {
  return util.promisify(getSize)(root)
}

function _asyncReadfile (filename) {
  return util.promisify(fs.readFile)(filename, 'utf-8')
}
<|endoftext|>


<commit_before>/*!
Kettle Utilities.

Copyright 2012-2013 OCAD University
Copyright 2012 Antranig Basman

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/kettle/LICENSE.txt
*/

(function () {

    "use strict";

    var fluid = require("infusion");
    var path = require("path");
    var os = require("os");
    var connect = require("express/node_modules/connect");

    var kettle = fluid.registerNamespace("kettle");

    fluid.registerNamespace("kettle.utils");
    fluid.registerNamespace("kettle.use");

    // Debugging definition - node.js's default is only 10!
    fluid.Error.stackTraceLimit = 100;

    // Handle an uncaught exception in case we get here when the fluid.fail does
    // not escape the function execution.
    process.on("uncaughtException", function onError(err) {
        var request = fluid.expand("{request}", {
                fetcher: fluid.makeEnvironmentFetcher()
            });
        // If request was already handled do nothing.
        if (!request) {
            return;
        }
        // Fire request's onError event in case it was not yet hendled.
        request.events.onError.fire({
            isError: true,
            message: err.message
        });
    });

    // This is a default handler for fluid.fail. The handler will
    // fetch a request object from the environment and fire its
    // onError event.
    fluid.pushSoftFailure(function errHandler(args, activity) {
        var messages = args.concat(activity),
            request = fluid.expand("{request}", {
                fetcher: fluid.makeEnvironmentFetcher()
            });
        if (!request) {
            messages = ["ASSERTION FAILED: "].concat(messages);
            console.log.apply(null, messages);
            throw new Error(args[0]);
        }
        request.events.onError.fire({
            isError: true,
            message: messages.join("")
        });
    });

    // There seems to be no other way to determine whether signals are supported
    // than direct OS detection. Signals are currently completely unsupported on
    // Windows - https://github.com/joyent/node/issues/1553
    // The purpose of this code is to avoid hung or detached processes if node
    // is "killed" with CTRL-C etc.
    if (os.type().indexOf("Windows") === -1) {
        console.log(typeof(process.on));

        process.on("SIGTERM", function handler() {
            process.exit(0);
        });
    }

    fluid.defaults("kettle.urlExpander", {
        gradeNames: ["fluid.eventedComponent", "autoInit"],
        listeners: {
            onCreate: {
                listener: "fluid.log",
                args: ["INFO", "urlExpander constructed with vars:", "{that}.options.vars"]
            }
        },
        invokers: {
            expand: {
                funcName: "kettle.urlExpander.expand",
                args: ["{arguments}.0", "{that}.options.vars"]
            }
        }
    });

    fluid.defaults("kettle.urlExpander.development", {
        gradeNames: ["kettle.urlExpander", "autoInit"],
        vars: {
            port: "{kettle.server}.options.port",
            root: "{kettle.app}.options.root"
        }
    });

    /**
     * Expand a URL based on the supplied vars object.
     * @param  {String} url a url string to be expanded.
     * @param  {JSON} vars a map of string to be expanded.
     * @return {String} an expanded url.
     */
    kettle.urlExpander.expand = function (url, vars) {
        fluid.log("INFO", "urlExpander expanding url:", url);
        var expanded = fluid.stringTemplate(url, vars);
        fluid.log("INFO", "urlExpander expanded:", expanded);
        return expanded;
    };

    /**
     * Cookie parser.
     */
    kettle.utils.cookieParser = connect.cookieParser;

    /**
     * A memory store constructor used for sessions.
     */
    kettle.utils.MemoryStore = connect.middleware.session.MemoryStore;

    /**
     * Determine whether the request needs a session.
     * @param  {JSON/Object} handlerOrRequest either a fluidRequest or a
     * handler spec.
     * @return {Boolean} need session indicator.
     */
    kettle.utils.needSession = function (handlerOrRequest) {
        return handlerOrRequest.needSession &&
            handlerOrRequest.needSession !== "none";
    };

    fluid.defaults("kettle.linkage", {
        gradeNames: ["autoInit", "fluid.littleComponent"]
    });

    /**
     * Indexes the linkage grades based on the context to result tranformation.
     * @param  {JSON} defaults component defaults.
     * @return {String} a short form tranfromation from context to result
     * grades. For example 'grade1,grade2=>grade3'
     */
    kettle.linkage.indexer = function (defaults) {
        if (!defaults.contextGrades || !defaults.resultGrades) {
            return;
        }
        return [fluid.makeArray(defaults.contextGrades).join(",") + "=>" +
            fluid.makeArray(defaults.resultGrades).join(",")];
    };

    /**
     * Determine the dynamic grades array based on the context of other grades.
     * @param  {Array} gradeNames current gradeNames options.
     * @return {Array} dynamic grades.
     */
    kettle.getDynamicGrade = function (gradeNames) {
        var togo = [];
        var linkages = fluid.indexDefaults("linkages", {
            gradeNames: "kettle.linkage",
            indexFunc: kettle.linkage.indexer
        });
        for (var linkage in linkages) {
            var segs = linkage.split("=>");
            var contextGrades = fluid.makeArray(segs[0].split(","));
            var resultGrades = fluid.makeArray(segs[1].split(","));
            var exclude = fluid.find(contextGrades, function (grade) {
                if (gradeNames.indexOf(grade) < 0) {
                    return true;
                }
            });
            if (!exclude) {
                togo.push.apply(togo, resultGrades);
            }
        }
        return togo;
    };

    fluid.defaults("kettle.dynamicGrade", {
        gradeNames: ["{that}.getDynamicGrade"],
        invokers: {
            getDynamicGrade: {
                funcName: "kettle.getDynamicGrade",
                args: "{that}.options.gradeNames"
            }
        }
    });

})();
<commit_msg>GPII-245: updated kettle.getDynamicGrade utility based on @amb26's comments.<commit_after>/*!
Kettle Utilities.

Copyright 2012-2013 OCAD University
Copyright 2012 Antranig Basman

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/kettle/LICENSE.txt
*/

(function () {

    "use strict";

    var fluid = require("infusion");
    var path = require("path");
    var os = require("os");
    var connect = require("express/node_modules/connect");

    var kettle = fluid.registerNamespace("kettle");

    fluid.registerNamespace("kettle.utils");
    fluid.registerNamespace("kettle.use");

    // Debugging definition - node.js's default is only 10!
    fluid.Error.stackTraceLimit = 100;

    // Handle an uncaught exception in case we get here when the fluid.fail does
    // not escape the function execution.
    process.on("uncaughtException", function onError(err) {
        var request = fluid.expand("{request}", {
                fetcher: fluid.makeEnvironmentFetcher()
            });
        // If request was already handled do nothing.
        if (!request) {
            return;
        }
        // Fire request's onError event in case it was not yet hendled.
        request.events.onError.fire({
            isError: true,
            message: err.message
        });
    });

    // This is a default handler for fluid.fail. The handler will
    // fetch a request object from the environment and fire its
    // onError event.
    fluid.pushSoftFailure(function errHandler(args, activity) {
        var messages = args.concat(activity),
            request = fluid.expand("{request}", {
                fetcher: fluid.makeEnvironmentFetcher()
            });
        if (!request) {
            messages = ["ASSERTION FAILED: "].concat(messages);
            console.log.apply(null, messages);
            throw new Error(args[0]);
        }
        request.events.onError.fire({
            isError: true,
            message: messages.join("")
        });
    });

    // There seems to be no other way to determine whether signals are supported
    // than direct OS detection. Signals are currently completely unsupported on
    // Windows - https://github.com/joyent/node/issues/1553
    // The purpose of this code is to avoid hung or detached processes if node
    // is "killed" with CTRL-C etc.
    if (os.type().indexOf("Windows") === -1) {
        console.log(typeof(process.on));

        process.on("SIGTERM", function handler() {
            process.exit(0);
        });
    }

    fluid.defaults("kettle.urlExpander", {
        gradeNames: ["fluid.eventedComponent", "autoInit"],
        listeners: {
            onCreate: {
                listener: "fluid.log",
                args: ["INFO", "urlExpander constructed with vars:", "{that}.options.vars"]
            }
        },
        invokers: {
            expand: {
                funcName: "kettle.urlExpander.expand",
                args: ["{arguments}.0", "{that}.options.vars"]
            }
        }
    });

    fluid.defaults("kettle.urlExpander.development", {
        gradeNames: ["kettle.urlExpander", "autoInit"],
        vars: {
            port: "{kettle.server}.options.port",
            root: "{kettle.app}.options.root"
        }
    });

    /**
     * Expand a URL based on the supplied vars object.
     * @param  {String} url a url string to be expanded.
     * @param  {JSON} vars a map of string to be expanded.
     * @return {String} an expanded url.
     */
    kettle.urlExpander.expand = function (url, vars) {
        fluid.log("INFO", "urlExpander expanding url:", url);
        var expanded = fluid.stringTemplate(url, vars);
        fluid.log("INFO", "urlExpander expanded:", expanded);
        return expanded;
    };

    /**
     * Cookie parser.
     */
    kettle.utils.cookieParser = connect.cookieParser;

    /**
     * A memory store constructor used for sessions.
     */
    kettle.utils.MemoryStore = connect.middleware.session.MemoryStore;

    /**
     * Determine whether the request needs a session.
     * @param  {JSON/Object} handlerOrRequest either a fluidRequest or a
     * handler spec.
     * @return {Boolean} need session indicator.
     */
    kettle.utils.needSession = function (handlerOrRequest) {
        return handlerOrRequest.needSession &&
            handlerOrRequest.needSession !== "none";
    };

    fluid.defaults("kettle.linkage", {
        gradeNames: ["autoInit", "fluid.littleComponent"]
    });

    /**
     * Indexes the linkage grades based on the context to result tranformation.
     * @param  {JSON} defaults component defaults.
     * @return {String} '*' that will index all linkage grades in one place.
     */
    kettle.linkage.indexer = function (defaults) {
        // Only index grades with correct defaults specified.
        if (defaults.contextGrades && defaults.resultGrades) {
            return ["*"];
        }
    };

    /**
     * Determine the dynamic grades array based on the context of other grades.
     * @param  {Array} gradeNames current gradeNames options.
     * @return {Array} dynamic grades.
     */
    kettle.getDynamicGrade = function (gradeNames) {
        var togo = [];
        var linkages = fluid.indexDefaults("linkages", {
            gradeNames: "kettle.linkage",
            indexFunc: kettle.linkage.indexer
        });
        fluid.each(linkages["*"], function (defaultsName) {
            var defaults = fluid.defaults(defaultsName);
            var exclude = fluid.find(fluid.makeArray(defaults.contextGrades),
                function (grade) {
                    if (gradeNames.indexOf(grade) < 0) {
                        return true;
                    }
                }
            );
            if (!exclude) {
                togo.push.apply(togo, fluid.makeArray(defaults.resultGrades));
            }
        });
        return togo;
    };

    fluid.defaults("kettle.dynamicGrade", {
        gradeNames: ["{that}.getDynamicGrade"],
        invokers: {
            getDynamicGrade: {
                funcName: "kettle.getDynamicGrade",
                args: "{that}.options.gradeNames"
            }
        }
    });

})();
<|endoftext|>


<commit_before>var path = require('path');
var url = require('url');

var Graph = require('algorithms/data_structures/graph');
var depthFirst = require('algorithms/graph').depthFirstSearch;

function fromFileURL(url) {
  return url.substr(7 + !!process.platform.match(/^win/)).replace(/\//g, path.sep);
}
exports.fromFileURL = fromFileURL;

function toFileURL(path) {
  return 'file://' + (process.platform.match(/^win/) ? '/' : '') + path.replace(/\\/g, '/');
}
exports.toFileURL = toFileURL;

function isFileURL(url) {
  return url.substr(0, 5) === 'file:';
}
exports.isFileURL = isFileURL;

/* Remove scheme prefix from file URLs, so that they are paths. */
function filePath(url) {
  if (isFileURL(url))
    return url.replace(/^file:\/+/, '/');
}
exports.filePath = filePath;

/* Coerce URLs to paths, assuming they are file URLs */
function coercePath(url) {
  if (isFileURL(url))
    return url.replace(/^file:\/+/, '/');
  else
    // assume relative
    return path.resolve(process.cwd(), url);
}
exports.coercePath = coercePath;

var absURLRegEx = /^[^\/]+:\/\//;

function normalizePath(loader, path, isPlugin) {
  var curPath;
  if (loader.paths[path][0] == '.')
    curPath = decodeURI(url.resolve(toFileURL(process.cwd()) + '/', loader.paths[path]));
  else
    curPath = decodeURI(url.resolve(loader.baseURL, loader.paths[path]));
  if (loader.defaultJSExtensions && !isPlugin && curPath.substr(curPath.length - 3, 3) != '.js')
    curPath += '.js';
  return curPath;
}

// syntax-free getCanonicalName
// just reverse-applies paths and defulatJSExtension to determine the canonical
function getCanonicalNamePlain(loader, normalized, isPlugin) {
  // now just reverse apply paths rules to get canonical name
  var pathMatch;

  // first check exact path matches
  for (var p in loader.paths) {
    if (loader.paths[p].indexOf('*') != -1)
      continue;

    var curPath = normalizePath(loader, p, isPlugin);

    if (normalized === curPath) {
      // always stop on first exact match
      pathMatch = p;
      break;
    }
  }

  // then wildcard matches
  var pathMatchLength = 0;
  var curMatchlength;
  if (!pathMatch)
    for (var p in loader.paths) {
      if (loader.paths[p].indexOf('*') == -1)
        continue;

      // normalize the output path
      var curPath = normalizePath(loader, p, isPlugin);

      // do reverse match
      var wIndex = curPath.indexOf('*');
      if (normalized.substr(0, wIndex) === curPath.substr(0, wIndex)
        && normalized.substr(normalized.length - curPath.length + wIndex + 1) === curPath.substr(wIndex + 1)) {
        curMatchLength = curPath.split('/').length;
        if (curMatchLength >= pathMatchLength) {
          pathMatch = p.replace('*', normalized.substr(wIndex, normalized.length - curPath.length + 1));
          pathMatchLength = curMatchLength;
        }
      }
    }

  // when no path was matched, act like the standard rule is *: baseURL/*
  if (!pathMatch) {
    if (normalized.substr(0, loader.baseURL.length) == loader.baseURL)
      pathMatch = normalized.substr(loader.baseURL.length);
    else if (normalized.match(absURLRegEx))
      throw 'Unable to calculate canonical name to bundle ' + normalized;
    else
      pathMatch = normalized;
  }

  return pathMatch;
}

exports.getCanonicalName = getCanonicalName;

// calculate the canonical name of the normalized module
// unwraps loader syntaxes to derive component parts
var interpolationRegEx = /#\{[^\}]+\}/;
function canonicalizeCondition(loader, conditionModule) {
  var conditionExport;
  var exportIndex = conditionModule.lastIndexOf('|');
  if (exportIndex != -1) {
    conditionExport = conditionModule.substr(exportIndex + 1)
    conditionModule = conditionModule.substr(0, exportIndex);
  }
  return getCanonicalName(loader, conditionModule) + (conditionExport ? '|' + conditionExport : '');
}

function getCanonicalName(loader, normalized, isPlugin) {
  // 1. Boolean conditional
  var booleanIndex = normalized.lastIndexOf('#?');
  if (booleanIndex != -1) {
    var booleanModule = normalized.substr(booleanIndex + 2);
    var negate = booleanModule[0] == '~';
    if (negate)
      booleanModule = booleanModule.substr(1);
    return getCanonicalName(loader, normalized.substr(0, booleanIndex)) + '#?' + (negate ? '~' : '') + canonicalizeCondition(loader, booleanModule);
  }

  // 2. Plugins
  var pluginIndex = loader.pluginFirst ? normalized.indexOf('!') : normalized.lastIndexOf('!');
  if (pluginIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pluginIndex), !loader.pluginFirst) + '!' + getCanonicalName(loader, normalized.substr(pluginIndex + 1), loader.pluginFirst);

  // 3. Package environment map
  var pkgEnvIndex = normalized.indexOf('#:');
  if (pkgEnvIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pkgEnvIndex), isPlugin) + normalized.substr(pkgEnvIndex);

  // Finally get canonical plain
  var canonical = getCanonicalNamePlain(loader, normalized, isPlugin);

  // 4. Canonicalize conditional interpolation
  var conditionalMatch = canonical.match(interpolationRegEx);
  if (conditionalMatch)
    return getCanonicalNamePlain(loader, normalized, isPlugin).replace(interpolationRegEx, '#{' + canonicalizeCondition(loader, conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)) + '}');

  return canonical;
}

exports.getAlias = getAlias
function getAlias(loader, canonicalName) {
  var bestAlias;

  function getBestAlias(mapped) {
    return canonicalName.substr(0, mapped.length) == mapped
        && (canonicalName.length == mapped.length || canonicalName[mapped.length + 1] == '/');
  }

  Object.keys(loader.map).forEach(function(alias) {
    if (getBestAlias(loader.map[alias]))
      bestAlias = alias;
  });

  if (bestAlias)
    return bestAlias;

  Object.keys(loader.packages).forEach(function(pkg) {
    Object.keys(loader.packages[pkg].map || {}).forEach(function(alias) {
      if (getBestAlias(loader.packages[pkg].map[alias]))
        bestAlias = alias;
    });
  });

  return bestAlias || canonicalName;
}

function getGraphEntryPoints(graph, entryPoints) {
  entryPoints = [].concat(entryPoints || []);

  var modules = Object.keys(graph.adjList);
  var discarded = {};

  modules.forEach(function (moduleName) {
    Object.keys(graph.adjList[moduleName]).forEach(function (depName) {
      discarded[depName] = true;
    });
  });

  modules.filter(function (moduleName) {
    return !discarded[moduleName];
  }).sort().forEach(function (moduleName) {
    if (entryPoints.indexOf(moduleName) === -1) {
      entryPoints.push(moduleName);
    }
  });

  return entryPoints;
}

exports.postOrderTraverseTree = function postOrderTraverseTree(tree, loader, entryPoints) {
  entryPoints = entryPoints || [];

  // Post order traversal sorted module list
  var postOrder = [];
  var graph = new Graph(true);

  // Seed graph with all relations
  Object.keys(tree).forEach(function (moduleName) {
    var module = tree[moduleName];

    module.deps.forEach(function (depName) {
      graph.addEdge(module.name, module.depMap[depName]);
    });
  });

  // Post order traversal of graph, one per entryPoint
  getGraphEntryPoints(graph, entryPoints).forEach(function (entryPoint) {
    depthFirst(graph, entryPoint, {
      leaveVertex: function (moduleName) {
        // Avoidj duplicates
        if (postOrder.indexOf(moduleName) === -1) {
          postOrder.push(moduleName);
        }
      }
    });
  });

  return postOrder;
};
<commit_msg>Filter out modules that are skipped in the trace when post order traversing<commit_after>var path = require('path');
var url = require('url');

var Graph = require('algorithms/data_structures/graph');
var depthFirst = require('algorithms/graph').depthFirstSearch;

function fromFileURL(url) {
  return url.substr(7 + !!process.platform.match(/^win/)).replace(/\//g, path.sep);
}
exports.fromFileURL = fromFileURL;

function toFileURL(path) {
  return 'file://' + (process.platform.match(/^win/) ? '/' : '') + path.replace(/\\/g, '/');
}
exports.toFileURL = toFileURL;

function isFileURL(url) {
  return url.substr(0, 5) === 'file:';
}
exports.isFileURL = isFileURL;

/* Remove scheme prefix from file URLs, so that they are paths. */
function filePath(url) {
  if (isFileURL(url))
    return url.replace(/^file:\/+/, '/');
}
exports.filePath = filePath;

/* Coerce URLs to paths, assuming they are file URLs */
function coercePath(url) {
  if (isFileURL(url))
    return url.replace(/^file:\/+/, '/');
  else
    // assume relative
    return path.resolve(process.cwd(), url);
}
exports.coercePath = coercePath;

var absURLRegEx = /^[^\/]+:\/\//;

function normalizePath(loader, path, isPlugin) {
  var curPath;
  if (loader.paths[path][0] == '.')
    curPath = decodeURI(url.resolve(toFileURL(process.cwd()) + '/', loader.paths[path]));
  else
    curPath = decodeURI(url.resolve(loader.baseURL, loader.paths[path]));
  if (loader.defaultJSExtensions && !isPlugin && curPath.substr(curPath.length - 3, 3) != '.js')
    curPath += '.js';
  return curPath;
}

// syntax-free getCanonicalName
// just reverse-applies paths and defulatJSExtension to determine the canonical
function getCanonicalNamePlain(loader, normalized, isPlugin) {
  // now just reverse apply paths rules to get canonical name
  var pathMatch;

  // first check exact path matches
  for (var p in loader.paths) {
    if (loader.paths[p].indexOf('*') != -1)
      continue;

    var curPath = normalizePath(loader, p, isPlugin);

    if (normalized === curPath) {
      // always stop on first exact match
      pathMatch = p;
      break;
    }
  }

  // then wildcard matches
  var pathMatchLength = 0;
  var curMatchlength;
  if (!pathMatch)
    for (var p in loader.paths) {
      if (loader.paths[p].indexOf('*') == -1)
        continue;

      // normalize the output path
      var curPath = normalizePath(loader, p, isPlugin);

      // do reverse match
      var wIndex = curPath.indexOf('*');
      if (normalized.substr(0, wIndex) === curPath.substr(0, wIndex)
        && normalized.substr(normalized.length - curPath.length + wIndex + 1) === curPath.substr(wIndex + 1)) {
        curMatchLength = curPath.split('/').length;
        if (curMatchLength >= pathMatchLength) {
          pathMatch = p.replace('*', normalized.substr(wIndex, normalized.length - curPath.length + 1));
          pathMatchLength = curMatchLength;
        }
      }
    }

  // when no path was matched, act like the standard rule is *: baseURL/*
  if (!pathMatch) {
    if (normalized.substr(0, loader.baseURL.length) == loader.baseURL)
      pathMatch = normalized.substr(loader.baseURL.length);
    else if (normalized.match(absURLRegEx))
      throw 'Unable to calculate canonical name to bundle ' + normalized;
    else
      pathMatch = normalized;
  }

  return pathMatch;
}

exports.getCanonicalName = getCanonicalName;

// calculate the canonical name of the normalized module
// unwraps loader syntaxes to derive component parts
var interpolationRegEx = /#\{[^\}]+\}/;
function canonicalizeCondition(loader, conditionModule) {
  var conditionExport;
  var exportIndex = conditionModule.lastIndexOf('|');
  if (exportIndex != -1) {
    conditionExport = conditionModule.substr(exportIndex + 1)
    conditionModule = conditionModule.substr(0, exportIndex);
  }
  return getCanonicalName(loader, conditionModule) + (conditionExport ? '|' + conditionExport : '');
}

function getCanonicalName(loader, normalized, isPlugin) {
  // 1. Boolean conditional
  var booleanIndex = normalized.lastIndexOf('#?');
  if (booleanIndex != -1) {
    var booleanModule = normalized.substr(booleanIndex + 2);
    var negate = booleanModule[0] == '~';
    if (negate)
      booleanModule = booleanModule.substr(1);
    return getCanonicalName(loader, normalized.substr(0, booleanIndex)) + '#?' + (negate ? '~' : '') + canonicalizeCondition(loader, booleanModule);
  }

  // 2. Plugins
  var pluginIndex = loader.pluginFirst ? normalized.indexOf('!') : normalized.lastIndexOf('!');
  if (pluginIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pluginIndex), !loader.pluginFirst) + '!' + getCanonicalName(loader, normalized.substr(pluginIndex + 1), loader.pluginFirst);

  // 3. Package environment map
  var pkgEnvIndex = normalized.indexOf('#:');
  if (pkgEnvIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pkgEnvIndex), isPlugin) + normalized.substr(pkgEnvIndex);

  // Finally get canonical plain
  var canonical = getCanonicalNamePlain(loader, normalized, isPlugin);

  // 4. Canonicalize conditional interpolation
  var conditionalMatch = canonical.match(interpolationRegEx);
  if (conditionalMatch)
    return getCanonicalNamePlain(loader, normalized, isPlugin).replace(interpolationRegEx, '#{' + canonicalizeCondition(loader, conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)) + '}');

  return canonical;
}

exports.getAlias = getAlias
function getAlias(loader, canonicalName) {
  var bestAlias;

  function getBestAlias(mapped) {
    return canonicalName.substr(0, mapped.length) == mapped
        && (canonicalName.length == mapped.length || canonicalName[mapped.length + 1] == '/');
  }

  Object.keys(loader.map).forEach(function(alias) {
    if (getBestAlias(loader.map[alias]))
      bestAlias = alias;
  });

  if (bestAlias)
    return bestAlias;

  Object.keys(loader.packages).forEach(function(pkg) {
    Object.keys(loader.packages[pkg].map || {}).forEach(function(alias) {
      if (getBestAlias(loader.packages[pkg].map[alias]))
        bestAlias = alias;
    });
  });

  return bestAlias || canonicalName;
}

function getGraphEntryPoints(graph, entryPoints) {
  entryPoints = [].concat(entryPoints || []);

  var modules = Object.keys(graph.adjList);
  var discarded = {};

  modules.forEach(function (moduleName) {
    Object.keys(graph.adjList[moduleName]).forEach(function (depName) {
      discarded[depName] = true;
    });
  });

  modules.filter(function (moduleName) {
    return !discarded[moduleName];
  }).sort().forEach(function (moduleName) {
    if (entryPoints.indexOf(moduleName) === -1) {
      entryPoints.push(moduleName);
    }
  });

  return entryPoints;
}

exports.postOrderTraverseTree = function postOrderTraverseTree(tree, loader, entryPoints) {
  entryPoints = entryPoints || [];

  // Post order traversal sorted module list
  var postOrder = [];
  var graph = new Graph(true);

  // Seed graph with all relations
  Object.keys(tree).forEach(function (moduleName) {
    var module = tree[moduleName];

    module.deps.forEach(function (depName) {
      graph.addEdge(module.name, module.depMap[depName]);
    });
  });

  // Post order traversal of graph, one per entryPoint
  getGraphEntryPoints(graph, entryPoints).forEach(function (entryPoint) {
    depthFirst(graph, entryPoint, {
      leaveVertex: function (moduleName) {
        // Avoidj duplicates
        if (postOrder.indexOf(moduleName) === -1) {
          postOrder.push(moduleName);
        }
      }
    });
  });

  // The graph some times includes things the tracer has already discarded. Filter those
  postOrder = postOrder.filter(function (moduleName) {
    return moduleName in tree;
  });

  return postOrder;
};
<|endoftext|>


<commit_before>const tabs = require("tabs");
const self = require("self");

exports.assert = function (cond) {
  if (! cond) {
    var args = Array.prototype.slice.call(arguments, 1);
    console.warn(["Assertion Error:"].concat(args));
    throw new Error("Assertion Error: " + args.join(" "));
  }
};

exports.openData = function (base, params) {
  var url = self.data.url(base) + "?";
  var first = true;
  for (var name in params) {
    if (first) {
      first = false;
    } else {
      url += "&";
    }
    url += name + "=" + encodeURIComponent(params[name]);
  }
  tabs.open(url);
};
<commit_msg>Added EventMethods, cleanForId, and bind<commit_after>const { EventTarget } = require("sdk/event/target");
const tabs = require("sdk/tabs");
const self = require("sdk/self");
const { Class } = require('sdk/core/heritage');
var { on, once, off, emit } = require('sdk/event/core');

exports.assert = function (cond) {
  if (! cond) {
    var args = Array.prototype.slice.call(arguments, 1);
    console.warn(["Assertion Error:"].concat(args));
    throw new Error("Assertion Error: " + args.join(" "));
  }
};

exports.openData = function (base, params) {
  var url = self.data.url(base) + "?";
  var first = true;
  for (var name in params) {
    if (first) {
      first = false;
    } else {
      url += "&";
    }
    url += name + "=" + encodeURIComponent(params[name]);
  }
  tabs.open(url);
};

/* Like sdk/core/heritage EventTarget, but also adds relevent
   methods */
exports.EventMethods = Class({
  extends: EventTarget,

  on: function (type, handler) {
    return on(this, type, handler);
  },

  off: function (type, handler) {
    return off(this, type, handler);
  },

  once: function (type, handler) {
    return once(this, type, handler);
  },

  emit: function (type, event) {
    return emit.apply(null, [this].concat(Array.prototype.slice.call(arguments)));
  }
});

exports.cleanForId = function (s) {
  s = s.replace(/[^a-zA-Z0-9_-]/g, "");
  return s;
};

exports.bind = function (this_, methods) {
  if (typeof methods == "string") {
    methods = methods.split(/\s+/g);
  }
  methods.forEach(function (m) {
    if (! this_[m]) {
      throw new Error("Object " + this_ + " has no method " + m);
    }
    this_[m] = this_[m].bind(this_);
  });
};
<|endoftext|>


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

var fs = require('fs')
  , cssom = require('cssom')
  , jsdom = require('jsdom')
  , own = {}.hasOwnProperty
  , os = require('os')
  , inline = require('html-resource-inline');

/**
 * Returns an array of the selectors.
 *
 * @license Sizzle CSS Selector Engine - MIT
 * @param {String} selectorText from cssom
 * @api public
 */

exports.extract = function extract (selectorText) {
  var attr = 0
    , sels = []
    , sel = ''

  for (var i = 0, l = selectorText.length; i < l; i++) {
    var c = selectorText.charAt(i);

    if (attr) {
      if (']' === c || ')' === c) attr--;
      sel += c;
    } else {
      if (',' === c) {
        sels.push(sel);
        sel = '';
      } else {
        if ('[' === c || '(' === c) attr++;
        if (sel.length || (c !== ',' && c !== '\n' && c !== ' ')) sel += c;
      }
    }
  }

  if (sel.length) sels.push(sel);

  return sels;
}

/**
 * Returns a parse tree for a CSS source.
 * If it encounters multiple selectors separated by a comma, it splits the
 * tree.
 *
 * @param {String} css source
 * @api public
 */

exports.parseCSS = function (css) {
  var rules = cssom.parse(css).cssRules || []
    , ret = []

  for (var i = 0, l = rules.length; i < l; i++) {
    if (rules[i].selectorText) { // media queries don't have selectorText
      var rule = rules[i]
        , selectors = exports.extract(rule.selectorText)

      for (var ii = 0, ll = selectors.length; ii < ll; ii++) {
        ret.push([selectors[ii], rule.style]);
      }
    }
  }

  return ret;
}

/**
 * Returns Media Query text for a CSS source.
 *
 * @param {String} css source
 * @api public
 */

exports.getMediaQueryText = function ( css )
{
	var rules = cssom.parse( css ).cssRules || []
	var queries = [];

	for ( var i = 0, l = rules.length; i < l; i++ )
	{
		/* CSS types
		  STYLE: 1,
		  IMPORT: 3,
		  MEDIA: 4,
		  FONT_FACE: 5,
		 */

		if ( rules[i].type === cssom.CSSMediaRule.prototype.type )
		{
			var query = rules[i];
			var queryString = [];

			queryString.push( os.EOL + "@media " + query.media[0] + " {" );

			for ( var ii = 0, ll = query.cssRules.length; ii < ll; ii++ )
			{
				var rule = query.cssRules[ii];

				if ( rule.type === cssom.CSSStyleRule.prototype.type || rule.type === cssom.CSSFontFaceRule.prototype.type )
				{
					queryString.push( "  " + ( rule.type === cssom.CSSStyleRule.prototype.type ? rule.selectorText : "@font-face" ) + " {" );

					for ( var style = 0; style < rule.style.length; style++ )
					{
						var property = rule.style[style];
						var value = rule.style[property];
						var important = rule.style._importants[property] ? " !important" : "";
						queryString.push( "    " + property + ": " + value + important + ";" );
					}
					queryString.push( "  }" );
				}
			}

			queryString.push( "}" );
			var result = queryString.length ? queryString.join( os.EOL ) + os.EOL : "";

			queries.push( result );
		}
	}

	return queries.join( os.EOL );
}

/**
 * Returns a JSDom jQuery object
 *
 * api public
 */

exports.jsdom = function (html, inlineOptions, callback) {

  var onInlined = function (err, html)
  {
    // hack to force jsdom to see this argument as html content, not a url
    // or a filename. https://github.com/tmpvar/jsdom/issues/554
    html += "\n";

    var document = jsdom.html(html, null, {
      features: {
          QuerySelector: ['1.0']
        , FetchExternalResources: false
        , ProcessExternalResources: false
        , MutationEvents: false
      }
    });

    callback(null, document);
  };

  var options = exports.extend({fileContent: html}, inlineOptions);
  inline.html(options, onInlined);
};

exports.docToString = function (doc) {
  var doctype = doc.doctype;
  var contents = doc.innerHTML;

  // normalize line endings
  contents = contents.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');

  return (doctype === null ? '' : doctype) + contents;
}

/**
 * Converts to array
 *
 * @api public
 */

exports.toArray = function (arr) {
  var ret = [];

  for (var i = 0, l = arr.length; i < l; i++)
    ret.push(arr[i]);

  return ret;
};

/**
 * Compares two specificity vectors, returning the winning one.
 *
 * @param {Array} vector a
 * @param {Array} vector b
 * @return {Array}
 * @api public
 */

exports.compare = function (a, b) {
  for (var i = 0; i < 4; i++) {
    if (a[i] === b[i]) continue;
    if (a[i] > b[i]) return a;
    return b;
  }

  return b;
}

exports.extend = function (obj, src) {
  for (var key in src) if (own.call(src, key)) obj[key] = src[key];
  return obj;
}
<commit_msg>depends<commit_after>
/**
 * Module dependencies.
 */

var fs = require('fs')
  , cssom = require('cssom')
  , jsdom = require('jsdom')
  , own = {}.hasOwnProperty
  , os = require('os')
  , inline = require('web-resource-inliner');

/**
 * Returns an array of the selectors.
 *
 * @license Sizzle CSS Selector Engine - MIT
 * @param {String} selectorText from cssom
 * @api public
 */

exports.extract = function extract (selectorText) {
  var attr = 0
    , sels = []
    , sel = ''

  for (var i = 0, l = selectorText.length; i < l; i++) {
    var c = selectorText.charAt(i);

    if (attr) {
      if (']' === c || ')' === c) attr--;
      sel += c;
    } else {
      if (',' === c) {
        sels.push(sel);
        sel = '';
      } else {
        if ('[' === c || '(' === c) attr++;
        if (sel.length || (c !== ',' && c !== '\n' && c !== ' ')) sel += c;
      }
    }
  }

  if (sel.length) sels.push(sel);

  return sels;
}

/**
 * Returns a parse tree for a CSS source.
 * If it encounters multiple selectors separated by a comma, it splits the
 * tree.
 *
 * @param {String} css source
 * @api public
 */

exports.parseCSS = function (css) {
  var rules = cssom.parse(css).cssRules || []
    , ret = []

  for (var i = 0, l = rules.length; i < l; i++) {
    if (rules[i].selectorText) { // media queries don't have selectorText
      var rule = rules[i]
        , selectors = exports.extract(rule.selectorText)

      for (var ii = 0, ll = selectors.length; ii < ll; ii++) {
        ret.push([selectors[ii], rule.style]);
      }
    }
  }

  return ret;
}

/**
 * Returns Media Query text for a CSS source.
 *
 * @param {String} css source
 * @api public
 */

exports.getMediaQueryText = function ( css )
{
	var rules = cssom.parse( css ).cssRules || []
	var queries = [];

	for ( var i = 0, l = rules.length; i < l; i++ )
	{
		/* CSS types
		  STYLE: 1,
		  IMPORT: 3,
		  MEDIA: 4,
		  FONT_FACE: 5,
		 */

		if ( rules[i].type === cssom.CSSMediaRule.prototype.type )
		{
			var query = rules[i];
			var queryString = [];

			queryString.push( os.EOL + "@media " + query.media[0] + " {" );

			for ( var ii = 0, ll = query.cssRules.length; ii < ll; ii++ )
			{
				var rule = query.cssRules[ii];

				if ( rule.type === cssom.CSSStyleRule.prototype.type || rule.type === cssom.CSSFontFaceRule.prototype.type )
				{
					queryString.push( "  " + ( rule.type === cssom.CSSStyleRule.prototype.type ? rule.selectorText : "@font-face" ) + " {" );

					for ( var style = 0; style < rule.style.length; style++ )
					{
						var property = rule.style[style];
						var value = rule.style[property];
						var important = rule.style._importants[property] ? " !important" : "";
						queryString.push( "    " + property + ": " + value + important + ";" );
					}
					queryString.push( "  }" );
				}
			}

			queryString.push( "}" );
			var result = queryString.length ? queryString.join( os.EOL ) + os.EOL : "";

			queries.push( result );
		}
	}

	return queries.join( os.EOL );
}

/**
 * Returns a JSDom jQuery object
 *
 * api public
 */

exports.jsdom = function (html, inlineOptions, callback) {

  var onInlined = function (err, html)
  {
    // hack to force jsdom to see this argument as html content, not a url
    // or a filename. https://github.com/tmpvar/jsdom/issues/554
    html += "\n";

    var document = jsdom.html(html, null, {
      features: {
          QuerySelector: ['1.0']
        , FetchExternalResources: false
        , ProcessExternalResources: false
        , MutationEvents: false
      }
    });

    callback(null, document);
  };

  var options = exports.extend({fileContent: html}, inlineOptions);
  inline.html(options, onInlined);
};

exports.docToString = function (doc) {
  var doctype = doc.doctype;
  var contents = doc.innerHTML;

  // normalize line endings
  contents = contents.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');

  return (doctype === null ? '' : doctype) + contents;
}

/**
 * Converts to array
 *
 * @api public
 */

exports.toArray = function (arr) {
  var ret = [];

  for (var i = 0, l = arr.length; i < l; i++)
    ret.push(arr[i]);

  return ret;
};

/**
 * Compares two specificity vectors, returning the winning one.
 *
 * @param {Array} vector a
 * @param {Array} vector b
 * @return {Array}
 * @api public
 */

exports.compare = function (a, b) {
  for (var i = 0; i < 4; i++) {
    if (a[i] === b[i]) continue;
    if (a[i] > b[i]) return a;
    return b;
  }

  return b;
}

exports.extend = function (obj, src) {
  for (var key in src) if (own.call(src, key)) obj[key] = src[key];
  return obj;
}
<|endoftext|>


<commit_before>/**
 * This function should be called to validate identifier
 *
 * @method validateIdentifier
 * @param {String} identifier
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateIdentifier = function (identifier) {
    return /^[0-9A-Z]{4}$/g.test(identifier);
};

/**
 * This function should be called to validate userid
 *
 * @method validateUserid
 * @param {String} userid
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateUserid = function (userid) {
    return /^[0-9A-Z]{9}$/g.test(userid);
};

/**
 * This function should be called to validate address
 *
 * @method validateAddress
 * @param {String} address
 * @returns {Boolean} true if it valid, otherwise false
 */
var validateAddress = function (address) {
    return /^0x[0-9a-f]{40}$/g.test(address);
};

/**
 * This function should be called to validate direct IBAN
 *
 * @method validateDirectIBAN
 * @param {String} iban
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateDirectIBAN = function (iban) {
    return /^XE[0-9]{2}[0-9A-Z]{30}/g.test(iban);
};

/**
 * This function should be called to transfer direct IBAN to
 * ethereum address
 *
 * @method directIBANToAddress
 * @param {String} iban
 * @returns {String} ethereum address
 */
var directIBANToAddress = function (iban) {
    return '0x' + (new BigNumber(iban.substr(4), 36).toString(16));
};

/**
 * This function should be called to validate indirect IBAN
 *
 * @method validateIndirectIBAN
 * @param {String} iban
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateIndirectIBAN = function (iban) {
    return /^XE[0-9]{2}ETH[0-9A-Z]{13}$/g.test(iban);
};

/**
 * This function should be called to get indirect IBAN's identifier
 *
 * @method indirectIBANToIdentifier
 * @param {String} iban
 * @returns {String} identifier
 */
var indirectIBANToIdentifier = function (iban) {
    return iban.substr(7, 4);
};

/**
 * This function should be called to get indirect IBAN's userid
 *
 * @method indirectIBANToUserid
 * @param {String} iban
 * @returns {String} userid
 */
var indirectIBANToUserid = function (iban) {
    return iban.substr(11);
};

/**
 * This function should be called to check if address is empty
 *
 * @method isEmptyAddress
 * @param {String} address
 * @returns {Boolean} true if the address is empty
 */
var isEmptyAddress = function (address) {
    return address === '0x0000000000000000000000000000000000000000' || address === '0x';
};

module.exports = {
    validateIdentifier: validateIdentifier,
    validateUserid: validateUserid,
    validateAddress: validateAddress,
    validateDirectIBAN: validateDirectIBAN,
    validateIndirectIBAN: validateIndirectIBAN,
    directIBANToAddress: directIBANToAddress,
    indirectIBANToUserid: indirectIBANToUserid,
    indirectIBANToIdentifier: indirectIBANToIdentifier,
    isEmptyAddress: isEmptyAddress
};

<commit_msg>fixed withdraw to direct iban<commit_after>var BigNumber = require('bignumber.js');

/**
 * This function should be called to validate identifier
 *
 * @method validateIdentifier
 * @param {String} identifier
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateIdentifier = function (identifier) {
    return /^[0-9A-Z]{4}$/g.test(identifier);
};

/**
 * This function should be called to validate userid
 *
 * @method validateUserid
 * @param {String} userid
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateUserid = function (userid) {
    return /^[0-9A-Z]{9}$/g.test(userid);
};

/**
 * This function should be called to validate address
 *
 * @method validateAddress
 * @param {String} address
 * @returns {Boolean} true if it valid, otherwise false
 */
var validateAddress = function (address) {
    return /^0x[0-9a-f]{40}$/g.test(address);
};

/**
 * This function should be called to validate direct IBAN
 *
 * @method validateDirectIBAN
 * @param {String} iban
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateDirectIBAN = function (iban) {
    return /^XE[0-9]{2}[0-9A-Z]{30,31}/g.test(iban);
};

/**
 * This function should be called to transfer direct IBAN to
 * ethereum address
 *
 * @method directIBANToAddress
 * @param {String} iban
 * @returns {String} ethereum address
 */
var directIBANToAddress = function (iban) {
    return '0x' + (new BigNumber(iban.substr(4), 36).toString(16));
};

/**
 * This function should be called to validate indirect IBAN
 *
 * @method validateIndirectIBAN
 * @param {String} iban
 * @returns {Boolean} true if it is valid, otherwise false
 */
var validateIndirectIBAN = function (iban) {
    return /^XE[0-9]{2}ETH[0-9A-Z]{13}$/g.test(iban);
};

/**
 * This function should be called to get indirect IBAN's identifier
 *
 * @method indirectIBANToIdentifier
 * @param {String} iban
 * @returns {String} identifier
 */
var indirectIBANToIdentifier = function (iban) {
    return iban.substr(7, 4);
};

/**
 * This function should be called to get indirect IBAN's userid
 *
 * @method indirectIBANToUserid
 * @param {String} iban
 * @returns {String} userid
 */
var indirectIBANToUserid = function (iban) {
    return iban.substr(11);
};

/**
 * This function should be called to check if address is empty
 *
 * @method isEmptyAddress
 * @param {String} address
 * @returns {Boolean} true if the address is empty
 */
var isEmptyAddress = function (address) {
    return address === '0x0000000000000000000000000000000000000000' || address === '0x';
};

module.exports = {
    validateIdentifier: validateIdentifier,
    validateUserid: validateUserid,
    validateAddress: validateAddress,
    validateDirectIBAN: validateDirectIBAN,
    validateIndirectIBAN: validateIndirectIBAN,
    directIBANToAddress: directIBANToAddress,
    indirectIBANToUserid: indirectIBANToUserid,
    indirectIBANToIdentifier: indirectIBANToIdentifier,
    isEmptyAddress: isEmptyAddress
};

<|endoftext|>