diff options
Diffstat (limited to '')
| -rw-r--r-- | lang/js/src/Keyring.js | 675 | 
1 files changed, 338 insertions, 337 deletions
| diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index d18fb649..de21736e 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -32,383 +32,384 @@ import { gpgme_error } from './Errors';   */  export class GPGME_Keyring {      constructor(){ +    } -        /** -         * Queries Keys (all Keys or a subset) from gnupg. -         * -         * @param {String | Array<String>} pattern (optional) A pattern to -         * search for in userIds or KeyIds. -         * @param {Boolean} prepare_sync (optional) if set to true, most data -         * (with the exception of armored Key blocks) will be cached for the -         * Keys. This enables direct, synchronous use of these properties for -         * all keys. It does not check for changes on the backend. The cached -         * information can be updated with the {@link Key.refresh} method. -         * @param {Boolean} search (optional) retrieve Keys from external -         * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup) -         * @returns {Promise<Array<GPGME_Key>>} -         * @static -         * @async -         */ -        this.getKeys = function(pattern, prepare_sync=false, search=false){ -            return new Promise(function(resolve, reject) { -                let msg = createMessage('keylist'); -                if (pattern !== undefined && pattern !== null){ -                    msg.setParameter('keys', pattern); -                } -                msg.setParameter('sigs', true); -                if (search === true){ -                    msg.setParameter('locate', true); -                } -                msg.post().then(function(result){ -                    let resultset = []; -                    if (result.keys.length === 0){ -                        resolve([]); +    /** +     * Queries Keys (all Keys or a subset) from gnupg. +     * +     * @param {String | Array<String>} pattern (optional) A pattern to +     * search for in userIds or KeyIds. +     * @param {Boolean} prepare_sync (optional) if set to true, most data +     * (with the exception of armored Key blocks) will be cached for the +     * Keys. This enables direct, synchronous use of these properties for +     * all keys. It does not check for changes on the backend. The cached +     * information can be updated with the {@link Key.refresh} method. +     * @param {Boolean} search (optional) retrieve Keys from external +     * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup) +     * @returns {Promise<Array<GPGME_Key>>} +     * @static +     * @async +     */ +    getKeys (pattern, prepare_sync=false, search=false){ +        return new Promise(function(resolve, reject) { +            let msg = createMessage('keylist'); +            if (pattern !== undefined && pattern !== null){ +                msg.setParameter('keys', pattern); +            } +            msg.setParameter('sigs', true); +            if (search === true){ +                msg.setParameter('locate', true); +            } +            msg.post().then(function(result){ +                let resultset = []; +                if (result.keys.length === 0){ +                    resolve([]); +                } else { +                    let secondrequest; +                    if (prepare_sync === true) { +                        secondrequest = function() { +                            let msg2 = createMessage('keylist'); +                            msg2.setParameter('keys', pattern); +                            msg2.setParameter('secret', true); +                            return msg2.post(); +                        };                      } else { -                        let secondrequest; -                        if (prepare_sync === true) { -                            secondrequest = function() { -                                let msg2 = createMessage('keylist'); -                                msg2.setParameter('keys', pattern); -                                msg2.setParameter('secret', true); -                                return msg2.post(); -                            }; -                        } else { -                            secondrequest = function() { -                                return Promise.resolve(true); -                            }; -                        } -                        secondrequest().then(function(answer) { -                            for (let i=0; i < result.keys.length; i++){ -                                if (prepare_sync === true){ -                                    if (answer && answer.keys) { -                                        for (let j=0; -                                            j < answer.keys.length; j++ ){ -                                            const a = answer.keys[j]; -                                            const b = result.keys[i]; -                                            if ( -                                                a.fingerprint === b.fingerprint -                                            ) { -                                                if (a.secret === true){ -                                                    b.hasSecret = true; -                                                } else { -                                                    b.hasSecret = false; -                                                } -                                                break; +                        secondrequest = function() { +                            return Promise.resolve(true); +                        }; +                    } +                    secondrequest().then(function(answer) { +                        for (let i=0; i < result.keys.length; i++){ +                            if (prepare_sync === true){ +                                if (answer && answer.keys) { +                                    for (let j=0; +                                        j < answer.keys.length; j++ ){ +                                        const a = answer.keys[j]; +                                        const b = result.keys[i]; +                                        if ( +                                            a.fingerprint === b.fingerprint +                                        ) { +                                            if (a.secret === true){ +                                                b.hasSecret = true; +                                            } else { +                                                b.hasSecret = false;                                              } +                                            break;                                          }                                      }                                  } -                                let k = createKey(result.keys[i].fingerprint, -                                    !prepare_sync, result.keys[i]); -                                resultset.push(k);                              } -                            resolve(resultset); -                        }, function(error){ -                            reject(error); -                        }); -                    } -                }); +                            let k = createKey(result.keys[i].fingerprint, +                                !prepare_sync, result.keys[i]); +                            resultset.push(k); +                        } +                        resolve(resultset); +                    }, function(error){ +                        reject(error); +                    }); +                }              }); -        }; +        }); +    } -        /** -         * @typedef {Object} exportResult The result of a getKeysArmored -         * operation. -         * @property {String} armored The public Key(s) as armored block. Note -         * that the result is one armored block, and not a block per key. -         * @property {Array<String>} secret_fprs (optional) list of -         * fingerprints for those Keys that also have a secret Key available in -         * gnupg. The secret key will not be exported, but the fingerprint can -         * be used in operations needing a secret key. -         */ +    /** +     * @typedef {Object} exportResult The result of a getKeysArmored +     * operation. +     * @property {String} armored The public Key(s) as armored block. Note +     * that the result is one armored block, and not a block per key. +     * @property {Array<String>} secret_fprs (optional) list of +     * fingerprints for those Keys that also have a secret Key available in +     * gnupg. The secret key will not be exported, but the fingerprint can +     * be used in operations needing a secret key. +     */ -        /** -         * Fetches the armored public Key blocks for all Keys matching the -         * pattern (if no pattern is given, fetches all keys known to gnupg). -         * @param {String|Array<String>} pattern (optional) The Pattern to -         * search for -         * @param {Boolean} with_secret_fpr (optional) also return a list of -         * fingerprints for the keys that have a secret key available -         * @returns {Promise<exportResult|GPGME_Error>} Object containing the -         * armored Key(s) and additional information. -         * @static -         * @async -         */ -        this.getKeysArmored = function(pattern, with_secret_fpr) { -            return new Promise(function(resolve, reject) { -                let msg = createMessage('export'); -                msg.setParameter('armor', true); -                if (with_secret_fpr === true) { -                    msg.setParameter('with-sec-fprs', true); -                } -                if (pattern !== undefined && pattern !== null){ -                    msg.setParameter('keys', pattern); +    /** +     * Fetches the armored public Key blocks for all Keys matching the +     * pattern (if no pattern is given, fetches all keys known to gnupg). +     * @param {String|Array<String>} pattern (optional) The Pattern to +     * search for +     * @param {Boolean} with_secret_fpr (optional) also return a list of +     * fingerprints for the keys that have a secret key available +     * @returns {Promise<exportResult|GPGME_Error>} Object containing the +     * armored Key(s) and additional information. +     * @static +     * @async +     */ +    getKeysArmored (pattern, with_secret_fpr) { +        return new Promise(function(resolve, reject) { +            let msg = createMessage('export'); +            msg.setParameter('armor', true); +            if (with_secret_fpr === true) { +                msg.setParameter('with-sec-fprs', true); +            } +            if (pattern !== undefined && pattern !== null){ +                msg.setParameter('keys', pattern); +            } +            msg.post().then(function(answer){ +                const result = {armored: answer.data}; +                if (with_secret_fpr === true +                    && answer.hasOwnProperty('sec-fprs') +                ) { +                    result.secret_fprs = answer['sec-fprs'];                  } -                msg.post().then(function(answer){ -                    const result = {armored: answer.data}; -                    if (with_secret_fpr === true -                        && answer.hasOwnProperty('sec-fprs') -                    ) { -                        result.secret_fprs = answer['sec-fprs']; -                    } -                    resolve(result); -                }, function(error){ -                    reject(error); -                }); +                resolve(result); +            }, function(error){ +                reject(error);              }); -        }; +        }); +    } -        /** -         * Returns the Key used by default in gnupg. -         * (a.k.a. 'primary Key or 'main key'). -         * It looks up the gpg configuration if set, or the first key that -         * contains a secret key. -         * -         * @returns {Promise<GPGME_Key|GPGME_Error>} -         * @async -         * @static -         */ -        this.getDefaultKey = function(prepare_sync = false) { -            let me = this; -            return new Promise(function(resolve, reject){ -                let msg = createMessage('config_opt'); -                msg.setParameter('component', 'gpg'); -                msg.setParameter('option', 'default-key'); -                msg.post().then(function(resp){ -                    if (resp.option !== undefined -                        && resp.option.hasOwnProperty('value') -                        && resp.option.value.length === 1 -                        && resp.option.value[0].hasOwnProperty('string') -                        && typeof(resp.option.value[0].string) === 'string'){ -                        me.getKeys(resp.option.value[0].string, true).then( -                            function(keys){ -                                if(keys.length === 1){ -                                    resolve(keys[0]); -                                } else { -                                    reject(gpgme_error('KEY_NO_DEFAULT')); -                                } -                            }, function(error){ -                                reject(error); -                            }); -                    } else { -                        let msg = createMessage('keylist'); -                        msg.setParameter('secret', true); -                        msg.post().then(function(result){ -                            if (result.keys.length === 0){ -                                reject(gpgme_error('KEY_NO_DEFAULT')); +    /** +     * Returns the Key used by default in gnupg. +     * (a.k.a. 'primary Key or 'main key'). +     * It looks up the gpg configuration if set, or the first key that +     * contains a secret key. +     * +     * @returns {Promise<GPGME_Key|GPGME_Error>} +     * @async +     * @static +     */ +    getDefaultKey(prepare_sync = false) { +        let me = this; +        return new Promise(function(resolve, reject){ +            let msg = createMessage('config_opt'); +            msg.setParameter('component', 'gpg'); +            msg.setParameter('option', 'default-key'); +            msg.post().then(function(resp){ +                if (resp.option !== undefined +                    && resp.option.hasOwnProperty('value') +                    && resp.option.value.length === 1 +                    && resp.option.value[0].hasOwnProperty('string') +                    && typeof(resp.option.value[0].string) === 'string'){ +                    me.getKeys(resp.option.value[0].string, true).then( +                        function(keys){ +                            if(keys.length === 1){ +                                resolve(keys[0]);                              } else { -                                for (let i=0; i< result.keys.length; i++ ) { -                                    if (result.keys[i].invalid === false) { -                                        let k = createKey( -                                            result.keys[i].fingerprint, -                                            !prepare_sync, -                                            result.keys[i]); -                                        resolve(k); -                                        break; -                                    } else if (i === result.keys.length - 1){ -                                        reject(gpgme_error('KEY_NO_DEFAULT')); -                                    } -                                } +                                reject(gpgme_error('KEY_NO_DEFAULT'));                              }                          }, function(error){                              reject(error);                          }); -                    } -                }, function(error){ -                    reject(error); -                }); +                } else { +                    let msg = createMessage('keylist'); +                    msg.setParameter('secret', true); +                    msg.post().then(function(result){ +                        if (result.keys.length === 0){ +                            reject(gpgme_error('KEY_NO_DEFAULT')); +                        } else { +                            for (let i=0; i< result.keys.length; i++ ) { +                                if (result.keys[i].invalid === false) { +                                    let k = createKey( +                                        result.keys[i].fingerprint, +                                        !prepare_sync, +                                        result.keys[i]); +                                    resolve(k); +                                    break; +                                } else if (i === result.keys.length - 1){ +                                    reject(gpgme_error('KEY_NO_DEFAULT')); +                                } +                            } +                        } +                    }, function(error){ +                        reject(error); +                    }); +                } +            }, function(error){ +                reject(error);              }); -        }; +        }); +    } -        /** -         * @typedef {Object} importResult The result of a Key update -         * @property {Object} summary Numerical summary of the result. See the -         * feedbackValues variable for available Keys values and the gnupg -         * documentation. -         * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html -         * for details on their meaning. -         * @property {Array<importedKeyResult>} Keys Array of Object containing -         * GPGME_Keys with additional import information -         * -         */ +    /** +     * @typedef {Object} importResult The result of a Key update +     * @property {Object} summary Numerical summary of the result. See the +     * feedbackValues variable for available Keys values and the gnupg +     * documentation. +     * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html +     * for details on their meaning. +     * @property {Array<importedKeyResult>} Keys Array of Object containing +     * GPGME_Keys with additional import information +     * +     */ -        /** -         * @typedef {Object} importedKeyResult -         * @property {GPGME_Key} key The resulting key -         * @property {String} status: -         *  'nochange' if the Key was not changed, -         *  'newkey' if the Key was imported in gpg, and did not exist -         *    previously, -         *  'change' if the key existed, but details were updated. For details, -         *    Key.changes is available. -         * @property {Boolean} changes.userId Changes in userIds -         * @property {Boolean} changes.signature Changes in signatures -         * @property {Boolean} changes.subkey Changes in subkeys -         */ +    /** +     * @typedef {Object} importedKeyResult +     * @property {GPGME_Key} key The resulting key +     * @property {String} status: +     *  'nochange' if the Key was not changed, +     *  'newkey' if the Key was imported in gpg, and did not exist +     *    previously, +     *  'change' if the key existed, but details were updated. For details, +     *    Key.changes is available. +     * @property {Boolean} changes.userId Changes in userIds +     * @property {Boolean} changes.signature Changes in signatures +     * @property {Boolean} changes.subkey Changes in subkeys +     */ -        /** -         * Import an armored Key block into gnupg. Note that this currently -         * will not succeed on private Key blocks. -         * @param {String} armored Armored Key block of the Key(s) to be -         * imported into gnupg -         * @param {Boolean} prepare_sync prepare the keys for synched use -         * (see {@link getKeys}). -         * @returns {Promise<importResult>} A summary and Keys considered. -         * @async -         * @static -         */ -        this.importKey = function (armored, prepare_sync) { -            let feedbackValues = ['considered', 'no_user_id', 'imported', -                'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys', -                'new_signatures', 'new_revocations', 'secret_read', -                'secret_imported', 'secret_unchanged', 'skipped_new_keys', -                'not_imported', 'skipped_v3_keys']; -            if (!armored || typeof(armored) !== 'string'){ -                return Promise.reject(gpgme_error('PARAM_WRONG')); -            } -            let me = this; -            return new Promise(function(resolve, reject){ -                let msg = createMessage('import'); -                msg.setParameter('data', armored); -                msg.post().then(function(response){ -                    let infos = {}; -                    let fprs = []; -                    let summary = {}; -                    for (let i=0; i < feedbackValues.length; i++ ){ -                        summary[feedbackValues[i]] = -                            response.result[feedbackValues[i]]; -                    } -                    if (!response.result.hasOwnProperty('imports') || -                        response.result.imports.length === 0 -                    ){ -                        resolve({Keys:[],summary: summary}); -                        return; +    /** +     * Import an armored Key block into gnupg. Note that this currently +     * will not succeed on private Key blocks. +     * @param {String} armored Armored Key block of the Key(s) to be +     * imported into gnupg +     * @param {Boolean} prepare_sync prepare the keys for synched use +     * (see {@link getKeys}). +     * @returns {Promise<importResult>} A summary and Keys considered. +     * @async +     * @static +     */ +    importKey (armored, prepare_sync) { +        let feedbackValues = ['considered', 'no_user_id', 'imported', +            'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys', +            'new_signatures', 'new_revocations', 'secret_read', +            'secret_imported', 'secret_unchanged', 'skipped_new_keys', +            'not_imported', 'skipped_v3_keys']; +        if (!armored || typeof(armored) !== 'string'){ +            return Promise.reject(gpgme_error('PARAM_WRONG')); +        } +        let me = this; +        return new Promise(function(resolve, reject){ +            let msg = createMessage('import'); +            msg.setParameter('data', armored); +            msg.post().then(function(response){ +                let infos = {}; +                let fprs = []; +                let summary = {}; +                for (let i=0; i < feedbackValues.length; i++ ){ +                    summary[feedbackValues[i]] = +                        response.result[feedbackValues[i]]; +                } +                if (!response.result.hasOwnProperty('imports') || +                    response.result.imports.length === 0 +                ){ +                    resolve({Keys:[],summary: summary}); +                    return; +                } +                for (let res=0; res<response.result.imports.length; res++){ +                    let result = response.result.imports[res]; +                    let status = ''; +                    if (result.status === 0){ +                        status = 'nochange'; +                    } else if ((result.status & 1) === 1){ +                        status = 'newkey'; +                    } else { +                        status = 'change';                      } -                    for (let res=0; res<response.result.imports.length; res++){ -                        let result = response.result.imports[res]; -                        let status = ''; -                        if (result.status === 0){ -                            status = 'nochange'; -                        } else if ((result.status & 1) === 1){ -                            status = 'newkey'; -                        } else { -                            status = 'change'; -                        } -                        let changes = {}; -                        changes.userId = (result.status & 2) === 2; -                        changes.signature = (result.status & 4) === 4; -                        changes.subkey = (result.status & 8) === 8; -                        //16 new secret key: not implemented +                    let changes = {}; +                    changes.userId = (result.status & 2) === 2; +                    changes.signature = (result.status & 4) === 4; +                    changes.subkey = (result.status & 8) === 8; +                    //16 new secret key: not implemented -                        fprs.push(result.fingerprint); -                        infos[result.fingerprint] = { -                            changes: changes, -                            status: status -                        }; -                    } -                    let resultset = []; -                    if (prepare_sync === true){ -                        me.getKeys(fprs, true).then(function(result){ -                            for (let i=0; i < result.length; i++) { -                                resultset.push({ -                                    key: result[i], -                                    changes: -                                        infos[result[i].fingerprint].changes, -                                    status: infos[result[i].fingerprint].status -                                }); -                            } -                            resolve({Keys:resultset,summary: summary}); -                        }, function(error){ -                            reject(error); -                        }); -                    } else { -                        for (let i=0; i < fprs.length; i++) { +                    fprs.push(result.fingerprint); +                    infos[result.fingerprint] = { +                        changes: changes, +                        status: status +                    }; +                } +                let resultset = []; +                if (prepare_sync === true){ +                    me.getKeys(fprs, true).then(function(result){ +                        for (let i=0; i < result.length; i++) {                              resultset.push({ -                                key: createKey(fprs[i]), -                                changes: infos[fprs[i]].changes, -                                status: infos[fprs[i]].status +                                key: result[i], +                                changes: +                                    infos[result[i].fingerprint].changes, +                                status: infos[result[i].fingerprint].status                              });                          } -                        resolve({Keys:resultset,summary:summary}); +                        resolve({Keys:resultset,summary: summary}); +                    }, function(error){ +                        reject(error); +                    }); +                } else { +                    for (let i=0; i < fprs.length; i++) { +                        resultset.push({ +                            key: createKey(fprs[i]), +                            changes: infos[fprs[i]].changes, +                            status: infos[fprs[i]].status +                        });                      } +                    resolve({Keys:resultset,summary:summary}); +                } -                }, function(error){ -                    reject(error); -                }); +            }, function(error){ +                reject(error); +            }); -            }); +        }); -        }; +    } -        /** -         * Convenience function for deleting a Key. See {@link Key.delete} for -         * further information about the return values. -         * @param {String} fingerprint -         * @returns {Promise<Boolean|GPGME_Error>} -         * @async -         * @static -         */ -        this.deleteKey = function(fingerprint){ -            if (isFingerprint(fingerprint) === true) { -                let key = createKey(fingerprint); -                return key.delete(); -            } else { -                return Promise.reject(gpgme_error('KEY_INVALID')); -            } -        }; +    /** +     * Convenience function for deleting a Key. See {@link Key.delete} for +     * further information about the return values. +     * @param {String} fingerprint +     * @returns {Promise<Boolean|GPGME_Error>} +     * @async +     * @static +     */ +    deleteKey(fingerprint){ +        if (isFingerprint(fingerprint) === true) { +            let key = createKey(fingerprint); +            return key.delete(); +        } else { +            return Promise.reject(gpgme_error('KEY_INVALID')); +        } +    } -        /** -         * Generates a new Key pair directly in gpg, and returns a GPGME_Key -         * representing that Key. Please note that due to security concerns, -         * secret Keys can not be deleted or exported from inside gpgme.js. -         * -         * @param {String} userId The user Id, e.g. 'Foo Bar <[email protected]>' -         * @param {String} algo (optional) algorithm (and optionally key size) -         * to be used. See {@link supportedKeyAlgos} below for supported -         * values. -         * @param {Date} expires (optional) Expiration date. If not set, -         * expiration will be set to 'never' -         * -         * @return {Promise<Key|GPGME_Error>} -         * @async -         */ -        this.generateKey = function (userId, algo = 'default', expires){ -            if ( -                typeof(userId) !== 'string' || -                supportedKeyAlgos.indexOf(algo) < 0 || -                (expires && !(expires instanceof Date)) -            ){ -                return Promise.reject(gpgme_error('PARAM_WRONG')); +    /** +     * Generates a new Key pair directly in gpg, and returns a GPGME_Key +     * representing that Key. Please note that due to security concerns, +     * secret Keys can not be deleted or exported from inside gpgme.js. +     * +     * @param {String} userId The user Id, e.g. 'Foo Bar <[email protected]>' +     * @param {String} algo (optional) algorithm (and optionally key size) +     * to be used. See {@link supportedKeyAlgos} below for supported +     * values. +     * @param {Date} expires (optional) Expiration date. If not set, +     * expiration will be set to 'never' +     * +     * @return {Promise<Key|GPGME_Error>} +     * @async +     */ +    generateKey(userId, algo = 'default', expires){ +        if ( +            typeof(userId) !== 'string' || +            supportedKeyAlgos.indexOf(algo) < 0 || +            (expires && !(expires instanceof Date)) +        ){ +            return Promise.reject(gpgme_error('PARAM_WRONG')); +        } +        let me = this; +        return new Promise(function(resolve, reject){ +            let msg = createMessage('createkey'); +            msg.setParameter('userid', userId); +            msg.setParameter('algo', algo ); +            if (expires){ +                msg.setParameter('expires', +                    Math.floor(expires.valueOf()/1000)); +            } else { +                msg.setParameter('expires', 0);              } -            let me = this; -            return new Promise(function(resolve, reject){ -                let msg = createMessage('createkey'); -                msg.setParameter('userid', userId); -                msg.setParameter('algo', algo ); -                if (expires){ -                    msg.setParameter('expires', -                        Math.floor(expires.valueOf()/1000)); -                } else { -                    msg.setParameter('expires', 0); -                } -                msg.post().then(function(response){ -                    me.getKeys(response.fingerprint, true).then( -                        // TODO prepare_sync? -                        function(result){ -                            resolve(result); -                        }, function(error){ -                            reject(error); -                        }); -                }, function(error) { -                    reject(error); -                }); +            msg.post().then(function(response){ +                me.getKeys(response.fingerprint, true).then( +                    // TODO prepare_sync? +                    function(result){ +                        resolve(result); +                    }, function(error){ +                        reject(error); +                    }); +            }, function(error) { +                reject(error);              }); -        }; +        });      }  } +  /**   * List of algorithms supported for key generation. Please refer to the gnupg   * documentation for details | 
