diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js
new file mode 100644
index 00000000..e6000003
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/encryptTest.js
@@ -0,0 +1,71 @@
+/* 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+describe('Encryption', function(){
+
+ it('Successfull encrypt', function(done){
+ let prm = Gpgmejs.init();
+ prm.then(function(context){
+ context.encrypt(
+ inputvalues.encrypt.good.data,
+ inputvalues.encrypt.good.fingerprint).then(function(answer){
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a("string");
+ expect(answer.data).to.include('BEGIN PGP MESSAGE');
+ expect(answer.data).to.include('END PGP MESSAGE');
+ done();
+ }, function(err){
+ expect(err).to.be.undefined;
+ done();
+ });
+ });
+ });
+
+ it('Sending encryption without keys fails', function(){
+ let prm = Gpgmejs.init();
+ prm.then(function(context){
+ context.encrypt(
+ inputvalues.encrypt.good.data,
+ null).then(function(answer){
+ expect(answer).to.be.undefined;
+ done();
+ }, function(error){
+ expect(error).to.be.an('Error');
+ expect(error.code).to.equal('MSG_INCOMPLETE');
+ done()
+ });
+ });
+ });
+
+ it('Sending encryption without data fails', function(){
+ let prm = Gpgmejs.init();
+ prm.then(function(context){
+ context.encrypt(
+ null,inputvalues.encrypt.good.keyid).then(function(answer){
+ expect(answer).to.be.undefined;
+ }, function(error){
+ expect(error).to.be.an.instanceof(Error);
+ expect(error.code).to.equal('MSG_INCOMPLETE');
+ done();
+ });
+ });
+ });
+
+ // TODO check different valid parameter
+});
diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js
index 47600c84..1761c82f 100644
--- a/lang/js/BrowserTestExtension/tests/inputvalues.js
+++ b/lang/js/BrowserTestExtension/tests/inputvalues.js
@@ -22,7 +22,11 @@ var inputvalues = {
encrypt: {
good:{
data : 'Hello World.',
- keyid : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40'
+ fingerprint : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40'
}
+ },
+ init: {
+ invalid_startups: [{all_passwords: true}, 'openpgpmode', {api_style:"frankenstein"}]
}
+
};
diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js
index 14d12c0a..a5614a83 100644
--- a/lang/js/BrowserTestExtension/tests/startup.js
+++ b/lang/js/BrowserTestExtension/tests/startup.js
@@ -20,32 +20,51 @@
describe('GPGME context', function(){
it('Starting a GpgME instance', function(done){
- Gpgmejs.init().then(
+ let prm = Gpgmejs.init();
+ prm.then(
function(context){
- expect(context.connection).to.not.be.undefined;
- expect(context).to.be.an('object');
- expect(context.connection).to.be.an('object');
- expect(context.Keyring).to.be.undefined;
- expect(context.encrypt).to.be.a('function');
- expect(context.decrypt).to.be.a('function');
- done();
- }, function(err){
- done(err);
- });
- });
- it('Starting an openpgp mode GPGME instance', function(done){
- Gpgmejs.init({api_style:"gpgme_openpgpjs"}).then(
- function(context){
- console.log(context);
+ expect(context.connection).to.not.be.undefined;
+ expect(context).to.be.an('object');
+ expect(context.connection).to.be.an('object');
+ expect(context.Keyring).to.be.undefined;
+ expect(context.encrypt).to.be.a('function');
+ expect(context.decrypt).to.be.a('function');
+ done();
+ }, function(errorr){
+ expect(error).to.be.undefined;
done();
- // expect(context).to.be.an('object');
- // expect(context.connection).to.be.undefined;
- // expect(context.Keyring).to.be.an('object');
- // expect(context.encrypt).to.be.a('function');
- // expect(context.decrypt).to.be.a('function');
- // done();
- }, function(err){
- done(err);
});
});
- });
+});
+describe('openpgp mode', function(){
+ it('startup of openpgp mode returns the correct parameters', function(done){
+ let prm = Gpgmejs.init({api_style:"gpgme_openpgpjs"});
+ prm.then(function(context){
+ expect(context).to.be.an('object');
+ expect(context.connection).to.be.undefined;
+ expect(context.Keyring).to.be.an('object');
+ expect(context.encrypt).to.be.a('function');
+ expect(context.decrypt).to.be.a('function');
+ done();
+ }, function(error){
+ expect(error).to.be.undefined;
+ done();
+ });
+ });
+});
+
+describe('GPGME does not start with invalid parameters', function(){
+ for (let i=0; i < inputvalues.init.invalid_startups.length; i++){
+ it('Parameter '+ i, function(done){
+ let prm = Gpgmejs.init(inputvalues.init.invalid_startups[i]);
+ prm.then(function(context){
+ expect(context).to.be.undefined;
+ done();
+ }, function(error){
+ expect(error).to.be.an.instanceof(Error);
+ expect(error.code).to.equal('PARAM_WRONG');
+ done();
+ });
+ })
+ }
+});
\ No newline at end of file
diff --git a/lang/js/build_extensions.sh b/lang/js/build_extensions.sh
index be7b0584..b99a362c 100755
--- a/lang/js/build_extensions.sh
+++ b/lang/js/build_extensions.sh
@@ -6,6 +6,7 @@ cp node_modules/chai/chai.js \
node_modules/mocha/mocha.css \
node_modules/mocha/mocha.js \
build/gpgmejs.bundle.js BrowserTestExtension/libs
+rm -rf build/extensions
mkdir -p build/extensions
zip -r build/extensions/browsertest.zip BrowserTestExtension
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
index a10f9d9a..a198bdc6 100644
--- a/lang/js/src/Connection.js
+++ b/lang/js/src/Connection.js
@@ -100,9 +100,7 @@ export class Connection{
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
} else if (msg.type === "error"){
me._connection.onMessage.removeListener(listener)
- reject(
- {code: 'GNUPG_ERROR',
- msg: msg.msg} );
+ reject(gpgme_error('GNUPG_ERROR', msg.msg));
} else {
let answer_result = answer.add(msg);
if (answer_result !== true){
@@ -129,6 +127,8 @@ export class Connection{
}, 5000);
}]).then(function(result){
return result;
+ }, function(error){
+ return error;
});
}
});
diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js
index 0b44b245..30449d63 100644
--- a/lang/js/src/Key.js
+++ b/lang/js/src/Key.js
@@ -51,10 +51,7 @@ export class GPGME_Key {
* hasSecret returns true if a secret subkey is included in this Key
*/
get hasSecret(){
- checkKey(this._fingerprint, 'secret').then( function(result){
- return Promise.resolve(result);
- });
-
+ return checkKey(this._fingerprint, 'secret');
}
get isRevoked(){
@@ -130,6 +127,8 @@ export class GPGME_Key {
}
}
return Promise.resolve(resultset);
+ }, function(error){
+ //TODO checkKey fails
});
}
@@ -175,8 +174,7 @@ export class GPGME_Key {
*/
function checkKey(fingerprint, property){
return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED'));
- if (!property ||
- permittedOperations[keyinfo].indexOf(property) < 0){
+ if (!property || !permittedOperations[keyinfo].hasOwnProperty(property)){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
return new Promise(function(resolve, reject){
@@ -188,19 +186,20 @@ function checkKey(fingerprint, property){
reject(gpgme_error('PARAM_WRONG'));
}
msg.setParameter('fingerprint', this.fingerprint);
- return (this.connection.post(msg)).then(function(result){
- if (result.hasOwnProperty(property)){
+ return (this.connection.post(msg)).then(function(result, error){
+ if (error){
+ reject(gpgme_error('GNUPG_ERROR',error.msg));
+ } else if (result.hasOwnProperty(property)){
resolve(result[property]);
}
else if (property == 'secret'){
- // TBD property undefined means "not true" in case of secret?
- resolve(false);
+ // TBD property undefined means "not true" in case of secret?
+ resolve(false);
} else {
reject(gpgme_error('CONN_UNEXPECTED_ANSWER'));
}
}, function(error){
- reject({code: 'GNUPG_ERROR',
- msg: error.msg});
+ //TODO error handling
});
});
};
\ No newline at end of file
diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js
index 364bfb46..d1f4122e 100644
--- a/lang/js/src/Keyring.js
+++ b/lang/js/src/Keyring.js
@@ -78,6 +78,8 @@ export class GPGME_Keyring {
}
}
return Promise.resolve(resultset);
+ }, function(error){
+ //TODO error handling
});
}
@@ -151,6 +153,8 @@ export class GPGME_Keyring {
}
}
return Promise.resolve(resultset);
+ }, function(error){
+ //TODO error handling
});
}
diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js
index 95d043ba..c42480f2 100644
--- a/lang/js/src/Message.js
+++ b/lang/js/src/Message.js
@@ -73,11 +73,60 @@ export class GPGME_Message {
if (!po){
return gpgme_error('MSG_WRONG_OP');
}
- if (po.required.indexOf(param) >= 0 || po.optional.indexOf(param) >= 0){
- this._msg[param] = value;
- return true;
+ let poparam = null;
+ if (po.required.hasOwnProperty(param)){
+ poparam = po.required[param];
+ } else if (po.optional.hasOwnProperty(param)){
+ poparam = po.optional[param];
+ } else {
+ return gpgme_error('PARAM_WRONG');
}
- return gpgme_error('PARAM_WRONG');
+ let checktype = function(val){
+ switch(typeof(val)){
+ case 'string':
+ case 'number':
+ case 'boolean':
+ if (poparam.allowed.indexOf(typeof(val)) >= 0){
+ return true;
+ }
+ return gpgme_error('PARAM_WRONG');
+ break;
+ case 'object':
+ if (Array.isArray(val)){
+ if (poparam.array_allowed !== true){
+ return gpgme_error('PARAM_WRONG');
+ }
+ for (let i=0; i < val.length; i++){
+ let res = checktype(val[i]);
+ if (res !== true){
+ return res;
+ }
+ }
+ return true;
+ } else if (val instanceof Uint8Array){
+ if (poparam.allowed.indexOf('Uint8Array') >= 0){
+ return true;
+ }
+ return gpgme_error('PARAM_WRONG');
+ } else {
+ return gpgme_error('PARAM_WRONG');
+ }
+ break;
+ default:
+ return gpgme_error('PARAM_WRONG');
+ }
+ };
+ let typechecked = checktype(value);
+ if (typechecked !== true){
+ return typechecked;
+ }
+ if (poparam.hasOwnProperty('allowed_data')){
+ if (poparam.allowed_data.indexOf(value) < 0){
+ return gpgme_error('PARAM_WRONG');
+ }
+ }
+ this._msg[param] = value;
+ return true;
}
/**
@@ -89,11 +138,12 @@ export class GPGME_Message {
if (!this._msg.op){
return false;
}
- let reqParams = permittedOperations[this._msg.op].required;
+ let reqParams = Object.keys(
+ permittedOperations[this._msg.op].required);
+ let msg_params = Object.keys(this._msg);
for (let i=0; i < reqParams.length; i++){
-
- if (!this._msg.hasOwnProperty(reqParams[i])){
- console.log(reqParams[i] + 'missing');
+ if (msg_params.indexOf(reqParams[i]) < 0){
+ console.log(reqParams[i] + ' missing');
return false;
}
}
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index 2ddf2964..9475b2b0 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -33,25 +33,24 @@ export class GpgME {
this.connection = connection;
}
- set connection(connection){
+ set connection(conn){
if (this._connection instanceof Connection){
gpgme_error('CONN_ALREADY_CONNECTED');
- }
- if (connection instanceof Connection){
- this._connection = connection;
+ } else if (conn instanceof Connection){
+ this._connection = conn;
} else {
gpgme_error('PARAM_WRONG');
}
}
get connection(){
- if (this._connection instanceof Connection){
- if (this._connection.isConnected){
+ if (this._connection){
+ if (this._connection.isConnected === true){
return this._connection;
}
- return undefined; //TODO: connection was lost!
+ return undefined;
}
- return undefined; //TODO: no connection there
+ return undefined;
}
set Keyring(keyring){
@@ -85,8 +84,11 @@ export class GpgME {
putData(msg, data);
if (wildcard === true){msg.setParameter('throw-keyids', true);
};
-
- return (this.connection.post(msg));
+ if (msg.isComplete === true){
+ return this.connection.post(msg);
+ } else {
+ return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
+ }
}
/**
@@ -133,20 +135,24 @@ export class GpgME {
msg.setParameter('delete_force', true);
// TBD
}
- this.connection.post(msg).then(function(success){
- // TODO: it seems that there is always errors coming back:
- }, function(error){
- switch (error.msg){
- case 'ERR_NO_ERROR':
- return Promise.resolve('okay'); //TBD
- default:
- return Promise.reject(gpgme_error('TODO') ); //
- // INV_VALUE,
- // GPG_ERR_NO_PUBKEY,
- // GPG_ERR_AMBIGUOUS_NAME,
- // GPG_ERR_CONFLICT
- }
- });
+ if (msg.isComplete === true){
+ this.connection.post(msg).then(function(success){
+ // TODO: it seems that there is always errors coming back:
+ }, function(error){
+ switch (error.msg){
+ case 'ERR_NO_ERROR':
+ return Promise.resolve('okay'); //TBD
+ default:
+ return Promise.reject(gpgme_error('TODO') ); //
+ // INV_VALUE,
+ // GPG_ERR_NO_PUBKEY,
+ // GPG_ERR_AMBIGUOUS_NAME,
+ // GPG_ERR_CONFLICT
+ }
+ });
+ } else {
+ return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
+ }
}
}
@@ -162,7 +168,7 @@ function putData(message, data){
return gpgme_error('PARAM_WRONG');
}
if (!data){
- message.setParameter('data', '');
+ return gpgme_error('PARAM_WRONG');
} else if (data instanceof Uint8Array){
let decoder = new TextDecoder('utf8');
message.setParameter('base64', true);
diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js
index cc2afde1..c80d5a86 100644
--- a/lang/js/src/gpgmejs_openpgpjs.js
+++ b/lang/js/src/gpgmejs_openpgpjs.js
@@ -109,7 +109,7 @@
return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED'));
}
}
- return this._GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard);
+ return this._GpgME.encrypt(data, translateKeys(publicKeys), wildcard);
}
/** Decrypt Message
@@ -201,6 +201,8 @@ class GPGME_Keyring_openpgpmode {
// TODO: Can there be several default keys?
return gpgme_error('TODO');
}
+ }, function(error){
+ //TODO
});
}
@@ -264,6 +266,9 @@ class GPGME_Key_openpgpmode {
* creates GPGME_Key_openpgpmode from GPGME_Keys
*/
function translateKeys(input){
+ if (!input){
+ return null;
+ }
if (!Array.isArray(input)){
input = [input];
}
diff --git a/lang/js/src/index.js b/lang/js/src/index.js
index 4de98457..90fe99e3 100644
--- a/lang/js/src/index.js
+++ b/lang/js/src/index.js
@@ -53,18 +53,17 @@ function init(config){
});
}
-function parseconfiguration(config){
- if (!config){
- return defaultConf;
- }
- if ( typeof(config) !== 'object'){
+function parseconfiguration(rawconfig = {}){
+ if ( typeof(rawconfig) !== 'object'){
return gpgme_error('PARAM_WRONG');
};
- let result_config = defaultConf;
- let conf_keys = Object.keys(config);
- for (let i=0; i < conf_keys; i++){
+ let result_config = {};
+ let conf_keys = Object.keys(rawconfig);
+
+ for (let i=0; i < conf_keys.length; i++){
+
if (availableConf.hasOwnProperty(conf_keys[i])){
- let value = config[conf_keys[i]];
+ let value = rawconfig[conf_keys[i]];
if (availableConf[conf_keys[i]].indexOf(value) < 0){
return gpgme_error('PARAM_WRONG');
} else {
@@ -75,6 +74,12 @@ function parseconfiguration(config){
return gpgme_error('PARAM_WRONG');
}
}
+ let default_keys = Object.keys(defaultConf);
+ for (let j=0; j < default_keys.length; j++){
+ if (!result_config.hasOwnProperty(default_keys[j])){
+ result_config[default_keys[j]] = defaultConf[default_keys[j]];
+ }
+ }
return result_config;
};
diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js
index 79e74223..274e037e 100644
--- a/lang/js/src/permittedOperations.js
+++ b/lang/js/src/permittedOperations.js
@@ -21,9 +21,16 @@
/**
* Definition of the possible interactions with gpgme-json.
* operation: