From eef3a509fa5744e5f09ec8084985e6070b78226b Mon Sep 17 00:00:00 2001 From: "raimund.renkert@intevation.de" Date: Tue, 10 Apr 2018 11:33:14 +0200 Subject: js: Initial commit for JavaScript Native Messaging API -- Note this code misses all the legal boilerplate; please add this as soon as possible and provide a DCO so we can merge it into master. I also removed the dist/ directory because that was not source code. --- lang/js/src/gpgmejs.js | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 lang/js/src/gpgmejs.js (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js new file mode 100644 index 00000000..dedbf809 --- /dev/null +++ b/lang/js/src/gpgmejs.js @@ -0,0 +1,187 @@ +import {Connection} from "./Connection" + +export function encrypt(data, publicKeys, privateKeys, passwords=null, + sessionKey, filename, compression, armor=true, detached=false, + signature=null, returnSessionKey=false, wildcard=false, date=new Date()){ + // gpgme_op_encrypt ( <-gpgme doc on this operation + // gpgme_ctx_t ctx, + // gpgme_key_t recp[], + // gpgme_encrypt_flags_t flags, + // gpgme_data_t plain, + // gpgme_data_t cipher) + // flags: + // GPGME_ENCRYPT_ALWAYS_TRUST + // GPGME_ENCRYPT_NO_ENCRYPT_TO + // GPGME_ENCRYPT_NO_COMPRESS + // GPGME_ENCRYPT_PREPARE + // GPGME_ENCRYPT_EXPECT_SIGN + // GPGME_ENCRYPT_SYMMETRIC + // GPGME_ENCRYPT_THROW_KEYIDS + // GPGME_ENCRYPT_WRAP + if (passwords !== null){ + throw('Password!'); // TBD + } + + let pubkeys = toKeyIdArray(publicKeys); + let privkeys = toKeyIdArray(privateKeys); + + // TODO filename: data is supposed to be empty, file is provided + // TODO config compression detached signature + // TODO signature to add to the encrypted message (?) || privateKeys: signature is desired + // gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) + + // TODO sign date overwriting implemented in gnupg? + + let conn = new Connection(); + if (wildcard){ + // Connection.set('throw-keyids', true); TODO Connection.set not yet existant + } + return conn.post('encrypt', { + 'data': data, + 'keys': publicKeys, + 'armor': armor}); +}; + +export function decrypt(message, privateKeys, passwords, sessionKeys, publicKeys, + format='utf8', signature=null, date=new Date()) { + if (passwords !== null){ + throw('Password!'); // TBD + } + if (format === 'binary'){ + // Connection.set('base64', true); + } + if (publicKeys || signature){ + // Connection.set('signature', signature); + // request verification, too + } + //privateKeys optionally if keyId was thrown? + // gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain) + // response is gpgme_op_decrypt_result (gpgme_ctx_t ctx) (next available?) + return conn.post('decrypt', { + 'data': message + }); +} + +// BIG TODO. +export function generateKey({userIds=[], passphrase, numBits=2048, unlocked=false, keyExpirationTime=0, curve="", date=new Date()}){ + throw('not implemented here'); + // gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo, unsigned long reserved, unsigned long expires, gpgme_key_t extrakey, unsigned int flags); + return false; +} + +export function sign({ data, privateKeys, armor=true, detached=false, date=new Date() }) { + //TODO detached GPGME_SIG_MODE_DETACH | GPGME_SIG_MODE_NORMAL + // gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig, gpgme_sig_mode_t mode) + // TODO date not supported + + let conn = new Connection(); + let privkeys = toKeyIdArray(privateKeys); + return conn.post('sign', { + 'data': data, + 'keys': privkeys, + 'armor': armor}); +}; + +export function verify({ message, publicKeys, signature=null, date=new Date() }) { + //TODO extra signature: sig, signed_text, plain: null + // inline sig: signed_text:null, plain as writable (?) + // date not supported + //gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plain) + let conn = new Connection(); + let privkeys = toKeyIdArray(privateKeys); + return conn.post('sign', { + 'data': data, + 'keys': privkeys, + 'armor': armor}); +} + + +export function reformatKey(privateKey, userIds=[], passphrase="", unlocked=false, keyExpirationTime=0){ + let privKey = toKeyIdArray(privateKey); + if (privKey.length !== 1){ + return false; //TODO some error handling. There is not exactly ONE key we are editing + } + let conn = new Connection(); + // TODO key management needs to be changed somewhat + return conn.post('TODO', { + 'key': privKey[0], + 'keyExpirationTime': keyExpirationTime, //TODO check if this is 0 or a positive and plausible number + 'userIds': userIds //TODO check if empty or plausible strings + }); + // unlocked will be ignored +} + +export function decryptKey({ privateKey, passphrase }) { + throw('not implemented here'); + return false; +}; + +export function encryptKey({ privateKey, passphrase }) { + throw('not implemented here'); + return false; +}; + +export function encryptSessionKey({data, algorithm, publicKeys, passwords, wildcard=false }) { + //openpgpjs: + // Encrypt a symmetric session key with public keys, passwords, or both at + // once. At least either public keys or passwords must be specified. + throw('not implemented here'); + return false; +}; + +export function decryptSessionKeys({ message, privateKeys, passwords }) { + throw('not implemented here'); + return false; +}; + +// //TODO worker handling + +// //TODO key representation +// //TODO: keyring handling + + +/** + * Helper functions and checks + */ + +/** + * Checks if the submitted value is a keyID. + * TODO: should accept all strings that are accepted as keyID by gnupg + * TODO: See if Key becomes an object later on + * @param {*} key input value. Is expected to be a string of 8,16 or 40 chars + * representing hex values. Will return false if that expectation is not met + */ +function isKeyId(key){ + if (!key || typeof(key) !== "string"){ + return false; + } + if ([8,16,40].indexOf(key.length) < 0){ + return false; + } + let regexp= /^[0-9a-fA-F]*$/i; + return regexp.test(key); +}; + +/** + * Tries to return an array of keyID values, either from a string or an array. + * Filters out those that do not meet the criteria. (TODO: silently for now) + * @param {*} array Input value. + */ +function toKeyIdArray(array){ + let result = []; + if (!array){ + return result; + } + if (!Array.isArray(array)){ + if (isKeyId(array) === true){ + return [keyId]; + } + return result; + } + for (let i=0; i < array.length; i++){ + if (isKeyId(array[i]) === true){ + result.push(array[i]); + } + } + return result; +}; -- cgit v1.2.3 From 6ab25e40d904007755c5d999bf66ae264236e745 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 18 Apr 2018 16:38:06 +0200 Subject: js: encrypt improvement and decrypt method * Compatibility class gpgme_openpgpjs offers an API that should accept openpgpjs syntax, throwing errors if a parameter is unexpected/not implemented * tried to be more generic in methods * waiting for multiple answers if 'more' is in the answer * more consistency checking on sending and receiving * updated the example extension -- --- lang/js/src/gpgmejs.js | 282 ++++++++++++++++++++----------------------------- 1 file changed, 113 insertions(+), 169 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index dedbf809..8323ac3b 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -1,187 +1,131 @@ -import {Connection} from "./Connection" - -export function encrypt(data, publicKeys, privateKeys, passwords=null, - sessionKey, filename, compression, armor=true, detached=false, - signature=null, returnSessionKey=false, wildcard=false, date=new Date()){ - // gpgme_op_encrypt ( <-gpgme doc on this operation - // gpgme_ctx_t ctx, - // gpgme_key_t recp[], - // gpgme_encrypt_flags_t flags, - // gpgme_data_t plain, - // gpgme_data_t cipher) - // flags: - // GPGME_ENCRYPT_ALWAYS_TRUST - // GPGME_ENCRYPT_NO_ENCRYPT_TO - // GPGME_ENCRYPT_NO_COMPRESS - // GPGME_ENCRYPT_PREPARE - // GPGME_ENCRYPT_EXPECT_SIGN - // GPGME_ENCRYPT_SYMMETRIC - // GPGME_ENCRYPT_THROW_KEYIDS - // GPGME_ENCRYPT_WRAP - if (passwords !== null){ - throw('Password!'); // TBD - } - - let pubkeys = toKeyIdArray(publicKeys); - let privkeys = toKeyIdArray(privateKeys); - - // TODO filename: data is supposed to be empty, file is provided - // TODO config compression detached signature - // TODO signature to add to the encrypted message (?) || privateKeys: signature is desired - // gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) - - // TODO sign date overwriting implemented in gnupg? - - let conn = new Connection(); - if (wildcard){ - // Connection.set('throw-keyids', true); TODO Connection.set not yet existant - } - return conn.post('encrypt', { - 'data': data, - 'keys': publicKeys, - 'armor': armor}); -}; +/* 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 . + * SPDX-License-Identifier: LGPL-2.1+ + */ -export function decrypt(message, privateKeys, passwords, sessionKeys, publicKeys, - format='utf8', signature=null, date=new Date()) { - if (passwords !== null){ - throw('Password!'); // TBD - } - if (format === 'binary'){ - // Connection.set('base64', true); - } - if (publicKeys || signature){ - // Connection.set('signature', signature); - // request verification, too +import {Connection} from "./Connection" +import {GPGME_Message} from './Message' +import {toKeyIdArray} from "./Helpers" + +export class GpgME { + /** + * initial check if connection si successfull. Will throw ERR_NO_CONNECT or + * ERR_NO_CONNECT_RLE (if chrome.runtime.lastError is available) if the + * connection fails. + * TODO The connection to the nativeMessaging host will, for now, be closed + * after each interaction. Session management with gpg_agent is TBD. + * TODO: add configuration + */ + constructor(){ + let conn = new Connection(); + // this.keyring = new Keyring(); TBD + // TODO config, e.g. + this.configuration = { + null_expire_is_never: true + }; + conn.disconnect(); } - //privateKeys optionally if keyId was thrown? - // gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain) - // response is gpgme_op_decrypt_result (gpgme_ctx_t ctx) (next available?) - return conn.post('decrypt', { - 'data': message - }); -} -// BIG TODO. -export function generateKey({userIds=[], passphrase, numBits=2048, unlocked=false, keyExpirationTime=0, curve="", date=new Date()}){ - throw('not implemented here'); - // gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo, unsigned long reserved, unsigned long expires, gpgme_key_t extrakey, unsigned int flags); - return false; -} + /** + * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array + * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message + * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message + */ + encrypt (data, publicKeys, wildcard=false){ -export function sign({ data, privateKeys, armor=true, detached=false, date=new Date() }) { - //TODO detached GPGME_SIG_MODE_DETACH | GPGME_SIG_MODE_NORMAL - // gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig, gpgme_sig_mode_t mode) - // TODO date not supported + let msg = new GPGME_Message; + msg.operation = 'encrypt'; - let conn = new Connection(); - let privkeys = toKeyIdArray(privateKeys); - return conn.post('sign', { - 'data': data, - 'keys': privkeys, - 'armor': armor}); -}; + // TODO temporary + msg.setParameter('armor', true); + msg.setParameter('always-trust', true); -export function verify({ message, publicKeys, signature=null, date=new Date() }) { - //TODO extra signature: sig, signed_text, plain: null - // inline sig: signed_text:null, plain as writable (?) - // date not supported - //gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plain) - let conn = new Connection(); - let privkeys = toKeyIdArray(privateKeys); - return conn.post('sign', { - 'data': data, - 'keys': privkeys, - 'armor': armor}); -} + let pubkeys = toKeyIdArray(publicKeys); + msg.setParameter('keys', pubkeys); + putData(msg, data); + if (wildcard === true){msg.setParameter('throw-keyids', true); + }; -export function reformatKey(privateKey, userIds=[], passphrase="", unlocked=false, keyExpirationTime=0){ - let privKey = toKeyIdArray(privateKey); - if (privKey.length !== 1){ - return false; //TODO some error handling. There is not exactly ONE key we are editing + if (msg.isComplete === true) { + let conn = new Connection(); + return (conn.post(msg.message)); + } + else { + return Promise.reject('NO_CONNECT'); + //TODO + } } - let conn = new Connection(); - // TODO key management needs to be changed somewhat - return conn.post('TODO', { - 'key': privKey[0], - 'keyExpirationTime': keyExpirationTime, //TODO check if this is 0 or a positive and plausible number - 'userIds': userIds //TODO check if empty or plausible strings - }); - // unlocked will be ignored -} -export function decryptKey({ privateKey, passphrase }) { - throw('not implemented here'); - return false; -}; + /** + * @param {String} data TODO Format: base64? String? Message with the encrypted data + * @returns {Promise} decrypted message: + data: The decrypted data. This may be base64 encoded. + base64: Boolean indicating whether data is base64 encoded. + mime: A Boolean indicating whether the data is a MIME object. + info: An optional object with extra information. + * @async + */ -export function encryptKey({ privateKey, passphrase }) { - throw('not implemented here'); - return false; -}; + decrypt(data){ -export function encryptSessionKey({data, algorithm, publicKeys, passwords, wildcard=false }) { - //openpgpjs: - // Encrypt a symmetric session key with public keys, passwords, or both at - // once. At least either public keys or passwords must be specified. - throw('not implemented here'); - return false; -}; - -export function decryptSessionKeys({ message, privateKeys, passwords }) { - throw('not implemented here'); - return false; -}; - -// //TODO worker handling - -// //TODO key representation -// //TODO: keyring handling - - -/** - * Helper functions and checks - */ - -/** - * Checks if the submitted value is a keyID. - * TODO: should accept all strings that are accepted as keyID by gnupg - * TODO: See if Key becomes an object later on - * @param {*} key input value. Is expected to be a string of 8,16 or 40 chars - * representing hex values. Will return false if that expectation is not met - */ -function isKeyId(key){ - if (!key || typeof(key) !== "string"){ - return false; - } - if ([8,16,40].indexOf(key.length) < 0){ - return false; + if (data === undefined){ + throw('ERR_EMPTY_MSG'); + } + let msg = new GPGME_Message; + msg.operation = 'decrypt'; + putData(msg, data); + // TODO: needs proper EOL to be decrypted. + + if (msg.isComplete === true){ + let conn = new Connection(); + return conn.post(msg.message); + } + else { + return Promise.reject('NO_CONNECT'); + //TODO + } } - let regexp= /^[0-9a-fA-F]*$/i; - return regexp.test(key); -}; +} /** - * Tries to return an array of keyID values, either from a string or an array. - * Filters out those that do not meet the criteria. (TODO: silently for now) - * @param {*} array Input value. + * Sets the data of the message, converting Uint8Array to base64 and setting + * the base64 flag + * @param {GPGME_Message} message The message where this data will be set + * @param {*} data The data to enter + * @param {String} propertyname // TODO unchecked still */ -function toKeyIdArray(array){ - let result = []; - if (!array){ - return result; - } - if (!Array.isArray(array)){ - if (isKeyId(array) === true){ - return [keyId]; - } - return result; +function putData(message, data){ + if (!message || !message instanceof GPGME_Message ) { + throw('NO_MESSAGE_OBJECT'); } - for (let i=0; i < array.length; i++){ - if (isKeyId(array[i]) === true){ - result.push(array[i]); - } + if (!data){ + //TODO Debug only! No data is legitimate + console.log('Warning. no data in message'); + message.setParameter('data', ''); + } else if (data instanceof Uint8Array){ + let decoder = new TextDecoder('utf8'); + message.setParameter('base64', true); + message.setParameter ('data', decoder.decode(data)); + } else if (typeof(data) === 'string') { + message.setParameter('base64', false); + message.setParameter('data', data); + } else { + throw('ERR_WRONG_TYPE'); } - return result; -}; +} \ No newline at end of file -- cgit v1.2.3 From d62f66b1fb47f2075770d896f672748a4136e70b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 23 Apr 2018 17:18:46 +0200 Subject: js: Key handling stubs, Error handling, refactoring -- * Error handling: introduced GPGMEJS_Error class that handles errors at a more centralized and consistent position * src/Connection.js: The nativeMessaging port now opens per session instead of per message. Some methods were added that reflect this change - added methods disconnect() and reconnect() - added connection status query * src/gpgmejs.js - stub for key deletion - error handling - high level API for changing connection status * src/gpgmejs_openpgpjs.js - added stubs for Key/Keyring handling according to current state of discussion. It is still subject to change * src/Helpers.js - toKeyIdArray creates an array of KeyIds, now accepting fingerprints, GPGMEJS_Key objects and openpgp Key objects. * Key objects (src/Key.js) Querying information about a key directly from gnupg. Currently a stub, only the Key.fingerprint is functional. * Keyring queries (src/Keyring.js): Listing and searching keys. Currently a stub. --- lang/js/src/gpgmejs.js | 108 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 31 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 8323ac3b..c23a356b 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -21,26 +21,54 @@ import {Connection} from "./Connection" import {GPGME_Message} from './Message' import {toKeyIdArray} from "./Helpers" +import {GPGMEJS_Error as Error, GPGMEJS_Error} from "./Errors" export class GpgME { /** - * initial check if connection si successfull. Will throw ERR_NO_CONNECT or - * ERR_NO_CONNECT_RLE (if chrome.runtime.lastError is available) if the - * connection fails. - * TODO The connection to the nativeMessaging host will, for now, be closed - * after each interaction. Session management with gpg_agent is TBD. + * initializes GpgME by opening a nativeMessaging port * TODO: add configuration */ - constructor(){ - let conn = new Connection(); - // this.keyring = new Keyring(); TBD - // TODO config, e.g. - this.configuration = { - null_expire_is_never: true - }; - conn.disconnect(); + constructor(configuration = { + null_expire_is_never: false + }){ + this._connection = new Connection; + } + + /** + * refreshes the nativeApp connection + */ + reconnect(){ + if (!this._connection || ! this._connection instanceof Connection){ + this._connection = new Connection; + } else { + this._connection.disconnect(); + this._connection.connect(); + } + } + + /** + * inmediately tries to destroy the nativeMessaging connection. + * TODO: may not be included in final API, as it is redundant. + * For now, it just serves paranoia + */ + disconnect(){ + if (this._connection){ + this._connection.disconnect(); + this._connection = null; + } + } + + /** + * tests the nativeApp connection + */ + get connected(){ + if (!this._connection || ! this._connection instanceof Connection){ + return false; + } + return this._connection.connected; } + /** * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message @@ -62,14 +90,7 @@ export class GpgME { if (wildcard === true){msg.setParameter('throw-keyids', true); }; - if (msg.isComplete === true) { - let conn = new Connection(); - return (conn.post(msg.message)); - } - else { - return Promise.reject('NO_CONNECT'); - //TODO - } + return (this._connection.post(msg)); } /** @@ -85,22 +106,47 @@ export class GpgME { decrypt(data){ if (data === undefined){ - throw('ERR_EMPTY_MSG'); + return Promise.reject(new GPGMEJS_Error ('EMPTY_MSG')); } let msg = new GPGME_Message; msg.operation = 'decrypt'; putData(msg, data); - // TODO: needs proper EOL to be decrypted. + return this._connection.post(msg); + + } - if (msg.isComplete === true){ - let conn = new Connection(); - return conn.post(msg.message); + deleteKey(key, delete_secret = false, no_confirm = false){ + return Promise.reject(new GPGMEJS_Error ('NOT_YET_IMPLEMENTED')); + let msg = new GPGME_Message; + msg.operation = 'deletekey'; + let key_arr = toKeyIdArray(key); + if (key_arr.length !== 1){ + throw('TODO'); + //should always be ONE key + } + msg.setParameter('key', key_arr[0]); + if (delete_secret === true){ + msg.setParameter('allow_secret', true); //TBD } - else { - return Promise.reject('NO_CONNECT'); - //TODO + if (no_confirm === true){ //TODO: Do we want this hidden deep in the code? + msg.setParameter('delete_force', true); //TBD } + this._connection.post(msg).then(function(success){ + //TODO: it seems that there is always errors coming back: + }, function(error){ + switch (error.msg){ + case 'ERR_NO_ERROR': + return Promise.resolve('okay'); //TBD + default: + return Promise.reject(new GPGMEJS_Error); + // INV_VALUE, + // GPG_ERR_NO_PUBKEY, + // GPG_ERR_AMBIGUOUS_NAME, + // GPG_ERR_CONFLICT + } + }); } + } /** @@ -112,7 +158,7 @@ export class GpgME { */ function putData(message, data){ if (!message || !message instanceof GPGME_Message ) { - throw('NO_MESSAGE_OBJECT'); + return new GPGMEJS_Error('WRONGPARAM'); } if (!data){ //TODO Debug only! No data is legitimate @@ -126,6 +172,6 @@ function putData(message, data){ message.setParameter('base64', false); message.setParameter('data', data); } else { - throw('ERR_WRONG_TYPE'); + return new GPGMEJS_Error('WRONGPARAM'); } } \ No newline at end of file -- cgit v1.2.3 From 727340b295f25e04cb595022ba143cda48364697 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 23 Apr 2018 19:15:40 +0200 Subject: js: don't allow message operation changes -- Once an operation is changed, their set of allowed/required parameters will change. So we shouldn't set/change the operation later. --- lang/js/src/gpgmejs.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c23a356b..b15477f0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -76,8 +76,7 @@ export class GpgME { */ encrypt (data, publicKeys, wildcard=false){ - let msg = new GPGME_Message; - msg.operation = 'encrypt'; + let msg = new GPGME_Message('encrypt'); // TODO temporary msg.setParameter('armor', true); @@ -108,8 +107,7 @@ export class GpgME { if (data === undefined){ return Promise.reject(new GPGMEJS_Error ('EMPTY_MSG')); } - let msg = new GPGME_Message; - msg.operation = 'decrypt'; + let msg = new GPGME_Message('decrypt'); putData(msg, data); return this._connection.post(msg); @@ -117,8 +115,7 @@ export class GpgME { deleteKey(key, delete_secret = false, no_confirm = false){ return Promise.reject(new GPGMEJS_Error ('NOT_YET_IMPLEMENTED')); - let msg = new GPGME_Message; - msg.operation = 'deletekey'; + let msg = new GPGME_Message('deletekey'); let key_arr = toKeyIdArray(key); if (key_arr.length !== 1){ throw('TODO'); -- cgit v1.2.3 From 461dd0c8b41683a91073b362d100ee5217ec53f6 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 24 Apr 2018 18:44:30 +0200 Subject: js: change in initialization ancd connection handling -- * The Connection will now be started before an object is created, to better account for failures. * index.js: now exposes an init(), which returns a Promise of configurable with an established connection. * TODO: There is currently no way to recover from a "connection lost" * Connection.js offers Connection.isConnected, which toggles on port closing. --- lang/js/src/gpgmejs.js | 61 +++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index b15477f0..4b2a03a4 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -22,59 +22,51 @@ import {Connection} from "./Connection" import {GPGME_Message} from './Message' import {toKeyIdArray} from "./Helpers" import {GPGMEJS_Error as Error, GPGMEJS_Error} from "./Errors" +import { GPGME_Keyring } from "./Keyring"; export class GpgME { /** * initializes GpgME by opening a nativeMessaging port * TODO: add configuration */ - constructor(configuration = { - null_expire_is_never: false - }){ - this._connection = new Connection; + constructor(connection){ + this.connection = connection; } - /** - * refreshes the nativeApp connection - */ - reconnect(){ - if (!this._connection || ! this._connection instanceof Connection){ - this._connection = new Connection; - } else { - this._connection.disconnect(); - this._connection.connect(); + set connection(connection){ + if (this._connection instanceof Connection){ + //TODO Warning: Connection already established + } + if (connection instanceof Connection){ + this._connection = connection; } } - /** - * inmediately tries to destroy the nativeMessaging connection. - * TODO: may not be included in final API, as it is redundant. - * For now, it just serves paranoia - */ - disconnect(){ - if (this._connection){ - this._connection.disconnect(); - this._connection = null; + get connection(){ + if (this._connection instanceof Connection){ + if (this._connection.isConnected){ + return this._connection; + } + return undefined; //TODO: connection was lost! } + return undefined; //TODO: no connection there } - /** - * tests the nativeApp connection - */ - get connected(){ - if (!this._connection || ! this._connection instanceof Connection){ - return false; + set Keyring(keyring){ + if (ring && ring instanceof GPGME_Keyring){ + this.Keyring = ring; } - return this._connection.connected; } + get Keyring(){ + } /** * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message */ - encrypt (data, publicKeys, wildcard=false){ + encrypt(data, publicKeys, wildcard=false){ let msg = new GPGME_Message('encrypt'); @@ -89,7 +81,7 @@ export class GpgME { if (wildcard === true){msg.setParameter('throw-keyids', true); }; - return (this._connection.post(msg)); + return (this.connection.post(msg)); } /** @@ -109,7 +101,7 @@ export class GpgME { } let msg = new GPGME_Message('decrypt'); putData(msg, data); - return this._connection.post(msg); + return this.connection.post(msg); } @@ -128,7 +120,7 @@ export class GpgME { if (no_confirm === true){ //TODO: Do we want this hidden deep in the code? msg.setParameter('delete_force', true); //TBD } - this._connection.post(msg).then(function(success){ + this.connection.post(msg).then(function(success){ //TODO: it seems that there is always errors coming back: }, function(error){ switch (error.msg){ @@ -143,7 +135,6 @@ export class GpgME { } }); } - } /** @@ -171,4 +162,4 @@ function putData(message, data){ } else { return new GPGMEJS_Error('WRONGPARAM'); } -} \ No newline at end of file +} -- cgit v1.2.3 From 30c47d80a27054aa340cbd6dc39d1b8a5dc5cf22 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 24 Apr 2018 19:47:48 +0200 Subject: js: allow openpgp-like Message objects as Data -- * src/gpgmejs.js: If a message offers a getText, consider it as the message's content --- lang/js/src/gpgmejs.js | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 4b2a03a4..03ed5cb6 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -159,6 +159,13 @@ function putData(message, data){ } else if (typeof(data) === 'string') { message.setParameter('base64', false); message.setParameter('data', data); + } else if ( typeof(data) === 'object' && data.hasOwnProperty(getText)){ + let txt = data.getText(); + if (txt instanceof Uint8Array){ + let decoder = new TextDecoder('utf8'); + message.setParameter('base64', true); + message.setParameter ('data', decoder.decode(txt)); + } } else { return new GPGMEJS_Error('WRONGPARAM'); } -- cgit v1.2.3 From c72adc00965fe4fcedd9d18609211021a091b28b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 25 Apr 2018 10:54:24 +0200 Subject: js: change in Error behaviour -- * Error objects will now return the error code if defined as error type in src/Errors.js, or do a console.log if it is a warning. Errors from the native gpgme-json will be marked as GNUPG_ERROR. --- lang/js/src/gpgmejs.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 03ed5cb6..b20ff0f2 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -95,9 +95,8 @@ export class GpgME { */ decrypt(data){ - if (data === undefined){ - return Promise.reject(new GPGMEJS_Error ('EMPTY_MSG')); + return Promise.reject(GPGMEJS_Error('MSG_EMPTY')); } let msg = new GPGME_Message('decrypt'); putData(msg, data); @@ -106,7 +105,7 @@ export class GpgME { } deleteKey(key, delete_secret = false, no_confirm = false){ - return Promise.reject(new GPGMEJS_Error ('NOT_YET_IMPLEMENTED')); + return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED')); let msg = new GPGME_Message('deletekey'); let key_arr = toKeyIdArray(key); if (key_arr.length !== 1){ @@ -127,7 +126,7 @@ export class GpgME { case 'ERR_NO_ERROR': return Promise.resolve('okay'); //TBD default: - return Promise.reject(new GPGMEJS_Error); + return Promise.reject(GPGMEJS_Error('TODO') ); // // INV_VALUE, // GPG_ERR_NO_PUBKEY, // GPG_ERR_AMBIGUOUS_NAME, @@ -146,11 +145,9 @@ export class GpgME { */ function putData(message, data){ if (!message || !message instanceof GPGME_Message ) { - return new GPGMEJS_Error('WRONGPARAM'); + return GPGMEJS_Error('PARAM_WRONG'); } if (!data){ - //TODO Debug only! No data is legitimate - console.log('Warning. no data in message'); message.setParameter('data', ''); } else if (data instanceof Uint8Array){ let decoder = new TextDecoder('utf8'); @@ -167,6 +164,6 @@ function putData(message, data){ message.setParameter ('data', decoder.decode(txt)); } } else { - return new GPGMEJS_Error('WRONGPARAM'); + return GPGMEJS_Error('PARAM_WRONG'); } } -- cgit v1.2.3 From 1fb310cabe578625f96fce5d84ff6f0092c08d24 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 25 Apr 2018 15:59:36 +0200 Subject: js: Configuration and Error handling -- * gpgmejs_openpgpjs - unsuported values with no negative consequences can now reject, warn or be ignored, according to config.unconsidered_params - cleanup of unsupported/supported parameters and TODOS * A src/index.js init() now accepts a configuration object * Errors will now be derived from Error, offering more info and a stacktrace. * Fixed Connection.post() timeout triggering on wrong cases * Added comments in permittedOperations.js, which gpgme interactions are still unimplemented and should be added next --- lang/js/src/gpgmejs.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index b20ff0f2..b504a457 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -21,7 +21,7 @@ import {Connection} from "./Connection" import {GPGME_Message} from './Message' import {toKeyIdArray} from "./Helpers" -import {GPGMEJS_Error as Error, GPGMEJS_Error} from "./Errors" +import { gpgme_error } from "./Errors" import { GPGME_Keyring } from "./Keyring"; export class GpgME { @@ -35,10 +35,12 @@ export class GpgME { set connection(connection){ if (this._connection instanceof Connection){ - //TODO Warning: Connection already established + gpgme_error('CONN_ALREADY_CONNECTED'); } if (connection instanceof Connection){ this._connection = connection; + } else { + gpgme_error('PARAM_WRONG'); } } @@ -54,11 +56,12 @@ export class GpgME { set Keyring(keyring){ if (ring && ring instanceof GPGME_Keyring){ - this.Keyring = ring; + this._Keyring = ring; } } get Keyring(){ + return this._Keyring; } /** @@ -96,7 +99,7 @@ export class GpgME { decrypt(data){ if (data === undefined){ - return Promise.reject(GPGMEJS_Error('MSG_EMPTY')); + return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = new GPGME_Message('decrypt'); putData(msg, data); @@ -105,7 +108,7 @@ export class GpgME { } deleteKey(key, delete_secret = false, no_confirm = false){ - return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED')); + return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); let msg = new GPGME_Message('deletekey'); let key_arr = toKeyIdArray(key); if (key_arr.length !== 1){ @@ -126,7 +129,7 @@ export class GpgME { case 'ERR_NO_ERROR': return Promise.resolve('okay'); //TBD default: - return Promise.reject(GPGMEJS_Error('TODO') ); // + return Promise.reject(gpgme_error('TODO') ); // // INV_VALUE, // GPG_ERR_NO_PUBKEY, // GPG_ERR_AMBIGUOUS_NAME, @@ -145,7 +148,7 @@ export class GpgME { */ function putData(message, data){ if (!message || !message instanceof GPGME_Message ) { - return GPGMEJS_Error('PARAM_WRONG'); + return gpgme_error('PARAM_WRONG'); } if (!data){ message.setParameter('data', ''); @@ -164,6 +167,6 @@ function putData(message, data){ message.setParameter ('data', decoder.decode(txt)); } } else { - return GPGMEJS_Error('PARAM_WRONG'); + return gpgme_error('PARAM_WRONG'); } } -- cgit v1.2.3 From 3685913bf510a14b8cb324d980217d90489e6453 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 25 Apr 2018 19:45:39 +0200 Subject: js: First testing and improvements -- * Introduced Mocha/chai as testsuite. After development build 'npm test' should run the unit tests. Functionality exclusive to Browsers/WebExtensions cannot be run this way, so some other testing is still needed. - package.json: Added required development packages - .babelrc indirect configuration for mocha. ES6 transpiling needs some babel configuration, but mocha has no setting for it. - test/mocha.opts Vonfiguration for mocha runs * Fixed errors: - Helpers.js toKeyIdArray; isLongId is now exported - Key.js Key constructor failed - Message.js will not throw an Error during construction, a new message is now created with createMessage, which can return an Error or a GPGME_Message object * Tests: - test/Helpers: exports from Helpers.js, GPGME_Error handling - test/Message: first init test with bad parameters --- lang/js/src/gpgmejs.js | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index b504a457..2ddf2964 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -19,7 +19,7 @@ */ import {Connection} from "./Connection" -import {GPGME_Message} from './Message' +import {GPGME_Message, createMessage} from './Message' import {toKeyIdArray} from "./Helpers" import { gpgme_error } from "./Errors" import { GPGME_Keyring } from "./Keyring"; @@ -71,8 +71,10 @@ export class GpgME { */ encrypt(data, publicKeys, wildcard=false){ - let msg = new GPGME_Message('encrypt'); - + let msg = createMessage('encrypt'); + if (msg instanceof Error){ + return Promise.reject(msg) + } // TODO temporary msg.setParameter('armor', true); msg.setParameter('always-trust', true); @@ -101,7 +103,10 @@ export class GpgME { if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } - let msg = new GPGME_Message('decrypt'); + let msg = createMessage('decrypt'); + if (msg instanceof Error){ + return Promise.reject(msg); + } putData(msg, data); return this.connection.post(msg); @@ -109,21 +114,27 @@ export class GpgME { deleteKey(key, delete_secret = false, no_confirm = false){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); - let msg = new GPGME_Message('deletekey'); + let msg = createMessage('deletekey'); + if (msg instanceof Error){ + return Promise.reject(msg); + } let key_arr = toKeyIdArray(key); if (key_arr.length !== 1){ - throw('TODO'); - //should always be ONE key + return Promise.reject( + gpgme_error('GENERIC_ERROR')); + // TBD should always be ONE key? } msg.setParameter('key', key_arr[0]); if (delete_secret === true){ - msg.setParameter('allow_secret', true); //TBD + msg.setParameter('allow_secret', true); + // TBD } if (no_confirm === true){ //TODO: Do we want this hidden deep in the code? - msg.setParameter('delete_force', true); //TBD + msg.setParameter('delete_force', true); + // TBD } this.connection.post(msg).then(function(success){ - //TODO: it seems that there is always errors coming back: + // TODO: it seems that there is always errors coming back: }, function(error){ switch (error.msg){ case 'ERR_NO_ERROR': -- cgit v1.2.3 From fda7b13f1b673962ce34b6f429158a7eb9cef47b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Apr 2018 20:03:09 +0200 Subject: js: more testing -- * Tests: initialization of the two modes, encryption * gpgme.js: reintroduced message check before calling Connection.post() * gpgmejs_openpgp.js: Fixed openpgp mode not passing keys * index.js: fixed some confusion in parseconfig() * Inserted some TODO stubs for missing error handling --- lang/js/src/gpgmejs.js | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 2ddf2964..9475b2b0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -33,25 +33,24 @@ export class GpgME { this.connection = connection; } - set connection(connection){ + set connection(conn){ if (this._connection instanceof Connection){ gpgme_error('CONN_ALREADY_CONNECTED'); - } - if (connection instanceof Connection){ - this._connection = connection; + } else if (conn instanceof Connection){ + this._connection = conn; } else { gpgme_error('PARAM_WRONG'); } } get connection(){ - if (this._connection instanceof Connection){ - if (this._connection.isConnected){ + if (this._connection){ + if (this._connection.isConnected === true){ return this._connection; } - return undefined; //TODO: connection was lost! + return undefined; } - return undefined; //TODO: no connection there + return undefined; } set Keyring(keyring){ @@ -85,8 +84,11 @@ export class GpgME { putData(msg, data); if (wildcard === true){msg.setParameter('throw-keyids', true); }; - - return (this.connection.post(msg)); + if (msg.isComplete === true){ + return this.connection.post(msg); + } else { + return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + } } /** @@ -133,20 +135,24 @@ export class GpgME { msg.setParameter('delete_force', true); // TBD } - this.connection.post(msg).then(function(success){ - // TODO: it seems that there is always errors coming back: - }, function(error){ - switch (error.msg){ - case 'ERR_NO_ERROR': - return Promise.resolve('okay'); //TBD - default: - return Promise.reject(gpgme_error('TODO') ); // - // INV_VALUE, - // GPG_ERR_NO_PUBKEY, - // GPG_ERR_AMBIGUOUS_NAME, - // GPG_ERR_CONFLICT - } - }); + if (msg.isComplete === true){ + this.connection.post(msg).then(function(success){ + // TODO: it seems that there is always errors coming back: + }, function(error){ + switch (error.msg){ + case 'ERR_NO_ERROR': + return Promise.resolve('okay'); //TBD + default: + return Promise.reject(gpgme_error('TODO') ); // + // INV_VALUE, + // GPG_ERR_NO_PUBKEY, + // GPG_ERR_AMBIGUOUS_NAME, + // GPG_ERR_CONFLICT + } + }); + } else { + return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + } } } @@ -162,7 +168,7 @@ function putData(message, data){ return gpgme_error('PARAM_WRONG'); } if (!data){ - message.setParameter('data', ''); + return gpgme_error('PARAM_WRONG'); } else if (data instanceof Uint8Array){ let decoder = new TextDecoder('utf8'); message.setParameter('base64', true); -- cgit v1.2.3 From cca40627b0afa2efc85ef7f5f1a1060a221ff2a2 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 8 May 2018 18:33:41 +0200 Subject: js: more testing -- * Tests: Under certain circumstances, some data change during encrypt-decrypt. Committing the current state so the problem can be discussed. * Fixes: - disconnecting the test ports after tests are complete - fixed passing of the error message from gpgme-json --- lang/js/src/gpgmejs.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 9475b2b0..c1a01377 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -170,18 +170,19 @@ function putData(message, data){ if (!data){ return gpgme_error('PARAM_WRONG'); } else if (data instanceof Uint8Array){ - let decoder = new TextDecoder('utf8'); message.setParameter('base64', true); - message.setParameter ('data', decoder.decode(data)); + message.setParameter ('data', btoa(data)); } else if (typeof(data) === 'string') { message.setParameter('base64', false); message.setParameter('data', data); - } else if ( typeof(data) === 'object' && data.hasOwnProperty(getText)){ + } else if ( typeof(data) === 'object' && data.hasOwnProperty('getText')){ let txt = data.getText(); if (txt instanceof Uint8Array){ - let decoder = new TextDecoder('utf8'); message.setParameter('base64', true); - message.setParameter ('data', decoder.decode(txt)); + message.setParameter ('data', btoa(txt)); + } + else { + return gpgme_error('PARAM_WRONG'); } } else { return gpgme_error('PARAM_WRONG'); -- cgit v1.2.3 From 987b31746809dfe04966e37edd759a448a28d975 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 14 May 2018 16:23:24 +0200 Subject: js: Tests and improvements for openpgp mode -- * Added openpgp - Mode tests to the browsertest Extension. These tests require openpgp, which should not be a hard dependency for the main project. Packing openpgpjs into the extension is still TODO * Fixes: - openpgp mode API now correctly handles parameters as an object, similar to openpgpjs - proper check and parsing of openpgpjs Message Objects --- lang/js/src/gpgmejs.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c1a01377..d106f4f7 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -80,7 +80,6 @@ export class GpgME { let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); - putData(msg, data); if (wildcard === true){msg.setParameter('throw-keyids', true); }; @@ -171,19 +170,32 @@ function putData(message, data){ return gpgme_error('PARAM_WRONG'); } else if (data instanceof Uint8Array){ message.setParameter('base64', true); + // TODO: btoa turns the array into a string + // of comma separated of numbers + // atob(data).split(',') would result in a "normal" array of numbers + // atob(btoa(data)).split(',') would result in a "normal" array of numbers + // would result in a "normal" array of numbers message.setParameter ('data', btoa(data)); + } else if (typeof(data) === 'string') { message.setParameter('base64', false); message.setParameter('data', data); - } else if ( typeof(data) === 'object' && data.hasOwnProperty('getText')){ + } else if ( + typeof(data) === 'object' && + typeof(data.getText) === 'function' + ){ let txt = data.getText(); if (txt instanceof Uint8Array){ message.setParameter('base64', true); message.setParameter ('data', btoa(txt)); } - else { + else if (typeof(txt) === 'string'){ + message.setParameter('base64', false); + message.setParameter ('data', txt); + } else { return gpgme_error('PARAM_WRONG'); } + } else { return gpgme_error('PARAM_WRONG'); } -- cgit v1.2.3 From ecad77263585cd5954758f797327d98232d880dc Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 22 May 2018 14:24:16 +0200 Subject: js: transfer encoding changes -- * Uint8Arrays are not supported for now there are unsolved issues in conversion, and they are lower priority * encrypt gains a new option to indicate that input values are base64 encoded * as decrypted values are always base64 encoded, the option base64 will not try to decode the result into utf, but leave it as it is --- lang/js/src/gpgmejs.js | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index d106f4f7..01cb92c3 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -64,11 +64,11 @@ export class GpgME { } /** - * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array + * @param {String} data text/data to be encrypted as String * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message */ - encrypt(data, publicKeys, wildcard=false){ + encrypt(data, publicKeys, base64=false, wildcard=false){ let msg = createMessage('encrypt'); if (msg instanceof Error){ @@ -77,11 +77,14 @@ export class GpgME { // TODO temporary msg.setParameter('armor', true); msg.setParameter('always-trust', true); - + if (base64 === true) { + msg.setParameter('base64', true); + } let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); putData(msg, data); - if (wildcard === true){msg.setParameter('throw-keyids', true); + if (wildcard === true){ + msg.setParameter('throw-keyids', true); }; if (msg.isComplete === true){ return this.connection.post(msg); @@ -91,7 +94,8 @@ export class GpgME { } /** - * @param {String} data TODO Format: base64? String? Message with the encrypted data + * @param {String} data TODO base64? Message with the encrypted data + * @param {Boolean} base64 (optional) Response should stay base64 * @returns {Promise} decrypted message: data: The decrypted data. This may be base64 encoded. base64: Boolean indicating whether data is base64 encoded. @@ -100,11 +104,14 @@ export class GpgME { * @async */ - decrypt(data){ + decrypt(data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); + if (base64 === true){ + msg.expected = 'base64'; + } if (msg instanceof Error){ return Promise.reject(msg); } @@ -156,11 +163,9 @@ export class GpgME { } /** - * Sets the data of the message, converting Uint8Array to base64 and setting - * the base64 flag + * Sets the data of the message * @param {GPGME_Message} message The message where this data will be set * @param {*} data The data to enter - * @param {String} propertyname // TODO unchecked still */ function putData(message, data){ if (!message || !message instanceof GPGME_Message ) { @@ -168,30 +173,15 @@ function putData(message, data){ } if (!data){ return gpgme_error('PARAM_WRONG'); - } else if (data instanceof Uint8Array){ - message.setParameter('base64', true); - // TODO: btoa turns the array into a string - // of comma separated of numbers - // atob(data).split(',') would result in a "normal" array of numbers - // atob(btoa(data)).split(',') would result in a "normal" array of numbers - // would result in a "normal" array of numbers - message.setParameter ('data', btoa(data)); - } else if (typeof(data) === 'string') { - message.setParameter('base64', false); message.setParameter('data', data); } else if ( typeof(data) === 'object' && typeof(data.getText) === 'function' ){ let txt = data.getText(); - if (txt instanceof Uint8Array){ - message.setParameter('base64', true); - message.setParameter ('data', btoa(txt)); - } - else if (typeof(txt) === 'string'){ - message.setParameter('base64', false); - message.setParameter ('data', txt); + if (typeof(txt) === 'string'){ + message.setParameter('data', txt); } else { return gpgme_error('PARAM_WRONG'); } -- cgit v1.2.3 From f7ed80ff6a66f2c5ee6f1c3daebd597f4592733d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 23 May 2018 12:56:23 +0200 Subject: js: remove openpgp mode -- * After discussion, that mode is not required, and can result in being quite misleading and a maintenance hassle later on. --- lang/js/src/gpgmejs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 01cb92c3..3aa5957a 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -54,8 +54,8 @@ export class GpgME { } set Keyring(keyring){ - if (ring && ring instanceof GPGME_Keyring){ - this._Keyring = ring; + if (keyring && keyring instanceof GPGME_Keyring){ + this._Keyring = keyring; } } -- cgit v1.2.3 From a4ba80c553c2ac42f9e311344302c04ec9aa715b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 24 May 2018 15:16:18 +0200 Subject: js: adding sign method -- * src/gpgmejs.js: method, update in src/permittedOperations * basic testing in BrowsertestExtension --- lang/js/src/gpgmejs.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 3aa5957a..1e76655e 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -120,6 +120,44 @@ export class GpgME { } + sign(data, keys, mode='clearsign', base64=false) { //sender + if (data === undefined){ + 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); + if (mode === 'detached') { + msg.expected = 'base64'; + } + let me = this; + return new Promise(function(resolve,reject) { + me.connection.post(msg).then( function(message) { + if (mode === 'clearsign'){ + resolve({ + data: message.data} + ); + } else if (mode === 'detached') { + resolve({ + data: data, + signature: message.data + }); + } + }, function(error){ + reject(error); + }) + }); + } + deleteKey(key, delete_secret = false, no_confirm = false){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); let msg = createMessage('deletekey'); -- cgit v1.2.3 From eff27d6387b1cad2ef9901fa03dbee2ea86c786a Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 25 May 2018 11:53:24 +0200 Subject: js: use version operation for connection checks -- * src/Connection.js: isConnected was renamed to checkConnection, that returns a promise with either version information or Boolean * Connection checks have been adapted to reflect that checkConnection returns a Promise * BrowsertestExtension: tests/signTest.js was missing from my last commit --- lang/js/src/gpgmejs.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 1e76655e..c182c175 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -44,13 +44,7 @@ export class GpgME { } get connection(){ - if (this._connection){ - if (this._connection.isConnected === true){ - return this._connection; - } - return undefined; - } - return undefined; + return this._connection; } set Keyring(keyring){ -- cgit v1.2.3 From d4adbf453d39659eee378b2be1d7125315d76083 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 28 May 2018 16:52:50 +0200 Subject: js: Treat a connection as a gpgme Context -- * After an operation a connection should be disconnected again. The "end of operation" is now assumed to be either an error as answer, or a message not including a "more" * GPGME, GPGME_Key, GPGME_Keyring don't require a connection anymore * Message.js: The Message.post() method will open a connection as required --- lang/js/src/gpgmejs.js | 45 ++++++++++----------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c182c175..88a91a60 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -18,7 +18,6 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -import {Connection} from "./Connection" import {GPGME_Message, createMessage} from './Message' import {toKeyIdArray} from "./Helpers" import { gpgme_error } from "./Errors" @@ -29,31 +28,20 @@ export class GpgME { * initializes GpgME by opening a nativeMessaging port * TODO: add configuration */ - constructor(connection){ - this.connection = connection; + constructor(config){ //TODO config not parsed + this._config = config; } - set connection(conn){ - if (this._connection instanceof Connection){ - gpgme_error('CONN_ALREADY_CONNECTED'); - } else if (conn instanceof Connection){ - this._connection = conn; - } else { - gpgme_error('PARAM_WRONG'); - } - } - - get connection(){ - return this._connection; - } - - set Keyring(keyring){ + set Keyring(keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } } get Keyring(){ + if (!this._Keyring){ + this._Keyring = new GPGME_Keyring; + } return this._Keyring; } @@ -81,7 +69,7 @@ export class GpgME { msg.setParameter('throw-keyids', true); }; if (msg.isComplete === true){ - return this.connection.post(msg); + return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } @@ -110,7 +98,7 @@ export class GpgME { return Promise.reject(msg); } putData(msg, data); - return this.connection.post(msg); + return msg.post(); } @@ -135,7 +123,7 @@ export class GpgME { } let me = this; return new Promise(function(resolve,reject) { - me.connection.post(msg).then( function(message) { + msg.post().then( function(message) { if (mode === 'clearsign'){ resolve({ data: message.data} @@ -174,20 +162,7 @@ export class GpgME { // TBD } if (msg.isComplete === true){ - this.connection.post(msg).then(function(success){ - // TODO: it seems that there is always errors coming back: - }, function(error){ - switch (error.msg){ - case 'ERR_NO_ERROR': - return Promise.resolve('okay'); //TBD - default: - return Promise.reject(gpgme_error('TODO') ); // - // INV_VALUE, - // GPG_ERR_NO_PUBKEY, - // GPG_ERR_AMBIGUOUS_NAME, - // GPG_ERR_CONFLICT - } - }); + return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } -- cgit v1.2.3 From 332b4adbcc52ccf337cbc1943d5abef500769e10 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 30 May 2018 17:05:54 +0200 Subject: js: more Keyring/Key handling -- * src/Keys.js - made setKeyData more consistent with other methods - added convenience methods (Key.armored, Key.hasSecret) - Added a Key delete function * src/Keyring.js: - added a getkeysArmored which allows for bulk export of public Keys gpgmejs: - removed deleteKey. It is now a method of the Key itself - Encrypt: Added some common options as parameter, and the possibility to set all allowed flags via an additional Object --- lang/js/src/gpgmejs.js | 85 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 40 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 88a91a60..39f6a2f0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -46,28 +46,48 @@ export class GpgME { } /** - * @param {String} data text/data to be encrypted as String + * Encrypt (and optionally sign) a Message + * @param {String|Object} data text/data to be encrypted as String. Also accepts Objects with a getText method * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message + * @param {GPGME_Key|String|Array|Array} secretKeys (optional) Keys used to sign the message + * @param {Boolean} base64 (optional) The data is already considered to be in base64 encoding + * @param {Boolean} armor (optional) Request the output as armored block * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message + * @param {Object} additional use additional gpg options (refer to src/permittedOperations) + * @returns {Promise} Encrypted message: + * data: The encrypted message + * base64: Boolean indicating whether data is base64 encoded. + * @async */ - encrypt(data, publicKeys, base64=false, wildcard=false){ - + encrypt(data, publicKeys, secretKeys, base64=false, armor=true, + wildcard=false, additional = {} + ){ let msg = createMessage('encrypt'); if (msg instanceof Error){ return Promise.reject(msg) } - // TODO temporary - msg.setParameter('armor', true); + msg.setParameter('armor', armor); msg.setParameter('always-trust', true); if (base64 === true) { msg.setParameter('base64', true); } let pubkeys = toKeyIdArray(publicKeys); 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++) { + msg.setParameter(additional_Keys[k], + additional[additional_Keys[k]]); + } + } if (msg.isComplete === true){ return msg.post(); } else { @@ -76,16 +96,17 @@ export class GpgME { } /** - * @param {String} data TODO base64? Message with the encrypted data - * @param {Boolean} base64 (optional) Response should stay base64 + * Decrypt a Message + * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a getText method + * @param {Boolean} base64 (optional) Response is expected to be base64 encoded * @returns {Promise} decrypted message: data: The decrypted data. This may be base64 encoded. base64: Boolean indicating whether data is base64 encoded. mime: A Boolean indicating whether the data is a MIME object. - info: An optional object with extra information. + signatures: Array of signature Objects TODO not yet implemented. + // should be an object that can tell if all signatures are valid etc. * @async */ - decrypt(data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); @@ -99,10 +120,22 @@ export class GpgME { } putData(msg, data); return msg.post(); - } - sign(data, keys, mode='clearsign', base64=false) { //sender + /** + * Sign a Message + * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a gettext methos + * @param {GPGME_Key|String|Array|Array} keys The key/keys to use for signing + * @param {*} mode The signing mode. Currently supported: + * 'clearsign': (default) The Message is embedded into the signature + * 'detached': The signature is stored separately + * @param {*} base64 input is considered base64 + * @returns {Promise} + * data: The resulting data. In clearsign mode this includes the signature + * signature: The detached signature (if in detached mode) + * @async + */ + sign(data, keys, mode='clearsign', base64=false) { if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -139,38 +172,10 @@ export class GpgME { }) }); } - - deleteKey(key, delete_secret = false, no_confirm = false){ - return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); - let msg = createMessage('deletekey'); - if (msg instanceof Error){ - return Promise.reject(msg); - } - let key_arr = toKeyIdArray(key); - if (key_arr.length !== 1){ - return Promise.reject( - gpgme_error('GENERIC_ERROR')); - // TBD should always be ONE key? - } - msg.setParameter('key', key_arr[0]); - if (delete_secret === true){ - msg.setParameter('allow_secret', true); - // TBD - } - if (no_confirm === true){ //TODO: Do we want this hidden deep in the code? - msg.setParameter('delete_force', true); - // TBD - } - if (msg.isComplete === true){ - return msg.post(); - } else { - return Promise.reject(gpgme_error('MSG_INCOMPLETE')); - } - } } /** - * Sets the data of the message + * 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 {*} data The data to enter */ -- cgit v1.2.3 From bfd3799d39df265882deedeee083fd5246a2f35d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 6 Jun 2018 13:05:53 +0200 Subject: js: code cleanup (eslint) -- * trying to stick to eslint from now on for readability * As some attribution was lost in previous git confusions, I added my name into some of the licence headers --- lang/js/src/gpgmejs.js | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 39f6a2f0..cbad9021 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -16,12 +16,16 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ + * + * Author(s): + * Maximilian Krambach */ -import {GPGME_Message, createMessage} from './Message' -import {toKeyIdArray} from "./Helpers" -import { gpgme_error } from "./Errors" -import { GPGME_Keyring } from "./Keyring"; + +import {GPGME_Message, createMessage} from './Message'; +import {toKeyIdArray} from './Helpers'; +import { gpgme_error } from './Errors'; +import { GPGME_Keyring } from './Keyring'; export class GpgME { /** @@ -32,7 +36,7 @@ export class GpgME { this._config = config; } - set Keyring(keyring){ + set Keyring(keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } @@ -47,13 +51,19 @@ export class GpgME { /** * Encrypt (and optionally sign) a Message - * @param {String|Object} data text/data to be encrypted as String. Also accepts Objects with a getText method - * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message - * @param {GPGME_Key|String|Array|Array} secretKeys (optional) Keys used to sign the message - * @param {Boolean} base64 (optional) The data is already considered to be in base64 encoding + * @param {String|Object} data text/data to be encrypted as String. Also + * accepts Objects with a getText method + * @param {GPGME_Key|String|Array|Array} publicKeys + * Keys used to encrypt the message + * @param {GPGME_Key|String|Array|Array} secretKeys + * (optional) Keys used to sign the message + * @param {Boolean} base64 (optional) The data is already considered to be + * in base64 encoding * @param {Boolean} armor (optional) Request the output as armored block - * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message - * @param {Object} additional use additional gpg options (refer to src/permittedOperations) + * @param {Boolean} wildcard (optional) If true, recipient information will + * not be added to the message + * @param {Object} additional use additional gpg options + * (refer to src/permittedOperations) * @returns {Promise} Encrypted message: * data: The encrypted message * base64: Boolean indicating whether data is base64 encoded. @@ -64,7 +74,7 @@ export class GpgME { ){ let msg = createMessage('encrypt'); if (msg instanceof Error){ - return Promise.reject(msg) + return Promise.reject(msg); } msg.setParameter('armor', armor); msg.setParameter('always-trust', true); @@ -80,7 +90,7 @@ export class GpgME { 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++) { @@ -97,14 +107,16 @@ export class GpgME { /** * Decrypt a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a getText method - * @param {Boolean} base64 (optional) Response is expected to be base64 encoded + * @param {String|Object} data text/data to be decrypted. Accepts Strings + * and Objects with a getText method + * @param {Boolean} base64 (optional) Response is expected to be base64 + * encoded * @returns {Promise} decrypted message: data: The decrypted data. This may be base64 encoded. base64: Boolean indicating whether data is base64 encoded. mime: A Boolean indicating whether the data is a MIME object. signatures: Array of signature Objects TODO not yet implemented. - // should be an object that can tell if all signatures are valid etc. + // should be an object that can tell if all signatures are valid . * @async */ decrypt(data, base64=false){ @@ -124,14 +136,16 @@ export class GpgME { /** * Sign a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a gettext methos - * @param {GPGME_Key|String|Array|Array} keys The key/keys to use for signing + * @param {String|Object} data text/data to be decrypted. Accepts Strings + * and Objects with a gettext methos + * @param {GPGME_Key|String|Array|Array} keys The + * key/keys to use for signing * @param {*} mode The signing mode. Currently supported: * 'clearsign': (default) The Message is embedded into the signature * 'detached': The signature is stored separately * @param {*} base64 input is considered base64 * @returns {Promise} - * data: The resulting data. In clearsign mode this includes the signature + * data: The resulting data. Includes the signature in clearsign mode * signature: The detached signature (if in detached mode) * @async */ @@ -154,7 +168,6 @@ export class GpgME { if (mode === 'detached') { msg.expected = 'base64'; } - let me = this; return new Promise(function(resolve,reject) { msg.post().then( function(message) { if (mode === 'clearsign'){ @@ -169,7 +182,7 @@ export class GpgME { } }, function(error){ reject(error); - }) + }); }); } } @@ -180,7 +193,7 @@ export class GpgME { * @param {*} data The data to enter */ function putData(message, data){ - if (!message || !message instanceof GPGME_Message ) { + if (!message || !(message instanceof GPGME_Message) ) { return gpgme_error('PARAM_WRONG'); } if (!data){ -- cgit v1.2.3 From c072675f3f2d734297a348c6de810148fb1424a2 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 8 Jun 2018 17:54:58 +0200 Subject: js: change chunksize handling and decoding -- * the nativeApp now sends all data in one base64-encoded string, which needs reassembly, but in a much easier way now. * there are some new performance problems now, especially with decrypting data --- lang/js/src/gpgmejs.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index cbad9021..09bca7f9 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -57,8 +57,8 @@ export class GpgME { * Keys used to encrypt the message * @param {GPGME_Key|String|Array|Array} secretKeys * (optional) Keys used to sign the message - * @param {Boolean} base64 (optional) The data is already considered to be - * in base64 encoding + * @param {Boolean} base64 (optional) The data will be interpreted as + * base64 encoded data * @param {Boolean} armor (optional) Request the output as armored block * @param {Boolean} wildcard (optional) If true, recipient information will * not be added to the message @@ -109,24 +109,20 @@ export class GpgME { * Decrypt a Message * @param {String|Object} data text/data to be decrypted. Accepts Strings * and Objects with a getText method - * @param {Boolean} base64 (optional) Response is expected to be base64 - * encoded * @returns {Promise} decrypted message: - data: The decrypted data. This may be base64 encoded. + data: The decrypted data. base64: Boolean indicating whether data is base64 encoded. mime: A Boolean indicating whether the data is a MIME object. signatures: Array of signature Objects TODO not yet implemented. - // should be an object that can tell if all signatures are valid . + // should be an object that can tell if all signatures are valid. * @async */ - decrypt(data, base64=false){ + decrypt(data){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); - if (base64 === true){ - msg.expected = 'base64'; - } + if (msg instanceof Error){ return Promise.reject(msg); } @@ -165,10 +161,10 @@ export class GpgME { } msg.setParameter('mode', mode); putData(msg, data); - if (mode === 'detached') { - msg.expected = 'base64'; - } return new Promise(function(resolve,reject) { + if (mode ==='detached'){ + msg.expect= 'base64'; + } msg.post().then( function(message) { if (mode === 'clearsign'){ resolve({ -- cgit v1.2.3 From e154554e9a48a08219649a58be0b641c561e1748 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 11 Jun 2018 15:10:43 +0200 Subject: js: removed config -- * There is no use for a configuration at the moment, and it seems improbable that this use will arise. --- lang/js/src/gpgmejs.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 09bca7f9..7fa7643c 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -30,10 +30,8 @@ import { GPGME_Keyring } from './Keyring'; export class GpgME { /** * initializes GpgME by opening a nativeMessaging port - * TODO: add configuration */ - constructor(config){ //TODO config not parsed - this._config = config; + constructor(){ } set Keyring(keyring){ -- cgit v1.2.3 From 3c783bd09ce54b0d50dc3bea201e70e4fcbbf6a3 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 14 Jun 2018 12:15:51 +0200 Subject: js: add verify and signature parsing -- * src/gpgmejs.js: - Added verify method - Added verification results in decrypt (if signatures are present in the message) - Added a base64 option to decrypt * src/Signature.js: Convenience class for verification results. Used for e.g. converting timestamps to javascript time, quick overall validity checks * src/Keyring.js: removed debug code * src/Errors.js add two new Signature errors --- lang/js/src/gpgmejs.js | 138 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 7fa7643c..a0f7e968 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -26,6 +26,7 @@ import {GPGME_Message, createMessage} from './Message'; import {toKeyIdArray} from './Helpers'; import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; +import { createSignature } from './Signature'; export class GpgME { /** @@ -107,15 +108,28 @@ export class GpgME { * Decrypt a Message * @param {String|Object} data text/data to be decrypted. Accepts Strings * and Objects with a getText method - * @returns {Promise} decrypted message: - data: The decrypted data. - base64: Boolean indicating whether data is base64 encoded. - mime: A Boolean indicating whether the data is a MIME object. - signatures: Array of signature Objects TODO not yet implemented. - // should be an object that can tell if all signatures are valid. + * @param {Boolean} base64 (optional) false if the data is an armored block, + * true if it is base64 encoded binary data + * @returns {Promise} result: Decrypted Message and information + * @returns {String} result.data: The decrypted data. + * @returns {Boolean} result.base64: indicating whether data is base64 + * encoded. + * @returns {Boolean} result.is_mime: Indicating whether the data is a MIME + * object. + * @returns {String} result.file_name: The optional original file name + * @returns {Object} message.signatures Verification details for signatures: + * @returns {Boolean} message.signatures.all_valid: true if all signatures + * are valid + * @returns {Number} message.signatures.count: Number of signatures found + * @returns {Number} message.signatures.failures Number of invalid + * signatures + * @returns {Array} message.signatures.signatures. Two arrays + * (good & bad) of {@link GPGME_Signature} objects, offering further + * information. + * * @async */ - decrypt(data){ + decrypt(data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -124,8 +138,32 @@ export class GpgME { if (msg instanceof Error){ return Promise.reject(msg); } + if (base64 === true){ + msg.setParameter('base64', true); + } putData(msg, data); - return msg.post(); + if (base64 === true){ + msg.setParameter('base64', true); + } + return new Promise(function(resolve, reject){ + msg.post().then(function(result){ + let _result = {data: result.data}; + _result.base64 = result.base64 ? true: false; + _result.is_mime = result.mime ? true: false; + if (result.file_name){ + _result.file_name = result.file_name; + } + if ( + result.hasOwnProperty('signatures') && + Array.isArray(result.signatures) + ) { + _result.signatures = collectSignatures(result.signatures); + } + resolve(_result); + }, function(error){ + reject(error); + }); + }); } /** @@ -179,6 +217,59 @@ export class GpgME { }); }); } + + /** + * Verifies data. + * @param {String|Object} data text/data to be verified. Accepts Strings + * and Objects with a gettext method + * @param {String} (optional) A detached signature. If not present, opaque + * mode is assumed + * @param {Boolean} (optional) Data and signature are base64 encoded + * // TODO verify if signature really is assumed to be base64 + * @returns {Promise} result: + * @returns {Boolean} result.data: The verified data + * @returns {Boolean} result.is_mime: The message claims it is MIME + * @returns {String} result.file_name: The optional filename of the message + * @returns {Boolean} result.all_valid: true if all signatures are valid + * @returns {Number} result.count: Number of signatures found + * @returns {Number} result.failures Number of unsuccessful signatures + * @returns {Array} result.signatures. Two arrays (good & bad) of + * {@link GPGME_Signature} objects, offering further information. + */ + verify(data, signature, base64 = false){ + let msg = createMessage('verify'); + let dt = this.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.signatures){ + reject(gpgme_error('SIG_NO_SIGS')); + } else { + let _result = collectSignatures(message.info.signatures); + _result.is_mime = message.info.is_mime? true: false; + if (message.info.filename){ + _result.file_name = message.info.filename; + } + _result.data = message.data; + resolve(_result); + } + }, function(error){ + reject(error); + }); + }); + } } /** @@ -209,3 +300,34 @@ function putData(message, data){ return gpgme_error('PARAM_WRONG'); } } + +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; +} \ No newline at end of file -- cgit v1.2.3 From 88e7f8ec2ef3d90ca014b0bdb246f4d99f82abc8 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 20 Jun 2018 13:42:19 +0200 Subject: js: Demoextension update -- * src/Signature: typo * src/gpgmejs.js: fixed wrong scope in verification * right now verify does not succeed in the DemoExtension. This is probably a problem in conversion or line ending. --- lang/js/src/gpgmejs.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index a0f7e968..c2a6b8b6 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -168,7 +168,7 @@ export class GpgME { /** * Sign a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings + * @param {String|Object} data text/data to be signed. Accepts Strings * and Objects with a gettext methos * @param {GPGME_Key|String|Array|Array} keys The * key/keys to use for signing @@ -238,7 +238,7 @@ export class GpgME { */ verify(data, signature, base64 = false){ let msg = createMessage('verify'); - let dt = this.putData(msg, data); + let dt = putData(msg, data); if (dt instanceof Error){ return Promise.reject(dt); } @@ -317,7 +317,7 @@ function collectSignatures(sigs){ for (let i=0; i< sigs.length; i++){ let sigObj = createSignature(sigs[i]); if (sigObj instanceof Error){ - return gpgme_error('SIG_WRONG'); + return gpgme_error(sigObj); } if (sigObj.valid !== true){ summary.failures += 1; -- cgit v1.2.3 From 10f2106404f01e7bb369fc66a597875fb455cd27 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 4 Jul 2018 15:46:45 +0200 Subject: js: properly reject pgp message without signature -- * A verify at gpgme-json does not fail if there is a valid pgp message that does not include a signature. Instead, the answer will be devoid of signatures. In javascript, the SIG_NO_SIG error should be reported here, but wasn't. --- lang/js/src/gpgmejs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c2a6b8b6..f49361dc 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -254,7 +254,7 @@ export class GpgME { } return new Promise(function(resolve, reject){ msg.post().then(function (message){ - if (!message.info.signatures){ + if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); } else { let _result = collectSignatures(message.info.signatures); -- cgit v1.2.3 From 4015f5b4983c8a4590aa71776880d8bc42c7918d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 10 Jul 2018 14:32:26 +0200 Subject: js: documentation -- * Fixed errors: - src/Message.js post(): Set chunksize to defined default value instead of hardcoded - src/Keys.js: added getHasSecret() to refreshKey operation. * Reviewed and updated the documentation * non-documentation changes which do not affect functionality: - src/Errors: disabled a console.warn that is only useful for debugging - helpers.js: renamed "string" to "value" in isFingerprint and isLongId to avoid confusion - src/Keyring: prepare_sync, search are both explicitly set to false by default --- lang/js/src/gpgmejs.js | 146 ++++++++++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 55 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index f49361dc..3f6dc947 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -28,10 +28,62 @@ import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; import { createSignature } from './Signature'; +/** + * @typedef {Object} decrypt_result + * @property {String} data The decrypted data + * @property {Boolean} base64 indicating whether data is base64 encoded. + * @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} signatures.good All valid signatures + * @property {Array} signatures.bad All invalid signatures + */ + +/** + * @typedef {Object} encrypt_result The result of an encrypt operation + * @property {String} data The encrypted message + * @property {Boolean} base64 Indicating whether data is base64 encoded. + */ + +/** + * @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 { - /** - * initializes GpgME by opening a nativeMessaging port - */ + constructor(){ } @@ -41,6 +93,9 @@ export class GpgME { } } + /** + * Accesses the {@link GPGME_Keyring}. + */ get Keyring(){ if (!this._Keyring){ this._Keyring = new GPGME_Keyring; @@ -49,23 +104,23 @@ export class GpgME { } /** - * Encrypt (and optionally sign) a Message + * Encrypt (and optionally sign) data * @param {String|Object} data text/data to be encrypted as String. Also * accepts Objects with a getText method - * @param {GPGME_Key|String|Array|Array} publicKeys + * @param {inputKeys} publicKeys * Keys used to encrypt the message - * @param {GPGME_Key|String|Array|Array} secretKeys - * (optional) Keys used to sign the message + * @param {inputKeys} secretKeys (optional) Keys used to sign the message. + * If Keys are present, the operation requested is assumed to be 'encrypt + * and sign' * @param {Boolean} base64 (optional) The data will be interpreted as - * base64 encoded data - * @param {Boolean} armor (optional) Request the output as armored block + * base64 encoded data. + * @param {Boolean} armor (optional) Request the output as armored block. * @param {Boolean} wildcard (optional) If true, recipient information will - * not be added to the message - * @param {Object} additional use additional gpg options - * (refer to src/permittedOperations) - * @returns {Promise} Encrypted message: - * data: The encrypted message - * base64: Boolean indicating whether data is base64 encoded. + * not be added to the message. + * @param {Object} additional use additional valid gpg options as defined + * in {@link permittedOperations} + * @returns {Promise} Object containing the encrypted + * message and additional info. * @async */ encrypt(data, publicKeys, secretKeys, base64=false, armor=true, @@ -105,28 +160,12 @@ export class GpgME { } /** - * Decrypt a Message + * Decrypts a Message * @param {String|Object} data text/data to be decrypted. Accepts Strings * and Objects with a getText method * @param {Boolean} base64 (optional) false if the data is an armored block, * true if it is base64 encoded binary data - * @returns {Promise} result: Decrypted Message and information - * @returns {String} result.data: The decrypted data. - * @returns {Boolean} result.base64: indicating whether data is base64 - * encoded. - * @returns {Boolean} result.is_mime: Indicating whether the data is a MIME - * object. - * @returns {String} result.file_name: The optional original file name - * @returns {Object} message.signatures Verification details for signatures: - * @returns {Boolean} message.signatures.all_valid: true if all signatures - * are valid - * @returns {Number} message.signatures.count: Number of signatures found - * @returns {Number} message.signatures.failures Number of invalid - * signatures - * @returns {Array} message.signatures.signatures. Two arrays - * (good & bad) of {@link GPGME_Signature} objects, offering further - * information. - * + * @returns {Promise} Decrypted Message and information * @async */ decrypt(data, base64=false){ @@ -169,16 +208,13 @@ export class GpgME { /** * Sign a Message * @param {String|Object} data text/data to be signed. Accepts Strings - * and Objects with a gettext methos - * @param {GPGME_Key|String|Array|Array} keys The - * key/keys to use for signing - * @param {*} mode The signing mode. Currently supported: - * 'clearsign': (default) The Message is embedded into the signature - * 'detached': The signature is stored separately - * @param {*} base64 input is considered base64 - * @returns {Promise} - * data: The resulting data. Includes the signature in clearsign mode - * signature: The detached signature (if in detached mode) + * and Objects with a getText method. + * @param {inputKeys} keys The key/keys to use for signing + * @param {String} mode The signing mode. Currently supported: + * 'clearsign':The Message is embedded into the signature; + * 'detached': The signature is stored separately + * @param {Boolean} base64 input is considered base64 + * @returns {Promise} * @async */ sign(data, keys, mode='clearsign', base64=false) { @@ -221,20 +257,12 @@ export class GpgME { /** * Verifies data. * @param {String|Object} data text/data to be verified. Accepts Strings - * and Objects with a gettext method + * and Objects with a getText method * @param {String} (optional) A detached signature. If not present, opaque * mode is assumed * @param {Boolean} (optional) Data and signature are base64 encoded - * // TODO verify if signature really is assumed to be base64 - * @returns {Promise} result: - * @returns {Boolean} result.data: The verified data - * @returns {Boolean} result.is_mime: The message claims it is MIME - * @returns {String} result.file_name: The optional filename of the message - * @returns {Boolean} result.all_valid: true if all signatures are valid - * @returns {Number} result.count: Number of signatures found - * @returns {Number} result.failures Number of unsuccessful signatures - * @returns {Array} result.signatures. Two arrays (good & bad) of - * {@link GPGME_Signature} objects, offering further information. + * @returns {Promise} + *@async */ verify(data, signature, base64 = false){ let msg = createMessage('verify'); @@ -275,7 +303,10 @@ export class GpgME { /** * 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 {*} data The data to enter + * @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) ) { @@ -301,6 +332,11 @@ function putData(message, data){ } } +/** + * Parses, validates and converts incoming objects into signatures. + * @param {Array} sigs + * @returns {signatureDetails} Details about the signatures + */ function collectSignatures(sigs){ if (!Array.isArray(sigs)){ return gpgme_error('SIG_NO_SIGS'); -- cgit v1.2.3 From 94ee0988d4eaac27785de6efb7c19ca9976e1e9c Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Jul 2018 20:36:21 +0200 Subject: js: change the write access for js class methods -- * src/ [Connection, Error, Key, Keyring, MEssage, Signature, gpgmejs]: Functions and values that are not meant to be overwritten are now moved into their constructors, thus eliminating the possibility of overwrites after initialization. * Key: The mode of use (synchronous cached, or async promises) ivs now determined at initialization of that Key. The property Key.isAsync reflects this state. * unittests: fixed old Key syntax for testing. * Message.js isComplete is now a method and not a getter anymore. * Added some startup tests. --- lang/js/src/gpgmejs.js | 77 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 27 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 3f6dc947..f587e854 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -22,8 +22,8 @@ */ -import {GPGME_Message, createMessage} from './Message'; -import {toKeyIdArray} from './Helpers'; +import { GPGME_Message, createMessage } from './Message'; +import { toKeyIdArray } from './Helpers'; import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; import { createSignature } from './Signature'; @@ -85,23 +85,27 @@ import { createSignature } from './Signature'; export class GpgME { constructor(){ - } + let _Keyring = null; - set Keyring(keyring){ - if (keyring && keyring instanceof GPGME_Keyring){ - this._Keyring = keyring; - } - } + /** + * Sets a new Keyring to be used + * @param {GPGME_Keyring} keyring + */ + this.setKeyring = function(keyring){ + if (keyring && keyring instanceof GPGME_Keyring){ + _Keyring = keyring; + } + }; - /** - * Accesses the {@link GPGME_Keyring}. - */ - get Keyring(){ - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring; - } - return this._Keyring; - } + /** + * Accesses the {@link GPGME_Keyring}. + */ + this.getKeyring = function(){ + if (!_Keyring){ + _Keyring = new GPGME_Keyring; + } + return _Keyring; + }; /** * Encrypt (and optionally sign) data @@ -123,8 +127,8 @@ export class GpgME { * message and additional info. * @async */ - encrypt(data, publicKeys, secretKeys, base64=false, armor=true, - wildcard=false, additional = {} + this.encrypt = function (data, publicKeys, secretKeys, base64=false, + armor=true, wildcard=false, additional = {} ){ let msg = createMessage('encrypt'); if (msg instanceof Error){ @@ -152,12 +156,12 @@ export class GpgME { additional[additional_Keys[k]]); } } - if (msg.isComplete === true){ + if (msg.isComplete() === true){ return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } - } + }; /** * Decrypts a Message @@ -168,7 +172,7 @@ export class GpgME { * @returns {Promise} Decrypted Message and information * @async */ - decrypt(data, base64=false){ + this.decrypt = function (data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -203,7 +207,7 @@ export class GpgME { reject(error); }); }); - } + }; /** * Sign a Message @@ -217,7 +221,7 @@ export class GpgME { * @returns {Promise} * @async */ - sign(data, keys, mode='clearsign', base64=false) { + this.sign = function (data, keys, mode='clearsign', base64=false) { if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -252,7 +256,7 @@ export class GpgME { reject(error); }); }); - } + }; /** * Verifies data. @@ -264,7 +268,7 @@ export class GpgME { * @returns {Promise} *@async */ - verify(data, signature, base64 = false){ + this.verify= function (data, signature, base64 = false){ let msg = createMessage('verify'); let dt = putData(msg, data); if (dt instanceof Error){ @@ -297,6 +301,25 @@ export class GpgME { reject(error); }); }); + }; +} + + /** + * setter for {@link setKeyring}. + * @param {GPGME_Keyring} keyring A Keyring to use + */ + set Keyring(keyring){ + this.setKeyring(keyring); + } + + /** + * Accesses the {@link GPGME_Keyring}. + */ + get Keyring(){ + if (!this._Keyring){ + this._Keyring = new GPGME_Keyring; + } + return this._Keyring; } } @@ -309,7 +332,7 @@ export class GpgME { * @private */ function putData(message, data){ - if (!message || !(message instanceof GPGME_Message) ) { + if (!message || !message instanceof GPGME_Message) { return gpgme_error('PARAM_WRONG'); } if (!data){ -- cgit v1.2.3 From 522121ea7e105acc22795b1997ca500c7b227b4f Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Jul 2018 20:56:11 +0200 Subject: js: fix indentaion -- * doing the indentation changes that became neccesary in the last commit. --- lang/js/src/gpgmejs.js | 371 +++++++++++++++++++++++++------------------------ 1 file changed, 187 insertions(+), 184 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index f587e854..720490d6 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -107,204 +107,207 @@ export class GpgME { return _Keyring; }; - /** - * Encrypt (and optionally sign) data - * @param {String|Object} data text/data to be encrypted as String. Also - * accepts Objects with a getText method - * @param {inputKeys} publicKeys - * Keys used to encrypt the message - * @param {inputKeys} secretKeys (optional) Keys used to sign the message. - * If Keys are present, the operation requested is assumed to be 'encrypt - * and sign' - * @param {Boolean} base64 (optional) The data will be interpreted as - * base64 encoded data. - * @param {Boolean} armor (optional) Request the output as armored block. - * @param {Boolean} wildcard (optional) If true, recipient information will - * not be added to the message. - * @param {Object} additional use additional valid gpg options as defined - * in {@link permittedOperations} - * @returns {Promise} Object containing the encrypted - * message and additional info. - * @async - */ - this.encrypt = function (data, publicKeys, secretKeys, base64=false, - armor=true, wildcard=false, additional = {} - ){ - let msg = createMessage('encrypt'); - if (msg instanceof Error){ - return Promise.reject(msg); - } - msg.setParameter('armor', armor); - msg.setParameter('always-trust', true); - if (base64 === true) { - msg.setParameter('base64', true); - } - let pubkeys = toKeyIdArray(publicKeys); - 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++) { - msg.setParameter(additional_Keys[k], - additional[additional_Keys[k]]); + /** + * Encrypt (and optionally sign) data + * @param {String|Object} data text/data to be encrypted as String. Also + * accepts Objects with a getText method + * @param {inputKeys} publicKeys + * Keys used to encrypt the message + * @param {inputKeys} secretKeys (optional) Keys used to sign the + * message. If Keys are present, the operation requested is assumed + * to be 'encrypt and sign' + * @param {Boolean} base64 (optional) The data will be interpreted as + * base64 encoded data. + * @param {Boolean} armor (optional) Request the output as armored + * block. + * @param {Boolean} wildcard (optional) If true, recipient information + * will not be added to the message. + * @param {Object} additional use additional valid gpg options as + * defined in {@link permittedOperations} + * @returns {Promise} Object containing the encrypted + * message and additional info. + * @async + */ + this.encrypt = function (data, publicKeys, secretKeys, base64=false, + armor=true, wildcard=false, additional = {} + ){ + let msg = createMessage('encrypt'); + if (msg instanceof Error){ + return Promise.reject(msg); } - } - if (msg.isComplete() === true){ - return msg.post(); - } else { - return Promise.reject(gpgme_error('MSG_INCOMPLETE')); - } - }; + msg.setParameter('armor', armor); + msg.setParameter('always-trust', true); + if (base64 === true) { + msg.setParameter('base64', true); + } + let pubkeys = toKeyIdArray(publicKeys); + 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++) { + msg.setParameter(additional_Keys[k], + additional[additional_Keys[k]]); + } + } + if (msg.isComplete() === true){ + return msg.post(); + } else { + return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + } + }; - /** - * Decrypts a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings - * and Objects with a getText method - * @param {Boolean} base64 (optional) false if the data is an armored block, - * true if it is base64 encoded binary data - * @returns {Promise} Decrypted Message and information - * @async - */ - this.decrypt = function (data, base64=false){ - if (data === undefined){ - return Promise.reject(gpgme_error('MSG_EMPTY')); - } - let msg = createMessage('decrypt'); + /** + * Decrypts a Message + * @param {String|Object} data text/data to be decrypted. Accepts + * Strings and Objects with a getText method + * @param {Boolean} base64 (optional) false if the data is an armored + * block, true if it is base64 encoded binary data + * @returns {Promise} Decrypted Message and information + * @async + */ + this.decrypt = function (data, base64=false){ + if (data === undefined){ + 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); - } - putData(msg, data); - if (base64 === true){ - msg.setParameter('base64', true); - } - return new Promise(function(resolve, reject){ - msg.post().then(function(result){ - let _result = {data: result.data}; - _result.base64 = result.base64 ? true: false; - _result.is_mime = result.mime ? true: false; - if (result.file_name){ - _result.file_name = result.file_name; - } - if ( - result.hasOwnProperty('signatures') && - Array.isArray(result.signatures) - ) { - _result.signatures = collectSignatures(result.signatures); - } - resolve(_result); - }, function(error){ - reject(error); + if (msg instanceof Error){ + return Promise.reject(msg); + } + if (base64 === true){ + msg.setParameter('base64', true); + } + putData(msg, data); + if (base64 === true){ + msg.setParameter('base64', true); + } + return new Promise(function(resolve, reject){ + msg.post().then(function(result){ + let _result = {data: result.data}; + _result.base64 = result.base64 ? true: false; + _result.is_mime = result.mime ? true: false; + if (result.file_name){ + _result.file_name = result.file_name; + } + if ( + result.hasOwnProperty('signatures') && + Array.isArray(result.signatures) + ) { + _result.signatures = collectSignatures( + result.signatures); + } + resolve(_result); + }, function(error){ + reject(error); + }); }); - }); - }; + }; - /** - * Sign a Message - * @param {String|Object} data text/data to be signed. Accepts Strings - * and Objects with a getText method. - * @param {inputKeys} keys The key/keys to use for signing - * @param {String} mode The signing mode. Currently supported: - * 'clearsign':The Message is embedded into the signature; - * 'detached': The signature is stored separately - * @param {Boolean} base64 input is considered base64 - * @returns {Promise} - * @async - */ - this.sign = function (data, keys, mode='clearsign', base64=false) { - if (data === undefined){ - 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'); + /** + * Sign a Message + * @param {String|Object} data text/data to be signed. Accepts Strings + * and Objects with a getText method. + * @param {inputKeys} keys The key/keys to use for signing + * @param {String} mode The signing mode. Currently supported: + * 'clearsign':The Message is embedded into the signature; + * 'detached': The signature is stored separately + * @param {Boolean} base64 input is considered base64 + * @returns {Promise} + * @async + */ + this.sign = function (data, keys, mode='clearsign', base64=false) { + if (data === undefined){ + 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) { - if (mode ==='detached'){ - msg.expect= 'base64'; + msg.setParameter('keys', key_arr); + if (base64 === true){ + msg.setParameter('base64', true); } - msg.post().then( function(message) { - if (mode === 'clearsign'){ - resolve({ - data: message.data} - ); - } else if (mode === 'detached') { - resolve({ - data: data, - signature: message.data - }); + msg.setParameter('mode', mode); + putData(msg, data); + return new Promise(function(resolve,reject) { + if (mode ==='detached'){ + msg.expect= 'base64'; } - }, function(error){ - reject(error); + 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 {String|Object} data text/data to be verified. Accepts Strings - * and Objects with a getText method - * @param {String} (optional) A detached signature. If not present, opaque - * mode is assumed - * @param {Boolean} (optional) Data and signature are base64 encoded - * @returns {Promise} - *@async - */ - this.verify= function (data, signature, base64 = false){ - 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); + /** + * Verifies data. + * @param {String|Object} data text/data to be verified. Accepts Strings + * and Objects with a getText method + * @param {String} (optional) A detached signature. If not present, + * opaque mode is assumed + * @param {Boolean} (optional) Data and signature are base64 encoded + * @returns {Promise} + *@async + */ + this.verify= function (data, signature, base64 = false){ + let msg = createMessage('verify'); + let dt = putData(msg, data); + if (dt instanceof Error){ + return Promise.reject(dt); } - } - 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')); + if (signature){ + if (typeof(signature)!== 'string'){ + return Promise.reject(gpgme_error('PARAM_WRONG')); } else { - let _result = collectSignatures(message.info.signatures); - _result.is_mime = message.info.is_mime? true: false; - if (message.info.filename){ - _result.file_name = message.info.filename; - } - _result.data = message.data; - resolve(_result); + msg.setParameter('signature', signature); } - }, function(error){ - reject(error); + } + 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 _result = collectSignatures( + message.info.signatures); + _result.is_mime = message.info.is_mime? true: false; + if (message.info.filename){ + _result.file_name = message.info.filename; + } + _result.data = message.data; + resolve(_result); + } + }, function(error){ + reject(error); + }); }); - }); - }; -} + }; + } - /** + /** * setter for {@link setKeyring}. * @param {GPGME_Keyring} keyring A Keyring to use */ @@ -332,7 +335,7 @@ export class GpgME { * @private */ function putData(message, data){ - if (!message || !message instanceof GPGME_Message) { + if (!message || !(message instanceof GPGME_Message)) { return gpgme_error('PARAM_WRONG'); } if (!data){ -- cgit v1.2.3 From e16a87e83910ebb6bfdc4148369165f121f0997e Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 30 Jul 2018 12:31:27 +0200 Subject: js: Making objects inmutable -- * An Object.freeze should stop any malicious third party from changing objects' methods once the objects are instantiated (see unittest for an approach that would have worked before) - An initialized gpgmejs- object doesn't have a '_Keyring' property anymore (it still has its 'Keyring') - The internal expect='base64' needed to be turned into a method. --- lang/js/src/gpgmejs.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 720490d6..9154979d 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -102,7 +102,7 @@ export class GpgME { */ this.getKeyring = function(){ if (!_Keyring){ - _Keyring = new GPGME_Keyring; + _Keyring = Object.freeze(new GPGME_Keyring); } return _Keyring; }; @@ -241,7 +241,7 @@ export class GpgME { putData(msg, data); return new Promise(function(resolve,reject) { if (mode ==='detached'){ - msg.expect= 'base64'; + msg.setExpect('base64'); } msg.post().then( function(message) { if (mode === 'clearsign'){ @@ -319,10 +319,7 @@ export class GpgME { * Accesses the {@link GPGME_Keyring}. */ get Keyring(){ - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring; - } - return this._Keyring; + return this.getKeyring(); } } -- cgit v1.2.3 From 5b0f8230b2172bffcb3a3b629a75c9cf1a50a3d8 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 17 Aug 2018 17:44:06 +0200 Subject: js: decrypt callback is_mime fix -- * src/gpgmejs: is_mime should report its' counterpart. Also, file_name is not optional in specification. We'll send null if there is no file_name --- lang/js/src/gpgmejs.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 9154979d..18164366 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -193,9 +193,11 @@ export class GpgME { msg.post().then(function(result){ let _result = {data: result.data}; _result.base64 = result.base64 ? true: false; - _result.is_mime = result.mime ? true: false; + _result.is_mime = result.is_mime ? true: false; if (result.file_name){ _result.file_name = result.file_name; + } else { + _result.file_name = null; } if ( result.hasOwnProperty('signatures') && -- cgit v1.2.3 From 1954d27be86b8e4eb801ca6ddcb670f8cfb149f5 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 20 Aug 2018 12:12:43 +0200 Subject: js: revert changes to class read/write restriction -- * undoes 94ee0988d4eaac27785de6efb7c19ca9976e1e9c and e16a87e83910ebb6bfdc4148369165f121f0997e. I do not fully understand why my approach was bad, but I am not in a position to argue. This revert was requested to me after a review, and I'm doing it in the assumption that more experienced people know better than me. * unittests: Also changed some outdated tests that stopped working since 754e799d35fd62d7a979452f44342934659908c7 (as GPGME_Key is not exported, one cannot check for instanceof in the tests anymore) --- lang/js/src/gpgmejs.js | 425 ++++++++++++++++++++++++------------------------- 1 file changed, 204 insertions(+), 221 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 18164366..4aa51759 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -85,243 +85,226 @@ import { createSignature } from './Signature'; export class GpgME { constructor(){ - let _Keyring = null; - - /** - * Sets a new Keyring to be used - * @param {GPGME_Keyring} keyring - */ - this.setKeyring = function(keyring){ - if (keyring && keyring instanceof GPGME_Keyring){ - _Keyring = keyring; - } - }; + this._Keyring = null; + } - /** - * Accesses the {@link GPGME_Keyring}. - */ - this.getKeyring = function(){ - if (!_Keyring){ - _Keyring = Object.freeze(new GPGME_Keyring); - } - return _Keyring; - }; + /** + * 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 {String|Object} data text/data to be encrypted as String. Also - * accepts Objects with a getText method - * @param {inputKeys} publicKeys - * Keys used to encrypt the message - * @param {inputKeys} secretKeys (optional) Keys used to sign the - * message. If Keys are present, the operation requested is assumed - * to be 'encrypt and sign' - * @param {Boolean} base64 (optional) The data will be interpreted as - * base64 encoded data. - * @param {Boolean} armor (optional) Request the output as armored - * block. - * @param {Boolean} wildcard (optional) If true, recipient information - * will not be added to the message. - * @param {Object} additional use additional valid gpg options as - * defined in {@link permittedOperations} - * @returns {Promise} Object containing the encrypted - * message and additional info. - * @async - */ - this.encrypt = function (data, publicKeys, secretKeys, base64=false, - armor=true, wildcard=false, additional = {} - ){ - let msg = createMessage('encrypt'); - if (msg instanceof Error){ - return Promise.reject(msg); - } - msg.setParameter('armor', armor); - msg.setParameter('always-trust', true); - if (base64 === true) { - msg.setParameter('base64', true); - } - let pubkeys = toKeyIdArray(publicKeys); - 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++) { - msg.setParameter(additional_Keys[k], - additional[additional_Keys[k]]); - } - } - if (msg.isComplete() === true){ - return msg.post(); - } else { - return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + /** + * Encrypt (and optionally sign) data + * @param {String|Object} data text/data to be encrypted as String. Also + * accepts Objects with a getText method + * @param {inputKeys} publicKeys + * Keys used to encrypt the message + * @param {inputKeys} secretKeys (optional) Keys used to sign the + * message. If Keys are present, the operation requested is assumed + * to be 'encrypt and sign' + * @param {Boolean} base64 (optional) The data will be interpreted as + * base64 encoded data. + * @param {Boolean} armor (optional) Request the output as armored + * block. + * @param {Boolean} wildcard (optional) If true, recipient information + * will not be added to the message. + * @param {Object} additional use additional valid gpg options as + * defined in {@link permittedOperations} + * @returns {Promise} Object containing the encrypted + * message and additional info. + * @async + */ + encrypt (data, publicKeys, secretKeys, base64=false, armor=true, + wildcard=false, additional = {}){ + let msg = createMessage('encrypt'); + if (msg instanceof Error){ + return Promise.reject(msg); + } + msg.setParameter('armor', armor); + msg.setParameter('always-trust', true); + if (base64 === true) { + msg.setParameter('base64', true); + } + let pubkeys = toKeyIdArray(publicKeys); + 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++) { + msg.setParameter(additional_Keys[k], + additional[additional_Keys[k]]); } - }; + } + if (msg.isComplete() === true){ + return msg.post(); + } else { + return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + } + } - /** - * Decrypts a Message - * @param {String|Object} data text/data to be decrypted. Accepts - * Strings and Objects with a getText method - * @param {Boolean} base64 (optional) false if the data is an armored - * block, true if it is base64 encoded binary data - * @returns {Promise} Decrypted Message and information - * @async - */ - this.decrypt = function (data, base64=false){ - if (data === undefined){ - return Promise.reject(gpgme_error('MSG_EMPTY')); - } - let msg = createMessage('decrypt'); + /** + * Decrypts a Message + * @param {String|Object} data text/data to be decrypted. Accepts + * Strings and Objects with a getText method + * @param {Boolean} base64 (optional) false if the data is an armored + * block, true if it is base64 encoded binary data + * @returns {Promise} Decrypted Message and information + * @async + */ + decrypt (data, base64=false){ + if (data === undefined){ + 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); - } - putData(msg, data); - if (base64 === true){ - msg.setParameter('base64', true); - } - return new Promise(function(resolve, reject){ - msg.post().then(function(result){ - let _result = {data: result.data}; - _result.base64 = result.base64 ? true: false; - _result.is_mime = result.is_mime ? true: false; - if (result.file_name){ - _result.file_name = result.file_name; - } else { - _result.file_name = null; - } - if ( - result.hasOwnProperty('signatures') && - Array.isArray(result.signatures) - ) { - _result.signatures = collectSignatures( - result.signatures); - } - resolve(_result); - }, function(error){ - reject(error); - }); + if (msg instanceof Error){ + return Promise.reject(msg); + } + if (base64 === true){ + msg.setParameter('base64', true); + } + putData(msg, data); + if (base64 === true){ + msg.setParameter('base64', true); + } + return new Promise(function(resolve, reject){ + msg.post().then(function(result){ + let _result = {data: result.data}; + _result.base64 = result.base64 ? true: false; + _result.is_mime = result.is_mime ? true: false; + if (result.file_name){ + _result.file_name = result.file_name; + } else { + _result.file_name = null; + } + if ( + result.hasOwnProperty('signatures') && + Array.isArray(result.signatures) + ) { + _result.signatures = collectSignatures( + result.signatures); + } + resolve(_result); + }, function(error){ + reject(error); }); - }; + }); + } - /** - * Sign a Message - * @param {String|Object} data text/data to be signed. Accepts Strings - * and Objects with a getText method. - * @param {inputKeys} keys The key/keys to use for signing - * @param {String} mode The signing mode. Currently supported: - * 'clearsign':The Message is embedded into the signature; - * 'detached': The signature is stored separately - * @param {Boolean} base64 input is considered base64 - * @returns {Promise} - * @async - */ - this.sign = function (data, keys, mode='clearsign', base64=false) { - if (data === undefined){ - 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'); + /** + * Sign a Message + * @param {String|Object} data text/data to be signed. Accepts Strings + * and Objects with a getText method. + * @param {inputKeys} keys The key/keys to use for signing + * @param {String} mode The signing mode. Currently supported: + * 'clearsign':The Message is embedded into the signature; + * 'detached': The signature is stored separately + * @param {Boolean} base64 input is considered base64 + * @returns {Promise} + * @async + */ + sign (data, keys, mode='clearsign', base64=false) { + if (data === undefined){ + 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('keys', key_arr); + if (base64 === true){ + msg.setParameter('base64', true); + } + msg.setParameter('mode', mode); + putData(msg, data); + return new Promise(function(resolve,reject) { + if (mode ==='detached'){ + msg.expected ='base64'; } - msg.setParameter('mode', mode); - putData(msg, data); - return new Promise(function(resolve,reject) { - if (mode ==='detached'){ - msg.setExpect('base64'); + msg.post().then( function(message) { + if (mode === 'clearsign'){ + resolve({ + data: message.data} + ); + } else if (mode === 'detached') { + resolve({ + data: data, + signature: message.data + }); } - 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); - }); + }, function(error){ + reject(error); }); - }; + }); + } - /** - * Verifies data. - * @param {String|Object} data text/data to be verified. Accepts Strings - * and Objects with a getText method - * @param {String} (optional) A detached signature. If not present, - * opaque mode is assumed - * @param {Boolean} (optional) Data and signature are base64 encoded - * @returns {Promise} - *@async - */ - this.verify= function (data, signature, base64 = false){ - let msg = createMessage('verify'); - let dt = putData(msg, data); - if (dt instanceof Error){ - return Promise.reject(dt); + /** + * Verifies data. + * @param {String|Object} data text/data to be verified. Accepts Strings + * and Objects with a getText method + * @param {String} (optional) A detached signature. If not present, + * opaque mode is assumed + * @param {Boolean} (optional) Data and signature are base64 encoded + * @returns {Promise} + *@async + */ + verify (data, signature, base64 = false){ + 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 (signature){ - if (typeof(signature)!== 'string'){ - return Promise.reject(gpgme_error('PARAM_WRONG')); + } + 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 { - 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 _result = collectSignatures( - message.info.signatures); - _result.is_mime = message.info.is_mime? true: false; - if (message.info.filename){ - _result.file_name = message.info.filename; - } - _result.data = message.data; - resolve(_result); + let _result = collectSignatures( + message.info.signatures); + _result.is_mime = message.info.is_mime? true: false; + if (message.info.filename){ + _result.file_name = message.info.filename; } - }, function(error){ - reject(error); - }); + _result.data = message.data; + resolve(_result); + } + }, function(error){ + reject(error); }); - }; - } - - /** - * setter for {@link setKeyring}. - * @param {GPGME_Keyring} keyring A Keyring to use - */ - set Keyring(keyring){ - this.setKeyring(keyring); - } - - /** - * Accesses the {@link GPGME_Keyring}. - */ - get Keyring(){ - return this.getKeyring(); + }); } } -- cgit v1.2.3 From dd32daad0bb21e3d5567326d0b2e548ff8510431 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 20 Aug 2018 15:12:01 +0200 Subject: js: add and apply eslint rules -- * mainly spacing, see .eslintrc.json for details --- lang/js/src/gpgmejs.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 4aa51759..9a0925b0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -84,7 +84,7 @@ import { createSignature } from './Signature'; */ export class GpgME { - constructor(){ + constructor (){ this._Keyring = null; } @@ -92,7 +92,7 @@ export class GpgME { * setter for {@link setKeyring}. * @param {GPGME_Keyring} keyring A Keyring to use */ - set Keyring(keyring){ + set Keyring (keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } @@ -100,7 +100,7 @@ export class GpgME { /** * Accesses the {@link GPGME_Keyring}. */ - get Keyring(){ + get Keyring (){ if (!this._Keyring){ this._Keyring = new GPGME_Keyring; } @@ -188,9 +188,9 @@ export class GpgME { if (base64 === true){ msg.setParameter('base64', true); } - return new Promise(function(resolve, reject){ - msg.post().then(function(result){ - let _result = {data: result.data}; + return new Promise(function (resolve, reject){ + msg.post().then(function (result){ + let _result = { data: result.data }; _result.base64 = result.base64 ? true: false; _result.is_mime = result.is_mime ? true: false; if (result.file_name){ @@ -206,7 +206,7 @@ export class GpgME { result.signatures); } resolve(_result); - }, function(error){ + }, function (error){ reject(error); }); }); @@ -240,14 +240,14 @@ export class GpgME { } msg.setParameter('mode', mode); putData(msg, data); - return new Promise(function(resolve,reject) { + return new Promise(function (resolve,reject) { if (mode ==='detached'){ msg.expected ='base64'; } - msg.post().then( function(message) { + msg.post().then( function (message) { if (mode === 'clearsign'){ resolve({ - data: message.data} + data: message.data } ); } else if (mode === 'detached') { resolve({ @@ -255,7 +255,7 @@ export class GpgME { signature: message.data }); } - }, function(error){ + }, function (error){ reject(error); }); }); @@ -278,7 +278,7 @@ export class GpgME { return Promise.reject(dt); } if (signature){ - if (typeof(signature)!== 'string'){ + if (typeof (signature)!== 'string'){ return Promise.reject(gpgme_error('PARAM_WRONG')); } else { msg.setParameter('signature', signature); @@ -287,7 +287,7 @@ export class GpgME { if (base64 === true){ msg.setParameter('base64', true); } - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ msg.post().then(function (message){ if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); @@ -301,7 +301,7 @@ export class GpgME { _result.data = message.data; resolve(_result); } - }, function(error){ + }, function (error){ reject(error); }); }); @@ -316,20 +316,20 @@ export class GpgME { * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise * @private */ -function putData(message, data){ +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') { + } else if (typeof (data) === 'string') { message.setParameter('data', data); } else if ( - typeof(data) === 'object' && - typeof(data.getText) === 'function' + typeof (data) === 'object' && + typeof (data.getText) === 'function' ){ let txt = data.getText(); - if (typeof(txt) === 'string'){ + if (typeof (txt) === 'string'){ message.setParameter('data', txt); } else { return gpgme_error('PARAM_WRONG'); @@ -345,7 +345,7 @@ function putData(message, data){ * @param {Array} sigs * @returns {signatureDetails} Details about the signatures */ -function collectSignatures(sigs){ +function collectSignatures (sigs){ if (!Array.isArray(sigs)){ return gpgme_error('SIG_NO_SIGS'); } -- cgit v1.2.3 From 6d720137dd9564931bf313a7e7078e63fb00287c Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 21 Aug 2018 15:26:17 +0200 Subject: js: update decrypt/verify results -- * src/gpgmejs.js: Decrypt now parses additional optional dec_info information, as well as any verify information, if present * src/permittedOperations: Now decrypt also expect the new return object dec_inf (containing info such as is_mime and file_name) --- lang/js/src/gpgmejs.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 9a0925b0..3be5cdd5 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -192,18 +192,21 @@ export class GpgME { msg.post().then(function (result){ let _result = { data: result.data }; _result.base64 = result.base64 ? true: false; - _result.is_mime = result.is_mime ? true: false; - if (result.file_name){ - _result.file_name = result.file_name; - } else { + if (result.hasOwnProperty('dec_info')){ + _result.is_mime = result.dec_info.is_mime ? true: false; + if (result.dec_info.file_name) { + _result.file_name = result.dec_info.file_name; + } + } + if (!result.file_name) { _result.file_name = null; } - if ( - result.hasOwnProperty('signatures') && - Array.isArray(result.signatures) + if (result.hasOwnProperty('info') + && result.info.hasOwnProperty('signatures') + && Array.isArray(result.info.signatures) ) { _result.signatures = collectSignatures( - result.signatures); + result.info.signatures); } resolve(_result); }, function (error){ -- cgit v1.2.3 From 93f674d33d4dacb115398196a7218c28323fd708 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 22 Aug 2018 12:18:55 +0200 Subject: js: throw errors in sync functions -- * synchronous functions should throw errors if something goes wrong, Promises should reject. This commit changes some error cases that returned Error objects instead of throwing them - src/Key.js: createKey() and sync Key.get() throw errors - src/Error.js: Exporting the list of errors to be able to test and compare against these strings - src/Keyring.js: Setting a null value in pattern is not useful, and now caused an error with the new changes. - src/Message.js: createMessage and Message.setParameter now throw errors --- lang/js/src/gpgmejs.js | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 3be5cdd5..2886c6f6 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -152,8 +152,13 @@ export class GpgME { if (additional){ let additional_Keys = Object.keys(additional); for (let k = 0; k < additional_Keys.length; k++) { - msg.setParameter(additional_Keys[k], - additional[additional_Keys[k]]); + try { + msg.setParameter(additional_Keys[k], + additional[additional_Keys[k]]); + } + catch (error){ + return Promise.reject(error); + } } } if (msg.isComplete() === true){ @@ -185,9 +190,6 @@ export class GpgME { msg.setParameter('base64', true); } putData(msg, data); - if (base64 === true){ - msg.setParameter('base64', true); - } return new Promise(function (resolve, reject){ msg.post().then(function (result){ let _result = { data: result.data }; @@ -208,7 +210,11 @@ export class GpgME { _result.signatures = collectSignatures( result.info.signatures); } - resolve(_result); + if (_result.signatures instanceof Error){ + reject(_result.signatures); + } else { + resolve(_result); + } }, function (error){ reject(error); }); @@ -295,14 +301,17 @@ export class GpgME { if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); } else { - let _result = collectSignatures( - message.info.signatures); - _result.is_mime = message.info.is_mime? true: false; - if (message.info.filename){ - _result.file_name = message.info.filename; + let _result = collectSignatures(message.info.signatures); + if (_result instanceof Error){ + reject(_result.signatures); + } else { + _result.is_mime = message.info.is_mime? true: false; + if (message.info.filename){ + _result.file_name = message.info.filename; + } + _result.data = message.data; + resolve(_result); } - _result.data = message.data; - resolve(_result); } }, function (error){ reject(error); @@ -363,8 +372,8 @@ function collectSignatures (sigs){ }; for (let i=0; i< sigs.length; i++){ let sigObj = createSignature(sigs[i]); - if (sigObj instanceof Error){ - return gpgme_error(sigObj); + if (sigObj instanceof Error) { + return gpgme_error('SIG_WRONG'); } if (sigObj.valid !== true){ summary.failures += 1; -- cgit v1.2.3 From d8fd4aad8a93f7745c63814b3779469b610a8db0 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 22 Aug 2018 12:44:05 +0200 Subject: js: changed verify signature result infos -- * the resulting information of verify now are as documented, and the same as in a decrypt callback --- lang/js/src/gpgmejs.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lang/js/src/gpgmejs.js') diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 2886c6f6..7692298f 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -301,8 +301,10 @@ export class GpgME { if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); } else { - let _result = collectSignatures(message.info.signatures); - if (_result instanceof Error){ + let _result = { + signatures: collectSignatures(message.info.signatures) + }; + if (_result.signatures instanceof Error){ reject(_result.signatures); } else { _result.is_mime = message.info.is_mime? true: false; -- cgit v1.2.3