[git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-61-g3c783bd
by Maximilian Krambach
cvs at cvs.gnupg.org
Thu Jun 14 12:15:42 CEST 2018
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 <maximilian.krambach at intevation.de>
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 <mkrambach at intevation.de>
+ */
+
+/**
+ * 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
More information about the Gnupg-commits
mailing list