diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 87ec8cf7..e6ff67be 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -1,194 +1,201 @@ import { GPGME_Message } from "./Message"; /* 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+ */ /** * A connection port will be opened for each communication between gpgmejs and * gnupg. It should be alive as long as there are additional messages to be * expected. */ import { permittedOperations } from './permittedOperations' import { GPGMEJS_Error} from "./Errors" /** * A Connection handles the nativeMessaging interaction. */ export class Connection{ constructor(){ this.connect(); + let me = this; + } + + /** + * (Simple) Connection check. + * @returns {Boolean} true if the onDisconnect event has not been fired. + * Please note that the event listener of the port takes some time + * (5 ms seems enough) to react after the port is created. Then this will + * return undefined + */ + get isConnected(){ + return this._isConnected; } /** * Immediately closes the open port. */ disconnect() { if (this._connection){ this._connection.disconnect(); } } /** * Opens a nativeMessaging port. - * returns nothing, but triggers errors if not successfull: - * NO_CONNECT: connection not successfull, chrome.runtime.lastError may be - * available - * ALREADY_CONNECTED: There is already a connection present. + * TODO: Error handling ALREADY_CONNECTED */ connect(){ - if (this._connection){ + if (this._isConnected === true){ return new GPGMEJS_Error('ALREADY_CONNECTED'); } + this._isConnected = true; this._connection = chrome.runtime.connectNative('gpgmejson'); - if (!this._connection){ - return new GPGMEJS_Error('NO_CONNECT'); - } - } - - /** - * checks if the connection is established - * TODO: some kind of ping to see if the other side responds as expected? - * @returns {Boolean} - */ - get connected(){ - return this._connection ? true: false; + let me = this; + this._connection.onDisconnect.addListener( + function(){ + me._isConnected = false; + } + ); } /** * Sends a message and resolves with the answer. * @param {GPGME_Message} message * @returns {Promise} the gnupg answer, or rejection with error * information. */ post(message){ + if (!this.isConnected){ + return Promise.reject(new GPGMEJS_Error('NO_CONNECT')); + } if (!message || !message instanceof GPGME_Message){ return Promise.reject(new GPGMEJS_Error('WRONGPARAM')); } if (message.isComplete !== true){ return Promise.reject(new GPGMEJS_Error('MSG_INCOMPLETE')); } // let timeout = 5000; //TODO config let me = this; return new Promise(function(resolve, reject){ let answer = new Answer(message.operation); let listener = function(msg) { if (!msg){ me._connection.onMessage.removeListener(listener) reject(new GPGMEJS_Error('EMPTY_GPG_ANSWER')); } else if (msg.type === "error"){ me._connection.onMessage.removeListener(listener) //TODO: GPGMEJS_Error? reject(msg.msg); } else { answer.add(msg); if (msg.more === true){ me._connection.postMessage({'op': 'getmore'}); } else { me._connection.onMessage.removeListener(listener) resolve(answer.message); } } }; me._connection.onMessage.addListener(listener); me._connection.postMessage(message.message); //TBD: needs to be aware if there is a pinentry pending // setTimeout( // function(){ // me.disconnect(); // reject(new GPGMEJS_Error('TIMEOUT', 5000)); // }, timeout); }); } }; /** * A class for answer objects, checking and processing the return messages of * the nativeMessaging communication. * @param {String} operation The operation, to look up validity of returning messages */ class Answer{ constructor(operation){ this.operation = operation; } /** * Add the information to the answer * @param {Object} msg The message as received with nativeMessaging */ add(msg){ if (this._response === undefined){ this._response = {}; } let messageKeys = Object.keys(msg); let poa = permittedOperations[this.operation].answer; for (let i= 0; i < messageKeys.length; i++){ let key = messageKeys[i]; switch (key) { case 'type': if ( msg.type !== 'error' && poa.type.indexOf(msg.type) < 0){ return new GPGMEJS_Error('UNEXPECTED_ANSWER'); } break; case 'more': break; default: //data should be concatenated if (poa.data.indexOf(key) >= 0){ if (!this._response.hasOwnProperty(key)){ this._response[key] = ''; } this._response[key] = this._response[key].concat(msg[key]); } //params should not change through the message else if (poa.params.indexOf(key) >= 0){ if (!this._response.hasOwnProperty(key)){ this._response[key] = msg[key]; } else if (this._response[key] !== msg[key]){ return new GPGMEJS_Error('UNEXPECTED_ANSWER',msg[key]); } } //infos may be json objects etc. Not yet defined. // Pushing them into arrays for now else if (poa.infos.indexOf(key) >= 0){ if (!this._response.hasOwnProperty(key)){ this._response[key] = []; } this._response.push(msg[key]); } else { return new GPGMEJS_Error('UNEXPECTED_ANSWER', key); } break; } } } /** * @returns {Object} the assembled message. * TODO: does not care yet if completed. */ get message(){ return this._response; } } diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index d8cb84b2..ef8028ff 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -1,150 +1,150 @@ /* 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+ */ import {GPGME_Message} from './Message' -import {Connection} from './Connection' import {GPGME_Key} from './Key' import { isFingerprint, isLongId } from './Helpers'; export class GPGME_Keyring { - constructor(){ - this.reconnect(); + constructor(connection){ + this.connection = connection; } - /** - * (Re)-establishes the connection - * TODO TEMP: should we better use the connection of our parent, - * which we do not control? - */ - 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 && connection instanceof Connection){ + this._connection = connection; + } + } + 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 } /** * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds * @param {Boolean} (optional) Include listing of secret keys * @returns {Promise.>} * */ getKeys(pattern, include_secret){ let msg = new GPGME_Message('listkeys'); if (pattern && typeof(pattern) === 'string'){ msg.setParameter('pattern', pattern); } if (include_secret){ msg.setParameter('with-secret', true); } - this._connection.post(msg).then(function(result){ + this.connection.post(msg).then(function(result){ let fpr_list = []; let resultset = []; if (!Array.isArray(result.keys)){ //TODO check assumption keys = Array fpr_list = [result.keys]; } else { fpr_list = result.keys; } for (let i=0; i < fpr_list.length; i++){ let newKey = new GPGME_Key(fpr_list[i]); if (newKey instanceof GPGME_Key){ resultset.push(newKey); } } return Promise.resolve(resultset); }); } /** * @param {Object} flags subset filter expecting at least one of the * filters described below. True will filter on the condition, False will * reverse the filter, if not present or undefined, the filter will not be * considered. Please note that some combination may not make sense * @param {Boolean} flags.defaultKey Only Keys marked as Default Keys * @param {Boolean} flags.secret Only Keys containing a secret part. * @param {Boolean} flags.valid Valid Keys only * @param {Boolean} flags.revoked revoked Keys only * @param {Boolean} flags.expired Expired Keys only * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds * @returns {Promise Array} * */ getSubset(flags, pattern){ if (flags === undefined) { throw('ERR_WRONG_PARAM'); }; let secretflag = false; if (flags.hasOwnProperty(secret) && flags.secret){ secretflag = true; } this.getKeys(pattern, secretflag).then(function(queryset){ let resultset = []; for (let i=0; i < queryset.length; i++ ){ let conditions = []; let anticonditions = []; if (secretflag === true){ conditions.push('hasSecret'); } else if (secretflag === false){ anticonditions.push('hasSecret'); } if (flags.defaultKey === true){ conditions.push('isDefault'); } else if (flags.defaultKey === false){ anticonditions.push('isDefault'); } if (flags.valid === true){ anticonditions.push('isInvalid'); } else if (flags.valid === false){ conditions.push('isInvalid'); } if (flags.revoked === true){ conditions.push('isRevoked'); } else if (flags.revoked === false){ anticonditions.push('isRevoked'); } if (flags.expired === true){ conditions.push('isExpired'); } else if (flags.expired === false){ anticonditions.push('isExpired'); } let decision = undefined; for (let con = 0; con < conditions.length; con ++){ if (queryset[i][conditions[con]] !== true){ decision = false; } } for (let acon = 0; acon < anticonditions.length; acon ++){ if (queryset[i][anticonditions[acon]] === true){ decision = false; } } if (decision !== false){ resultset.push(queryset[i]); } } return Promise.resolve(resultset); }); } }; 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 @@ -1,174 +1,165 @@ /* 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+ */ 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'); // TODO temporary msg.setParameter('armor', true); msg.setParameter('always-trust', true); let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); putData(msg, data); if (wildcard === true){msg.setParameter('throw-keyids', true); }; - return (this._connection.post(msg)); + return (this.connection.post(msg)); } /** * @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 */ decrypt(data){ if (data === undefined){ return Promise.reject(new GPGMEJS_Error ('EMPTY_MSG')); } let msg = new GPGME_Message('decrypt'); putData(msg, data); - return this._connection.post(msg); + return this.connection.post(msg); } deleteKey(key, delete_secret = false, no_confirm = false){ return Promise.reject(new GPGMEJS_Error ('NOT_YET_IMPLEMENTED')); let msg = new GPGME_Message('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 } 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){ 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 } }); } - } /** * 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 putData(message, data){ if (!message || !message instanceof GPGME_Message ) { return new GPGMEJS_Error('WRONGPARAM'); } 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 { return new GPGMEJS_Error('WRONGPARAM'); } -} \ No newline at end of file +} diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js index 54b9dd45..f1ddb5d6 100644 --- a/lang/js/src/gpgmejs_openpgpjs.js +++ b/lang/js/src/gpgmejs_openpgpjs.js @@ -1,201 +1,214 @@ /* 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+ */ /** * This is a compatibility API to be used as openpgpjs syntax. * Non-implemented options will throw an error if set (not null or undefined) * TODO Some info about differences */ import { GpgME } from "./gpgmejs"; import {GPGME_Keyring} from "./Keyring" import { GPGME_Key } from "./Key"; import { isFingerprint } from "./Helpers" import { GPGMEJS_Error } from './Errors' + export class GpgME_openPGPCompatibility { - constructor(){ - this._gpgme = new GpgME({ - null_expire_is_never: false - }); - this.Keyring = this.initKeyring(); + constructor(connection){ + this.initGpgME(connection); + } + + get Keyring(){ + if (this._keyring){ + return this._keyring; + } + return undefined; + } + + initGpgME(connection){ + this._GpgME = new GpgME(connection); + this._Keyring = new GPGME_Keyring_openPGPCompatibility(connection); + } + + get GpgME(){ + if (this._GpGME){ + return this._GpGME; + } } /** * Encrypt Message * Supported: * @param {String|Uint8Array} data * @param {Key|Array} publicKeys * @param {Boolean} wildcard * TODO: * @param {Key|Array} privateKeys * @param {String} filename * @param {module:enums.compression} compression * @param {Boolean} armor * @param {Boolean} detached * unsupported: * @param {String|Array} passwords * @param {Object} sessionKey * @param {Signature} signature * @param {Boolean} returnSessionKey * * @returns {Promise} * {data: ASCII armored message, * signature: detached signature if 'detached' is true * } * @async * @static */ encrypt({data = '', publicKeys = '', privateKeys, passwords, sessionKey, filename, compression, armor=true, detached=false, signature=null, returnSessionKey=null, wildcard=false, date=null}) { if (passwords !== undefined || sessionKey !== undefined || signature !== null || returnSessionKey !== null || date !== null){ return Promise.reject(new GPMGEJS_Error('NOT_IMPLEMENTED')); } if ( privateKeys || filename || compression || armor === false || detached == true){ return Promise.reject(new GPGMEJS_Error('NOT_YET_IMPLEMENTED')); } return this.GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard); } /** Decrypt Message * supported * TODO: @param {Message} message TODO: for now it accepts an armored string only * Unsupported: * @param {String|Array} passwords * @param {Object|Array} sessionKeys * @param {Date} date * TODO * @param {Key|Array} privateKey * @param {Key|Array} publicKeys * @param {String} format (optional) return data format either as 'utf8' or 'binary' * @param {Signature} signature (optional) detached signature for verification * @returns {Promise} decrypted and verified message in the form: * { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] } * @async * @static */ decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format='utf8', signature=null, date}) { if (passwords !== undefined || sessionKeys || date){ return Promise.reject(new GPGMEJS_Error('NOT_IMPLEMENTED')); } if ( privateKeys || publicKeys || format !== 'utf8' || signature ){ return Promise.reject(new GPGMEJS_Error('NOT_YET_IMPLEMENTED')); } return this.GpgME.decrypt(message); // TODO: translate between: // openpgp: // { data:Uint8Array|String, // filename:String, // signatures:[{ keyid:String, valid:Boolean }] } // and gnupg: // 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. } - initKeyring(){ - return new GPGME_Keyring_openPGPCompatibility; - } } /** * Translation layer offering basic Keyring API to be used in Mailvelope. * It may still be changed/expanded/merged with GPGME_Keyring */ class GPGME_Keyring_openPGPCompatibility { - constructor(){ - this._gpgme_keyring = new GPGME_Keyring; + constructor(connection){ + this._gpgme_keyring = new GPGME_Keyring(connection); } /** * Returns a GPGME_Key Object for each Key in the gnupg Keyring. This * includes keys openpgpjs considers 'private' (usable for signing), with * the difference that Key.armored will NOT contain any secret information. * Please also note that a GPGME_Key does not offer full openpgpjs- Key * compatibility. * @returns {Array} with the objects offering at least: * @property {String} armored The armored key block (does not include secret blocks) * @property {Boolean} hasSecret Indicator if a private/secret key exists * @property {Boolean} isDefault Indicator if private key exists and is the default key in this keyring * @property {String} fingerprint The fingerprint identifying this key * //TODO: Check if IsDefault is also always hasSecret */ getPublicKeys(){ return this._gpgme_keyring.getKeys(null, true); } /** * Returns the Default Key used for crypto operation in gnupg. * Please note that the armored property does not contained secret key blocks, * despite secret blocks being part of the key itself. * @returns {Promise } */ getDefaultKey(){ this._gpgme_keyring.getSubset({defaultKey: true}).then(function(result){ if (result.length === 1){ return Promise.resolve(result[0]); } else { // TODO: Can there be "no default key"? // TODO: Can there be several default keys? return new GPGMEJS_Error; //TODO } }); } /** * Deletes a Key * @param {Object} Object identifying key * @param {String} key.fingerprint - fingerprint of the to be deleted key * @param {Boolean} key.secret - indicator if private key should be deleted as well * @returns {Promise., Error>} TBD: Not sure what is wanted TODO @throws {Error} error.code = ‘KEY_NOT_EXIST’ - there is no key for the given fingerprint TODO @throws {Error} error.code = ‘NO_SECRET_KEY’ - secret indicator set, but no secret key exists */ deleteKey(key){ if (typeof(key) !== "object"){ return Promise.reject(new GPGMEJS_Error('WRONGPARAM')); } if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){ return Promise.reject(new GPGMEJS_Error('WRONGPARAM')); } let key_to_delete = new GPGME_Key(key.fingerprint); return key_to_delete.deleteKey(key.secret); } } diff --git a/lang/js/src/index.js b/lang/js/src/index.js index f70bd2d8..0e2beda4 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -1,23 +1,57 @@ /* 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+ */ -import { GpgME as gpgmejs } from "./gpgmejs"; -// import { GpgME_openPGPCompatibility as gpgmejs } from "./gpgmejs_openpgpjs"; -export default gpgmejs; +import { GpgME } from "./gpgmejs"; +import { GpgME_openPGPCompatibility } from "./gpgmejs_openpgpjs"; +import { Connection } from "./Connection"; + +/** + * Initializes a nativeMessaging Connection and returns a GPGMEjs object + * @param {*} conf Configuration. TBD + */ +function init( config = { + api_style: 'gpgme', // | gpgme_openpgpjs + null_expire_is_never: true // Boolean + }){ + return new Promise(function(resolve, reject){ + let connection = new Connection; + // TODO: Delayed reaction is ugly. We need to listen to the port's + // event listener in isConnected, but this takes some time (<5ms) to + // disconnect if there is no successfull connection. + let delayedreaction = function(){ + if (connection.isConnected === true){ + let gpgme = null; + if (config.api_style && config.api_style === 'gpgme_openpgpjs'){ + resolve( + new GpgME_openPGPCompatibility(connection)); + } else { + resolve(new GpgME(connection)); + } + } else { + reject('NO_CONNECT'); + } + }; + setTimeout(delayedreaction, 5); + }); +}; + +export default { + init: init +} \ No newline at end of file diff --git a/lang/js/testapplication.js b/lang/js/testapplication.js index 97b35527..f47299e8 100644 --- a/lang/js/testapplication.js +++ b/lang/js/testapplication.js @@ -1,57 +1,55 @@ /* 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+ * */ -function encryptbuttonclicked(event){ - let data = document.getElementById('cleartext').value; - let keyId = document.getElementById('pubkey').value; - let communication = new Gpgmejs; - let enc = communication.encrypt(data, keyId).then( - function(answer){ - console.log(answer); - if (answer.data){ - console.log(answer.data); - document.getElementById('answer').value = answer.data; - } - }, function(errormsg){ - alert('Error: '+ errormsg); - }); -}; - -function decryptbuttonclicked(event){ - let data = document.getElementById("ciphertext").value; - let communication = new Gpgmejs; - let enc = communication.decrypt(data).then( - function(answer){ - console.log(answer); - if (answer.data){ - document.getElementById('answer').value = answer.data; - } - }, function(errormsg){ - alert('Error: '+ errormsg); - }); -}; - document.addEventListener('DOMContentLoaded', function() { - document.getElementById("buttonencrypt").addEventListener("click", - encryptbuttonclicked); - document.getElementById("buttondecrypt").addEventListener("click", - decryptbuttonclicked); + Gpgmejs.init().then(function(gpgmejs){ + document.getElementById("buttonencrypt").addEventListener("click", + function(){ + let data = document.getElementById('cleartext').value; + let keyId = document.getElementById('pubkey').value; + gpgmejs.encrypt(data, keyId).then( + function(answer){ + console.log(answer); + if (answer.data){ + console.log(answer.data); + document.getElementById('answer').value = answer.data; + } + }, function(errormsg){ + alert('Error: '+ errormsg); + }); + }); + + document.getElementById("buttondecrypt").addEventListener("click", + function(){ + let data = document.getElementById("ciphertext").value; + gpgmejs.decrypt(data).then( + function(answer){ + console.log(answer); + if (answer.data){ + document.getElementById('answer').value = answer.data; + } + }, function(errormsg){ + alert('Error: '+ errormsg); + }); + }); + }, + function(error){console.log(error)}); });