[git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-61-g3c783bd

[email protected] (by Maximilian Krambach)
Newsgroups gmane.comp.encryption.gpg.cvs
Message-ID <[email protected]>
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, javascript-binding has been updated
       via  3c783bd09ce54b0d50dc3bea201e70e4fcbbf6a3 (commit)
      from  aed402c5d572b60246f1f8e57ae269f8c91b0b7c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 3c783bd09ce54b0d50dc3bea201e70e4fcbbf6a3
Author: Maximilian Krambach <[email protected]>
Date:   Thu Jun 14 12:15:51 2018 +0200

    js: add verify and signature parsing
    
    --
    
    * src/gpgmejs.js:
      - Added verify method
      - Added verification results in decrypt (if signatures are present
        in the message)
      - Added a base64 option to decrypt
    
    * src/Signature.js: Convenience class for verification results. Used
       for e.g. converting timestamps to javascript time, quick overall
       validity checks
    
    * src/Keyring.js: removed debug code
    
    * src/Errors.js add two new Signature errors

diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js
index 73e7438..a8cd8b5 100644
--- a/lang/js/src/Errors.js
+++ b/lang/js/src/Errors.js
@@ -83,6 +83,14 @@ const err_list = {
             'configuration',
         type: 'error'
     },
+    'SIG_WRONG': {
+        msg:'A malformed signature was created',
+        type: 'error'
+    },
+    'SIG_NO_SIGS': {
+        msg:'There were no signatures found',
+        type: 'error'
+    },
     // generic
     'PARAM_WRONG':{
         msg: 'Invalid parameter was found',
diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js
index e07a593..451f936 100644
--- a/lang/js/src/Keyring.js
+++ b/lang/js/src/Keyring.js
@@ -135,8 +135,6 @@ export class GPGME_Keyring {
                     // and probably performance, too
                     me.getKeys(null,true).then(function(keys){
                         for (let i=0; i < keys.length; i++){
-                            console.log(keys[i]);
-                            console.log(keys[i].get('hasSecret'));
                             if (keys[i].get('hasSecret') === true){
                                 resolve(keys[i]);
                                 break;
diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js
new file mode 100644
index 0000000..d7d0598
--- /dev/null
+++ b/lang/js/src/Signature.js
@@ -0,0 +1,193 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author(s):
+ *     Maximilian Krambach <[email protected]>
+ */
+
+/**
+ * Validates a signature object and returns
+ * @param {Object} sigObject Object as returned by gpgme-json. The definition
+ * of the expected values are to be found in the constants 'expKeys', 'expSum',
+ * 'expNote' in this file.
+ * @returns {GPGME_Signature} Signature Object
+ */
+
+import { gpgme_error } from './Errors';
+
+export function createSignature(sigObject){
+    if (
+        typeof(sigObject) !=='object' ||
+        !sigObject.hasOwnProperty('summary') ||
+        !sigObject.hasOwnProperty('fingerpprint') ||
+        !sigObject.hasOwnProperty('timestamp')
+        //TODO check if timestamp is mandatory in specification
+    ){
+        return gpgme_error('SIG_WRONG');
+    }
+    let keys = Object.keys(sigObject);
+    for (let i=0; i< keys.length; i++){
+        if ( typeof(sigObject[keys[i]]) !== expKeys[keys[i]] ){
+            return gpgme_error('SIG_WRONG');
+        }
+    }
+    let sumkeys = Object.keys(sigObject.summary);
+    for (let i=0; i< sumkeys.length; i++){
+        if ( typeof(sigObject.summary[sumkeys[i]]) !== expSum[sumkeys[i]] ){
+            return gpgme_error('SIG_WRONG');
+        }
+    }
+    if (sigObject.hasOwnProperty('notations')){
+        if (!Array.isArray(sigObject.notations)){
+            return gpgme_error('SIG_WRONG');
+        }
+        for (let i=0; i < sigObject.notations.length; i++){
+            let notation = sigObject.notations[i];
+            let notekeys = Object.keys(notation);
+            for (let j=0; j < notekeys.length; j++){
+                if ( typeof(notation[notekeys[j]]) !== expNote[notekeys[j]] ){
+                    return gpgme_error('SIG_WRONG');
+                }
+            }
+        }
+    }
+    return new GPGME_Signature(sigObject);
+}
+
+
+/**
+ * Representing the details of a signature. It is supposed to be read-only. The
+ * full details as given by gpgme-json can be accessed from the _rawSigObject.
+ * )
+ */
+class GPGME_Signature {
+    constructor(sigObject){
+        this._rawSigObject = sigObject;
+    }
+
+    /**
+     * The signatures' fingerprint
+     */
+    get fingerprint(){
+        return this._rawSigObject.fingerprint;
+    }
+
+    /**
+     * The expiration of this Signature as Javascript date, or null if
+     * signature does not expire
+     * @returns {Date | null}
+     */
+    get expiration(){
+        if (!this._rawSigObject.exp_timestamp){
+            return null;
+        }
+        return new Date(this._rawSigObject.exp_timestamp* 1000);
+    }
+
+    /**
+     * The creation date of this Signature in Javascript Date
+     * @returns {Date}
+     */
+    get timestamp(){
+        return new Date(this._rawSigObject.timestamp* 1000);
+    }
+
+    /**
+     * The overall validity of the key. If false, errorDetails may contain
+     * additional information
+     */
+    get valid() {
+        if (this._rawSigObject.valid === true){
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * gives more information on non-valid signatures. Refer to the gpgme docs
+     * https://www.gnupg.org/documentation/manuals/gpgme/Verify.html for
+     * details on the values
+     * @returns {Object} Object with boolean properties
+     */
+    get errorDetails(){
+        let properties = ['revoked', 'key-expired', 'sig-expired',
+            'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy',
+            'sys-error'];
+        let result = {};
+        for (let i=0; i< properties.length; i++){
+            if ( this._rawSigObject.hasOwnProperty(properties[i]) ){
+                result[properties[i]] = this._rawSigObject[properties[i]];
+            }
+        }
+        return result;
+    }
+
+}
+
+/**
+ * Keys and their value's type for the signature Object
+ */
+const expKeys = {
+    'wrong_key_usage': 'boolean',
+    'chain_model': 'boolean',
+    'summary': 'object',
+    'is_de_vs': 'boolean',
+    'status_string':'string',
+    'fingerprint':'string',
+    'validity_string': 'string',
+    'pubkey_algo_name':'string',
+    'hash_algo_name':'string',
+    'pka_address':'string',
+    'status_code':'number',
+    'timestamp':'number',
+    'exp_timestamp':'number',
+    'pka_trust':'number',
+    'validity':'number',
+    'validity_reason':'number',
+    'notations': 'object'
+};
+
+/**
+ * Keys and their value's type for the summary
+ */
+const expSum = {
+    'valid': 'boolean',
+    'green': 'boolean',
+    'red': 'boolean',
+    'revoked': 'boolean',
+    'key-expired': 'boolean',
+    'sig-expired': 'boolean',
+    'key-missing': 'boolean',
+    'crl-missing': 'boolean',
+    'crl-too-old': 'boolean',
+    'bad-policy': 'boolean',
+    'sys-error': 'boolean'
+};
+
+/**
+ * Keys and their value's type for notations objects
+ */
+const expNote = {
+    'human_readable': 'boolean',
+    'critical':'boolean',
+    'name': 'string',
+    'value': 'string',
+    'flags': 'number'
+};
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index 7fa7643..a0f7e96 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -26,6 +26,7 @@ import {GPGME_Message, createMessage} from './Message';
 import {toKeyIdArray} from './Helpers';
 import { gpgme_error } from './Errors';
 import { GPGME_Keyring } from './Keyring';
+import { createSignature } from './Signature';
 
 export class GpgME {
     /**
@@ -107,15 +108,28 @@ export class GpgME {
     * Decrypt a Message
     * @param {String|Object} data text/data to be decrypted. Accepts Strings
     *  and Objects with a getText method
-    * @returns {Promise<Object>} decrypted message:
-        data:   The decrypted data.
-        base64: Boolean indicating whether data is base64 encoded.
-        mime:   A Boolean indicating whether the data is a MIME object.
-        signatures: Array of signature Objects TODO not yet implemented.
-            // should be an object that can tell if all signatures are valid.
+    * @param {Boolean} base64 (optional) false if the data is an armored block,
+    *   true if it is base64 encoded binary data
+    * @returns {Promise<Object>} result: Decrypted Message and information
+    * @returns {String} result.data: The decrypted data.
+    * @returns {Boolean} result.base64: indicating whether data is base64
+    *   encoded.
+    * @returns {Boolean} result.is_mime: Indicating whether the data is a MIME
+    *   object.
+    * @returns {String} result.file_name: The optional original file name
+    * @returns {Object} message.signatures Verification details for signatures:
+    * @returns {Boolean} message.signatures.all_valid: true if all signatures
+    *   are valid
+    * @returns {Number} message.signatures.count: Number of signatures found
+    * @returns {Number} message.signatures.failures Number of invalid
+    *   signatures
+    * @returns {Array<Object>} message.signatures.signatures. Two arrays
+    *   (good & bad) of {@link GPGME_Signature} objects, offering further
+    *   information.
+    *
     * @async
     */
-    decrypt(data){
+    decrypt(data, base64=false){
         if (data === undefined){
             return Promise.reject(gpgme_error('MSG_EMPTY'));
         }
@@ -124,8 +138,32 @@ export class GpgME {
         if (msg instanceof Error){
             return Promise.reject(msg);
         }
+        if (base64 === true){
+            msg.setParameter('base64', true);
+        }
         putData(msg, data);
-        return msg.post();
+        if (base64 === true){
+            msg.setParameter('base64', true);
+        }
+        return new Promise(function(resolve, reject){
+            msg.post().then(function(result){
+                let _result = {data: result.data};
+                _result.base64 = result.base64 ? true: false;
+                _result.is_mime = result.mime ? true: false;
+                if (result.file_name){
+                    _result.file_name = result.file_name;
+                }
+                if (
+                    result.hasOwnProperty('signatures') &&
+                    Array.isArray(result.signatures)
+                ) {
+                    _result.signatures = collectSignatures(result.signatures);
+                }
+                resolve(_result);
+            }, function(error){
+                reject(error);
+            });
+        });
     }
 
     /**
@@ -179,6 +217,59 @@ export class GpgME {
             });
         });
     }
+
+    /**
+     * Verifies data.
+     * @param {String|Object} data text/data to be verified. Accepts Strings
+     * and Objects with a gettext method
+     * @param {String} (optional) A detached signature. If not present, opaque
+     * mode is assumed
+     * @param {Boolean} (optional) Data and signature are base64 encoded
+     * // TODO verify if signature really is assumed to be base64
+     * @returns {Promise<Object>} result:
+     * @returns {Boolean} result.data: The verified data
+     * @returns {Boolean} result.is_mime: The message claims it is MIME
+     * @returns {String} result.file_name: The optional filename of the message
+     * @returns {Boolean} result.all_valid: true if all signatures are valid
+     * @returns {Number} result.count: Number of signatures found
+     * @returns {Number} result.failures Number of unsuccessful signatures
+     * @returns {Array<Object>} result.signatures. Two arrays (good & bad) of
+     *      {@link GPGME_Signature} objects, offering further information.
+     */
+    verify(data, signature, base64 = false){
+        let msg = createMessage('verify');
+        let dt = this.putData(msg, data);
+        if (dt instanceof Error){
+            return Promise.reject(dt);
+        }
+        if (signature){
+            if (typeof(signature)!== 'string'){
+                return Promise.reject(gpgme_error('PARAM_WRONG'));
+            } else {
+                msg.setParameter('signature', signature);
+            }
+        }
+        if (base64 === true){
+            msg.setParameter('base64', true);
+        }
+        return new Promise(function(resolve, reject){
+            msg.post().then(function (message){
+                if (!message.info.signatures){
+                    reject(gpgme_error('SIG_NO_SIGS'));
+                } else {
+                    let _result = collectSignatures(message.info.signatures);
+                    _result.is_mime = message.info.is_mime? true: false;
+                    if (message.info.filename){
+                        _result.file_name = message.info.filename;
+                    }
+                    _result.data = message.data;
+                    resolve(_result);
+                }
+            }, function(error){
+                reject(error);
+            });
+        });
+    }
 }
 
 /**
@@ -209,3 +300,34 @@ function putData(message, data){
         return gpgme_error('PARAM_WRONG');
     }
 }
+
+function collectSignatures(sigs){
+    if (!Array.isArray(sigs)){
+        return gpgme_error('SIG_NO_SIGS');
+    }
+    let summary = {
+        all_valid: false,
+        count: sigs.length,
+        failures: 0,
+        signatures: {
+            good: [],
+            bad: [],
+        }
+    };
+    for (let i=0; i< sigs.length; i++){
+        let sigObj = createSignature(sigs[i]);
+        if (sigObj instanceof Error){
+            return gpgme_error('SIG_WRONG');
+        }
+        if (sigObj.valid !== true){
+            summary.failures += 1;
+            summary.signatures.bad.push(sigObj);
+        } else {
+            summary.signatures.good.push(sigObj);
+        }
+    }
+    if (summary.failures === 0){
+        summary.all_valid = true;
+    }
+    return summary;
+}
\ No newline at end of file

-----------------------------------------------------------------------

Summary of changes:
 lang/js/src/Errors.js    |   8 ++
 lang/js/src/Keyring.js   |   2 -
 lang/js/src/Signature.js | 193 +++++++++++++++++++++++++++++++++++++++++++++++
 lang/js/src/gpgmejs.js   | 138 +++++++++++++++++++++++++++++++--
 4 files changed, 331 insertions(+), 10 deletions(-)
 create mode 100644 lang/js/src/Signature.js


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
[email protected]
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.