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)});
});