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 <GpgME | gpgmeGpgME_openPGPCompatibility> 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.
This commit is contained in:
parent
727340b295
commit
461dd0c8b4
@ -35,6 +35,18 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,28 +60,20 @@ export class Connection{
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,6 +83,9 @@ export class Connection{
|
||||
* 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'));
|
||||
}
|
||||
|
@ -19,28 +19,28 @@
|
||||
*/
|
||||
|
||||
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
|
||||
@ -57,7 +57,7 @@ export class GPGME_Keyring {
|
||||
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)){
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
set Keyring(keyring){
|
||||
if (ring && ring instanceof GPGME_Keyring){
|
||||
this.Keyring = ring;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tests the nativeApp connection
|
||||
*/
|
||||
get connected(){
|
||||
if (!this._connection || ! this._connection instanceof Connection){
|
||||
return false;
|
||||
}
|
||||
return this._connection.connected;
|
||||
get Keyring(){
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array
|
||||
* @param {GPGME_Key|String|Array<String>|Array<GPGME_Key>} 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,13 +30,29 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,9 +144,6 @@ export class GpgME_openPGPCompatibility {
|
||||
// mime: A Boolean indicating whether the data is a MIME object.
|
||||
// info: An optional object with extra information.
|
||||
}
|
||||
initKeyring(){
|
||||
return new GPGME_Keyring_openPGPCompatibility;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,8 +151,8 @@ export class GpgME_openPGPCompatibility {
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,40 @@
|
||||
* 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
|
||||
}
|
@ -19,39 +19,37 @@
|
||||
*
|
||||
*/
|
||||
|
||||
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)});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user