<commit_before>/* gpgme.js - Javascript integration for gpgme
 * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
 *
 * This file is part of GPGME.
 *
 * GPGME is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * GPGME is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 * SPDX-License-Identifier: LGPL-2.1+
 *
 * Author(s):
 *     Maximilian Krambach <mkrambach@intevation.de>
 */

import { GPGME_Message, createMessage } from './Message';
import { toKeyIdArray } from './Helpers';
import { gpgme_error } from './Errors';
import { GPGME_Keyring } from './Keyring';
import { createSignature } from './Signature';

/**
 * @typedef {Object} decrypt_result
 * @property {String|Uint8Array} data The decrypted data
 * @property {String} format Indicating how the data was converted after being
 * received from gpgme.
 *      'string': Data was decoded into an utf-8 string,
 *      'base64': Data was not processed and is a base64 string
 *      'uint8': data was turned into a Uint8Array
 * @property {Boolean} is_mime (optional) the data claims to be a MIME
 * object.
 * @property {String} file_name (optional) the original file name
 * @property {signatureDetails} signatures Verification details for
 * signatures
 */

/**
 * @typedef {Object} signatureDetails
 * @property {Boolean} all_valid Summary if all signatures are fully valid
 * @property {Number} count Number of signatures found
 * @property {Number} failures Number of invalid signatures
 * @property {Array<GPGME_Signature>} signatures.good All valid signatures
 * @property {Array<GPGME_Signature>} signatures.bad All invalid signatures
 */

/**
 * @typedef {Object} encrypt_result The result of an encrypt operation
 * @property {String} data The encrypted message
 * @property {String} format Indicating how the data was converted after being
 *  received from gpgme.
 *      'ascii': Data was ascii-encoded and no further processed
 *      'string': Data was decoded into an utf-8 string,
 *      'base64': Data was not processed and is a base64 string
 *      'uint8': Data was turned into a Uint8Array
 */

/**
 * @typedef { GPGME_Key | String | Object } inputKeys
 * Accepts different identifiers of a gnupg Key that can be parsed by
 * {@link toKeyIdArray}. Expected inputs are: One or an array of
 * GPGME_Keys; one or an array of fingerprint strings; one or an array of
 * openpgpjs Key objects.
 */

/**
 * @typedef {Object} signResult The result of a signing operation
 * @property {String} data The resulting data. Includes the signature in
 *  clearsign mode
 * @property {String} signature The detached signature (if in detached mode)
 */

/** @typedef {Object} verifyResult The result of a verification
 * @property {Boolean} data: The verified data
 * @property {Boolean} is_mime (optional) the data claims to be a MIME
 * object.
 * @property {String} file_name (optional) the original file name
 * @property {signatureDetails} signatures Verification details for
 * signatures
 */

/**
 * The main entry point for gpgme.js.
 * @class
 */
export class GpgME {

    constructor (){
        this._Keyring = null;
    }

    /**
     * setter for {@link setKeyring}.
     * @param {GPGME_Keyring} keyring A Keyring to use
     */
    set Keyring (keyring){
        if (keyring && keyring instanceof GPGME_Keyring){
            this._Keyring = keyring;
        }
    }
    /**
     * Accesses the {@link GPGME_Keyring}.
     */
    get Keyring (){
        if (!this._Keyring){
            this._Keyring = new GPGME_Keyring;
        }
        return this._Keyring;
    }

    /**
     * Encrypt (and optionally sign) data
     * @param {Object} options
     * @param {String|Object} options.data text/data to be encrypted as String.
     * Also accepts Objects with a getText method
     * @param {inputKeys} options.publicKeys
     * Keys used to encrypt the message
     * @param {inputKeys} opions.secretKeys (optional) Keys used to sign the
     * message. If Keys are present, the  operation requested is assumed
     * to be 'encrypt and sign'
     * @param {Boolean} options.base64 (optional) The data will be interpreted
     * as base64 encoded data.
     * @param {Boolean} options.armor (optional) Request the output as armored
     * block.
     * @param {Boolean} options.wildcard (optional) If true, recipient
     * information will not be added to the message.
     * @param {Boolean} always_trust (optional, default true) This assumes that
     * used keys are fully trusted. If set to false, encryption to a key not
     * fully trusted in gnupg will fail
     * @param {Object} additional use additional valid gpg options as
     * defined in {@link permittedOperations}
     * @returns {Promise<encrypt_result>} Object containing the encrypted
     * message and additional info.
     * @async
     */
    encrypt ({ data, publicKeys, secretKeys, base64 = false, armor = true,
        wildcard, always_trust = true, additional = {} } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data || !publicKeys){
            return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
        }
        let msg = createMessage('encrypt');
        if (msg instanceof Error){
            return Promise.reject(msg);
        }
        msg.setParameter('armor', armor);

        if (base64 === true) {
            msg.setParameter('base64', true);
        }
        if (always_trust === true) {
            msg.setParameter('always-trust', true);
        }
        let pubkeys = toKeyIdArray(publicKeys);
        if (!pubkeys.length) {
            return Promise.reject(gpgme_error('MSG_NO_KEYS'));
        }
        msg.setParameter('keys', pubkeys);
        let sigkeys = toKeyIdArray(secretKeys);
        if (sigkeys.length > 0) {
            msg.setParameter('signing_keys', sigkeys);
        }
        putData(msg, data);
        if (wildcard === true){
            msg.setParameter('throw-keyids', true);
        }
        if (additional){
            let additional_Keys = Object.keys(additional);
            for (let k = 0; k < additional_Keys.length; k++) {
                try {
                    msg.setParameter(additional_Keys[k],
                        additional[additional_Keys[k]]);
                }
                catch (error){
                    return Promise.reject(error);
                }
            }
        }
        if (msg.isComplete() === true){
            return msg.post();
        } else {
            return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
        }
    }

    /**
    * Decrypts a Message
    * @param {Object} options
    * @param {String|Object} options.data text/data to be decrypted. Accepts
    * Strings and Objects with a getText method
    * @param {Boolean} options.base64 (optional) false if the data is an
    * armored block, true if it is base64 encoded binary data
    * @param {String} options.expect (optional) can be set to 'uint8' or
    * 'base64'. Does no extra decoding on the data, and returns the decoded
    * data as either Uint8Array or unprocessed(base64 encoded) string.
    * @returns {Promise<decrypt_result>} Decrypted Message and information
    * @async
    */
    decrypt ({ data, base64, expect } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('MSG_EMPTY'));
        }
        let msg = createMessage('decrypt');

        if (msg instanceof Error){
            return Promise.reject(msg);
        }
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        if (expect === 'base64' || expect === 'uint8'){
            msg.expected = expect;
        }
        putData(msg, data);
        return new Promise(function (resolve, reject){
            msg.post().then(function (result){
                let returnValue = { data: result.data };
                returnValue.format = result.format ? result.format : null;
                if (result.hasOwnProperty('dec_info')){
                    returnValue.is_mime = result.dec_info.is_mime ? true: false;
                    if (result.dec_info.file_name) {
                        returnValue.file_name = result.dec_info.file_name;
                    }
                }
                if (!returnValue.file_name) {
                    returnValue.file_name = null;
                }
                if (result.hasOwnProperty('info')
                    && result.info.hasOwnProperty('signatures')
                    && Array.isArray(result.info.signatures)
                ) {
                    returnValue.signatures = collectSignatures(
                        result.info.signatures);
                }
                if (returnValue.signatures instanceof Error){
                    reject(returnValue.signatures);
                } else {
                    resolve(returnValue);
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Sign a Message
     * @param {Object} options Signing options
     * @param {String|Object} options.data text/data to be signed. Accepts
     * Strings and Objects with a getText method.
     * @param {inputKeys} options.keys The key/keys to use for signing
     * @param {String} options.mode The signing mode. Currently supported:
     *  'clearsign':The Message is embedded into the signature;
     *  'detached': The signature is stored separately
     * @param {Boolean} options.base64 input is considered base64
     * @returns {Promise<signResult>}
     * @async
     */
    sign ({ data, keys, mode = 'clearsign', base64 } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('MSG_EMPTY'));
        }
        let key_arr = toKeyIdArray(keys);
        if (key_arr.length === 0){
            return Promise.reject(gpgme_error('MSG_NO_KEYS'));
        }

        let msg = createMessage('sign');
        msg.setParameter('keys', key_arr);
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        msg.setParameter('mode', mode);
        putData(msg, data);

        return new Promise(function (resolve,reject) {
            msg.post().then( function (message) {
                if (mode === 'clearsign'){
                    resolve({
                        data: message.data }
                    );
                } else if (mode === 'detached') {
                    resolve({
                        data: data,
                        signature: message.data
                    });
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Verifies data.
     * @param {Object} options
     * @param {String|Object} options.data text/data to be verified. Accepts
     * Strings and Objects with a getText method
     * @param {String} options.signature A detached signature. If not present,
     * opaque mode is assumed
     * @param {Boolean} options.base64 Indicating that data and signature are
     * base64 encoded
     * @returns {Promise<verifyResult>}
     *@async
    */
    verify ({ data, signature, base64 } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let msg = createMessage('verify');
        let dt = putData(msg, data);
        if (dt instanceof Error){
            return Promise.reject(dt);
        }
        if (signature){
            if (typeof signature !== 'string'){
                return Promise.reject(gpgme_error('PARAM_WRONG'));
            } else {
                msg.setParameter('signature', signature);
            }
        }
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        return new Promise(function (resolve, reject){
            msg.post().then(function (message){
                if (!message.info || !message.info.signatures){
                    reject(gpgme_error('SIG_NO_SIGS'));
                } else {
                    let returnValue = {
                        signatures: collectSignatures(message.info.signatures)
                    };
                    if (returnValue.signatures instanceof Error){
                        reject(returnValue.signatures);
                    } else {
                        returnValue.is_mime = message.info.is_mime? true: false;
                        if (message.info.filename){
                            returnValue.file_name = message.info.filename;
                        }
                        returnValue.data = message.data;
                        resolve(returnValue);
                    }
                }
            }, function (error){
                reject(error);
            });
        });
    }
}

/**
 * Sets the data of the message, setting flags according on the data type
 * @param {GPGME_Message} message The message where this data will be set
 * @param { String| Object } data The data to enter. Expects either a string of
 * data, or an object with a getText method
 * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise
 * @private
 */
function putData (message, data){
    if (!message || !(message instanceof GPGME_Message)) {
        return gpgme_error('PARAM_WRONG');
    }
    if (!data){
        return gpgme_error('PARAM_WRONG');
    } else if (typeof data === 'string') {
        message.setParameter('data', data);
    } else if (
        (typeof data === 'object') &&
        (typeof data.getText === 'function')
    ){
        let txt = data.getText();
        if (typeof txt === 'string'){
            message.setParameter('data', txt);
        } else {
            return gpgme_error('PARAM_WRONG');
        }

    } else {
        return gpgme_error('PARAM_WRONG');
    }
}

/**
 * Parses, validates and converts incoming objects into signatures.
 * @param {Array<Object>} sigs
 * @returns {signatureDetails} Details about the signatures
 */
function collectSignatures (sigs){
    if (!Array.isArray(sigs)){
        return gpgme_error('SIG_NO_SIGS');
    }
    let summary = {
        all_valid: false,
        count: sigs.length,
        failures: 0,
        signatures: {
            good: [],
            bad: [],
        }
    };
    for (let i=0; i< sigs.length; i++){
        let sigObj = createSignature(sigs[i]);
        if (sigObj instanceof Error) {
            return gpgme_error('SIG_WRONG');
        }
        if (sigObj.valid !== true){
            summary.failures += 1;
            summary.signatures.bad.push(sigObj);
        } else {
            summary.signatures.good.push(sigObj);
        }
    }
    if (summary.failures === 0){
        summary.all_valid = true;
    }
    return summary;
}<commit_msg>js: small documentation update<commit_after>/* gpgme.js - Javascript integration for gpgme
 * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
 *
 * This file is part of GPGME.
 *
 * GPGME is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * GPGME is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 * SPDX-License-Identifier: LGPL-2.1+
 *
 * Author(s):
 *     Maximilian Krambach <mkrambach@intevation.de>
 */

import { GPGME_Message, createMessage } from './Message';
import { toKeyIdArray } from './Helpers';
import { gpgme_error } from './Errors';
import { GPGME_Keyring } from './Keyring';
import { createSignature } from './Signature';

/**
 * @typedef {Object} decrypt_result
 * @property {String|Uint8Array} data The decrypted data
 * @property {String} format Indicating how the data was converted after being
 * received from gpgme.
 *      'ascii': Data was ascii-encoded and no further processed
 *      'string': Data was decoded into an utf-8 string,
 *      'base64': Data was not processed and is a base64 string
 *      'uint8': data was turned into a Uint8Array
 *
 * @property {Boolean} is_mime (optional) the data claims to be a MIME
 * object.
 * @property {String} file_name (optional) the original file name
 * @property {signatureDetails} signatures Verification details for
 * signatures
 */

/**
 * @typedef {Object} signatureDetails
 * @property {Boolean} all_valid Summary if all signatures are fully valid
 * @property {Number} count Number of signatures found
 * @property {Number} failures Number of invalid signatures
 * @property {Array<GPGME_Signature>} signatures.good All valid signatures
 * @property {Array<GPGME_Signature>} signatures.bad All invalid signatures
 */

/**
 * @typedef {Object} encrypt_result The result of an encrypt operation
 * @property {String} data The encrypted message
 * @property {String} format Indicating how the data was converted after being
 *  received from gpgme.
 *      'ascii': Data was ascii-encoded and no further processed
 *      'string': Data was decoded into an utf-8 string,
 *      'base64': Data was not processed and is a base64 string
 *      'uint8': Data was turned into a Uint8Array
 */

/**
 * @typedef { GPGME_Key | String | Object } inputKeys
 * Accepts different identifiers of a gnupg Key that can be parsed by
 * {@link toKeyIdArray}. Expected inputs are: One or an array of
 * GPGME_Keys; one or an array of fingerprint strings; one or an array of
 * openpgpjs Key objects.
 */

/**
 * @typedef {Object} signResult The result of a signing operation
 * @property {String} data The resulting data. Includes the signature in
 *  clearsign mode
 * @property {String} signature The detached signature (if in detached mode)
 */

/** @typedef {Object} verifyResult The result of a verification
 * @property {Boolean} data: The verified data
 * @property {Boolean} is_mime (optional) the data claims to be a MIME
 * object.
 * @property {signatureDetails} signatures Verification details for
 * signatures
 */

/**
 * The main entry point for gpgme.js.
 * @class
 */
export class GpgME {

    constructor (){
        this._Keyring = null;
    }

    /**
     * setter for {@link setKeyring}.
     * @param {GPGME_Keyring} keyring A Keyring to use
     */
    set Keyring (keyring){
        if (keyring && keyring instanceof GPGME_Keyring){
            this._Keyring = keyring;
        }
    }
    /**
     * Accesses the {@link GPGME_Keyring}.
     */
    get Keyring (){
        if (!this._Keyring){
            this._Keyring = new GPGME_Keyring;
        }
        return this._Keyring;
    }

    /**
     * Encrypt (and optionally sign) data
     * @param {Object} options
     * @param {String|Object} options.data text/data to be encrypted as String.
     * Also accepts Objects with a getText method
     * @param {inputKeys} options.publicKeys
     * Keys used to encrypt the message
     * @param {inputKeys} opions.secretKeys (optional) Keys used to sign the
     * message. If Keys are present, the  operation requested is assumed
     * to be 'encrypt and sign'
     * @param {Boolean} options.base64 (optional) The data will be interpreted
     * as base64 encoded data.
     * @param {Boolean} options.armor (optional) Request the output as armored
     * block.
     * @param {Boolean} options.wildcard (optional) If true, recipient
     * information will not be added to the message.
     * @param {Boolean} always_trust (optional, default true) This assumes that
     * used keys are fully trusted. If set to false, encryption to a key not
     * fully trusted in gnupg will fail
     * @param {Object} additional use additional valid gpg options as
     * defined in {@link permittedOperations}
     * @returns {Promise<encrypt_result>} Object containing the encrypted
     * message and additional info.
     * @async
     */
    encrypt ({ data, publicKeys, secretKeys, base64 = false, armor = true,
        wildcard, always_trust = true, additional = {} } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data || !publicKeys){
            return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
        }
        let msg = createMessage('encrypt');
        if (msg instanceof Error){
            return Promise.reject(msg);
        }
        msg.setParameter('armor', armor);

        if (base64 === true) {
            msg.setParameter('base64', true);
        }
        if (always_trust === true) {
            msg.setParameter('always-trust', true);
        }
        let pubkeys = toKeyIdArray(publicKeys);
        if (!pubkeys.length) {
            return Promise.reject(gpgme_error('MSG_NO_KEYS'));
        }
        msg.setParameter('keys', pubkeys);
        let sigkeys = toKeyIdArray(secretKeys);
        if (sigkeys.length > 0) {
            msg.setParameter('signing_keys', sigkeys);
        }
        putData(msg, data);
        if (wildcard === true){
            msg.setParameter('throw-keyids', true);
        }
        if (additional){
            let additional_Keys = Object.keys(additional);
            for (let k = 0; k < additional_Keys.length; k++) {
                try {
                    msg.setParameter(additional_Keys[k],
                        additional[additional_Keys[k]]);
                }
                catch (error){
                    return Promise.reject(error);
                }
            }
        }
        if (msg.isComplete() === true){
            return msg.post();
        } else {
            return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
        }
    }

    /**
    * Decrypts a Message
    * @param {Object} options
    * @param {String|Object} options.data text/data to be decrypted. Accepts
    * Strings and Objects with a getText method
    * @param {Boolean} options.base64 (optional) false if the data is an
    * armored block, true if it is base64 encoded binary data
    * @param {String} options.expect (optional) can be set to 'uint8' or
    * 'base64'. Does no extra decoding on the data, and returns the decoded
    * data as either Uint8Array or unprocessed(base64 encoded) string.
    * @returns {Promise<decrypt_result>} Decrypted Message and information
    * @async
    */
    decrypt ({ data, base64, expect } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('MSG_EMPTY'));
        }
        let msg = createMessage('decrypt');

        if (msg instanceof Error){
            return Promise.reject(msg);
        }
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        if (expect === 'base64' || expect === 'uint8'){
            msg.expected = expect;
        }
        putData(msg, data);
        return new Promise(function (resolve, reject){
            msg.post().then(function (result){
                let returnValue = { data: result.data };
                returnValue.format = result.format ? result.format : null;
                if (result.hasOwnProperty('dec_info')){
                    returnValue.is_mime = result.dec_info.is_mime ? true: false;
                    if (result.dec_info.file_name) {
                        returnValue.file_name = result.dec_info.file_name;
                    }
                }
                if (!returnValue.file_name) {
                    returnValue.file_name = null;
                }
                if (result.hasOwnProperty('info')
                    && result.info.hasOwnProperty('signatures')
                    && Array.isArray(result.info.signatures)
                ) {
                    returnValue.signatures = collectSignatures(
                        result.info.signatures);
                }
                if (returnValue.signatures instanceof Error){
                    reject(returnValue.signatures);
                } else {
                    resolve(returnValue);
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Sign a Message
     * @param {Object} options Signing options
     * @param {String|Object} options.data text/data to be signed. Accepts
     * Strings and Objects with a getText method.
     * @param {inputKeys} options.keys The key/keys to use for signing
     * @param {String} options.mode The signing mode. Currently supported:
     *  'clearsign':The Message is embedded into the signature;
     *  'detached': The signature is stored separately
     * @param {Boolean} options.base64 input is considered base64
     * @returns {Promise<signResult>}
     * @async
     */
    sign ({ data, keys, mode = 'clearsign', base64 } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('MSG_EMPTY'));
        }
        let key_arr = toKeyIdArray(keys);
        if (key_arr.length === 0){
            return Promise.reject(gpgme_error('MSG_NO_KEYS'));
        }

        let msg = createMessage('sign');
        msg.setParameter('keys', key_arr);
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        msg.setParameter('mode', mode);
        putData(msg, data);

        return new Promise(function (resolve,reject) {
            msg.post().then( function (message) {
                if (mode === 'clearsign'){
                    resolve({
                        data: message.data }
                    );
                } else if (mode === 'detached') {
                    resolve({
                        data: data,
                        signature: message.data
                    });
                }
            }, function (error){
                reject(error);
            });
        });
    }

    /**
     * Verifies data.
     * @param {Object} options
     * @param {String|Object} options.data text/data to be verified. Accepts
     * Strings and Objects with a getText method
     * @param {String} options.signature A detached signature. If not present,
     * opaque mode is assumed
     * @param {Boolean} options.base64 Indicating that data and signature are
     * base64 encoded
     * @returns {Promise<verifyResult>}
     *@async
    */
    verify ({ data, signature, base64 } = {}){
        if (typeof arguments[0] !== 'object') {
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        if (!data){
            return Promise.reject(gpgme_error('PARAM_WRONG'));
        }
        let msg = createMessage('verify');
        let dt = putData(msg, data);
        if (dt instanceof Error){
            return Promise.reject(dt);
        }
        if (signature){
            if (typeof signature !== 'string'){
                return Promise.reject(gpgme_error('PARAM_WRONG'));
            } else {
                msg.setParameter('signature', signature);
            }
        }
        if (base64 === true){
            msg.setParameter('base64', true);
        }
        return new Promise(function (resolve, reject){
            msg.post().then(function (message){
                if (!message.info || !message.info.signatures){
                    reject(gpgme_error('SIG_NO_SIGS'));
                } else {
                    let returnValue = {
                        signatures: collectSignatures(message.info.signatures)
                    };
                    if (returnValue.signatures instanceof Error){
                        reject(returnValue.signatures);
                    } else {
                        returnValue.is_mime = message.info.is_mime? true: false;
                        if (message.info.filename){
                            returnValue.file_name = message.info.filename;
                        }
                        returnValue.data = message.data;
                        resolve(returnValue);
                    }
                }
            }, function (error){
                reject(error);
            });
        });
    }
}

/**
 * Sets the data of the message, setting flags according on the data type
 * @param {GPGME_Message} message The message where this data will be set
 * @param { String| Object } data The data to enter. Expects either a string of
 * data, or an object with a getText method
 * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise
 * @private
 */
function putData (message, data){
    if (!message || !(message instanceof GPGME_Message)) {
        return gpgme_error('PARAM_WRONG');
    }
    if (!data){
        return gpgme_error('PARAM_WRONG');
    } else if (typeof data === 'string') {
        message.setParameter('data', data);
    } else if (
        (typeof data === 'object') &&
        (typeof data.getText === 'function')
    ){
        let txt = data.getText();
        if (typeof txt === 'string'){
            message.setParameter('data', txt);
        } else {
            return gpgme_error('PARAM_WRONG');
        }

    } else {
        return gpgme_error('PARAM_WRONG');
    }
}

/**
 * Parses, validates and converts incoming objects into signatures.
 * @param {Array<Object>} sigs
 * @returns {signatureDetails} Details about the signatures
 */
function collectSignatures (sigs){
    if (!Array.isArray(sigs)){
        return gpgme_error('SIG_NO_SIGS');
    }
    let summary = {
        all_valid: false,
        count: sigs.length,
        failures: 0,
        signatures: {
            good: [],
            bad: [],
        }
    };
    for (let i=0; i< sigs.length; i++){
        let sigObj = createSignature(sigs[i]);
        if (sigObj instanceof Error) {
            return gpgme_error('SIG_WRONG');
        }
        if (sigObj.valid !== true){
            summary.failures += 1;
            summary.signatures.bad.push(sigObj);
        } else {
            summary.signatures.good.push(sigObj);
        }
    }
    if (summary.failures === 0){
        summary.all_valid = true;
    }
    return summary;
}<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name angularApp.controller:FormCtrl
 * @description
 * # FormCtrl
 * Controller of the angularApp
 */
angular.module('angularApp')
  .controller('FormCtrl', function ($scope, $rootScope, APP, resourceManager, exMsg, $state, $stateParams, $http, $translate, fieldService, formService) {
    var vm = $scope;
    window.formCtrl = vm;

    vm.model = resourceManager.register($stateParams.model, APP.apiPrefix + $stateParams.model.replace(/-/gi, '_') + '/:id');

    vm.record = {};
    vm.action = { loading: true, saving: false, creating: false, updating: false, deleting: false };

    vm.schema = {};

    vm.formlyFields  = fieldService.get(vm.model.key);
    vm.formlyOptions = {};
    vm.formlyForm    = {};

    vm.loadConfig = function () {
      $http.get(APP.apiPrefix + 'config/' + vm.model.url)
        .success(function (data) {
          vm.schema  = data.schema;
          vm.setDisableFields();
          vm.form = formService.get(vm.model.key);
          $rootScope.$broadcast('model:form-config-loaded', vm.model.name, data, vm);
          vm.setRecord();
        })
        .error(function(data, status, headers, config) {
          exMsg.error('error');
        });
    };

    vm.hasCreateAccess = function () {
      return vm.hasAccess(vm.model.name + ':create');
    }

    vm.hasShowAccess = function () {
      return vm.hasAccess(vm.model.name + ':show');
    }

    vm.hasUpdateAccess = function () {
      return vm.hasAccess(vm.model.name + ':update');
    }

    vm.hasDeleteAccess = function () {
      return vm.hasAccess(vm.model.name + ':delete');
    }

    vm.setDisableFields = function () {
      if ($state.$current.name === 'app.module.model.show') {
        angular.forEach(vm.schema.properties, function (field) {
          field.readonly = true;
        });
      } else {
        angular.forEach(vm.schema.properties, function (field) {
          field.readonly = false;
        });
      }
      vm.$broadcast('schemaFormRedraw');
    }

    vm.loadRecord = function () {
      vm.action.loading = true;

      if($stateParams.id) {
        var data = { id: $stateParams.id };
        resourceManager.get(vm.model.name, data)
          .then(function (data) {
            vm.record = data;
            vm.sanitizeRecord();
            $rootScope.$broadcast('model:record-loaded', vm.model.name, vm.record, vm);
            vm.action.loading = false;
            vm.$broadcast('schemaFormRedraw');
          })
          .catch(function (error) {
            vm.error(error);
            vm.action.loading = false;
          });
      } else {
        $rootScope.$broadcast('model:record-new', vm.model.name, vm.record, vm);
      }
    };

    vm.$on('model:reload-record', function(evt, modelName, record) {
      if (modelName === vm.model.name && record.id === vm.record.id) {
        vm.loadRecord();
      }
    });

    vm.sanitizeRecord = function () {
      _.each(vm.record, function (value, key) {
        if (value === null) {
          vm.record[key] = '';
        }
      });
    }

    vm.setRecord = function () {
      if (!vm.record.id && $stateParams.q) {
        _.each(vm.splitQ($stateParams.q), function (v, k) {
          vm.record[k] = v;
        });
        $rootScope.$broadcast('model:record-set', vm.model.name, vm.record, vm);
      }
    };

    vm.close = function () {
      vm.record = {};
      $state.go('^');
    };

    vm.redirectBack = function () {
      vm.record = {};

      if ($state.$current.name === 'app.module.form.model') {
        $state.go('.', $stateParams, { reload: true });
      } else {
        $state.go('^');
      }
    };

    vm.create = function () {
      vm.action.saving = true;
      vm.action.creating = true;

      var data = {};
      data[vm.model.key] = vm.record;

      resourceManager.create(vm.model.name, data)
        .then(function (data) {
          $rootScope.$broadcast('model:record-created', vm.model.name, vm.record, vm);
          exMsg.success(vm.schema.title + ' created successfully');
          vm.record.id = data.id;
          vm.redirectBack();
        })
        .catch(function (error) {
          vm.error(error);
        })
        .finally(function () {
          vm.action.saving = false;
          vm.action.creating = false;
        });
    };

    vm.edit = function () {
      $state.go('^.edit', $stateParams.id);
    };

    vm.update = function () {
      vm.action.saving = true;
      vm.action.updating = true;

      var data = { id: $stateParams.id };
      data[vm.model.key] = vm.record;

      resourceManager.update(vm.model.name, data)
        .then(function (data) {
          $rootScope.$broadcast('model:record-updated', vm.model.name, vm.record, vm);
          exMsg.success(vm.schema.title + ' updated successfully');
          vm.redirectBack();
        })
        .catch(function (error) {
          vm.error(error);
        })
        .finally(function () {
          vm.action.saving = false;
          vm.action.updating = false;
        });
    };

    vm.save = function () {
      PNotify.removeAll();
      vm.$broadcast('schemaFormValidate');

      if (vm.formObject && !vm.formObject.$valid) {
        return;
      }

      if($stateParams.id) {
        vm.update();
      } else {
        vm.create();
      }
    };

    vm.delete = function () {
      vm.action.deleting = true;

      var msg = "Are you sure you want to delete this " + vm.schema.title + "?";
      exMsg.confirm(msg, "Confirm Delete").then(function () {
        var data = { id: vm.record.id };
        data[vm.model.key] = vm.record;
        resourceManager.delete(vm.model.name, data)
          .then(function (data) {
          $rootScope.$broadcast('model:record-deleted', vm.model.name, vm.record, vm);
            exMsg.success(vm.schema.title + " deleted successfully");
            vm.redirectBack();
          })
          .catch(function (error) {
            vm.error(error);
          }).finally(function () {
            vm.action.deleting = false;
          });
      }).catch(function () {
        vm.action.deleting = false;
      });
    };

    vm.loadConfig();
    vm.loadRecord();
  });
<commit_msg>Fixed bug with record broadcast<commit_after>'use strict';

/**
 * @ngdoc function
 * @name angularApp.controller:FormCtrl
 * @description
 * # FormCtrl
 * Controller of the angularApp
 */
angular.module('angularApp')
  .controller('FormCtrl', function ($scope, $rootScope, APP, resourceManager, exMsg, $state, $stateParams, $http, $translate, fieldService, formService) {
    var vm = $scope;
    window.formCtrl = vm;

    vm.model = resourceManager.register($stateParams.model, APP.apiPrefix + $stateParams.model.replace(/-/gi, '_') + '/:id');

    vm.record = {};
    vm.action = { loading: true, saving: false, creating: false, updating: false, deleting: false };

    vm.schema = {};

    vm.formlyFields  = fieldService.get(vm.model.key);
    vm.formlyOptions = {};
    vm.formlyForm    = {};

    vm.loadConfig = function () {
      $http.get(APP.apiPrefix + 'config/' + vm.model.url)
        .success(function (data) {
          vm.schema  = data.schema;
          vm.setDisableFields();
          vm.form = formService.get(vm.model.key);
          $rootScope.$broadcast('model:form-config-loaded', vm.model.name, data, vm);
          vm.setRecord();
        })
        .error(function(data, status, headers, config) {
          exMsg.error('error');
        });
    };

    vm.hasCreateAccess = function () {
      return vm.hasAccess(vm.model.name + ':create');
    }

    vm.hasShowAccess = function () {
      return vm.hasAccess(vm.model.name + ':show');
    }

    vm.hasUpdateAccess = function () {
      return vm.hasAccess(vm.model.name + ':update');
    }

    vm.hasDeleteAccess = function () {
      return vm.hasAccess(vm.model.name + ':delete');
    }

    vm.setDisableFields = function () {
      if ($state.$current.name === 'app.module.model.show') {
        angular.forEach(vm.schema.properties, function (field) {
          field.readonly = true;
        });
      } else {
        angular.forEach(vm.schema.properties, function (field) {
          field.readonly = false;
        });
      }
      vm.$broadcast('schemaFormRedraw');
    }

    vm.loadRecord = function () {
      vm.action.loading = true;

      if($stateParams.id) {
        var data = { id: $stateParams.id };
        resourceManager.get(vm.model.name, data)
          .then(function (data) {
            vm.record = data;
            vm.sanitizeRecord();
            $rootScope.$broadcast('model:record-loaded', vm.model.name, vm.record, vm);
            vm.action.loading = false;
            vm.$broadcast('schemaFormRedraw');
          })
          .catch(function (error) {
            vm.error(error);
            vm.action.loading = false;
          });
      } else {
        $rootScope.$broadcast('model:record-new', vm.model.name, vm.record, vm);
      }
    };

    vm.$on('model:reload-record', function(evt, modelName, record) {
      if (modelName === vm.model.name && record.id === vm.record.id) {
        vm.loadRecord();
      }
    });

    vm.sanitizeRecord = function () {
      _.each(vm.record, function (value, key) {
        if (value === null) {
          vm.record[key] = '';
        }
      });
    }

    vm.setRecord = function () {
      if (!vm.record.id && $stateParams.q) {
        _.each(vm.splitQ($stateParams.q), function (v, k) {
          vm.record[k] = v;
        });
        $rootScope.$broadcast('model:record-set', vm.model.name, vm.record, vm);
      }
    };

    vm.close = function () {
      vm.record = {};
      $state.go('^');
    };

    vm.redirectBack = function () {
      vm.record = {};

      if ($state.$current.name === 'app.module.form.model') {
        $state.go('.', $stateParams, { reload: true });
      } else {
        $state.go('^');
      }
    };

    vm.create = function () {
      vm.action.saving = true;
      vm.action.creating = true;

      var data = {};
      data[vm.model.key] = vm.record;

      resourceManager.create(vm.model.name, data)
        .then(function (data) {
          $rootScope.$broadcast('model:record-created', vm.model.name, data, vm);
          exMsg.success(vm.schema.title + ' created successfully');
          vm.record.id = data.id;
          vm.redirectBack();
        })
        .catch(function (error) {
          vm.error(error);
        })
        .finally(function () {
          vm.action.saving = false;
          vm.action.creating = false;
        });
    };

    vm.edit = function () {
      $state.go('^.edit', $stateParams.id);
    };

    vm.update = function () {
      vm.action.saving = true;
      vm.action.updating = true;

      var data = { id: $stateParams.id };
      data[vm.model.key] = vm.record;

      resourceManager.update(vm.model.name, data)
        .then(function (data) {
          $rootScope.$broadcast('model:record-updated', vm.model.name, data, vm);
          exMsg.success(vm.schema.title + ' updated successfully');
          vm.redirectBack();
        })
        .catch(function (error) {
          vm.error(error);
        })
        .finally(function () {
          vm.action.saving = false;
          vm.action.updating = false;
        });
    };

    vm.save = function () {
      PNotify.removeAll();
      vm.$broadcast('schemaFormValidate');

      if (vm.formObject && !vm.formObject.$valid) {
        return;
      }

      if($stateParams.id) {
        vm.update();
      } else {
        vm.create();
      }
    };

    vm.delete = function () {
      vm.action.deleting = true;

      var msg = "Are you sure you want to delete this " + vm.schema.title + "?";
      exMsg.confirm(msg, "Confirm Delete").then(function () {
        var data = { id: vm.record.id };
        data[vm.model.key] = vm.record;
        resourceManager.delete(vm.model.name, data)
          .then(function (data) {
          $rootScope.$broadcast('model:record-deleted', vm.model.name, vm.record, vm);
            exMsg.success(vm.schema.title + " deleted successfully");
            vm.redirectBack();
          })
          .catch(function (error) {
            vm.error(error);
          }).finally(function () {
            vm.action.deleting = false;
          });
      }).catch(function () {
        vm.action.deleting = false;
      });
    };

    vm.loadConfig();
    vm.loadRecord();
  });
<|endoftext|>


<commit_before>/**
 * SnapshotController
 *
 * @description :: Server-side logic for managing snapshots
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var _ = require("lodash");
var KongService = require('../services/KongService');

module.exports = _.merge(_.cloneDeep(require('../base/Controller')), {

  consumers: async (req,res) => {

    const routeId = req.params.id;
    let routeAclPlugin;
    let jwtPlugin;
    let basicAuthPlugin;
    let keyAuthPlugin;
    let hmacAuthPlugin;
    let oauth2Plugin;

    sails.log("KongRoutesController:consumers called");

    let plugins = await KongService.fetch(`/routes/${routeId}/plugins?enabled=true`, req);

    if(plugins.total == 0) return res.json([]);

    sails.log("Route plugins =>", plugins);

    routeAclPlugin = _.filter(plugins.data, item => item.name === 'acl')[0];
    jwtPlugin = _.filter(plugins.data, item => item.name === 'jwt')[0];
    basicAuthPlugin = _.filter(plugins.data, item => item.name === 'basic-auth')[0];
    keyAuthPlugin = _.filter(plugins.data, item => item.name === 'key-auth')[0];
    hmacAuthPlugin = _.filter(plugins.data, item => item.name === 'hmac-auth')[0];
    oauth2Plugin = _.filter(plugins.data, item => item.name === 'oauth2')[0];

    sails.log("routeAclPlugin",routeAclPlugin)
    sails.log("jwtPlugin",jwtPlugin)
    sails.log("basicAuthPlugin",basicAuthPlugin)
    sails.log("keyAuthPlugin",keyAuthPlugin)
    sails.log("hmacAuthPlugin",hmacAuthPlugin)
    sails.log("oauth2Plugin",oauth2Plugin)

    let aclConsumerIds;
    let authenticationPlugins = _.filter(plugins.data, item => ['jwt','basic-auth','key-auth','hmac-auth','oauth2'].indexOf(item.name) > -1);
    authenticationPlugins = _.map(authenticationPlugins, item => item.name);
    sails.log("authenticationPlugins",authenticationPlugins);

    let whiteListedGroups = routeAclPlugin ? routeAclPlugin.config.whitelist || [] : [];
    let blackListedGroups = routeAclPlugin ? routeAclPlugin.config.blacklist || [] : [];

    // ACL
    sails.log("whiteListedGroups",whiteListedGroups)
    sails.log("blackListedGroups",blackListedGroups)

    // We need to retrieve all acls and filter the accessible ones based on the whitelisted and blacklisted groups
    let acls = await KongService.fetch(`/acls`, req);

    sails.log("acls",acls);

    let filteredAcls = _.filter(acls.data, item => {
      return whiteListedGroups.indexOf(item.group) > -1 && blackListedGroups.indexOf(item.group) === -1;
    });

    sails.log("filteredAcls", filteredAcls);

    // Gather the consumer ids of the filtered groups
    aclConsumerIds = _.map(filteredAcls, item => item.consumer_id);
    sails.log("aclConsumerIds", aclConsumerIds);

    // If the route is access controlled and no aclConsumerIds are found,
    // it means that noone can access this route
    if(routeAclPlugin && (!aclConsumerIds || !aclConsumerIds.length)) {
      return res.json({
        total: 0,
        acl: routeAclPlugin,
        authenticationPlugins: authenticationPlugins,
        data: []
      })
    }

    let jwts, keyAuths, hmacAuths, oauth2, basicAuths

    if(jwtPlugin) jwts = await KongService.fetch(`/jwts`, req);
    if(keyAuthPlugin) keyAuths = await KongService.fetch(`/key-auths`, req);
    if(hmacAuthPlugin) hmacAuths = await KongService.fetch(`/hmac-auths`, req);
    if(oauth2Plugin) oauth2 = await KongService.fetch(`/oauth2`, req);
    if(basicAuthPlugin) basicAuths = await KongService.fetch(`/basic-auths`, req);

    sails.log("jwts",jwts)
    sails.log("keyAuths",keyAuths)
    sails.log("hmacAuths",hmacAuths)
    sails.log("oauth2",oauth2)
    sails.log("basicAuths",basicAuths)

    let jwtConsumerIds = jwts ? _.map(jwts.data, item => item.consumer_id) : [];
    let keyAuthConsumerIds = keyAuths ? _.map(keyAuths.data, item => item.consumer_id) : [];
    let hmacAuthConsumerIds = hmacAuths ? _.map(hmacAuths.data, item => item.consumer_id) : [];
    let oauth2ConsumerIds = oauth2 ? _.map(oauth2.data, item => item.consumer_id) : [];
    let basicAuthConsumerIds = basicAuths ? _.map(basicAuths.data, item => item.consumer_id) : [];

    sails.log("jwtConsumerIds",jwtConsumerIds)
    sails.log("keyAuthConsumerIds",keyAuthConsumerIds)
    sails.log("hmacAuthConsumerIds",hmacAuthConsumerIds)
    sails.log("oauth2ConsumerIds",oauth2ConsumerIds)
    sails.log("basicAuthConsumerIds",basicAuthConsumerIds)

    let consumerIds;
    let authenticationPluginsConsumerIds = _.uniq([
      ...jwtConsumerIds,
      ...keyAuthConsumerIds,
      ...hmacAuthConsumerIds,
      ...oauth2ConsumerIds,
      ...basicAuthConsumerIds
    ]);

    if(aclConsumerIds && aclConsumerIds.length) {
      sails.log("authenticationPluginsConsumerIds", authenticationPluginsConsumerIds);
      sails.log("aclConsumerIds", _.uniq(aclConsumerIds));
      consumerIds = authenticationPluginsConsumerIds.length ? _.intersection(_.uniq(aclConsumerIds), authenticationPluginsConsumerIds) : _.uniq(aclConsumerIds);
    }else{
      consumerIds = authenticationPluginsConsumerIds;
    }

    sails.log("consumerIds => ", consumerIds);

    // Fetch all consumers
    KongService.listAllCb(req, `/consumers`, (err, consumers) => {
      if (err) return res.negotiate(err);
      if(!consumers.data || !consumers.data.length) return res.json([]);

      let eligibleConsumers = _.filter(consumers.data, item => {
        return consumerIds.indexOf(item.id) > -1;
      })

      eligibleConsumers.forEach(consumer => {
        let plugins = [];
        if(keyAuths && _.filter(keyAuths.data,item => item.consumer_id === consumer.id).length) {
          plugins.push('key-auth')
        }
        if(jwts && _.filter(jwts.data,item => item.consumer_id === consumer.id).length) {
          plugins.push('jwt')
        }
        if(hmacAuths && _.filter(hmacAuths.data,item => item.consumer_id === consumer.id).length) {
          plugins.push('hmac-auth')
        }
        if(oauth2 && _.filter(oauth2.data,item => item.consumer_id === consumer.id).length) {
          plugins.push('oauth2')
        }
        if(basicAuths && _.filter(basicAuths.data,item => item.consumer_id === consumer.id).length) {
          plugins.push('basic-auth')
        }
        consumer.plugins = plugins;

      })

      return res.json({
        total: eligibleConsumers.length,
        acl: routeAclPlugin,
        authenticationPlugins: authenticationPlugins,
        data: eligibleConsumers
      })

    })
  }

});

<commit_msg>Fix eligible consumers compatibility with Kong 1.x. Ref issue #288<commit_after>/**
 * SnapshotController
 *
 * @description :: Server-side logic for managing snapshots
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var _ = require("lodash");
var KongService = require('../services/KongService');

module.exports = _.merge(_.cloneDeep(require('../base/Controller')), {

  consumers: async (req,res) => {

    const routeId = req.params.id;
    let routeAclPlugin;
    let jwtPlugin;
    let basicAuthPlugin;
    let keyAuthPlugin;
    let hmacAuthPlugin;
    let oauth2Plugin;

    sails.log("KongRoutesController:consumers called");

    let plugins = await KongService.fetch(`/routes/${routeId}/plugins?enabled=true`, req);

    // Make sure only the enabled plugins are listed.
    // Kong 1.x API stopped honoring the query string parameters for some reason,
    // so ?enabled=true, makes no difference whatsoever.
    // Putting this monkey patch here with the plan to remove it if Kong starts accepting query strings again.
    plugins.data = _.filter(plugins.data, plugin => plugin.enabled);
    plugins.total = plugins.data.length;

    if(plugins.total == 0) return res.json([]);

    sails.log("Route plugins =>", plugins);

    routeAclPlugin = _.filter(plugins.data, item => item.name === 'acl')[0];
    jwtPlugin = _.filter(plugins.data, item => item.name === 'jwt')[0];
    basicAuthPlugin = _.filter(plugins.data, item => item.name === 'basic-auth')[0];
    keyAuthPlugin = _.filter(plugins.data, item => item.name === 'key-auth')[0];
    hmacAuthPlugin = _.filter(plugins.data, item => item.name === 'hmac-auth')[0];
    oauth2Plugin = _.filter(plugins.data, item => item.name === 'oauth2')[0];

    sails.log("routeAclPlugin",routeAclPlugin)
    sails.log("jwtPlugin",jwtPlugin)
    sails.log("basicAuthPlugin",basicAuthPlugin)
    sails.log("keyAuthPlugin",keyAuthPlugin)
    sails.log("hmacAuthPlugin",hmacAuthPlugin)
    sails.log("oauth2Plugin",oauth2Plugin)

    let aclConsumerIds;
    let authenticationPlugins = _.filter(plugins.data, item => ['jwt','basic-auth','key-auth','hmac-auth','oauth2'].indexOf(item.name) > -1);
    authenticationPlugins = _.map(authenticationPlugins, item => item.name);
    sails.log("authenticationPlugins",authenticationPlugins);

    let whiteListedGroups = routeAclPlugin ? routeAclPlugin.config.whitelist || [] : [];
    let blackListedGroups = routeAclPlugin ? routeAclPlugin.config.blacklist || [] : [];

    // ACL
    sails.log("whiteListedGroups",whiteListedGroups)
    sails.log("blackListedGroups",blackListedGroups)

    // We need to retrieve all acls and filter the accessible ones based on the whitelisted and blacklisted groups
    let acls = await KongService.fetch(`/acls`, req);

    sails.log("acls",acls);

    let filteredAcls = _.filter(acls.data, item => {
      return whiteListedGroups.indexOf(item.group) > -1 && blackListedGroups.indexOf(item.group) === -1;
    });

    sails.log("filteredAcls", filteredAcls);

    // Gather the consumer ids of the filtered groups
    aclConsumerIds = _.map(filteredAcls, item => item.consumer.id);
    sails.log("aclConsumerIds", aclConsumerIds);

    // If the route is access controlled and no aclConsumerIds are found,
    // it means that noone can access this route
    if(routeAclPlugin && (!aclConsumerIds || !aclConsumerIds.length)) {
      return res.json({
        total: 0,
        acl: routeAclPlugin,
        authenticationPlugins: authenticationPlugins,
        data: []
      })
    }

    let jwts, keyAuths, hmacAuths, oauth2, basicAuths

    if(jwtPlugin) jwts = await KongService.fetch(`/jwts`, req);
    if(keyAuthPlugin) keyAuths = await KongService.fetch(`/key-auths`, req);
    if(hmacAuthPlugin) hmacAuths = await KongService.fetch(`/hmac-auths`, req);
    if(oauth2Plugin) oauth2 = await KongService.fetch(`/oauth2`, req);
    if(basicAuthPlugin) basicAuths = await KongService.fetch(`/basic-auths`, req);

    sails.log("jwts",jwts)
    sails.log("keyAuths",keyAuths)
    sails.log("hmacAuths",hmacAuths)
    sails.log("oauth2",oauth2)
    sails.log("basicAuths",basicAuths)

    let jwtConsumerIds = jwts ? _.map(jwts.data, item => item.consumer.id) : [];
    let keyAuthConsumerIds = keyAuths ? _.map(keyAuths.data, item => item.consumer.id) : [];
    let hmacAuthConsumerIds = hmacAuths ? _.map(hmacAuths.data, item => item.consumer.id) : [];
    let oauth2ConsumerIds = oauth2 ? _.map(oauth2.data, item => item.consumer.id) : [];
    let basicAuthConsumerIds = basicAuths ? _.map(basicAuths.data, item => item.consumer.id) : [];

    sails.log("jwtConsumerIds",jwtConsumerIds)
    sails.log("keyAuthConsumerIds",keyAuthConsumerIds)
    sails.log("hmacAuthConsumerIds",hmacAuthConsumerIds)
    sails.log("oauth2ConsumerIds",oauth2ConsumerIds)
    sails.log("basicAuthConsumerIds",basicAuthConsumerIds)

    let consumerIds;
    let authenticationPluginsConsumerIds = _.uniq([
      ...jwtConsumerIds,
      ...keyAuthConsumerIds,
      ...hmacAuthConsumerIds,
      ...oauth2ConsumerIds,
      ...basicAuthConsumerIds
    ]);

    if(aclConsumerIds && aclConsumerIds.length) {
      sails.log("authenticationPluginsConsumerIds", authenticationPluginsConsumerIds);
      sails.log("aclConsumerIds", _.uniq(aclConsumerIds));
      consumerIds = authenticationPluginsConsumerIds.length ? _.intersection(_.uniq(aclConsumerIds), authenticationPluginsConsumerIds) : _.uniq(aclConsumerIds);
    }else{
      consumerIds = authenticationPluginsConsumerIds;
    }

    sails.log("consumerIds => ", consumerIds);

    // Fetch all consumers
    KongService.listAllCb(req, `/consumers`, (err, consumers) => {
      if (err) return res.negotiate(err);
      if(!consumers.data || !consumers.data.length) return res.json([]);

      let eligibleConsumers = _.filter(consumers.data, item => {
        return consumerIds.indexOf(item.id) > -1;
      })

      eligibleConsumers.forEach(consumer => {
        let plugins = [];
        if(keyAuths && _.filter(keyAuths.data,item => item.consumer.id === consumer.id).length) {
          plugins.push('key-auth')
        }
        if(jwts && _.filter(jwts.data,item => item.consumer.id === consumer.id).length) {
          plugins.push('jwt')
        }
        if(hmacAuths && _.filter(hmacAuths.data,item => item.consumer.id === consumer.id).length) {
          plugins.push('hmac-auth')
        }
        if(oauth2 && _.filter(oauth2.data,item => item.consumer.id === consumer.id).length) {
          plugins.push('oauth2')
        }
        if(basicAuths && _.filter(basicAuths.data,item => item.consumer.id === consumer.id).length) {
          plugins.push('basic-auth')
        }
        consumer.plugins = plugins;

      })

      return res.json({
        total: eligibleConsumers.length,
        acl: routeAclPlugin,
        authenticationPlugins: authenticationPlugins,
        data: eligibleConsumers
      })

    })
  }

});

<|endoftext|>


<commit_before>define(function(require) {

	var API = require('FoowdAPI');
	var Navbar = require('NavbarController');
	var templates = require('templates');
	var utils = require('Utils');
	var $ = require('jquery');
	var service = require('foowdServices');

	var UserBoardController = (function(){

		var preferencesContainerId =  "#preferences-container";
		var userDetailsContainer = "#account-menu";
		//userId reference
   		var group = false;

   		/* SS: parametro aggiunto ipotizzando che la board possa essere visualizzata anche da amici */
   		var userName = null;
   		//preferenza utente
   		var preference = {
   				OfferId : "",
   				ExternalId : "",
   				type : "create",
   				Qt : "",
   		};

   		//nel controller devo essere sicuro che il dom sia stato casricato correttamente
		function _stateCheck(){
			switch(document.readyState){
				case "loading":
					document.onreadystatechange = function (){
						_stateCheck();
					}
				break;
				case "interactive":
				case "complete":
					_init();
				break;
			}
		}
   		//controller init
   		function _init(){
				Navbar.loadNavbar(true);
	   			//carico i template
	   			group=false;
	   			_getUserPreferences();
	   			_getUserInfo();
   		}

   		function _getUserPreferences(){
			var userId = utils.getUserId();
			if(userId!=null && group){
				_getUserPreferencesGroup(userId);
			}else{
				_getUserPreferencesSingle(userId);
			}

		}

		function _getUserPreferencesSingle(userId){
			API.getUserPreferences(userId).then(function(data){
				var rawData = data;
				var parsedProducts = _applyPreferencesContext(rawData.body);
				_fillBoard(parsedProducts);
				$(document).trigger('preferences-loaded');
			},function(e){
				console.log(e);
			});

		}
		function _getUserPreferencesGroup(userId){
			API.getFriend(userId).then(function(data){
				var friendsStr='';
				if(data.result && data.result.friends){
					 friendsStr = data.result.friends.join();
				}
				_getUserPreferencesSingle(userId+','+friendsStr);
			},function(error){
					console.log(error);
			});

		}

   		function _applyPreferencesContext(context) {
			var result = "";
			context.map(function(el) {
				//aggiungo l'immagine al json di contesto
				utils.addPicture(el.Offer, 'small');
				utils.setLoggedGroup(el, group);

				//ottengo l'html dal template + contesto
				var htmlComponent = templates.userPreference(el);
				//concateno
				result += htmlComponent;
			});

			return result;
		}
		function _fillBoard(content) {
			$(preferencesContainerId).html(content);
		}

		function _getUserInfo(){
			var userId = utils.getUserId();
			API.getUserPics(userId).then(function(data){
				var user = {};
				user.avatar = utils.isValid(data.avatar) ? data.avatar[3] : null;
				var parsedProducts = _applyUserContext(user,userId);
				_fillUserDetails(parsedProducts);
			}, function(error){
				console.log(error);
			});
		}

		function _applyUserContext(avatar,userId){
			var context = {};
			context.user = {
				"name"  : userName,
				"Publisher" : userId,
				"likes" : $('.preference').length,
			}
			context.user = utils.addProfilePicture(context.user,avatar);
			return templates.preferenceAccountDetails(context);
		}

		function _fillUserDetails(content){
			$(userDetailsContainer).html(content);
		}

		function _fillProgressBars(){
			$('.progress').each(function(i) {
			    var unit = $(this).data('unit');
			    var progress = $(this).data('progress');
			    var total = $(this).data('total');

			    var width = (progress/total)*100;
			    width = width > 100 ? 100 : width;

			    $(this).width(width + "%");
			});
		}

		function _addPreference(offerId, qt) {
    		//setto i parametri della mia preferenza
			preference.OfferId = offerId;
			preference.ExternalId = userId;
			preference.Qt = qt;
			//richiamo l'API per settare la preferenza
			API.addPreference(preference).then(function(data){
				$(document).trigger('preferenceAdded');
			}, function(error){
				$(document).trigger('preferenceError');
				console.log(error);
			});

		}

		$(document).on('preferences-loaded', function(){
			_fillProgressBars();
		});

		$(document).on('preferenceAdded', function(){
			_getUserPreferences();
			_getUserInfo();
		});
		function toggleGroup(){
			$('#groupBtn').toggleClass('foowd-icon-user foowd-icon-heart-edge');
			group=!group;
			_getUserPreferences();
		}

	   	window.toggleGroup = toggleGroup;

		return{
			init 		  : _stateCheck,
			addPreference : _addPreference,
		};

	})();

	return UserBoardController;
});<commit_msg>https://github.com/coder-molok/foowd_alpha2/issues/141<commit_after>define(function(require) {

	var API = require('FoowdAPI');
	var Navbar = require('NavbarController');
	var templates = require('templates');
	var utils = require('Utils');
	var $ = require('jquery');
	var service = require('foowdServices');

	var UserBoardController = (function(){

		var preferencesContainerId =  "#preferences-container";
		var userDetailsContainer = "#account-menu";
		//userId reference
   		var group = false;

   		/* SS: parametro aggiunto ipotizzando che la board possa essere visualizzata anche da amici */
   		var userName = null;
   		//preferenza utente
   		var preference = {
   				OfferId : "",
   				ExternalId : "",
   				type : "create",
   				Qt : "",
   		};

   		//nel controller devo essere sicuro che il dom sia stato casricato correttamente
		function _stateCheck(){
			switch(document.readyState){
				case "loading":
					document.onreadystatechange = function (){
						_stateCheck();
					}
				break;
				case "interactive":
				case "complete":
					_init();
				break;
			}
		}
   		//controller init
   		function _init(){
				Navbar.loadNavbar(true);
	   			//carico i template
	   			group=false;
	   			_getUserPreferences();
	   			_getUserInfo();
   		}

   		function _getUserPreferences(){
			var userId = utils.getUserId();
			if(userId!=null && group){
				_getUserPreferencesGroup(userId);
			}else{
				_getUserPreferencesSingle(userId);
			}

		}

		function _getUserPreferencesSingle(userId){
			API.getUserPreferences(userId).then(function(data){
				var rawData = data;
				var parsedProducts = _applyPreferencesContext(rawData.body);
				_fillBoard(parsedProducts);
				$(document).trigger('preferences-loaded');
			},function(e){
				console.log(e);
			});

		}
		function _getUserPreferencesGroup(userId){
			API.getFriend(userId).then(function(data){
				var friendsStr='';
				if(data.result && data.result.friends){
					 friendsStr = data.result.friends.join();
				}
				_getUserPreferencesSingle(userId+','+friendsStr);
			},function(error){
					console.log(error);
			});

		}

   		function _applyPreferencesContext(context) {
			var result = "";
			context.map(function(el) {
				//aggiungo l'immagine al json di contesto
				utils.addPicture(el.Offer, 'small');
				utils.setLoggedGroup(el, group);

				//ottengo l'html dal template + contesto
				var htmlComponent = templates.userPreference(el);
				//concateno
				result += htmlComponent;
			});

			return result;
		}
		function _fillBoard(content) {
			$(preferencesContainerId).html(content);
		}

		function _getUserInfo(){
			var userId = utils.getUserId();
			API.getUserPics(userId).then(function(data){
				var user = {};
				user.avatar = utils.isValid(data.avatar) ? data.avatar[3] : null;
				var parsedProducts = _applyUserContext(user,userId);
				_fillUserDetails(parsedProducts);
			}, function(error){
				console.log(error);
			});
		}

		function _applyUserContext(avatar,userId){
			var context = {};
			context.user = {
				"name"  : userName,
				"Publisher" : userId,
				"likes" : $('.preference').length,
			}
			context.user = utils.addProfilePicture(context.user,avatar);
			return templates.preferenceAccountDetails(context);
		}

		function _fillUserDetails(content){
			$(userDetailsContainer).html(content);
		}

		function _fillProgressBars(){
			$('.progress').each(function(i) {
			    var unit = $(this).data('unit');
			    var progress = $(this).data('progress');
			    var total = $(this).data('total');

			    var width = (progress/total)*100;
			    width = width > 100 ? 100 : width;

			    $(this).width(width + "%");
			});
		}

		function _addPreference(offerId, qt) {
						var userId = utils.getUserId();

    		//setto i parametri della mia preferenza
			preference.OfferId = offerId;
			preference.ExternalId = userId;
			preference.Qt = qt;
			//richiamo l'API per settare la preferenza
			API.addPreference(preference).then(function(data){
				$(document).trigger('preferenceAdded');
			}, function(error){
				$(document).trigger('preferenceError');
				console.log(error);
			});

		}

		$(document).on('preferences-loaded', function(){
			_fillProgressBars();
		});

		$(document).on('preferenceAdded', function(){
			_getUserPreferences();
			_getUserInfo();
		});
		function toggleGroup(){
			$('#groupBtn').toggleClass('foowd-icon-user foowd-icon-heart-edge');
			group=!group;
			_getUserPreferences();
		}

	   	window.toggleGroup = toggleGroup;

		return{
			init 		  : _stateCheck,
			addPreference : _addPreference,
		};

	})();

	return UserBoardController;
});<|endoftext|>


<commit_before>var format = require('util').format;

module.exports = function checkAndSetWritablePost(req, res, next) {

  Post.find(req.param('postId'))
  .tap(function(post) {
    if (!post) throw new Error(format('Seed %s not found', req.param('postId')));

    if (Admin.isSignedIn(req) || post.get('creator_id') == req.session.userId)
      return Promise.resolve(true);

    return Membership.hasModeratorRole(req.session.userId, req.param('communityId')).then(function(isModerator) {
      return (isModerator ? Promise.resolve() : Promise.reject());
    });
  })
  .then(function(post) {
    res.locals.post = post;
    next();
  })
  .catch(function(err) {
    sails.log.debug(format("Fail checkAndSetWritablePost policy %s %s: %s",
      req.session.userId, req.param('postId'), err.message));
    res.forbidden();
  });
};
<commit_msg>allow moderators to remove posts<commit_after>var format = require('util').format;

module.exports = function checkAndSetWritablePost(req, res, next) {

  Post.find(req.param('postId'), {withRelated: [{communities: function(qb) { qb.column('id'); }}]})
  .tap(function(post) {
    if (!post) throw new Error(format('post %s not found', req.param('postId')));

    if (Admin.isSignedIn(req) || post.get('creator_id') == req.session.userId)
      return true;

    var communityId = post.relations.communities.first().id;
    return Membership.hasModeratorRole(req.session.userId, communityId).then(function(isModerator) {
      if (!isModerator) throw 'not a moderator';
    });
  })
  .then(function(post) {
    res.locals.post = post;
    next();
  })
  .catch(function(err) {
    sails.log.debug(format("Fail checkAndSetWritablePost policy %s %s: %s",
      req.session.userId, req.param('postId'), err));
    res.forbidden();
  });
};
<|endoftext|>


<commit_before>(function () {
    var cogClass = function () {};
    cogClass.prototype.exec = function (params, request, response) {
        var oops = this.utils.apiError;
        var sys = this.sys;
        var classID = params.classid;
        var quizNumber = params.quizno;
        var studentID = params.studentid;
        var sql = 'SELECT a.questionNumber,q.correct,a.choice FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber WHERE a.classID=? AND a.quizNumber=? AND a.studentID=? AND NOT a.choice=q.correct';
        sys.db.all(sql,[classID,quizNumber,studentID],function(err,rows){
            if (err||!rows) {return oops(response,err,'*quiz/myquizresult(1)')};
            if (rows.length) {
                var items = [];
                var mistakeCount = rows.length;
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    var fields = ['qOneID','qTwoID','qThreeID','qFourID'];
                    var questionNumber = row.questionNumber;
                    var wrongAnswerFieldName = fields[row.choice];
                    var rightAnswerFieldName = fields[row.correct];
                    getMistakes(classID,quizNumber,questionNumber,studentID,rightAnswerFieldName,wrongAnswerFieldName);

                }
            } else {
                var data = JSON.stringify([])
                response.writeHead(200, {'Content-Type': 'application/json'});
                response.end(data);
            }
        });

        function getMistakes (classID,quizNumber,questionNumber,studentID,rightAnswerFieldName,wrongAnswerFieldName) {
            var sql = 'SELECT r.string AS rubric,qq.string AS right,aa.string AS wrong,a.choice AS wrongChoice FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber LEFT JOIN strings AS r ON r.stringID=q.rubricID LEFT JOIN strings AS qq ON qq.stringID=q.' + fields[row.correct] + ' LEFT JOIN strings AS aa ON aa.stringID=q.' + fields[row.choice] + ' WHERE a.classID=? AND a.quizNumber=? AND a.questionNumber=? AND a.studentID=?';
            sys.db.get(sql,[classID,quizNumber,questionNumber,studentID],function(err,row) {
                if (err||!row) {return oops(response,err,'*quiz/myquizresult(2)')}
                var rubric = row.rubric;
                var right = row.right;
                var wrong = row.wrong;
                var wrongChoice = row.wrongChoice;
                getGoodAnswerStudents(classID,quizNumber,questionNumber);
            });
        }

        function getGoodAnswerStudents(classID,quizNumber,questionNumber) {
            sys.db.all('SELECT s.name FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber JOIN students AS s ON s.studentID=a.studentID WHERE a.classID=? AND a.quizNumber=? AND a.questionNumber=? AND q.correct=a.choice',[classID,quizNumber,questionNumber],function(err,rows){
                if (err||!rows) {return oops(response,err,'*quiz/myquizresult(3)')}
                var goodAnswerStudents = [];
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    goodAnswerStudents.push(row.name);
                }
                getComments(classID,quizNumber,questionNumber,wrongChoice);
            });
        }

        function getComments(classID,quizNumber,questionNumber,wrongChoice) {
            sys.db.all('SELECT c.commenter,s.string AS comment FROM comments AS c LEFT JOIN strings AS s ON s.stringID=c.commentTextID WHERE classID=? AND quizNumber=? AND questionNumber=? AND choice=?',[classID,quizNumber,questionNumber,wrongChoice],function(err,rows){
                if (err||!rows) {return oops(response,err,'*quiz/myquizresults(4)')};
                var comments = [];
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    comments.push({commenter:row.commenter,comment:row.comment});
                }
                items.push({
                    rubric:rubric,
                    right:right,
                    wrong:wrong,
                    goodAnswerStudents:goodAnswerStudents,
                    comments:comments
                });
                mistakeCount += -1;
                if (!mistakeCount) {
                    var data = JSON.stringify(items);
                    response.writeHead(200, {'Content-Type': 'application/json'});
                    response.end(data);
                }
            });
        }
    }
    exports.cogClass = cogClass;
})();
<commit_msg>Use variable names that exist<commit_after>(function () {
    var cogClass = function () {};
    cogClass.prototype.exec = function (params, request, response) {
        var oops = this.utils.apiError;
        var sys = this.sys;
        var classID = params.classid;
        var quizNumber = params.quizno;
        var studentID = params.studentid;
        var sql = 'SELECT a.questionNumber,q.correct,a.choice FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber WHERE a.classID=? AND a.quizNumber=? AND a.studentID=? AND NOT a.choice=q.correct';
        sys.db.all(sql,[classID,quizNumber,studentID],function(err,rows){
            if (err||!rows) {return oops(response,err,'*quiz/myquizresult(1)')};
            if (rows.length) {
                var items = [];
                var mistakeCount = rows.length;
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    var fields = ['qOneID','qTwoID','qThreeID','qFourID'];
                    var questionNumber = row.questionNumber;
                    var wrongAnswerFieldName = fields[row.choice];
                    var rightAnswerFieldName = fields[row.correct];
                    getMistakes(classID,quizNumber,questionNumber,studentID,rightAnswerFieldName,wrongAnswerFieldName);

                }
            } else {
                var data = JSON.stringify([])
                response.writeHead(200, {'Content-Type': 'application/json'});
                response.end(data);
            }
        });

        function getMistakes (classID,quizNumber,questionNumber,studentID,rightAnswerFieldName,wrongAnswerFieldName) {
            var sql = 'SELECT r.string AS rubric,qq.string AS right,aa.string AS wrong,a.choice AS wrongChoice FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber LEFT JOIN strings AS r ON r.stringID=q.rubricID LEFT JOIN strings AS qq ON qq.stringID=q.' + wrongAnswerFieldName + ' LEFT JOIN strings AS aa ON aa.stringID=q.' + rightAnswerFieldName + ' WHERE a.classID=? AND a.quizNumber=? AND a.questionNumber=? AND a.studentID=?';
            sys.db.get(sql,[classID,quizNumber,questionNumber,studentID],function(err,row) {
                if (err||!row) {return oops(response,err,'*quiz/myquizresult(2)')}
                var rubric = row.rubric;
                var right = row.right;
                var wrong = row.wrong;
                var wrongChoice = row.wrongChoice;
                getGoodAnswerStudents(classID,quizNumber,questionNumber);
            });
        }

        function getGoodAnswerStudents(classID,quizNumber,questionNumber) {
            sys.db.all('SELECT s.name FROM answers AS a JOIN questions AS q ON q.classID=a.classID AND q.quizNumber=a.quizNumber AND q.questionNumber=a.questionNumber JOIN students AS s ON s.studentID=a.studentID WHERE a.classID=? AND a.quizNumber=? AND a.questionNumber=? AND q.correct=a.choice',[classID,quizNumber,questionNumber],function(err,rows){
                if (err||!rows) {return oops(response,err,'*quiz/myquizresult(3)')}
                var goodAnswerStudents = [];
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    goodAnswerStudents.push(row.name);
                }
                getComments(classID,quizNumber,questionNumber,wrongChoice);
            });
        }

        function getComments(classID,quizNumber,questionNumber,wrongChoice) {
            sys.db.all('SELECT c.commenter,s.string AS comment FROM comments AS c LEFT JOIN strings AS s ON s.stringID=c.commentTextID WHERE classID=? AND quizNumber=? AND questionNumber=? AND choice=?',[classID,quizNumber,questionNumber,wrongChoice],function(err,rows){
                if (err||!rows) {return oops(response,err,'*quiz/myquizresults(4)')};
                var comments = [];
                for (var i=0,ilen=rows.length;i<ilen;i+=1) {
                    var row = rows[i];
                    comments.push({commenter:row.commenter,comment:row.comment});
                }
                items.push({
                    rubric:rubric,
                    right:right,
                    wrong:wrong,
                    goodAnswerStudents:goodAnswerStudents,
                    comments:comments
                });
                mistakeCount += -1;
                if (!mistakeCount) {
                    var data = JSON.stringify(items);
                    response.writeHead(200, {'Content-Type': 'application/json'});
                    response.end(data);
                }
            });
        }
    }
    exports.cogClass = cogClass;
})();
<|endoftext|>


<commit_before>'use strict';

const builder = require('electron-builder');

builder
  .build({
    mac: ['mas'],
    linux: ['snap'],
    win: ['appx'],
    config: {
      appId: '*PACKAGENAMEIDDESKTOP*',
      productName: '*USERVISIBLENAME*',
      afterPack: './electron/afterPack.js',
      files: [
        './electron/main.js',
        './package.json',
        './www/**/*',
        './build',
        '!./node_modules/.cache/',
        '!./**/*.map'
      ],
      protocols: {
        name: 'URL protocol schemes',
        schemes: ['bitcoin', 'bitcoincash', 'bchtest', '*NAME*']
      },
      mac: {
        category: 'public.app-category.finance',
        icon: 'resources/*NAME*/mac/app.icns',
        artifactName: '*USERVISIBLENAME*.pkg',
        darkModeSupport: false,
        extendInfo: {
          NSCameraUsageDescription:
            'Scan a Bitcoin Address directly to your Wallet and send funds to it'
        },
        target: ['mas']
      },
      mas: {
        identity: 'BitPay, Inc. (884JRH5R93)',
        entitlements: './*PACKAGENAME*-entitlements.mas.plist',
        provisioningProfile: './*PACKAGENAME*-embedded.provisionprofile'
      },
      win: {
        target: ['appx'],
        icon: 'resources/*NAME*/windows/icon.ico',
        artifactName: '*USERVISIBLENAME*.appx'
      },
      appx: {
        identityName: '*WINDOWSSTOREIDENTITYNAME*',
        publisher: 'CN=F89609D1-EB3E-45FD-A58A-C2E3895FCE7B',
        publisherDisplayName: 'BitPay Inc.',
        applicationId: '*WINDOWSAPPLICATIONID*',
        displayName: '*WINDOWSSTOREDISPLAYNAME*'
      },
      linux: {
        target: ['snap'],
        artifactName: '*USERVISIBLENAME*-linux.snap'
      }
    }
  })
  .then(() => {
    // handle result
    console.log('Build OK!');
  })
  .catch(error => {
    // handle error
    console.log(error);
  });
<commit_msg>adds ethereum url scheme to electron-builder<commit_after>'use strict';

const builder = require('electron-builder');

builder
  .build({
    mac: ['mas'],
    linux: ['snap'],
    win: ['appx'],
    config: {
      appId: '*PACKAGENAMEIDDESKTOP*',
      productName: '*USERVISIBLENAME*',
      afterPack: './electron/afterPack.js',
      files: [
        './electron/main.js',
        './package.json',
        './www/**/*',
        './build',
        '!./node_modules/.cache/',
        '!./**/*.map'
      ],
      protocols: {
        name: 'URL protocol schemes',
        schemes: ['bitcoin', 'bitcoincash', 'bchtest', 'ethereum', '*NAME*']
      },
      mac: {
        category: 'public.app-category.finance',
        icon: 'resources/*NAME*/mac/app.icns',
        artifactName: '*USERVISIBLENAME*.pkg',
        darkModeSupport: false,
        extendInfo: {
          NSCameraUsageDescription:
            'Scan a Bitcoin Address directly to your Wallet and send funds to it'
        },
        target: ['mas']
      },
      mas: {
        identity: 'BitPay, Inc. (884JRH5R93)',
        entitlements: './*PACKAGENAME*-entitlements.mas.plist',
        provisioningProfile: './*PACKAGENAME*-embedded.provisionprofile'
      },
      win: {
        target: ['appx'],
        icon: 'resources/*NAME*/windows/icon.ico',
        artifactName: '*USERVISIBLENAME*.appx'
      },
      appx: {
        identityName: '*WINDOWSSTOREIDENTITYNAME*',
        publisher: 'CN=F89609D1-EB3E-45FD-A58A-C2E3895FCE7B',
        publisherDisplayName: 'BitPay Inc.',
        applicationId: '*WINDOWSAPPLICATIONID*',
        displayName: '*WINDOWSSTOREDISPLAYNAME*'
      },
      linux: {
        target: ['snap'],
        artifactName: '*USERVISIBLENAME*-linux.snap'
      }
    }
  })
  .then(() => {
    // handle result
    console.log('Build OK!');
  })
  .catch(error => {
    // handle error
    console.log(error);
  });
<|endoftext|>


<commit_before>var bole = require('bole'),
  Boom = require('boom'),
  Customer = require('../agents/customer'),
  Hoek = require('hoek'),
  humans = require('npm-humans'),
  featureFlag = require('../lib/feature-flags.js'),
  toCommonLogFormat = require('hapi-common-log'),
  url = require('url'),
  UserModel = require('../models/user');

exports.register = function(server, options, next) {

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

  server.ext('onPreHandler', function(request, reply) {

    // Generate `request.packageName` for global and scoped package requests
    if (request.params.package || request.params.scope) {
      request.packageName = request.params.package ||
        request.params.scope + "/" + request.params.project;
    }

    request.metrics = metrics;
    request.redis = request.server.app.cache._cache.connection.client;
    request.logger = bole(request.id);
    request.timing = {
      start: Date.now(),
    };

    if (request.auth && request.auth.credentials && !request.path.match(/static\//)) {
      UserModel.new(request).get(request.auth.credentials.name, function(err, user) {
        if (err) {
          request.logger.warn(err);
        }
        if (user) {
          user.sid = request.auth.credentials.sid;
        }
        request.loggedInUser = user;
        request.customer = user && new Customer(user.name);
        completePreHandler();
      });
    } else {
      completePreHandler();
    }

    function completePreHandler() {

      // Add feature flags to request
      request.features = featureFlag.getFeatures(request);

      if (request.method !== "post") {
        return reply.continue();
      }

      return reply.continue();
    }

  });

  server.ext('onPostHandler', function(request, reply) {

    var latency = Date.now() - request.timing.start;
    metrics.metric({
      name: 'latency.page',
      value: latency,
      page: request.timing.page,
    });

    // TODO log request info in as close to common log format as possible
    request.logger.info(toCommonLogFormat(request, {
      ipHeader: 'fastly-client-ip'
    }), latency + 'ms');

    return reply.continue();
  });

  server.ext('onPreResponse', function(request, reply) {

    var options = {
      correlationID: request.id,
      stamp: request.server.stamp,
      features: request.features,
      devEnv: (process.env.NODE_ENV === 'dev')
    };

    if (request.response && request.response.variety && request.response.variety.match(/view|plain/)) {
      if (process.env.CANONICAL_HOST) {
        if (request.url.query.page || request.url.query.q) {
          options.canonicalURL = url.resolve(process.env.CANONICAL_HOST, request.url.path);
        } else {
          options.canonicalURL = url.resolve(process.env.CANONICAL_HOST, request.url.pathname);
        }
      }
    }

    switch (request.response.variety) {
      case "view":
        request.response.source.context = Hoek.applyToDefaults(options, request.response.source.context);
        request.response.source.context.user = request.loggedInUser;

        // appends charset to content-type header, for security reasons
        request.response.type('text/html').charset('utf-8');

        break;
      case "plain":
        if (typeof (request.response.source) === "object") {
          request.response.source = Hoek.applyToDefaults(options, request.response.source);
        }
        break;
    }

    // Allow npm humans to view JSON context for any page
    // by adding a `?json` query parameter to the URL
    if ('json' in request.query &&
      Hoek.reach(request, 'response.source.context') &&
      (process.env.NODE_ENV === "dev" || Hoek.reach(request, "loggedInUser.name") in humans)
    ) {
      if (request.query.json.length > 1) {
        // deep reference: ?json=profile.packages
        return reply(Hoek.reach(request.response.source.context, request.query.json));
      } else {
        // the whole enchilada: ?json
        return reply(request.response.source.context);
      }
    }

    return reply.continue();
  });

  return next();
};

exports.register.attributes = {
  name: 'bonbon',
  version: '1.0.0'
};
<commit_msg>Add only two vars to env to unbreak npmo<commit_after>var bole = require('bole'),
  Boom = require('boom'),
  Customer = require('../agents/customer'),
  Hoek = require('hoek'),
  humans = require('npm-humans'),
  featureFlag = require('../lib/feature-flags.js'),
  toCommonLogFormat = require('hapi-common-log'),
  url = require('url'),
  UserModel = require('../models/user');

exports.register = function(server, options, next) {

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

  server.ext('onPreHandler', function(request, reply) {

    // Generate `request.packageName` for global and scoped package requests
    if (request.params.package || request.params.scope) {
      request.packageName = request.params.package ||
        request.params.scope + "/" + request.params.project;
    }

    request.metrics = metrics;
    request.redis = request.server.app.cache._cache.connection.client;
    request.logger = bole(request.id);
    request.timing = {
      start: Date.now(),
    };

    if (request.auth && request.auth.credentials && !request.path.match(/static\//)) {
      UserModel.new(request).get(request.auth.credentials.name, function(err, user) {
        if (err) {
          request.logger.warn(err);
        }
        if (user) {
          user.sid = request.auth.credentials.sid;
        }
        request.loggedInUser = user;
        request.customer = user && new Customer(user.name);
        completePreHandler();
      });
    } else {
      completePreHandler();
    }

    function completePreHandler() {

      // Add feature flags to request
      request.features = featureFlag.getFeatures(request);

      if (request.method !== "post") {
        return reply.continue();
      }

      return reply.continue();
    }

  });

  server.ext('onPostHandler', function(request, reply) {

    var latency = Date.now() - request.timing.start;
    metrics.metric({
      name: 'latency.page',
      value: latency,
      page: request.timing.page,
    });

    // TODO log request info in as close to common log format as possible
    request.logger.info(toCommonLogFormat(request, {
      ipHeader: 'fastly-client-ip'
    }), latency + 'ms');

    return reply.continue();
  });

  server.ext('onPreResponse', function(request, reply) {

    var options = {
      correlationID: request.id,
      stamp: request.server.stamp,
      features: request.features,
      devEnv: (process.env.NODE_ENV === 'dev'),
      env: {
        NPMO_COBRAND: process.env.NPMO_COBRAND,
        CANONICAL_HOST: process.env.CANONICAL_HOST
      }
    };

    if (request.response && request.response.variety && request.response.variety.match(/view|plain/)) {
      if (process.env.CANONICAL_HOST) {
        if (request.url.query.page || request.url.query.q) {
          options.canonicalURL = url.resolve(process.env.CANONICAL_HOST, request.url.path);
        } else {
          options.canonicalURL = url.resolve(process.env.CANONICAL_HOST, request.url.pathname);
        }
      }
    }

    switch (request.response.variety) {
      case "view":
        request.response.source.context = Hoek.applyToDefaults(options, request.response.source.context);
        request.response.source.context.user = request.loggedInUser;

        // appends charset to content-type header, for security reasons
        request.response.type('text/html').charset('utf-8');

        break;
      case "plain":
        if (typeof (request.response.source) === "object") {
          request.response.source = Hoek.applyToDefaults(options, request.response.source);
        }
        break;
    }

    // Allow npm humans to view JSON context for any page
    // by adding a `?json` query parameter to the URL
    if ('json' in request.query &&
      Hoek.reach(request, 'response.source.context') &&
      (process.env.NODE_ENV === "dev" || Hoek.reach(request, "loggedInUser.name") in humans)
    ) {
      if (request.query.json.length > 1) {
        // deep reference: ?json=profile.packages
        return reply(Hoek.reach(request.response.source.context, request.query.json));
      } else {
        // the whole enchilada: ?json
        return reply(request.response.source.context);
      }
    }

    return reply.continue();
  });

  return next();
};

exports.register.attributes = {
  name: 'bonbon',
  version: '1.0.0'
};
<|endoftext|>


<commit_before>jest.mock(
  'popper.js',
  () =>
    class Popper {
      static placements = [
        'auto',
        'auto-end',
        'auto-start',
        'bottom',
        'bottom-end',
        'bottom-start',
        'left',
        'left-end',
        'left-start',
        'right',
        'right-end',
        'right-start',
        'top',
        'top-end',
        'top-start',
      ];
      destroy() { }
      scheduleUpdate() { }
      disableEventListeners() { }
    }
);
<commit_msg>mock overlay<commit_after>jest.mock(
  'popper.js',
  () =>
    class Popper {
      static placements = [
        'auto',
        'auto-end',
        'auto-start',
        'bottom',
        'bottom-end',
        'bottom-start',
        'left',
        'left-end',
        'left-start',
        'right',
        'right-end',
        'right-start',
        'top',
        'top-end',
        'top-start',
      ];
      destroy() { }
      scheduleUpdate() { }
      disableEventListeners() { }
    }
);

jest.mock('react-overlays/Overlay.js', () =>
  function MockedOverlay({ children }) {
    return children;
  }
);
<|endoftext|>


<commit_before><commit_msg>Add .js<commit_after><|endoftext|>


<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */
/**
* @class
*/
OpenLayers.Icon = Class.create();
OpenLayers.Icon.prototype = {

    /** image url
    * @type String */
    url: null,

    /** @type OpenLayers.Size */
    size:null,

    /** distance in pixels to offset the image when being rendered
    * @type OpenLayers.Pixel */
    offset: null,

    /** Function to calculate the offset (based on the size)
     * @type OpenLayers.Pixel */
    calculateOffset: null,

    /** @type DOMElement */
    imageDiv: null,

    /** @type OpenLayers.Pixel */
    px: null,

    /**
    * @constructor
    *
    * @param {String} url
    * @param {OpenLayers.Size} size
    * @param {Function} calculateOffset
    */
    initialize: function(url, size, offset, calculateOffset) {
        this.url = url;
        this.size = (size) ? size : new OpenLayers.Size(20,20);
        this.offset = (offset) ? offset : new OpenLayers.Pixel(0,0);
        this.calculateOffset = calculateOffset;

        this.imageDiv = OpenLayers.Util.createAlphaImageDiv();
    },

    destroy: function() {
        this.imageDiv = null;
    },

    /**
    * @returns A fresh copy of the icon.
    * @type OpenLayers.Icon
    */
    clone: function() {
        return new OpenLayers.Icon(this.url, this.size, this.offset);
    },

    /**
     * @param {OpenLayers.Size} size
     */
    setSize: function(size) {
        if (size != null) {
            this.size = size;
        }
        this.draw();
    },

    /**
    * @param {OpenLayers.Pixel} px
    *
    * @return A new DOM Image of this icon set at the location passed-in
    * @type DOMElement
    */
    draw: function(px) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
                                            null,
                                            null,
                                            this.size,
                                            this.url,
                                            "absolute");
        this.moveTo(px);
        return this.imageDiv;
    },

    /**
    * @param {OpenLayers.Pixel} px
    */
    moveTo: function (px) {
        //if no px passed in, use stored location
        if (px != null) {
            this.px = px;
        }

        if ((this.px != null) && (this.imageDiv != null)) {
            if (this.calculateOffset) {
                this.offset = this.calculateOffset(this.size);
            }
            var offsetPx = this.px.offset(this.offset);
            OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
        }
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Icon"
};<commit_msg>when cloning an icon, set the calculateOffset() function too, if it exists.<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */
/**
* @class
*/
OpenLayers.Icon = Class.create();
OpenLayers.Icon.prototype = {

    /** image url
    * @type String */
    url: null,

    /** @type OpenLayers.Size */
    size:null,

    /** distance in pixels to offset the image when being rendered
    * @type OpenLayers.Pixel */
    offset: null,

    /** Function to calculate the offset (based on the size)
     * @type OpenLayers.Pixel */
    calculateOffset: null,

    /** @type DOMElement */
    imageDiv: null,

    /** @type OpenLayers.Pixel */
    px: null,

    /**
    * @constructor
    *
    * @param {String} url
    * @param {OpenLayers.Size} size
    * @param {Function} calculateOffset
    */
    initialize: function(url, size, offset, calculateOffset) {
        this.url = url;
        this.size = (size) ? size : new OpenLayers.Size(20,20);
        this.offset = (offset) ? offset : new OpenLayers.Pixel(0,0);
        this.calculateOffset = calculateOffset;

        this.imageDiv = OpenLayers.Util.createAlphaImageDiv();
    },

    destroy: function() {
        this.imageDiv = null;
    },

    /**
    * @returns A fresh copy of the icon.
    * @type OpenLayers.Icon
    */
    clone: function() {
        return new OpenLayers.Icon(this.url,
                                   this.size,
                                   this.offset,
                                   this.calculateOffset);
    },

    /**
     * @param {OpenLayers.Size} size
     */
    setSize: function(size) {
        if (size != null) {
            this.size = size;
        }
        this.draw();
    },

    /**
    * @param {OpenLayers.Pixel} px
    *
    * @return A new DOM Image of this icon set at the location passed-in
    * @type DOMElement
    */
    draw: function(px) {
        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
                                            null,
                                            null,
                                            this.size,
                                            this.url,
                                            "absolute");
        this.moveTo(px);
        return this.imageDiv;
    },

    /**
    * @param {OpenLayers.Pixel} px
    */
    moveTo: function (px) {
        //if no px passed in, use stored location
        if (px != null) {
            this.px = px;
        }

        if ((this.px != null) && (this.imageDiv != null)) {
            if (this.calculateOffset) {
                this.offset = this.calculateOffset(this.size);
            }
            var offsetPx = this.px.offset(this.offset);
            OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
        }
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Icon"
};<|endoftext|>