<commit_before>#!/usr/bin/env node

var fs = require('fs');
var _ = require('lodash');
var forge = require('node-forge');
var xmlcrypto = require('xml-crypto');
var pd = require('pretty-data').pd;

var utils = require('./utils');

var singleDayMillis = 86400000;
var yargs = require('yargs');
var argv = yargs
    .usage('Usage: $0 -c <file-path> -f <p12|pem> -p <password> -t <file-path> -d <int> -o <file-path>')
    .example('$0 -c user123.p12 -f p12 -p 123456 -t yourepm.pem', 'Generate a speaks-for credential which delegates access to YourEPM tool during 120 days. In this case the signing credential is a PKCS#12 container')
    .example('$0 --credential user123.pem --format pem --password <PASSWORD> --toolcertificate yourepm.pem --duration 365', 'The Fed4FIRE user credential is PEM formatted, and access is delegated during 1 year')
    .example('$0 -vv -c user123.pem -f pem -p 123456 -t yourepm.pem -d 365 -o s4cred.base64', 'Same command as previous one, but with DEBUG verbosity and storing the result on an output file')
    .options({
        'c': {
            alias: 'credential',
            required: true,
            nargs: 1,
            description: "User credential file path",
            group: 'Signing User'
        },
        'f': {
            alias: 'format',
            required: true,
            choices: ['pem', 'p12'],
            description: "Provided credential container format",
            group: 'Signing User'
        },
        'p': {
            alias: 'password',
            required: false,
            nargs: 1,
            default: "",
            description: "User credential password (only for encrypted credentials)",
            group: 'Signing User'
        },
        't': {
            alias: ['tc', 'toolcertificate'],
            required: true,
            nargs: 1,
            description: "Tool certificate file path",
            group: 'Speaks-for Parameters'
        },
        'd': {
            alias: ['days', 'duration'],
            required: false,
            nargs: 1,
            default: 120,
            description: "Number of days the speaks-for credential will be valid",
            group: 'Speaks-for Parameters'
        },
        'o': {
            alias: 'output',
            required: false,
            nargs: 1,
            description: "Output file to store speaks-for credential (base64 encoded)"
        },
        'v': {
            alias: 'verbose',
            count: true,
            description: "Verbosity level (none, -v or -vv)"
        }
    })
    .help('h')
    .alias('h', 'help')
    .version(function() {
        return require('./package').version;
    })
    .epilog('Fed4FIRE - University of Cantabria - Copyright 2016')
    .strict()
    .wrap(yargs.terminalWidth())
    .argv;


var VERBOSE_LEVEL = argv.verbose;

function WARN() {
    VERBOSE_LEVEL >= 0 && console.log.apply(console, arguments);
}

function INFO() {
    VERBOSE_LEVEL >= 1 && console.log.apply(console, arguments);
}

function DEBUG() {
    VERBOSE_LEVEL >= 2 && console.log.apply(console, arguments);
}

try {
    // Load user credential
    INFO("## Loading user credential...");
    var userCredential = null;
    if (argv.format === 'pem') {
        userCredential = loadPemCredential(argv.credential, argv.password);
    } else if (argv.format === 'p12') {
        userCredential = loadPkcs12Credential(argv.credential, argv.password);
    }
    var userKeyhash = forge.pki.getPublicKeyFingerprint(userCredential.certChain[0].publicKey, {
        encoding: 'hex'
    });
    printCredentialEntryInfo(userCredential, DEBUG);
    INFO("## User certificate keyhash: %s", userKeyhash);

    // Load tool certificate
    INFO("## Loading tool certificate...");
    var toolCertificate = loadPemCertificate(argv.toolcertificate);
    var toolKeyhash = forge.pki.getPublicKeyFingerprint(toolCertificate.publicKey, {
        encoding: 'hex'
    });
    INFO("## Tool certificate keyhash: %s", userKeyhash);


    // Calculate expiration time
    var timeOffset = argv.days * singleDayMillis;
    var expireDate = new Date();
    expireDate.setTime(expireDate.getTime() + timeOffset);

    // Load credential template file and generate the XML
    credentialTemplate = _.template(fs.readFileSync(require('path').resolve(__dirname, 'resources', 'credential-template.txt'), "utf8"));
    xml = credentialTemplate({
        'expires': expireDate.toISOString(),
        'userKeyhash': userKeyhash,
        'toolKeyhash': toolKeyhash
    });
    var toolPublicId = extractFed4FIREPublicId(toolCertificate);
    WARN("## Speaks-for credential will be delegated to [%s] tool until %s", toolPublicId, expireDate.toISOString());
    DEBUG("\n## XML Template to be signed:\n%s", _.trim(xml, ' \n'));

    utils.monkeyPatchSignedXmlExclusiveCanonicalization(xmlcrypto);
    var signedXml = new xmlcrypto.SignedXml(null, {
        idAttribute: "id"
    });
    signedXml.addReference("/*/*[local-name(.)='credential']");
    signedXml.signingKey = forge.pki.privateKeyToPem(userCredential.privateKey);
    signedXml.keyInfoProvider = new SpeaksForKeyInfo(userCredential.certChain);
    signedXml.computeSignature(xml, {
        location: {
            reference: "/*/*[local-name(.)='signatures']"
        }
    });
    var speaksForCredential = signedXml.getSignedXml();<commit_msg>Fixed copy & paste bug<commit_after>#!/usr/bin/env node

var fs = require('fs');
var _ = require('lodash');
var forge = require('node-forge');
var xmlcrypto = require('xml-crypto');
var pd = require('pretty-data').pd;

var utils = require('./utils');

var singleDayMillis = 86400000;
var yargs = require('yargs');
var argv = yargs
    .usage('Usage: $0 -c <file-path> -f <p12|pem> -p <password> -t <file-path> -d <int> -o <file-path>')
    .example('$0 -c user123.p12 -f p12 -p 123456 -t yourepm.pem', 'Generate a speaks-for credential which delegates access to YourEPM tool during 120 days. In this case the signing credential is a PKCS#12 container')
    .example('$0 --credential user123.pem --format pem --password <PASSWORD> --toolcertificate yourepm.pem --duration 365', 'The Fed4FIRE user credential is PEM formatted, and access is delegated during 1 year')
    .example('$0 -vv -c user123.pem -f pem -p 123456 -t yourepm.pem -d 365 -o s4cred.base64', 'Same command as previous one, but with DEBUG verbosity and storing the result on an output file')
    .options({
        'c': {
            alias: 'credential',
            required: true,
            nargs: 1,
            description: "User credential file path",
            group: 'Signing User'
        },
        'f': {
            alias: 'format',
            required: true,
            choices: ['pem', 'p12'],
            description: "Provided credential container format",
            group: 'Signing User'
        },
        'p': {
            alias: 'password',
            required: false,
            nargs: 1,
            default: "",
            description: "User credential password (only for encrypted credentials)",
            group: 'Signing User'
        },
        't': {
            alias: ['tc', 'toolcertificate'],
            required: true,
            nargs: 1,
            description: "Tool certificate file path",
            group: 'Speaks-for Parameters'
        },
        'd': {
            alias: ['days', 'duration'],
            required: false,
            nargs: 1,
            default: 120,
            description: "Number of days the speaks-for credential will be valid",
            group: 'Speaks-for Parameters'
        },
        'o': {
            alias: 'output',
            required: false,
            nargs: 1,
            description: "Output file to store speaks-for credential (base64 encoded)"
        },
        'v': {
            alias: 'verbose',
            count: true,
            description: "Verbosity level (none, -v or -vv)"
        }
    })
    .help('h')
    .alias('h', 'help')
    .version(function() {
        return require('./package').version;
    })
    .epilog('Fed4FIRE - University of Cantabria - Copyright 2016')
    .strict()
    .wrap(yargs.terminalWidth())
    .argv;


var VERBOSE_LEVEL = argv.verbose;

function WARN() {
    VERBOSE_LEVEL >= 0 && console.log.apply(console, arguments);
}

function INFO() {
    VERBOSE_LEVEL >= 1 && console.log.apply(console, arguments);
}

function DEBUG() {
    VERBOSE_LEVEL >= 2 && console.log.apply(console, arguments);
}

try {
    // Load user credential
    INFO("## Loading user credential...");
    var userCredential = null;
    if (argv.format === 'pem') {
        userCredential = loadPemCredential(argv.credential, argv.password);
    } else if (argv.format === 'p12') {
        userCredential = loadPkcs12Credential(argv.credential, argv.password);
    }
    var userKeyhash = forge.pki.getPublicKeyFingerprint(userCredential.certChain[0].publicKey, {
        encoding: 'hex'
    });
    printCredentialEntryInfo(userCredential, DEBUG);
    INFO("## User certificate keyhash: %s", userKeyhash);

    // Load tool certificate
    INFO("## Loading tool certificate...");
    var toolCertificate = loadPemCertificate(argv.toolcertificate);
    var toolKeyhash = forge.pki.getPublicKeyFingerprint(toolCertificate.publicKey, {
        encoding: 'hex'
    });
    INFO("## Tool certificate keyhash: %s", toolKeyhash);


    // Calculate expiration time
    var timeOffset = argv.days * singleDayMillis;
    var expireDate = new Date();
    expireDate.setTime(expireDate.getTime() + timeOffset);

    // Load credential template file and generate the XML
    credentialTemplate = _.template(fs.readFileSync(require('path').resolve(__dirname, 'resources', 'credential-template.txt'), "utf8"));
    xml = credentialTemplate({
        'expires': expireDate.toISOString(),
        'userKeyhash': userKeyhash,
        'toolKeyhash': toolKeyhash
    });
    var toolPublicId = extractFed4FIREPublicId(toolCertificate);
    WARN("## Speaks-for credential will be delegated to [%s] tool until %s", toolPublicId, expireDate.toISOString());
    DEBUG("\n## XML Template to be signed:\n%s", _.trim(xml, ' \n'));

    utils.monkeyPatchSignedXmlExclusiveCanonicalization(xmlcrypto);
    var signedXml = new xmlcrypto.SignedXml(null, {
        idAttribute: "id"
    });
    signedXml.addReference("/*/*[local-name(.)='credential']");
    signedXml.signingKey = forge.pki.privateKeyToPem(userCredential.privateKey);
    signedXml.keyInfoProvider = new SpeaksForKeyInfo(userCredential.certChain);
    signedXml.computeSignature(xml, {
        location: {
            reference: "/*/*[local-name(.)='signatures']"
        }
    });
    var speaksForCredential = signedXml.getSignedXml();
{'fraction_non_alphanumeric': 0.13488285260897975, 'fraction_numerical': 0.015308503687109119, 'mean_word_length': 2.5916862219242374, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 14}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2429684', 'n_tokens_mistral': 3307, 'n_tokens_neox': 3150, 'n_words': 842}