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(){
|
constructor(){
|
||||||
this.connect();
|
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.
|
* Opens a nativeMessaging port.
|
||||||
* returns nothing, but triggers errors if not successfull:
|
* TODO: Error handling ALREADY_CONNECTED
|
||||||
* NO_CONNECT: connection not successfull, chrome.runtime.lastError may be
|
|
||||||
* available
|
|
||||||
* ALREADY_CONNECTED: There is already a connection present.
|
|
||||||
*/
|
*/
|
||||||
connect(){
|
connect(){
|
||||||
if (this._connection){
|
if (this._isConnected === true){
|
||||||
return new GPGMEJS_Error('ALREADY_CONNECTED');
|
return new GPGMEJS_Error('ALREADY_CONNECTED');
|
||||||
}
|
}
|
||||||
|
this._isConnected = true;
|
||||||
this._connection = chrome.runtime.connectNative('gpgmejson');
|
this._connection = chrome.runtime.connectNative('gpgmejson');
|
||||||
if (!this._connection){
|
let me = this;
|
||||||
return new GPGMEJS_Error('NO_CONNECT');
|
this._connection.onDisconnect.addListener(
|
||||||
}
|
function(){
|
||||||
}
|
me._isConnected = false;
|
||||||
|
}
|
||||||
/**
|
);
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,6 +83,9 @@ export class Connection{
|
|||||||
* information.
|
* information.
|
||||||
*/
|
*/
|
||||||
post(message){
|
post(message){
|
||||||
|
if (!this.isConnected){
|
||||||
|
return Promise.reject(new GPGMEJS_Error('NO_CONNECT'));
|
||||||
|
}
|
||||||
if (!message || !message instanceof GPGME_Message){
|
if (!message || !message instanceof GPGME_Message){
|
||||||
return Promise.reject(new GPGMEJS_Error('WRONGPARAM'));
|
return Promise.reject(new GPGMEJS_Error('WRONGPARAM'));
|
||||||
}
|
}
|
||||||
|
@ -19,28 +19,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {GPGME_Message} from './Message'
|
import {GPGME_Message} from './Message'
|
||||||
import {Connection} from './Connection'
|
|
||||||
import {GPGME_Key} from './Key'
|
import {GPGME_Key} from './Key'
|
||||||
import { isFingerprint, isLongId } from './Helpers';
|
import { isFingerprint, isLongId } from './Helpers';
|
||||||
|
|
||||||
export class GPGME_Keyring {
|
export class GPGME_Keyring {
|
||||||
constructor(){
|
constructor(connection){
|
||||||
this.reconnect();
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
set connection(connection){
|
||||||
* (Re)-establishes the connection
|
if (!this._connection && connection instanceof Connection){
|
||||||
* TODO TEMP: should we better use the connection of our parent,
|
this._connection = connection;
|
||||||
* which we do not control?
|
|
||||||
*/
|
|
||||||
reconnect(){
|
|
||||||
if (!this._connection || ! this._connection instanceof Connection){
|
|
||||||
this._connection = new Connection;
|
|
||||||
} else {
|
|
||||||
this._connection.disconnect();
|
|
||||||
this._connection.connect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 {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);
|
msg.setParameter('with-secret', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._connection.post(msg).then(function(result){
|
this.connection.post(msg).then(function(result){
|
||||||
let fpr_list = [];
|
let fpr_list = [];
|
||||||
let resultset = [];
|
let resultset = [];
|
||||||
if (!Array.isArray(result.keys)){
|
if (!Array.isArray(result.keys)){
|
||||||
|
@ -22,59 +22,51 @@ import {Connection} from "./Connection"
|
|||||||
import {GPGME_Message} from './Message'
|
import {GPGME_Message} from './Message'
|
||||||
import {toKeyIdArray} from "./Helpers"
|
import {toKeyIdArray} from "./Helpers"
|
||||||
import {GPGMEJS_Error as Error, GPGMEJS_Error} from "./Errors"
|
import {GPGMEJS_Error as Error, GPGMEJS_Error} from "./Errors"
|
||||||
|
import { GPGME_Keyring } from "./Keyring";
|
||||||
|
|
||||||
export class GpgME {
|
export class GpgME {
|
||||||
/**
|
/**
|
||||||
* initializes GpgME by opening a nativeMessaging port
|
* initializes GpgME by opening a nativeMessaging port
|
||||||
* TODO: add configuration
|
* TODO: add configuration
|
||||||
*/
|
*/
|
||||||
constructor(configuration = {
|
constructor(connection){
|
||||||
null_expire_is_never: false
|
this.connection = connection;
|
||||||
}){
|
|
||||||
this._connection = new Connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
set connection(connection){
|
||||||
* refreshes the nativeApp connection
|
if (this._connection instanceof Connection){
|
||||||
*/
|
//TODO Warning: Connection already established
|
||||||
reconnect(){
|
}
|
||||||
if (!this._connection || ! this._connection instanceof Connection){
|
if (connection instanceof Connection){
|
||||||
this._connection = new Connection;
|
this._connection = connection;
|
||||||
} else {
|
|
||||||
this._connection.disconnect();
|
|
||||||
this._connection.connect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
get connection(){
|
||||||
* inmediately tries to destroy the nativeMessaging connection.
|
if (this._connection instanceof Connection){
|
||||||
* TODO: may not be included in final API, as it is redundant.
|
if (this._connection.isConnected){
|
||||||
* For now, it just serves paranoia
|
return this._connection;
|
||||||
*/
|
}
|
||||||
disconnect(){
|
return undefined; //TODO: connection was lost!
|
||||||
if (this._connection){
|
}
|
||||||
this._connection.disconnect();
|
return undefined; //TODO: no connection there
|
||||||
this._connection = null;
|
}
|
||||||
|
|
||||||
|
set Keyring(keyring){
|
||||||
|
if (ring && ring instanceof GPGME_Keyring){
|
||||||
|
this.Keyring = ring;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
get Keyring(){
|
||||||
* 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 {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 {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
|
* @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');
|
let msg = new GPGME_Message('encrypt');
|
||||||
|
|
||||||
@ -89,7 +81,7 @@ export class GpgME {
|
|||||||
if (wildcard === true){msg.setParameter('throw-keyids', true);
|
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');
|
let msg = new GPGME_Message('decrypt');
|
||||||
putData(msg, data);
|
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?
|
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){
|
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){
|
}, function(error){
|
||||||
switch (error.msg){
|
switch (error.msg){
|
||||||
@ -143,7 +135,6 @@ export class GpgME {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,4 +162,4 @@ function putData(message, data){
|
|||||||
} else {
|
} else {
|
||||||
return new GPGMEJS_Error('WRONGPARAM');
|
return new GPGMEJS_Error('WRONGPARAM');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,29 @@
|
|||||||
import { isFingerprint } from "./Helpers"
|
import { isFingerprint } from "./Helpers"
|
||||||
import { GPGMEJS_Error } from './Errors'
|
import { GPGMEJS_Error } from './Errors'
|
||||||
|
|
||||||
|
|
||||||
export class GpgME_openPGPCompatibility {
|
export class GpgME_openPGPCompatibility {
|
||||||
|
|
||||||
constructor(){
|
constructor(connection){
|
||||||
this._gpgme = new GpgME({
|
this.initGpgME(connection);
|
||||||
null_expire_is_never: false
|
}
|
||||||
});
|
|
||||||
this.Keyring = this.initKeyring();
|
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.
|
// mime: A Boolean indicating whether the data is a MIME object.
|
||||||
// info: An optional object with extra information.
|
// 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
|
* It may still be changed/expanded/merged with GPGME_Keyring
|
||||||
*/
|
*/
|
||||||
class GPGME_Keyring_openPGPCompatibility {
|
class GPGME_Keyring_openPGPCompatibility {
|
||||||
constructor(){
|
constructor(connection){
|
||||||
this._gpgme_keyring = new GPGME_Keyring;
|
this._gpgme_keyring = new GPGME_Keyring(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,40 @@
|
|||||||
* SPDX-License-Identifier: LGPL-2.1+
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GpgME as gpgmejs } from "./gpgmejs";
|
import { GpgME } from "./gpgmejs";
|
||||||
// import { GpgME_openPGPCompatibility as gpgmejs } from "./gpgmejs_openpgpjs";
|
import { GpgME_openPGPCompatibility } from "./gpgmejs_openpgpjs";
|
||||||
export default gpgmejs;
|
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.addEventListener('DOMContentLoaded', function() {
|
||||||
document.getElementById("buttonencrypt").addEventListener("click",
|
Gpgmejs.init().then(function(gpgmejs){
|
||||||
encryptbuttonclicked);
|
document.getElementById("buttonencrypt").addEventListener("click",
|
||||||
document.getElementById("buttondecrypt").addEventListener("click",
|
function(){
|
||||||
decryptbuttonclicked);
|
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