diff options
| -rw-r--r-- | lang/js/src/Connection.js | 68 | ||||
| -rw-r--r-- | lang/js/src/Errors.js | 12 | ||||
| -rw-r--r-- | lang/js/src/index.js | 14 | ||||
| -rw-r--r-- | lang/js/unittests.js | 32 | 
4 files changed, 99 insertions, 27 deletions
| diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 8a965479..923698a4 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -40,7 +40,15 @@ import { decode, atobArray, Utf8ArrayToStr } from './Helpers';  export class Connection{      constructor (){ +        this._connectionError = null;          this._connection = chrome.runtime.connectNative('gpgmejson'); +        this._connection.onDisconnect.addListener(() => { +            if (chrome.runtime.lastError) { +                this._connectionError = chrome.runtime.lastError.message; +            } else { +                this._connectionError = 'Disconnected without error message'; +            } +        });      }      /** @@ -50,9 +58,16 @@ export class Connection{          if (this._connection){              this._connection.disconnect();              this._connection = null; +            this._connectionError = 'Disconnect requested by gpgmejs';          }      } +    /** +     * Checks if the connection terminated with an error state +     */ +    get isDisconnected (){ +        return this._connectionError !== null; +    }      /**      * @typedef {Object} backEndDetails @@ -126,9 +141,17 @@ export class Connection{              this.disconnect();              return Promise.reject(gpgme_error('MSG_INCOMPLETE'));          } +        if (this.isDisconnected) { +            if ( this.isNativeHostUnknown === true) { +                return Promise.reject(gpgme_error('CONN_NO_CONFIG')); +            } else { +                return Promise.reject(gpgme_error( +                    'CONN_NO_CONNECT', this._connectionError)); +            } +        }          let chunksize = message.chunksize;          const me = this; -        return new Promise(function (resolve, reject){ +        const nativeCommunication = new Promise(function (resolve, reject){              let answer = new Answer(message);              let listener = function (msg) {                  if (!msg){ @@ -161,29 +184,21 @@ export class Connection{                  }              };              me._connection.onMessage.addListener(listener); -            if (permittedOperations[message.operation].pinentry){ -                return me._connection.postMessage(message.message); -            } else { -                return Promise.race([ -                    me._connection.postMessage(message.message), -                    function (resolve, reject){ -                        setTimeout(function (){ -                            me._connection.disconnect(); -                            reject(gpgme_error('CONN_TIMEOUT')); -                        }, 5000); -                    } -                ]).then(function (result){ -                    return result; -                }, function (reject){ -                    if (!(reject instanceof Error)) { -                        me._connection.disconnect(); -                        return gpgme_error('GNUPG_ERROR', reject); -                    } else { -                        return reject; -                    } -                }); -            } +            me._connection.postMessage(message.message);          }); +        if (permittedOperations[message.operation].pinentry === true) { +            return nativeCommunication; +        } else { +            return Promise.race([ +                nativeCommunication, +                new Promise(function (resolve, reject){ +                    setTimeout(function (){ +                        me._connection.disconnect(); +                        reject(gpgme_error('CONN_TIMEOUT')); +                    }, 5000); +                }) +            ]); +        }      }  } @@ -213,6 +228,13 @@ class Answer{      }      /** +     * Checks if an error matching browsers 'host not known' messages occurred +     */ +    get isNativeHostUnknown () { +        return this._connectionError === 'Specified native messaging host not found.'; +    } + +    /**       * Adds incoming base64 encoded data to the existing response       * @param {*} msg base64 encoded data.       * @returns {Boolean} diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index bf52cce7..6189414f 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -35,6 +35,14 @@ export const err_list = {          msg: 'The nativeMessaging answer was empty.',          type: 'error'      }, +    'CONN_NO_CONFIG':{ +        msg: 'The browser does not recognize the nativeMessaging host.', +        type: 'error' +    }, +    'CONN_NATIVEMESSAGE':{ +        msg: 'The native messaging was not successful.', +        type: 'error' +    },      'CONN_TIMEOUT': {          msg: 'A connection timeout was exceeded.',          type: 'error' @@ -156,8 +164,8 @@ export function gpgme_error (code = 'GENERIC_ERROR', info){   */  class GPGME_Error extends Error{      constructor (code = 'GENERIC_ERROR', msg=''){ - -        if (code === 'GNUPG_ERROR' && typeof (msg) === 'string'){ +        const verboseErrors = ['GNUPG_ERROR', 'CONN_NATIVEMESSAGE']; +        if (verboseErrors.includes(code) && typeof (msg) === 'string'){              super(msg);          } else if (err_list.hasOwnProperty(code)){              if (msg){ diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 106086fb..3c31a047 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -33,7 +33,7 @@ import { Connection } from './Connection';   * An unsuccessful attempt will reject as a GPGME_Error.   * @param {Object} config (optional) configuration options   * @param {Number} config.timeout set the timeout for the initial connection - * check. On some machines and operating systems a default timeout of 500 ms is + * check. On some machines and operating systems a default timeout of 1000 ms is   * too low, so a higher number might be attempted.   * @returns {Promise<GpgME>}   * @async @@ -46,7 +46,17 @@ function init ({ timeout = 1000 } = {}){                  if (result === true) {                      resolve(new GpgME());                  } else { -                    reject(gpgme_error('CONN_NO_CONNECT')); +                    if (connection._connectionError) { +                        if (connection.isNativeHostUnknown){ +                            reject(gpgme_error('CONN_NO_CONFIG')); +                        } else { +                            reject(gpgme_error('CONN_NATIVEMESSAGE', +                                connection._connectionError) +                            ); +                        } +                    } else { +                        reject(gpgme_error('CONN_TIMEOUT')); +                    }                  }              }, function (){ // unspecific connection error. Should not happen                  reject(gpgme_error('CONN_NO_CONNECT')); diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 414d18d1..45e2b93c 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -49,11 +49,42 @@ function unittests (){                      expect(answer.info).to.be.an('Array');                      expect(conn0.disconnect).to.be.a('function');                      expect(conn0.post).to.be.a('function'); +                    expect(conn0.isDisconnected).to.be.false;                      done();                  });          }); +        it('Simple connection check', function (done) { +            let conn0 = new Connection; +            conn0.checkConnection(false, connectionTimeout).then( +                function (answer) { +                    expect(answer).to.be.true; +                    expect(conn0.isDisconnected).to.be.false; +                    done(); +                }); +        }); + +        it('Connection check with backend information', function (done) { +            let conn0 = new Connection; +            conn0.checkConnection(true, connectionTimeout).then( +                function (answer) { +                    expect(answer).to.be.an('Object'); +                    expect(answer.gpgme).to.be.a('String'); +                    expect(answer.info).to.be.an('Array'); +                    expect(answer.info.length).to.be.above(0); +                    for (const item of answer.info) { +                        expect(item).to.have.property('protocol'); +                        expect(item).to.have.property('fname'); +                        expect(item).to.have.property('version'); +                        expect(item).to.have.property('req_version'); +                        expect(item).to.have.property('homedir'); +                    } +                    expect(conn0.isDisconnected).to.be.false; +                    done(); +                }); +        }); +          it('Disconnecting', function (done) {              let conn0 = new Connection;              conn0.checkConnection(false, connectionTimeout).then( @@ -63,6 +94,7 @@ function unittests (){                      conn0.checkConnection(false, connectionTimeout).then(                          function (result) {                              expect(result).to.be.false; +                            expect(conn0.isDisconnected).to.be.true;                              done();                          });                  }); | 
