js: change in Error behaviour
authorMaximilian Krambach <maximilian.krambach@intevation.de>
Wed, 25 Apr 2018 08:54:24 +0000 (10:54 +0200)
committerMaximilian Krambach <maximilian.krambach@intevation.de>
Wed, 25 Apr 2018 08:54:24 +0000 (10:54 +0200)
--

* Error objects will now return the error code if defined as error type
  in src/Errors.js, or do a console.log if it is a warning. Errors from
  the native gpgme-json will be marked as GNUPG_ERROR.

lang/js/src/Connection.js
lang/js/src/Errors.js
lang/js/src/Helpers.js
lang/js/src/Key.js
lang/js/src/Message.js
lang/js/src/gpgmejs.js
lang/js/src/gpgmejs_openpgpjs.js
lang/js/src/index.js

index e6ff67b..8bc3d42 100644 (file)
@@ -1,5 +1,3 @@
-import { GPGME_Message } from "./Message";
-
 /* gpgme.js - Javascript integration for gpgme
  * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
  *
@@ -26,7 +24,8 @@ import { GPGME_Message } from "./Message";
  * expected.
  */
 import { permittedOperations } from './permittedOperations'
-import { GPGMEJS_Error} from "./Errors"
+import { GPGMEJS_Error } from "./Errors"
+import { GPGME_Message } from "./Message";
 
 /**
  * A Connection handles the nativeMessaging interaction.
@@ -60,20 +59,20 @@ export class Connection{
 
     /**
      * Opens a nativeMessaging port.
-     * TODO: Error handling ALREADY_CONNECTED
      */
     connect(){
         if (this._isConnected === true){
-            return new GPGMEJS_Error('ALREADY_CONNECTED');
+            GPGMEJS_Error('CONN_ALREADY_CONNECTED');
+        } else {
+            this._isConnected = true;
+            this._connection = chrome.runtime.connectNative('gpgmejson');
+            let me = this;
+            this._connection.onDisconnect.addListener(
+                function(){
+                    me._isConnected = false;
+                }
+            );
         }
-        this._isConnected = true;
-        this._connection = chrome.runtime.connectNative('gpgmejson');
-        let me = this;
-        this._connection.onDisconnect.addListener(
-            function(){
-                me._isConnected = false;
-            }
-        );
     }
 
     /**
@@ -84,28 +83,31 @@ export class Connection{
      */
     post(message){
         if (!this.isConnected){
-            return Promise.reject(new GPGMEJS_Error('NO_CONNECT'));
+            return Promise.reject(GPGMEJS_Error('CONN_NO_CONNECT'));
         }
         if (!message || !message instanceof GPGME_Message){
-            return Promise.reject(new GPGMEJS_Error('WRONGPARAM'));
+            return Promise.reject(GPGMEJS_Error('PARAM_WRONG'), message);
         }
         if (message.isComplete !== true){
-            return Promise.reject(new GPGMEJS_Error('MSG_INCOMPLETE'));
+            return Promise.reject(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'));
+                    reject(GPGMEJS_Error('CONN_EMPTY_GPG_ANSWER'));
                 } else if (msg.type === "error"){
                     me._connection.onMessage.removeListener(listener)
-                    //TODO: GPGMEJS_Error?
-                    reject(msg.msg);
+                    reject(
+                        {code: 'GNUPG_ERROR',
+                         msg: msg.msg} );
                 } else {
-                    answer.add(msg);
+                    let answer_result = answer.add(msg);
+                    if (answer_result !== true){
+                        reject(answer_result);
+                    }
                     if (msg.more === true){
                         me._connection.postMessage({'op': 'getmore'});
                     } else {
@@ -117,11 +119,12 @@ export class Connection{
 
             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));
+            //         reject(GPGMEJS_Error('CONN_TIMEOUT'));
             //     }, timeout);
         });
      }
@@ -141,6 +144,7 @@ class Answer{
     /**
      * Add the information to the answer
      * @param {Object} msg The message as received with nativeMessaging
+     * returns true if successfull, GPGMEJS_Error otherwise
      */
     add(msg){
         if (this._response === undefined){
@@ -148,12 +152,15 @@ class Answer{
         }
         let messageKeys = Object.keys(msg);
         let poa = permittedOperations[this.operation].answer;
+        if (messageKeys.length === 0){
+            return GPGMEJS_Error('CONN_UNEXPECTED_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');
+                        return GPGMEJS_Error('CONN_UNEXPECTED_ANSWER');
                     }
                     break;
                 case 'more':
@@ -172,7 +179,7 @@ class Answer{
                             this._response[key] = msg[key];
                         }
                         else if (this._response[key] !== msg[key]){
-                                return new GPGMEJS_Error('UNEXPECTED_ANSWER',msg[key]);
+                                return GPGMEJS_Error('CONN_UNEXPECTED_ANSWER',msg[key]);
                         }
                     }
                     //infos may be json objects etc. Not yet defined.
@@ -184,11 +191,12 @@ class Answer{
                         this._response.push(msg[key]);
                     }
                     else {
-                        return new GPGMEJS_Error('UNEXPECTED_ANSWER', key);
+                        return GPGMEJS_Error('CONN_UNEXPECTED_ANSWER', key);
                     }
                     break;
             }
         }
+        return true;
     }
 
     /**
index c2356f7..c49bfe2 100644 (file)
  * SPDX-License-Identifier: LGPL-2.1+
  */
 
-// This is a preliminary collection of erors and warnings to be thrown and implemented.
-
-// general idea: if throw , throw the NAME
-// return false || 'return' property
-
-//TODO: Connection.NOCONNECT promise
-//connection.timeout: Be aware of pinentry
-
-export class GPGMEJS_Error {
-
-    constructor(code = 'GENERIC_ERROR', details){
-        let config = { //TODO TEMP
-            debug: 'console', // |'alert'
-            throw: 'default'  // | 'always' | 'never'
-        };
+/**
+ * Checks the given error code and returns some information about it's meaning
+ * @param {String} code The error code
+ * @returns {Object} An object containing string properties code and msg
+ * TODO: error-like objects with the code 'GNUPG_ERROR' are errors sent
+ * directly by gnupg as answer in Connection.post()
+ */
+export function GPGMEJS_Error(code = 'GENERIC_ERROR'){
+        if (!typeof(code) === 'string'){
+            code = 'GENERIC_ERROR';
+        }
         let errors = { //TODO: someplace else
-            //Connection errors
-            'ALREADY_CONNECTED':{
-                msg: 'The connection was already established. The action would overwrite the context',
-                throw: true
+            // Connection
+            'CONN_NO_CONNECT': {
+                msg:'Connection with the nativeMessaging host could not be'
+                    + ' established.',
+                type: 'error'
             },
-            'NO_CONNECT': {
-                msg:'Connection with the nativeMessaging host could not be established.',
-                throw: true
+            'CONN_EMPTY_GPG_ANSWER':{
+                msg: 'The nativeMessaging answer was empty.',
+                type: 'error'
             },
-            'EMPTY_GPG_ANSWER':{
-                msg: 'The nativeMesaging answer was empty',
-                throw: true
+            'CONN_TIMEOUT': {
+                msg: 'A connection timeout was exceeded.',
+                type: 'error'
             },
-            'TIMEOUT': {
-                msg: 'A timeout was exceeded.',
-                throw: false
+            'CONN_UNEXPECTED_ANSWER': {
+                msg: 'The answer from gnupg was not as expected.',
+                type: 'error'
             },
-
-            'UNEXPECTED_ANSWER': {
-                msg: 'The answer from gnupg was not as expected',
-                throw: true
-            },
-
-            // Message/Data Errors
-
-            'NO_KEYS' : {
-                msg: 'There were no valid keys provided.',
-                throw: true
-            },
-            'NOT_A_FPR': {
-                msg: 'The String is not an accepted fingerprint',
-                throw: false
+            'CONN_ALREADY_CONNECTED':{
+                msg: 'A connection was already established.',
+                type: 'warn'
             },
+            // Message/Data
             'MSG_INCOMPLETE': {
-                msg: 'The Message did not match the minimum requirements for the interaction',
-                throw: true
-            },
-            'EMPTY_MSG' : {
-                msg: 'The Message has no data.',
-                throw: true
+                msg: 'The Message did not match the minimum requirements for'
+                    + ' the interaction.',
+                type: 'error'
             },
-            'MSG_NODATA':{
-                msg: 'The data sent is empty. This may be unintentional.',
-                throw: false
+            'MSG_EMPTY' : {
+                msg: 'The Message is empty.',
+                type: 'error'
             },
             'MSG_OP_PENDING': {
-                msg: 'There is no operation specified yet. The parameter cannot be set',
-                throw: false
+                msg: 'There is no operation specified yet. The parameter cannot'
+                    + ' be set',
+                type: 'warning'
             },
-            'WRONG_OP': {
-                msg: "The operation requested could not be found",
-                throw: true
+            'MSG_WRONG_OP': {
+                msg: 'The operation requested could not be found',
+                type: 'warning'
+            },
+            'MSG_NO_KEYS' : {
+                msg: 'There were no valid keys provided.',
+                type: 'warn'
+            },
+            'MSG_NOT_A_FPR': {
+                msg: 'The String is not an accepted fingerprint',
+                type: 'warn'
             },
 
-            //generic errors
-
-            'WRONGPARAM':{
+            // generic
+            'PARAM_WRONG':{
                 msg: 'invalid parameter was found',
-                throw: true
-            },
-            'WRONGTYPE':{
-                msg: 'invalid parameter type was found',
-                throw: true
+                type: 'error'
             },
             'NOT_IMPLEMENTED': {
                 msg: 'A openpgpjs parameter was submitted that is not implemented',
-                throw: true
+                type: 'error'
+            },
+            'NOT_YET_IMPLEMENTED': {
+                msg: 'Support of this is probable, but it is not implemented yet',
+                type: 'error'
             },
             'GENERIC_ERROR': {
                 msg: 'Unspecified error',
-                throw: true
+                type: 'error'
             },
-
-            // hopefully temporary errors
-
-            'NOT_YET_IMPLEMENTED': {
-                msg: 'Support of this is probable, but it is not implemented yet',
-                throw: false
-            }
-        }
-        if (!errors.hasOwnProperty(code)){
-            throw('GENERIC_ERROR');
         }
-        let msg = code;
-        if (errors[code].msg !== undefined){
-            msg = msg + ': ' + errors[code].msg;
+        if (code === 'TODO'){
+            alert('TODO_Error!');
         }
-        if (details){
-            msg = msg + ' ' + details;
+        if (errors.hasOwnProperty(code)){
+            code = 'GENERIC_ERROR';
         }
-        if (config.debug === 'console'){
-            console.log(msg);
-        } else if (config.debug === 'alert'){
-            alert(msg);
+        if (error.type === 'error'){
+            return {code: 'code',
+                    msg: errors[code].msg
+                };
         }
-        switch (config.throw) {
-            case 'default':
-                if (errors[code].throw === true){
-                    throw(code);
-                }
-                break;
-            case 'always':
-                throw(code);
-                break;
-
-            case 'never':
-                break;
-            default:
-                throw('GENERIC_ERROR');
+        if (error.type === 'warning'){
+            console.log(code + ': ' + error[code].msg);
         }
-    }
+        return undefined;
 }
index 922ca06..d9750ba 100644 (file)
@@ -1,5 +1,3 @@
-import { GPGMEJS_Error } from "./Errors";
-
 /* gpgme.js - Javascript integration for gpgme
  * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
  *
@@ -19,18 +17,19 @@ import { GPGMEJS_Error } from "./Errors";
  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: LGPL-2.1+
  */
+import { GPGMEJS_Error } from "./Errors";
 
 /**
  * Tries to return an array of fingerprints, either from input fingerprints or
  * from Key objects
  * @param {Key |Array<Key>| GPGME_Key | Array<GPGME_Key>|String|Array<String>} input
- * @param {Boolean} nocheck if set, an empty result is acceptable
  * @returns {Array<String>} Array of fingerprints.
  */
 
 export function toKeyIdArray(input, nocheck){
     if (!input){
-        return (nocheck ===true)? [] : new GPGMEJS_Error('NO_KEYS');
+        GPGMEJS_Error('MSG_NO_KEYS');
+        return [];
     }
     if (!Array.isArray(input)){
         input = [input];
@@ -41,7 +40,7 @@ export function toKeyIdArray(input, nocheck){
             if (isFingerprint(input[i]) === true){
                 result.push(input[i]);
             } else {
-                GPGMEJS_Error
+                GPGMEJS_Error('MSG_NOT_A_FPR');
             }
         } else if (typeof(input[i]) === 'object'){
             let fpr = '';
@@ -53,13 +52,16 @@ export function toKeyIdArray(input, nocheck){
             }
             if (isFingerprint(fpr) === true){
                 result.push(fpr);
+            } else {
+                GPGMEJS_Error('MSG_NOT_A_FPR');
             }
         } else {
-            return new GPGMEJS_Error('WRONGTYPE');
+            return GPGMEJS_Error('PARAM_WRONG');
         }
     }
     if (result.length === 0){
-        return (nocheck===true)? [] : new GPGMEJS_Error('NO_KEYS');
+        GPGMEJS_Error('MSG_NO_KEYS');
+        return [];
     } else {
         return result;
     }
index f59b990..5ae8043 100644 (file)
@@ -172,7 +172,7 @@ export class GPGME_Key {
  *
  */
 function checkKey(fingerprint, property){
-    return Promise.reject(new GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
+    return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
 
     return new Promise(function(resolve, reject){
         if (!isFingerprint(fingerprint)){
index f5e21e0..1b36f11 100644 (file)
@@ -39,20 +39,20 @@ export class GPGME_Message {
      */
     setParameter(param,value){
         if (!param || typeof(param) !== 'string'){
-            return new GPGMEJS_Error('WRONGPARAM', 'type check failed');
+            return GPGMEJS_Error('PARAM_WRONG');
         }
         if (!this._msg || !this._msg.op){
-            return new GPGMEJS_Error('MSG_OP_PENDING');
+            return GPGMEJS_Error('MSG_OP_PENDING');
         }
         let po = permittedOperations[this._msg.op];
         if (!po){
-            return new GPGMEJS_Error('WRONG_OP', param);
+            return GPGMEJS_Error('MSG_WRONG_OP');
         }
         if (po.required.indexOf(param) >= 0 || po.optional.indexOf(param) >= 0){
             this._msg[param] = value;
             return true;
         }
-        return new GPGMEJS_Error('WRONGPARAM', param);
+        return GPGMEJS_Error('PARAM_WRONG');
     }
 
     /**
@@ -98,7 +98,7 @@ export class GPGME_Message {
  */
 function setOperation (scope, operation){
     if (!operation || typeof(operation) !== 'string'){
-        return new GPGMEJS_Error('WRONGTYPE');
+        return GPGMEJS_Error('PARAM_WRONG');
     }
     if (permittedOperations.hasOwnProperty(operation)){
         if (!scope._msg){
@@ -106,6 +106,6 @@ function setOperation (scope, operation){
         }
         scope._msg.op = operation;
     } else {
-        return new GPGMEJS_Error('WRONG_OP');
+        return GPGMEJS_Error('MSG_WRONG_OP');
     }
 }
\ No newline at end of file
index 03ed5cb..b20ff0f 100644 (file)
@@ -95,9 +95,8 @@ export class GpgME {
     */
 
     decrypt(data){
-
         if (data === undefined){
-            return Promise.reject(new GPGMEJS_Error ('EMPTY_MSG'));
+            return Promise.reject(GPGMEJS_Error('MSG_EMPTY'));
         }
         let msg = new GPGME_Message('decrypt');
         putData(msg, data);
@@ -106,7 +105,7 @@ export class GpgME {
     }
 
     deleteKey(key, delete_secret = false, no_confirm = false){
-        return Promise.reject(new GPGMEJS_Error ('NOT_YET_IMPLEMENTED'));
+        return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
         let msg = new GPGME_Message('deletekey');
         let key_arr = toKeyIdArray(key);
         if (key_arr.length !== 1){
@@ -127,7 +126,7 @@ export class GpgME {
             case 'ERR_NO_ERROR':
                 return Promise.resolve('okay'); //TBD
             default:
-                return Promise.reject(new GPGMEJS_Error);
+                return Promise.reject(GPGMEJS_Error('TODO') ); //
                 // INV_VALUE,
                 // GPG_ERR_NO_PUBKEY,
                 // GPG_ERR_AMBIGUOUS_NAME,
@@ -146,11 +145,9 @@ export class GpgME {
  */
 function putData(message, data){
     if (!message || !message instanceof GPGME_Message ) {
-        return new GPGMEJS_Error('WRONGPARAM');
+        return GPGMEJS_Error('PARAM_WRONG');
     }
     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');
@@ -167,6 +164,6 @@ function putData(message, data){
             message.setParameter ('data', decoder.decode(txt));
         }
     } else {
-        return new GPGMEJS_Error('WRONGPARAM');
+        return GPGMEJS_Error('PARAM_WRONG');
     }
 }
index 2307656..e32f43a 100644 (file)
             || signature !== null
             || returnSessionKey !== null
             || date !== null){
-            return Promise.reject(new GPMGEJS_Error('NOT_IMPLEMENTED'));
+            return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED'));
         }
         if ( privateKeys
             || filename
             || compression
             || armor === false
             || detached == true){
-                return Promise.reject(new GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
+                return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
         }
         return this.GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard);
     }
         if (passwords !== undefined
             || sessionKeys
             || date){
-            return Promise.reject(new GPGMEJS_Error('NOT_IMPLEMENTED'));
+            return Promise.reject(GPGMEJS_Error('NOT_IMPLEMENTED'));
         }
         if ( privateKeys
             || publicKeys
             || format !== 'utf8'
             || signature
         ){
-            return Promise.reject(new GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
+            return Promise.reject(GPGMEJS_Error('NOT_YET_IMPLEMENTED'));
         }
         return this.GpgME.decrypt(message);
         // TODO: translate between:
@@ -185,7 +185,7 @@ class GPGME_Keyring_openpgpmode {
             else {
                 // TODO: Can there be "no default key"?
                 // TODO: Can there be several default keys?
-                return new GPGMEJS_Error; //TODO
+                return GPGMEJS_Error('TODO');
             }
         });
     }
@@ -202,10 +202,10 @@ class GPGME_Keyring_openpgpmode {
      */
     deleteKey(key){
         if (typeof(key) !== "object"){
-            return Promise.reject(new GPGMEJS_Error('WRONGPARAM'));
+            return Promise.reject(GPGMEJS_Error('PARAM_WRONG'));
         }
         if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){
-            return Promise.reject(new GPGMEJS_Error('WRONGPARAM'));
+            return Promise.reject(GPGMEJS_Error('PARAM_WRONG'));
         }
         let key_to_delete = new GPGME_Key(key.fingerprint);
         return key_to_delete.deleteKey(key.secret);
index 0cb2301..a54277c 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 import { GpgME } from "./gpgmejs";
+import { GPGMEJS_Error } from "./Errors";
 import { GpgME_openpgpmode } from "./gpgmejs_openpgpjs";
 import { Connection } from "./Connection";
 
@@ -45,7 +46,7 @@ function init( config = {
                         resolve(new GpgME(connection));
                     }
                 } else {
-                    reject('NO_CONNECT');
+                    reject(GPGMEJS_Error('CONN_NO_CONNECT'));
                 }
             };
             setTimeout(delayedreaction, 5);