Skip to content
Snippets Groups Projects
run.js 5.92 KiB
Newer Older
Thomas Rientjes's avatar
Thomas Rientjes committed
/**
 * Resource Audit Script
 * Belongs to Decentraleyes.
 *
 * @author      Thomas Rientjes
 * @since       2014-07-24
 * @license     MPL 2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/**
 * Imports
 */

var fileSystem, crypto, http, path, sourceMappingURL;

fileSystem = require('fs');
crypto = require('crypto');
https = require('https');
path = require('path');

sourceMappingURL = require('source-map-url');

/**
 * Variables
 */

var localResourceLocation = '../resources';
var localResourceLocationLength = localResourceLocation.length;
var localResourcePaths = [];
var comparedResourceAmount = 0;
Thomas Rientjes's avatar
Thomas Rientjes committed
var resourceAmount = 0;

/**
 * Functions
 */

function _fetchLocalResourcePaths(folderPath) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    fileSystem.readdirSync(folderPath).forEach(function (resourceName) {
Thomas Rientjes's avatar
Thomas Rientjes committed

        var resourcePath = folderPath + '/' + resourceName;
        var resourceStatistics = fileSystem.statSync(resourcePath);
Thomas Rientjes's avatar
Thomas Rientjes committed

        if (resourceStatistics && resourceStatistics.isDirectory()) {
            _fetchLocalResourcePaths(resourcePath);
        } else {
            localResourcePaths.push(resourcePath);
        }
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed

    return localResourcePaths;
Thomas Rientjes's avatar
Thomas Rientjes committed
}

function _getLocalResourceContents(fileLocation, callback) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    fileSystem.exists(fileLocation, function (exists) {
Thomas Rientjes's avatar
Thomas Rientjes committed

        if (exists) {
Thomas Rientjes's avatar
Thomas Rientjes committed

            fileSystem.stat(fileLocation, function (error, statistics) {
Thomas Rientjes's avatar
Thomas Rientjes committed

                fileSystem.open(fileLocation, 'r', function (error, fileDescriptor) {
Thomas Rientjes's avatar
Thomas Rientjes committed

                    var buffer = new Buffer(statistics.size);
Thomas Rientjes's avatar
Thomas Rientjes committed

                    fileSystem.read(fileDescriptor, buffer, 0, buffer.length, null, function (error, bytesRead, buffer) {
Thomas Rientjes's avatar
Thomas Rientjes committed

                        var localFileContents = buffer.toString('utf8', 0, buffer.length);
Thomas Rientjes's avatar
Thomas Rientjes committed

                        fileSystem.close(fileDescriptor, function () {});
                        callback(localFileContents);
                    });
                });
            });
        }
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
}

function _getRemoteResourceContents(remoteResourceRoute, callback) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    var resourceURL = 'https://ajax.googleapis.com/ajax/libs/' + remoteResourceRoute;
Thomas Rientjes's avatar
Thomas Rientjes committed

    https.get(resourceURL, function (response) {
Thomas Rientjes's avatar
Thomas Rientjes committed

        var resourceContents = '';
Thomas Rientjes's avatar
Thomas Rientjes committed

        response.on('data', function (chunk) {
            resourceContents = resourceContents + chunk;
        });
Thomas Rientjes's avatar
Thomas Rientjes committed

        response.on('end', function () {
Thomas Rientjes's avatar
Thomas Rientjes committed

            if (response.statusCode === 200) {
Thomas Rientjes's avatar
Thomas Rientjes committed

                callback(resourceContents, resourceURL);
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed

                resourceURL = 'https://cdnjs.cloudflare.com/ajax/libs/' + remoteResourceRoute;
Thomas Rientjes's avatar
Thomas Rientjes committed

                https.get(resourceURL, function (response) {
Thomas Rientjes's avatar
Thomas Rientjes committed

                    resourceContents = '';
Thomas Rientjes's avatar
Thomas Rientjes committed

                    response.on('data', function (chunk) {
                        resourceContents = resourceContents + chunk;
                    });
Thomas Rientjes's avatar
Thomas Rientjes committed

                    response.on('end', function () {
Thomas Rientjes's avatar
Thomas Rientjes committed

                        if (response.statusCode !== 200) {
                            throw 'Error: Resource ' + remoteResourceRoute + ' could not be fetched.';
                        }
Thomas Rientjes's avatar
Thomas Rientjes committed

                        callback(resourceContents, resourceURL);
                    });

                });

            }
function _hashFileContents(fileContents) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    var hash;
Thomas Rientjes's avatar
Thomas Rientjes committed

    hash = crypto.createHash('sha512');
Thomas Rientjes's avatar
Thomas Rientjes committed

    hash.setEncoding('hex');
    hash.write(fileContents);
    hash.end();
Thomas Rientjes's avatar
Thomas Rientjes committed

    return hash.read();
function _compareResources(localResourceContents, remoteResourceContents, URL) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    var hasSourceMappingURL = sourceMappingURL.existsIn(remoteResourceContents);
    var sourceMappingNotice = '[ ] REMOTE RESOURCE HAD SOURCE MAPPING URL';
Thomas Rientjes's avatar
Thomas Rientjes committed

    if (hasSourceMappingURL) {
        remoteResourceContents = sourceMappingURL.removeFrom(remoteResourceContents);
        sourceMappingNotice = '[X] REMOTE RESOURCE HAD SOURCE MAPPING URL';
    }
Thomas Rientjes's avatar
Thomas Rientjes committed

    var localResourceHash = _hashFileContents(localResourceContents);
    var remoteResourceHash = _hashFileContents(remoteResourceContents);
Thomas Rientjes's avatar
Thomas Rientjes committed

    console.log('RESOURCE HASH (SHA512): ' + localResourceHash);
    console.log('RESOURCE HASH (SHA512): ' + remoteResourceHash);
Thomas Rientjes's avatar
Thomas Rientjes committed

    var fileHashesMatch = (localResourceHash === remoteResourceHash);
Thomas Rientjes's avatar
Thomas Rientjes committed

    if (!fileHashesMatch) {
        console.log(URL);
        console.log(remoteResourceContents);
        throw 'Error: Decentraleyes resource hash mismatch.';
    }
Thomas Rientjes's avatar
Thomas Rientjes committed

    console.log();
    console.log('[X] LOCAL AND REMOTE RESOURCE HASHES MATCH');
    console.log(sourceMappingNotice);

    _incrementComparedResourceAmount();
function _showCompletedMessage() {
Thomas Rientjes's avatar
Thomas Rientjes committed

    console.log();
    console.log('       *** FILE INTEGRITY CHECKS COMPLETED');
    console.log('       *** ' + resourceAmount + '/' + resourceAmount + ' RESOURCES WERE ANALYZED');
    console.log();
function _incrementComparedResourceAmount() {

    comparedResourceAmount++;

    if (comparedResourceAmount === resourceAmount) {

        setTimeout(function () {
            _showCompletedMessage();
        }, 500);
    }
}

Thomas Rientjes's avatar
Thomas Rientjes committed
/**
 * Initializations
 */

_fetchLocalResourcePaths(localResourceLocation);
resourceAmount = localResourcePaths.length;

/**
 * Script
 */

localResourcePaths.forEach(function (resourcePath, index) {

    var resourceRoute = resourcePath.substr(localResourceLocationLength + 1);
    resourceRoute = resourceRoute.substring(0, resourceRoute.length - 4);
Thomas Rientjes's avatar
Thomas Rientjes committed

    _getLocalResourceContents(resourcePath, function (localResourceContents) {
Thomas Rientjes's avatar
Thomas Rientjes committed

        _getRemoteResourceContents(resourceRoute, function (remoteResourceContents, URL) {
Thomas Rientjes's avatar
Thomas Rientjes committed

            console.log();
            console.log(resourceRoute.toUpperCase());
            console.log();
Thomas Rientjes's avatar
Thomas Rientjes committed

            // Compare resource content hashes.
            _compareResources(localResourceContents, remoteResourceContents, URL);
Thomas Rientjes's avatar
Thomas Rientjes committed

            console.log();
            console.log('------------------------------------------');
        });
Thomas Rientjes's avatar
Thomas Rientjes committed
    });

});