From 1f7b19512cfa7e1b153b99d6a2b40bad82a5496e Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 26 Apr 2018 17:13:34 +0200 Subject: js: created TestExtension and smaller fixes -- * Extensions: - Moved testapplication to Demoextension - Created BrowserTestExtension. Includes mocha and chai. For running tests that cannot be run outside a WebExtension Both Extensions can be found zipped in build/extensions after running build_extensions.sh * Code changes: - src/Config: Place for the configuration - small fixes raised during testing in Keyring.js, Message.js, - src/gpgmejs_openpgpjs.js don't offer direct GpgME object to the outside, as it only causes confusion - index.js init() now checks the config for validity * Tests: - Reordered tests in test/. - Input values are now in a separate file which may be of use for bulk testing * moved the build directory from dist to build --- lang/js/BrowserTestExtension/browsertest.html | 23 ++++++++++ lang/js/BrowserTestExtension/manifest.json | 13 ++++++ lang/js/BrowserTestExtension/popup.html | 9 ++++ lang/js/BrowserTestExtension/popup.js | 44 +++++++++++++++++++ lang/js/BrowserTestExtension/runbrowsertest.js | 21 +++++++++ lang/js/BrowserTestExtension/setup_testing.js | 22 ++++++++++ lang/js/BrowserTestExtension/testicon.png | Bin 0 -> 16192 bytes lang/js/BrowserTestExtension/tests/inputvalues.js | 28 ++++++++++++ lang/js/BrowserTestExtension/tests/startup.js | 51 ++++++++++++++++++++++ 9 files changed, 211 insertions(+) create mode 100644 lang/js/BrowserTestExtension/browsertest.html create mode 100644 lang/js/BrowserTestExtension/manifest.json create mode 100644 lang/js/BrowserTestExtension/popup.html create mode 100644 lang/js/BrowserTestExtension/popup.js create mode 100644 lang/js/BrowserTestExtension/runbrowsertest.js create mode 100644 lang/js/BrowserTestExtension/setup_testing.js create mode 100644 lang/js/BrowserTestExtension/testicon.png create mode 100644 lang/js/BrowserTestExtension/tests/inputvalues.js create mode 100644 lang/js/BrowserTestExtension/tests/startup.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html new file mode 100644 index 00000000..d2c6396f --- /dev/null +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -0,0 +1,23 @@ + + + + + + + +

Browsertest

+
+ + + + + + + + + + + + + + diff --git a/lang/js/BrowserTestExtension/manifest.json b/lang/js/BrowserTestExtension/manifest.json new file mode 100644 index 00000000..a9e605bc --- /dev/null +++ b/lang/js/BrowserTestExtension/manifest.json @@ -0,0 +1,13 @@ +{ + "manifest_version": 2, + + "name": "Browsertests for gpgmejs", + "description": "Run the browsertests.", + "version": "0.1", + "content_security_policy": "default-src 'self' filesystem:", + "browser_action": { + "default_icon": "testicon.png", + "default_popup": "popup.html" + }, + "permissions": ["nativeMessaging", "activeTab"] + } diff --git a/lang/js/BrowserTestExtension/popup.html b/lang/js/BrowserTestExtension/popup.html new file mode 100644 index 00000000..f17f262a --- /dev/null +++ b/lang/js/BrowserTestExtension/popup.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/popup.js b/lang/js/BrowserTestExtension/popup.js new file mode 100644 index 00000000..4764df55 --- /dev/null +++ b/lang/js/BrowserTestExtension/popup.js @@ -0,0 +1,44 @@ +/* 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+ + */ +/* 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+ + */ + +document.addEventListener('DOMContentLoaded', function() { + chrome.tabs.create({ + url: './browsertest.html' + }); +}); diff --git a/lang/js/BrowserTestExtension/runbrowsertest.js b/lang/js/BrowserTestExtension/runbrowsertest.js new file mode 100644 index 00000000..39bc3fb9 --- /dev/null +++ b/lang/js/BrowserTestExtension/runbrowsertest.js @@ -0,0 +1,21 @@ +/* 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+ + */ + +mocha.run(); diff --git a/lang/js/BrowserTestExtension/setup_testing.js b/lang/js/BrowserTestExtension/setup_testing.js new file mode 100644 index 00000000..7f70d347 --- /dev/null +++ b/lang/js/BrowserTestExtension/setup_testing.js @@ -0,0 +1,22 @@ +/* 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+ + */ +mocha.setup('bdd'); +var expect = chai.expect; +chai.config.includeStack = true; \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/testicon.png b/lang/js/BrowserTestExtension/testicon.png new file mode 100644 index 00000000..12c3f5df Binary files /dev/null and b/lang/js/BrowserTestExtension/testicon.png differ diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js new file mode 100644 index 00000000..47600c84 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -0,0 +1,28 @@ +/* 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+ + */ + +var inputvalues = { + encrypt: { + good:{ + data : 'Hello World.', + keyid : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40' + } + } +}; diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js new file mode 100644 index 00000000..14d12c0a --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -0,0 +1,51 @@ +/* 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('GPGME context', function(){ + it('Starting a GpgME instance', function(done){ + Gpgmejs.init().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); + 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); + }); + }); + }); -- cgit From fda7b13f1b673962ce34b6f429158a7eb9cef47b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Apr 2018 20:03:09 +0200 Subject: js: more testing -- * Tests: initialization of the two modes, encryption * gpgme.js: reintroduced message check before calling Connection.post() * gpgmejs_openpgp.js: Fixed openpgp mode not passing keys * index.js: fixed some confusion in parseconfig() * Inserted some TODO stubs for missing error handling --- lang/js/BrowserTestExtension/tests/encryptTest.js | 71 ++++++++++++++++ lang/js/BrowserTestExtension/tests/inputvalues.js | 6 +- lang/js/BrowserTestExtension/tests/startup.js | 67 ++++++++++------ lang/js/build_extensions.sh | 1 + lang/js/src/Connection.js | 6 +- lang/js/src/Key.js | 23 +++--- lang/js/src/Keyring.js | 4 + lang/js/src/Message.js | 66 +++++++++++++-- lang/js/src/gpgmejs.js | 56 +++++++------ lang/js/src/gpgmejs_openpgpjs.js | 7 +- lang/js/src/index.js | 23 +++--- lang/js/src/permittedOperations.js | 98 +++++++++++++++++------ lang/js/test/Helpers.js | 2 +- lang/js/test/Message.js | 62 ++++++++++++-- lang/js/test/index.js | 28 +++++++ lang/js/test/inputvalues.js | 10 +++ 16 files changed, 416 insertions(+), 114 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/encryptTest.js create mode 100644 lang/js/test/index.js (limited to 'lang/js/BrowserTestExtension') 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); + 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(); }); }); - it('Starting an openpgp mode GPGME instance', function(done){ - Gpgmejs.init({api_style:"gpgme_openpgpjs"}).then( - function(context){ - console.log(context); - 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: - required: Array - optional: Array - pinentry: Boolean If a pinentry dialog is expected, and a timeout of + required: Array + name The name of the property + allowed: Array of allowed types. Currently accepted values: + ['number', 'string', 'boolean', 'Uint8Array'] + array_allowed: Boolean. If the value can be an array of the above + allowed_data: If present, restricts to the given value + optional: Array + see 'required', with these parameters not being mandatory for a + complete message + pinentry: boolean If a pinentry dialog is expected, and a timeout of 5000 ms would be too short answer: type: . + * SPDX-License-Identifier: LGPL-2.1+ + */ +import { Helpertest } from "./Helpers"; +import { Messagetest } from "./Message"; + +/** + * Unit tests. + */ + +Helpertest(); +Messagetest(); diff --git a/lang/js/test/inputvalues.js b/lang/js/test/inputvalues.js index a50c8162..f6cd75aa 100644 --- a/lang/js/test/inputvalues.js +++ b/lang/js/test/inputvalues.js @@ -8,6 +8,8 @@ export const helper_params = { 'ADDBC303B6D31026F5EB4591A27EABDF283121BB', new GPGME_Key('EE17AEE730F88F1DE7713C54BBE0A4FF7851650A')], validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', + validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', + '9AAE7A338A9A9A7A7A8A9A9A7A7A8A9A9A7A7DDA'], invalidLongId: '9A9A7A7A8A9A9A7A7A8A', invalidFingerprint: [{hello:'World'}], invalidKeyArray: {curiosity:'uncat'}, @@ -21,8 +23,16 @@ export const helper_params = { export const message_params = { invalid_op_action : 'dance', invalid_op_type : [234, 34, '<>'], + valid_encrypt_data: "مرحبا بالعالم", + invalid_param_test: { + valid_op: 'encrypt', + invalid_param_names: [22,'dance', {}], + validparam_name_0: 'mime', + invalid_values_0: [2134, 'All your passwords', new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null] + } } + export default { helper_params: helper_params, message_params: message_params -- cgit From c755287ba845c4cbbf1d50e5aafecb2e687c7ac9 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 3 May 2018 18:03:22 +0200 Subject: js: Added browser testing for unit tests -- * Added unittests to be run inside a Browser. To be able to access the non-exposed functions and classes, a testing bundle will be created, containing the tests (unittests.js) and the items to be tested. * src/Helpelpers, src/Key, src/Keyring: fixed some errors found during testing. --- lang/js/BrowserTestExtension/browsertest.html | 2 + lang/js/BrowserTestExtension/runbrowsertest.js | 1 + lang/js/BrowserTestExtension/tests/encryptTest.js | 14 +- lang/js/README_testing | 14 + lang/js/build_extensions.sh | 4 +- lang/js/src/Helpers.js | 4 +- lang/js/src/Key.js | 11 +- lang/js/src/Keyring.js | 2 +- lang/js/unittest_inputvalues.js | 45 +++ lang/js/unittests.js | 321 ++++++++++++++++++++++ lang/js/webpack.conf_unittests.js | 34 +++ 11 files changed, 436 insertions(+), 16 deletions(-) create mode 100644 lang/js/README_testing create mode 100644 lang/js/unittest_inputvalues.js create mode 100644 lang/js/unittests.js create mode 100644 lang/js/webpack.conf_unittests.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index d2c6396f..ce037a11 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -14,9 +14,11 @@ + + diff --git a/lang/js/BrowserTestExtension/runbrowsertest.js b/lang/js/BrowserTestExtension/runbrowsertest.js index 39bc3fb9..308c716d 100644 --- a/lang/js/BrowserTestExtension/runbrowsertest.js +++ b/lang/js/BrowserTestExtension/runbrowsertest.js @@ -19,3 +19,4 @@ */ mocha.run(); +Gpgmejs_test.unittests(); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index e6000003..2178efac 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -18,8 +18,7 @@ * SPDX-License-Identifier: LGPL-2.1+ */ describe('Encryption', function(){ - - it('Successfull encrypt', function(done){ + it('Successfull encrypt', function(){ let prm = Gpgmejs.init(); prm.then(function(context){ context.encrypt( @@ -29,10 +28,6 @@ describe('Encryption', function(){ 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(); }); }); }); @@ -44,11 +39,10 @@ describe('Encryption', function(){ 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() + //TODO: MSG_INCOMPLETE desired, GNUPG_ERROR coming }); }); }); @@ -61,11 +55,9 @@ describe('Encryption', function(){ expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an.instanceof(Error); - expect(error.code).to.equal('MSG_INCOMPLETE'); - done(); + expect(error.code).to.equal('PARAM_WRONG'); }); }); }); - // TODO check different valid parameter }); diff --git a/lang/js/README_testing b/lang/js/README_testing new file mode 100644 index 00000000..b61ca1a6 --- /dev/null +++ b/lang/js/README_testing @@ -0,0 +1,14 @@ +Test extension: + +The test extension contains tests with mocha and chai. It will be packed as an +extra extension (see build_extension.sh). + +Tests from BrowserTestExtension/tests will be run against the gpgmejs.bundle.js +itself. They aim to test the outward facing functionality and API. + +Unittests as defined in ./unittests.js will be bundled in +gpgmejs_unittests.bundle.js, and test the separate components of gpgmejs, +which mostly are not exported. + +The BrowserExtension can be installed the same way as the DemoExtension +(see README). \ No newline at end of file diff --git a/lang/js/build_extensions.sh b/lang/js/build_extensions.sh index b99a362c..91d5479b 100755 --- a/lang/js/build_extensions.sh +++ b/lang/js/build_extensions.sh @@ -1,11 +1,13 @@ #/!bin/bash npx webpack --config webpack.conf.js +npx webpack --config webpack.conf_unittests.js mkdir -p BrowserTestExtension/libs cp node_modules/chai/chai.js \ node_modules/mocha/mocha.css \ node_modules/mocha/mocha.js \ - build/gpgmejs.bundle.js BrowserTestExtension/libs + build/gpgmejs.bundle.js \ + build/gpgmejs_unittests.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/Helpers.js b/lang/js/src/Helpers.js index 9a69f851..ea056fff 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -91,9 +91,9 @@ export function isFingerprint(string){ return hextest(string, 40); }; /** - * check if the input is a valid Hex string with a length of 16 + * TODO no usage; check if the input is a valid Hex string with a length of 16 */ -export function isLongId(string){ +function isLongId(string){ return hextest(string, 16); }; diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 1e0d3195..6d3cf17d 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -61,6 +61,9 @@ export class GPGME_Key { } get connection(){ + if (!this._fingerprint){ + return gpgme_error('KEY_INVALID'); + } if (!this._connection instanceof Connection){ return gpgme_error('CONN_NO_CONNECT'); } else { @@ -75,6 +78,9 @@ export class GPGME_Key { } get fingerprint(){ + if (!this._fingerprint){ + return gpgme_error('KEY_INVALID'); + } return this._fingerprint; } @@ -125,7 +131,7 @@ export class GPGME_Key { let msg = createMessage ('export_key'); msg.setParameter('armor', true); if (msg instanceof Error){ - return gpgme_error('INVALID_KEY'); + return gpgme_error('KEY_INVALID'); } this.connection.post(msg).then(function(result){ return result.data; @@ -203,6 +209,9 @@ export class GPGME_Key { * TODO: check if Promise.then(return) */ checkKey(property){ + if (!this._fingerprint){ + return gpgme_error('KEY_INVALID'); + } return gpgme_error('NOT_YET_IMPLEMENTED'); // TODO: async is not what is to be ecpected from Key information :( if (!property || typeof(property) !== 'string' || diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 2cf87c24..4596035a 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -20,7 +20,7 @@ import {createMessage} from './Message' import {GPGME_Key} from './Key' -import { isFingerprint, isLongId } from './Helpers'; +import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; import { Connection } from './Connection'; diff --git a/lang/js/unittest_inputvalues.js b/lang/js/unittest_inputvalues.js new file mode 100644 index 00000000..3450afd2 --- /dev/null +++ b/lang/js/unittest_inputvalues.js @@ -0,0 +1,45 @@ +import {Connection} from "./src/Connection"; +import {createKey} from "./src/Key"; + +let conn = new Connection; + +export const helper_params = { + validLongId: '0A0A0A0A0A0A0A0A', + validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3', + createKey('ADDBC303B6D31026F5EB4591A27EABDF283121BB', conn), + 'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'], + validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', + validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', + '9AAE7A338A9A9A7A7A8A9A9A7A7A8A9A9A7A7DDA'], + invalidLongId: '9A9A7A7A8A9A9A7A7A8A', + invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)], + invalidKeyArray: {curiosity:'uncat'}, + invalidKeyArray_OneBad: [ + createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), + 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', + '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], + invalidErrorCode: 'Please type in all your passwords.', + validGPGME_Key: createKey('ADDBC303B6D31026F5EB4591A27EABDF283121BB', conn), + valid_openpgplike: { primaryKey: { + getFingerprint: function(){ + return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';} + } + } +} + +export const message_params = { + invalid_op_action : 'dance', + invalid_op_type : [234, 34, '<>'], + valid_encrypt_data: "مرحبا بالعالم", + invalid_param_test: { + valid_op: 'encrypt', + invalid_param_names: [22,'dance', {}], + validparam_name_0: 'mime', + invalid_values_0: [2134, 'All your passwords', + createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), null] + } +} + +export const whatever_params = { + four_invalid_params: ['<(((-<', '>°;==;~~', '^^', '{{{{o}}}}'] +} diff --git a/lang/js/unittests.js b/lang/js/unittests.js new file mode 100644 index 00000000..0a1b4b48 --- /dev/null +++ b/lang/js/unittests.js @@ -0,0 +1,321 @@ +/* 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+ + */ +import "./node_modules/mocha/mocha"; +import "./node_modules/chai/chai"; +import { helper_params as hp } from "./unittest_inputvalues"; +import { message_params as mp } from "./unittest_inputvalues"; +import { whatever_params as wp } from "./unittest_inputvalues"; +import { Connection } from "./src/Connection"; +import { gpgme_error } from "./src/Errors"; +import { toKeyIdArray , isFingerprint } from "./src/Helpers"; +import { GPGME_Key , createKey } from "./src/Key"; +import { GPGME_Keyring } from "./src/Keyring"; +import {GPGME_Message, createMessage} from "./src/Message"; +import { setTimeout } from "timers"; + +mocha.setup('bdd'); +var expect = chai.expect; +chai.config.includeStack = true; + +function unittests (){ + describe('Connection testing', function(){ + + it('Connecting', function(done) { + let conn0 = new Connection; + let delayed = function(){ + expect(conn0.isConnected).to.be.true; + expect(conn0.connect).to.be.a('function'); + expect(conn0.disconnect).to.be.a('function'); + expect(conn0.post).to.be.a('function'); + done(); + }; + setTimeout(delayed, 5); + + }); + + it('Disconnecting', function(done) { + let conn0 = new Connection; + let delayed = function(){ + conn0.disconnect(); // TODO fails! + expect(conn0.isConnected).to.be.false; + done(); + }; + setTimeout(delayed, 5); + }); + + // broken + // it('Connect info still only available after a delay', function(done){ + // // if false, all delayed connections can be refactored + // let conn0 = new Connection; + // expect(conn0.isConnected).to.be.undefined; + // // + // }) + }); + + describe('Error Object handling', function(){ + + it('check the Timeout error', function(){ + let test0 = gpgme_error('CONN_TIMEOUT'); + + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('CONN_TIMEOUT'); + }); + + it('Error Object returns generic code if code is not listed', function(){ + let test0 = gpgme_error(hp.invalidErrorCode); + + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('GENERIC_ERROR'); + }); + + it('Warnings like PARAM_IGNORED should not return errors', function(){ + let test0 = gpgme_error('PARAM_IGNORED'); + + expect(test0).to.be.null; + }); + }); + + describe('Fingerprint checking', function(){ + + it('isFingerprint(): valid Fingerprint', function(){ + let test0 = isFingerprint(hp.validFingerprint); + + expect(test0).to.be.true; + }); + + it('isFingerprint(): invalid Fingerprints', function(){ + for (let i=0; i < hp.invalidFingerprints.length; i++){ + let test0 = isFingerprint(hp.invalidFingerprints[i]); + + expect(test0).to.be.false; + } + }); + }); + + describe('toKeyIdArray() (converting input to fingerprint', function(){ + + it('Correct fingerprint string', function(){ + let test0 = toKeyIdArray(hp.validFingerprint); + + expect(test0).to.be.an('array'); + expect(test0).to.include(hp.validFingerprint); + }); + + it('correct GPGME_Key', function(){ + expect(hp.validGPGME_Key).to.be.an.instanceof(GPGME_Key); + let test0 = toKeyIdArray(hp.validGPGME_Key); + + expect(test0).to.be.an('array'); + expect(test0).to.include(hp.validGPGME_Key.fingerprint); + }); + + it('openpgpjs-like object', function(){ + let test0 = toKeyIdArray(hp.valid_openpgplike); + + expect(test0).to.be.an('array').with.lengthOf(1); + console.log(test0); + expect(test0).to.include( + hp.valid_openpgplike.primaryKey.getFingerprint()); + }); + + it('Array of valid inputs', function(){ + let test0 = toKeyIdArray(hp.validKeys); + expect(test0).to.be.an('array'); + expect(test0).to.have.lengthOf(hp.validKeys.length); + }); + + it('Incorrect inputs', function(){ + + it('valid Long ID', function(){ + let test0 = toKeyIdArray(hp.validLongId); + + expect(test0).to.be.empty; + }); + + it('invalidFingerprint', function(){ + let test0 = toKeyIdArray(hp.invalidFingerprint); + + expect(test0).to.be.empty; + }); + + it('invalidKeyArray', function(){ + let test0 = toKeyIdArray(hp.invalidKeyArray); + + expect(test0).to.be.empty; + }); + + it('Partially invalid array', function(){ + let test0 = toKeyIdArray(hp.invalidKeyArray_OneBad); + + expect(test0).to.be.an('array'); + expect(test0).to.have.lengthOf( + hp.invalidKeyArray_OneBad.length - 1); + }); + }); + }); + + describe('GPGME_Key', function(){ + + it('correct Key initialization', function(){ + let conn = new Connection; + let key = createKey(hp.validFingerprint, conn); + + expect(key).to.be.an.instanceof(GPGME_Key); + expect(key.connection).to.be.an.instanceof(Connection); + // TODO not implemented yet: Further Key functionality + }); + + it('Key can use the connection', function(){ + let conn = new Connection; + let key = createKey(hp.validFingerprint, conn); + + expect(key.connection.isConnected).to.be.true; + + key.connection.disconnect(); + expect(key.connection.isConnected).to.be.false; + }); + + it('createKey returns error if parameters are wrong', function(){ + let conn = new Connection; + for (let i=0; i< 4; i++){ + let key0 = createKey(wp.four_invalid_params[i], conn); + + expect(key0).to.be.an.instanceof(Error); + expect(key0.code).to.equal('PARAM_WRONG'); + } + for (let i=0; i< 4; i++){ + let key0 = createKey( + hp.validFingerprint, wp.four_invalid_params[i]); + + expect(key0).to.be.an.instanceof(Error); + expect(key0.code).to.equal('PARAM_WRONG'); + } + }); + it('bad GPGME_Key returns Error if used', function(){ + let conn = new Connection; + for (let i=0; i < 4; i++){ + let key = new GPGME_Key(wp.four_invalid_params[i], conn); + + expect(key.connection).to.be.an.instanceof(Error); + expect(key.connection.code).to.equal('KEY_INVALID'); + } + }); + }); + + describe('GPGME_Keyring', function(){ + + it('correct initialization', function(){ + let conn = new Connection; + let keyring = new GPGME_Keyring(conn); + + expect(keyring).to.be.an.instanceof(GPGME_Keyring); + expect(keyring.connection).to.be.an.instanceof(Connection); + expect(keyring.getKeys).to.be.a('function'); + expect(keyring.getSubset).to.be.a('function'); + }); + + it('Keyring should return errors if not connected', function(){ + let keyring = new GPGME_Keyring; + + expect(keyring).to.be.an.instanceof(GPGME_Keyring); + expect(keyring.connection).to.be.an.instanceof(Error); + expect(keyring.connection.code).to.equal('CONN_NO_CONNECT'); + expect(keyring.getKeys).to.be.an.instanceof(Error); + expect(keyring.getkeys.code).to.equal('CONN_NO_CONNECT'); + }); + //TODO not yet implemented: + // getKeys(pattern, include_secret) //note: pattern can be null + // getSubset(flags, pattern) + // available Boolean flags: secret revoked expired + }); + + describe('GPGME_Message', function(){ + + it('creating encrypt Message', function(){ + let test0 = createMessage('encrypt'); + + expect(test0).to.be.an.instanceof(GPGME_Message); + expect(test0.isComplete).to.be.false; + }); + + it('Message is complete after setting mandatoy data', function(){ + let test0 = createMessage('encrypt'); + test0.setParameter('data', mp.valid_encrypt_data); + test0.setParameter('keys', hp.validFingerprints); + + expect(test0.isComplete).to.be.true; + }); + + it('Complete Message contains the data that was set', function(){ + let test0 = createMessage('encrypt'); + test0.setParameter('data', mp.valid_encrypt_data); + test0.setParameter('keys', hp.validFingerprints); + + expect(test0.message).to.not.be.null; + expect(test0.message).to.have.keys('op', 'data', 'keys'); + expect(test0.message.op).to.equal('encrypt'); + expect(test0.message.data).to.equal( + mp.valid_encrypt_data); + }); + + it ('Not accepting non-allowed operation', function(){ + let test0 = createMessage(mp.invalid_op_action); + + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('MSG_WRONG_OP'); + }); + it('Not accepting wrong parameter type', function(){ + let test0 = createMessage(mp.invalid_op_type); + + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('PARAM_WRONG'); + }); + + it('Not accepting wrong parameter name', function(){ + let test0 = createMessage(mp.invalid_param_test.valid_op); + for (let i=0; + i < mp.invalid_param_test.invalid_param_names.length; i++){ + let ret = test0.setParameter( + mp.invalid_param_test.invalid_param_names[i], + 'Somevalue'); + + expect(ret).to.be.an.instanceof(Error); + expect(ret.code).to.equal('PARAM_WRONG'); + } + }); + + it('Not accepting wrong parameter value', function(){ + let test0 = createMessage(mp.invalid_param_test.valid_op); + for (let j=0; + j < mp.invalid_param_test.invalid_values_0.length; j++){ + let ret = test0.setParameter( + mp.invalid_param_test.validparam_name_0, + mp.invalid_param_test.invalid_values_0[j]); + + expect(ret).to.be.an.instanceof(Error); + expect(ret.code).to.equal('PARAM_WRONG'); + } + }); + }); + + mocha.run(); +} + +export default {unittests}; \ No newline at end of file diff --git a/lang/js/webpack.conf_unittests.js b/lang/js/webpack.conf_unittests.js new file mode 100644 index 00000000..4b903be6 --- /dev/null +++ b/lang/js/webpack.conf_unittests.js @@ -0,0 +1,34 @@ +/* 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+ + * + * This is the configuration file for building the gpgmejs-Library with webpack + */ +const path = require('path'); + +module.exports = { + entry: './unittests.js', + mode: 'production', + output: { + path: path.resolve(__dirname, 'build'), + filename: 'gpgmejs_unittests.bundle.js', + libraryTarget: 'var', + libraryExport: 'default', + library: 'Gpgmejs_test' + } +}; -- cgit From 8f3d83e5f0903323ec92f588f60dcecb0ae96de4 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 7 May 2018 18:27:25 +0200 Subject: js: fixing errors found by testing: encrypt/decrypt -- * Key.js: Error code for wrong parameter in createKey should be "PARAM_WRONG" * Helpers.js: The property openpgpjs-like Objects were checked for in toKeyIdArray was not defined. * src/permittedOperations.js: updated more expectations and assumptions for the native API * new Problems: - There seems to be a message size limit of about 21 MB for nativeMessaging, much lower than the documented 4GB. - Some bytes are lost with random data in an encrypt-decrypt roundtrip. The culprit is unclear. --- lang/js/BrowserTestExtension/browsertest.html | 1 + .../tests/encryptDecryptTest.js | 72 +++++++++++++ lang/js/BrowserTestExtension/tests/encryptTest.js | 114 ++++++++++++++++++--- lang/js/BrowserTestExtension/tests/inputvalues.js | 12 +++ lang/js/src/Connection.js | 13 ++- lang/js/src/Message.js | 19 +++- lang/js/unittests.js | 11 +- 7 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/encryptDecryptTest.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index ce037a11..d12e03cf 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -18,6 +18,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js new file mode 100644 index 00000000..7abf2d94 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -0,0 +1,72 @@ +/* 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 and Decryption', function () { + it('Successful encrypt and decrypt', 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'); + context.decrypt(answer.data).then(function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(inputvalues.encrypt.good.data); + done(); + }); + }); + }); + }); + +/** + * Fails with random data! Some bytes (up to 100) of the original are missing in + * the result + */ +/** + for (let i=0; i< 20; i++) { + it('Successful encrypt 1 MB '+ i+ '/20', function (done) { + let prm = Gpgmejs.init(); + let data = bigString(0.1); + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }); + }).timeout(10000); + };*/ +}); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 2178efac..37b319ed 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -17,47 +17,133 @@ * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ -describe('Encryption', function(){ - it('Successfull encrypt', function(){ +describe('Encryption', function () { + it('Successful encrypt', function (done) { let prm = Gpgmejs.init(); - prm.then(function(context){ + prm.then(function (context) { context.encrypt( - inputvalues.encrypt.good.data, - inputvalues.encrypt.good.fingerprint).then(function(answer){ + 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(); }); }); }); - it('Sending encryption without keys fails', function(){ + it('Successful encrypt 5 MB', function (done) { let prm = Gpgmejs.init(); - prm.then(function(context){ + let data = bigString(5); + prm.then(function (context) { + context.encrypt( + 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(); + }); + }); + }).timeout(5000); + + it('Successful encrypt 20 MB', function (done) { + let prm = Gpgmejs.init(); + let data = bigString(20); + prm.then(function (context) { + context.encrypt( + 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(); + }); + }); + }).timeout(20000); + +/** + it('Successful encrypt 30 MB', function (done) { + // TODO: There seems to be a limit imposed at least by chrome at about 21 MB + let prm = Gpgmejs.init(); + let data = bigString(30); + prm.then(function (context) { + context.encrypt( + 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(); + }); + }); + }).timeout(20000); +*/ + + it('Sending encryption without keys fails', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, - null).then(function(answer){ + null).then(function (answer) { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an('Error'); expect(error.code).to.equal('MSG_INCOMPLETE'); - //TODO: MSG_INCOMPLETE desired, GNUPG_ERROR coming + done(); }); }); }); - it('Sending encryption without data fails', function(){ + it('Sending encryption without data fails', function (done) { let prm = Gpgmejs.init(); - prm.then(function(context){ + prm.then(function (context) { context.encrypt( - null,inputvalues.encrypt.good.keyid).then(function(answer){ + null, inputvalues.encrypt.good.keyid).then(function (answer) { expect(answer).to.be.undefined; - }, function(error){ + }, function (error) { expect(error).to.be.an.instanceof(Error); - expect(error.code).to.equal('PARAM_WRONG'); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); + }); + }); + }); + + + it('Sending encryption with non existing keys fails', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt( + inputvalues.encrypt.good.data, + inputvalues.encrypt.bad.fingerprint).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.not.be.undefined; + expect(error.code).to.equal('GNUPG_ERROR'); + done(); }); }); }); + + it('Overly large message ( >= 48MB) is rejected', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt( + bigString(48), + inputvalues.encrypt.good.fingerprint).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an.instanceof(Error); + // TODO who is throwing the error here? + // It is not a GPGME_Error! + done(); + }); + }); + }).timeout(8000); // TODO check different valid parameter }); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 1761c82f..3cd1e92a 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -23,6 +23,9 @@ var inputvalues = { good:{ data : 'Hello World.', fingerprint : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40' + }, + bad: { + fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } }, init: { @@ -30,3 +33,12 @@ var inputvalues = { } }; + +function bigString(megabytes){ + let maxlength = 1024 * 1024 * megabytes; + let uint = new Uint8Array(maxlength); + for (let i= 0; i < maxlength; i++){ + uint[i] = Math.random() * Math.floor(256); + } + return new TextDecoder('utf-8').decode(uint); +} diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index a198bdc6..2c8792d6 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -99,11 +99,12 @@ export class Connection{ me._connection.onMessage.removeListener(listener) reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); } else if (msg.type === "error"){ - me._connection.onMessage.removeListener(listener) + me._connection.onMessage.removeListener(listener); reject(gpgme_error('GNUPG_ERROR', msg.msg)); } else { let answer_result = answer.add(msg); if (answer_result !== true){ + me._connection.onMessage.removeListener(listener); reject(answer_result); } if (msg.more === true){ @@ -127,8 +128,12 @@ export class Connection{ }, 5000); }]).then(function(result){ return result; - }, function(error){ - return error; + }, function(reject){ + if(!reject instanceof Error) { + return gpgme_error('GNUPG_ERROR', reject); + } else { + return reject; + } }); } }); @@ -196,7 +201,7 @@ class Answer{ this._response.push(msg[key]); } else { - return gpgme_error('CONN_UNEXPECTED_ANSWER', key); + return gpgme_error('CONN_UNEXPECTED_ANSWER'); } break; } diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index c42480f2..6a59c3e0 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -84,9 +84,22 @@ export class GPGME_Message { let checktype = function(val){ switch(typeof(val)){ case 'string': + if (poparam.allowed.indexOf(typeof(val)) >= 0 + && val.length > 0) { + return true; + } + return gpgme_error('PARAM_WRONG'); + break; case 'number': + if ( + poparam.allowed.indexOf('number') >= 0 + && isNaN(value) === false){ + return true; + } + return gpgme_error('PARAM_WRONG'); + break; case 'boolean': - if (poparam.allowed.indexOf(typeof(val)) >= 0){ + if (poparam.allowed.indexOf('boolean') >= 0){ return true; } return gpgme_error('PARAM_WRONG'); @@ -102,7 +115,9 @@ export class GPGME_Message { return res; } } - return true; + if (val.length > 0) { + return true; + } } else if (val instanceof Uint8Array){ if (poparam.allowed.indexOf('Uint8Array') >= 0){ return true; diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 6c0d1890..c437d599 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -130,7 +130,6 @@ function unittests (){ let test0 = toKeyIdArray(hp.valid_openpgplike); expect(test0).to.be.an('array').with.lengthOf(1); - console.log(test0); expect(test0).to.include( hp.valid_openpgplike.primaryKey.getFingerprint()); }); @@ -255,7 +254,7 @@ function unittests (){ expect(test0.isComplete).to.be.false; }); - it('Message is complete after setting mandatoy data', function(){ + it('Message is complete after setting mandatory data', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); @@ -263,6 +262,13 @@ function unittests (){ expect(test0.isComplete).to.be.true; }); + it('Message is not complete after mandatory data is empty', function(){ + let test0 = createMessage('encrypt'); + test0.setParameter('data', ''); + test0.setParameter('keys', hp.validFingerprints); + expect(test0.isComplete).to.be.false; + }); + it('Complete Message contains the data that was set', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); @@ -315,7 +321,6 @@ function unittests (){ }); }); - mocha.run(); } export default {unittests}; \ No newline at end of file -- cgit From cca40627b0afa2efc85ef7f5f1a1060a221ff2a2 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 8 May 2018 18:33:41 +0200 Subject: js: more testing -- * Tests: Under certain circumstances, some data change during encrypt-decrypt. Committing the current state so the problem can be discussed. * Fixes: - disconnecting the test ports after tests are complete - fixed passing of the error message from gpgme-json --- lang/js/BrowserTestExtension/testkey.pub | 30 ++++ lang/js/BrowserTestExtension/testkey.sec | 57 +++++++ .../tests/encryptDecryptTest.js | 186 +++++++++++++++++++-- lang/js/BrowserTestExtension/tests/encryptTest.js | 13 +- lang/js/BrowserTestExtension/tests/inputvalues.js | 62 ++++++- lang/js/src/Errors.js | 2 +- lang/js/src/gpgmejs.js | 11 +- 7 files changed, 342 insertions(+), 19 deletions(-) create mode 100644 lang/js/BrowserTestExtension/testkey.pub create mode 100644 lang/js/BrowserTestExtension/testkey.sec (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/testkey.pub b/lang/js/BrowserTestExtension/testkey.pub new file mode 100644 index 00000000..cfc329f3 --- /dev/null +++ b/lang/js/BrowserTestExtension/testkey.pub @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFrsKEkBCADKw4Wt8J6M/88qD8PO6lSMCxH1cpwH8iK0uPaFFYsJkkXo7kWf +PTAtrV+REqF/o80dvYcdLvRsV21pvncZz/HXLu1yQ18mC3XObrKokbdgrTTKA5XE +BZkNsqyaMMJauT18H4hYkSg62/tTdO1cu/zWv/LFf7Xyn6+uA74ovXCJlO1s0N2c +PShtr98QRzPMf2owgVk37JnDNp4gGVDGHxSZOuUwxgYAZYnA8SFc+c+3ZrQfY870 ++O4j3Mz4p7yD13AwP4buQLBsb/icxekeQCqpRJhLH9f7MdEcGXa1x36RcEkHdu+M +yJ392eMgD+dKNfRCtyTPhjZTxvbNELIBYICfABEBAAG0EHRlc3RAZXhhbXBsZS5v +cmeJAVQEEwEIAD4WIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbAwUJA8Jn +AAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAjAWNe7/DLBf9kB/wOQ/S60HGw +Fq07W9N01HWULyhHKoMmcHL6rfZ64oDqLxolPSasz7WAMW1jN4qtWJ0mFzwO83V6 +kaBe+wF6Kqir6udFSBW9rPcFg6/VZXPltT0a6uacIHq6DyQ5iMW4YQWbVy9OR2rN +GkYo1JCBR0XdRJYCSX3yB4TWv/eXnZ37/WjmiTOIZh35rjs+NuU/S5JPDfAp2/k7 +0DevQeBsv+UjVXjWpNTZmPbvDnd995uSmC6UY4hzyP84ORYMYn9n1QAR0goxDN6U +unOf9Rlp1oMzdxMool/d1MlCxg2h3jheuhv7lgUF4KpvHOuEPXQ7UO417E0TYcDZ +1J8Nsv87SZeEuQENBFrsKEkBCADjoEBhG/QPqZHg8VyoD1xYRAWGxyDJkX/GrSs6 +yE+x2hk5FoQCajxKa/d4AVxOnJpdwhAfeXeSNaql5Ejgzax+Tdj9BV6vtGVJVv0p +O7bgAiZxkA6RHxtNqhpPnPQoXvUzkzpRgpuL+Nj4yIg7z1ITH6KQH4u5SI9vd+j/ +8i9Taz67pdZwuJjac8qBuJHjzAo1bjYctFYUSG5pbmMQyNLySzgiNkFa4DajODlt +3RuqVGP316Fk+Sy2+60tC/HlX8jgMyMONfOGBQx6jk8tvAphS/LAqrrNepnagIyL +UGKU+L8cB2g1PGGp2biBFWqZbudZoyRBet/0yH/zirBdQJw1ABEBAAGJATwEGAEI +ACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAKCRAjAWNe +7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ5F32NDJ9 +PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7Jq3e/4Iy +0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02Lkr+2Cc/Q +k6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe23nntMSD +A+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t9Mmd7bM1 ++UyPgbPEr0iWMeyctYsuOLeUyQKMscDT +=QyY6 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/lang/js/BrowserTestExtension/testkey.sec b/lang/js/BrowserTestExtension/testkey.sec new file mode 100644 index 00000000..ced8f3ec --- /dev/null +++ b/lang/js/BrowserTestExtension/testkey.sec @@ -0,0 +1,57 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lQOYBFrsKEkBCADKw4Wt8J6M/88qD8PO6lSMCxH1cpwH8iK0uPaFFYsJkkXo7kWf +PTAtrV+REqF/o80dvYcdLvRsV21pvncZz/HXLu1yQ18mC3XObrKokbdgrTTKA5XE +BZkNsqyaMMJauT18H4hYkSg62/tTdO1cu/zWv/LFf7Xyn6+uA74ovXCJlO1s0N2c +PShtr98QRzPMf2owgVk37JnDNp4gGVDGHxSZOuUwxgYAZYnA8SFc+c+3ZrQfY870 ++O4j3Mz4p7yD13AwP4buQLBsb/icxekeQCqpRJhLH9f7MdEcGXa1x36RcEkHdu+M +yJ392eMgD+dKNfRCtyTPhjZTxvbNELIBYICfABEBAAEAB/wLJ0gyMjs2fFfT83wM +5Lzz2yQIwV4t3bblBAujdHTqeN5Zmsm/oakFyjSokULK96Kv0R4ej9eoIgMFvxFk +HRkrggxTrbsNJ7I6QcKYHTPeIIj318ykNL6fj0WJUcdPIENukXl5jbqNyk3/4D2y +TTDySyq6jHTgvMH4K4KJUSpglvSJPntTk9RhuFGHAF+sNR9atygDYctAaERMRtSg +LCoSt/AoX5GRMlQjXT9oqQjwSQoZyF4s8HMC8wdTFIE/E0L4IVdHVp8sz2UszNtT +W/evmCA+KVruKjRH/Fhrq4hHkEamW28+j4L6uAyagONP7BONs+S5Oo2zTT9+tV2R +ILTZBADdgLuAgF6C5Lu9jCF6DfFgaT/uafMyQNkEGNlxOHMWHTgLHe475V2eG9gA +amd4yXKyEFKU1PWnvlGuicQSGdzVcwmq61msvXgYD0FK3LP3yWzKnE4X1tzrC9Vp +/uHJxKjewCuyt1f5in919v+T8TbUxBYKC0zX/qWtX+10cTx77QQA6leqhToJ95Yc +u4UBrKMEO+y2v8Svb3LG7yI5oY8tkw0EkJ/kpZ8xTAfZYCe6fXdvVE3PHg2lrxyc +Wv/EU3QY/qA3G82mbXYeJ2jNZaTNYo4MylMrt4Mx25x4ke7JlsE8SVrQ+4CrHkqp +OjSIa7fppLrQ78uW980AtN8NNQGrlTsD/A9aoA60Igxy1Q3K2uSyDCyjLknv57ym +ZSBD3/t7m0l6Q6gbdfhNGosT+Hd4y3actqEqzXZHW2VG4dKZ/wRNkxtSm9adU9vs +EHyzxjb6mKIH32zAG5TaFT20hC+NK6lsyHr9UE2ZrS6ma2sLxGW2O40hqNsdD+5m +NrqeBc2I/js1PMK0EHRlc3RAZXhhbXBsZS5vcmeJAVQEEwEIAD4WIQTUFzW5Ejb9 +uIIEjFojAWNe7/DLBQUCWuwoSQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIe +AQIXgAAKCRAjAWNe7/DLBf9kB/wOQ/S60HGwFq07W9N01HWULyhHKoMmcHL6rfZ6 +4oDqLxolPSasz7WAMW1jN4qtWJ0mFzwO83V6kaBe+wF6Kqir6udFSBW9rPcFg6/V +ZXPltT0a6uacIHq6DyQ5iMW4YQWbVy9OR2rNGkYo1JCBR0XdRJYCSX3yB4TWv/eX +nZ37/WjmiTOIZh35rjs+NuU/S5JPDfAp2/k70DevQeBsv+UjVXjWpNTZmPbvDnd9 +95uSmC6UY4hzyP84ORYMYn9n1QAR0goxDN6UunOf9Rlp1oMzdxMool/d1MlCxg2h +3jheuhv7lgUF4KpvHOuEPXQ7UO417E0TYcDZ1J8Nsv87SZeEnQOYBFrsKEkBCADj +oEBhG/QPqZHg8VyoD1xYRAWGxyDJkX/GrSs6yE+x2hk5FoQCajxKa/d4AVxOnJpd +whAfeXeSNaql5Ejgzax+Tdj9BV6vtGVJVv0pO7bgAiZxkA6RHxtNqhpPnPQoXvUz +kzpRgpuL+Nj4yIg7z1ITH6KQH4u5SI9vd+j/8i9Taz67pdZwuJjac8qBuJHjzAo1 +bjYctFYUSG5pbmMQyNLySzgiNkFa4DajODlt3RuqVGP316Fk+Sy2+60tC/HlX8jg +MyMONfOGBQx6jk8tvAphS/LAqrrNepnagIyLUGKU+L8cB2g1PGGp2biBFWqZbudZ +oyRBet/0yH/zirBdQJw1ABEBAAEAB/4lN3gXOI4OuoOcsvHak4pebx61Mt0YP9cT +qZASIBqxok5x8E28pFh/tYfkYdqRCtdNYZOnxcEoUWh5j6nfwZkEnJ9P/T8GPNk7 +pMKnKXmExi05b5uGHD8nU1rSbf/YkvAF0vpbxd4/RDxbbtQhbUwGzusSI+pBLM0w +5TreEB+vRGBc2gOvXXOtKLNEa7M9rH2EwbAkP3jOGGwgk6adxbQdBcRxq4merqhL +YrVz73bCj8TDc0fsNJyIaZZJ++ejfBFYavsF1pvx9z7FNFi8rSXoiB3SBtaWGfhr +bwNaMZrDc7TRIq/fgGaL6g//bzcWrr1YaHXZ10Bgx6UymDOlYkCpBADm0Hv46sPw +07SO8+IACcaQliOto1pndOPwTimCeo58/7rf8I2a5uuJloGrnPwAX65bKDnUALp6 +X3lnXRNMhnB3Uewx4i00LQmjsxhJfQiGLpMv0j58tn64s7GqQzGVV1JKcQm992RV +jFOydyjZ+K4LGWEOITG/bZrMEVNGCM+OnQQA/Haz8xN0NFSlq7tyfFc0pkx/TiCX +xGfBqbO0wU2b5GMnZbY/06HENpidIzpa231VQaw5/nPTvfhlLKW1iGAkc148cX1q +lL9w2ksXuaHR3LXud2VcfVTIdxU/7h7u1dD/85+c0+7jlGObD9cXKxlM6OjpIJz1 +l5/1h3C5S0TuxHkEAL/3BGihkhNfv1Xx0rWu0/732usX/nE/A9C26hGu41FUf3fp +0ilonKpKZUEwWt5hWSEFCSrznNVekiO0rxvuu3RVegvzThPNU4Pf4JZtJpRVhvUQ +d9ulxJw7V9rs75uNBatTNC0kXuGoXhehw4Bn93xa67gYGd3LfrH+oT0GCDpTSHCJ +ATwEGAEIACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAK +CRAjAWNe7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ +5F32NDJ9PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7 +Jq3e/4Iy0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02L +kr+2Cc/Qk6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe +23nntMSDA+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t +9Mmd7bM1+UyPgbPEr0iWMeyctYsuOLeUyQKMscDT +=hkUm +-----END PGP PRIVATE KEY BLOCK----- diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index 7abf2d94..e28dd66b 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -24,30 +24,144 @@ describe('Encryption and Decryption', function () { prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, - inputvalues.encrypt.good.fingerprint).then( function(answer){ + 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'); - context.decrypt(answer.data).then(function(result){ + context.decrypt(answer.data).then(function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(inputvalues.encrypt.good.data); + context.connection.disconnect(); done(); }); }); }); }); + /** + * Fails with random data! Some bytes (up to 100) of the original are missing in + * the result +*/ /** - * Fails with random data! Some bytes (up to 100) of the original are missing in - * the result - */ + for (let j = 0; j < 10; j++){ + it('Successful encrypt and decrypt specific sets: ', + function (done) { + let prm = Gpgmejs.init(); + let data = bigBoringString(5); //see ./inputvalues.js + expect(Object.prototype.toString.call(data)).to.equal("[object String]"); + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function (result) { + if (data.length !== result.data.length) { + + for (let k = 0; k < data.length; k++) { + if (data[k] !== result.data[k]) { + console.log(k); + console.log(data[k - 2] + data[k - 1] + data[k] + data[k + 1]); + console.log(result.data[k - 2] + result.data[k - 1] + result.data[k] + result.data[k + 1]); + break; + } + } + } + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + + }); + }); + }); + }).timeout(5000); + } + + + it('Roundtrip does not destroy trailing whitespace', + function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = 'Keks. \rKeks \n Keks \r\n'; + context.encrypt(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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + + }); + }); + }); + }).timeout(3000); + + it('Test with simple non-ascii input', + function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = ''; + for (let i=0; i < 1024 * 1024 * 0.1; i++){ + data += inputvalues.encrypt.good.data_nonascii; + } + context.encrypt(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'); + console.log(answer); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + if (data.length !== result.data.length) { + + for (let k = 0; k < data.length; k++) { + if (data[k] !== result.data[k]) { + console.log(k); + console.log(data[k - 2] + data[k - 1] + data[k] + data[k + 1]); + console.log(result.data[k - 2] + result.data[k - 1] + result.data[k] + result.data[k + 1]); + break; + } + } + } + console.log(data.length - result.data.length); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + + }); + }); + }); + }).timeout(3000); +*/ /** - for (let i=0; i< 20; i++) { - it('Successful encrypt 1 MB '+ i+ '/20', function (done) { + for (let i=0; i< 100; i++) { + it('Successful encrypt random data '+ (i+1) + '/100', function (done) { let prm = Gpgmejs.init(); - let data = bigString(0.1); + let data = bigString(0.2); // << set source data here prm.then(function (context) { context.encrypt(data, inputvalues.encrypt.good.fingerprint).then( @@ -63,10 +177,62 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); + context.connection.disconnect(); done(); }); }); }); - }).timeout(10000); - };*/ + }).timeout(5000); + }; +*/ + +/** still fails + it('Successful encrypt 0.8 MB Uint8Array', function (done) { + let prm = Gpgmejs.init(); + let data = bigUint8(0.8); + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }); + }).timeout(5000); +*/ + + it('Decrypt simple non-ascii', + function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + data = encryptedData; + context.decrypt(data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(inputvalues.encrypt.good.data_nonascii); + context.encrypt(inputvalues.encrypt.good.data_nonascii, inputvalues.encrypt.good.fingerprint).then( + function(result){ + context.decrypt(result.data).then(function(answer){ + expect(answer.data).to.equal(inputvalues.encrypt.good.data_nonascii); + context.connection.disconnect(); + done(); + }); + }); + }); + + }); + }).timeout(8000); + }); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 37b319ed..2e95151b 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -28,6 +28,7 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); + context.connection.disconnect(); done(); }); }); @@ -44,11 +45,13 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); + context.connection.disconnect(); done(); }); }); }).timeout(5000); +/** it('Successful encrypt 20 MB', function (done) { let prm = Gpgmejs.init(); let data = bigString(20); @@ -60,11 +63,12 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); + context.connection.disconnect(); done(); }); }); }).timeout(20000); - +*/ /** it('Successful encrypt 30 MB', function (done) { // TODO: There seems to be a limit imposed at least by chrome at about 21 MB @@ -78,6 +82,7 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); + context.connection.disconnect(); done(); }); }); @@ -94,6 +99,7 @@ describe('Encryption', function () { }, function(error){ expect(error).to.be.an('Error'); expect(error.code).to.equal('MSG_INCOMPLETE'); + context.connection.disconnect(); done(); }); }); @@ -108,6 +114,7 @@ describe('Encryption', function () { }, function (error) { expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('MSG_INCOMPLETE'); + context.connection.disconnect(); done(); }); }); @@ -125,10 +132,11 @@ describe('Encryption', function () { expect(error).to.be.an('Error'); expect(error.code).to.not.be.undefined; expect(error.code).to.equal('GNUPG_ERROR'); + context.connection.disconnect(); done(); }); }); - }); + }).timeout(5000);; it('Overly large message ( >= 48MB) is rejected', function (done) { let prm = Gpgmejs.init(); @@ -141,6 +149,7 @@ describe('Encryption', function () { expect(error).to.be.an.instanceof(Error); // TODO who is throwing the error here? // It is not a GPGME_Error! + context.connection.disconnect(); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 3cd1e92a..bc8c97bb 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -22,7 +22,8 @@ var inputvalues = { encrypt: { good:{ data : 'Hello World.', - fingerprint : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40' + fingerprint : 'D41735B91236FDB882048C5A2301635EEFF0CB05', + data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n' }, bad: { fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' @@ -42,3 +43,62 @@ function bigString(megabytes){ } return new TextDecoder('utf-8').decode(uint); } + +function bigUint8(megabytes){ + let maxlength = 1024 * 1024 * megabytes; + let uint = new Uint8Array(maxlength); + for (let i= 0; i < maxlength; i++){ + uint[i] = Math.random() * Math.floor(256); + } + return uint; +} + +function bigBoringString(megabytes){ + let maxlength = 1024 * 1024 * megabytes; + let string = ''; + let chars = ' ä0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + for (let i= 0; i < maxlength; i++){ + string = string + chars[Math.floor(Math.random() * chars.length)]; + } + return string; +} + +function slightlyLessBoringString(megabytes, set){ + let maxlength = 1024 * 1024 * megabytes; + let string = ''; + let chars = ''; + if (!set){ + + } else if (set ===1 ) { + chars = '\n\"\r \''; + } else if (set === 2 ) { + chars = '()=?`#+-{}[]'; + } else if (set === 3){ + chars = '^°/'; + //'*<>\\^°/'; + } else if (set ===4) { + chars = 'äüßµüþÖ~ɁÑ||@'; + } else { + chars = '*<>\n\"\r§$%&/()=?`#+-{}[] \''; //fails! + + } + for (let i= 0; i < maxlength; i++){ + string = string + chars[Math.floor(Math.random() * chars.length)]; + } + return string; +} + +var encryptedData = + '-----BEGIN PGP MESSAGE-----\n' + + '\n' + + 'hQEMA6B8jfIUScGEAQgAlANd3uyhmhYLzVcfz4LEqA8tgUC3n719YH0iuKEzG/dv\n' + + 'B8fsIK2HoeQh2T3/Cc2LBMjgn4K33ksG3k2MqrbIvxWGUQlOAuggc259hquWtX9B\n' + + 'EcEoOAeh5DuZT/b8CM5seJKNEpPzNxbEDiGikp9DV9gfIQTTUnrDjAu5YtgCN9vA\n' + + '3PJxihioH8ODoQw2jlYSkqgXpBVP2Fbx7qgTuxGNu5w36E0/P93//4hDXcKou7ez\n' + + 'o0+NEGSkbaY+OPk1k7k9n+vBSC3F440dxsTNs5WmRvx9XZEotJkUBweE+8XaoLCn\n' + + '3RrtyD/lj63qi3dbyI5XFLuPU1baFskJ4UAmI4wNhdJ+ASailpnFBnNgiFBh3ZfB\n' + + 'G5Rmd3ocSL7l6lq1bVK9advXb7vcne502W1ldAfHgTdQgc2CueIDFUYAaXP2OvhP\n' + + 'isGL7jOlDCBKwep67ted0cTRPLWkk3NSuLIlvD5xs6L4z3rPu92gXYgbZoMMdP0N\n' + + 'kSAQYOHplfA7YJWkrlRm\n' + + '=zap6\n' + + '-----END PGP MESSAGE-----\n'; \ No newline at end of file diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index d26aab18..b71004a5 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -110,7 +110,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ } return null; } else if (code === 'GNUPG_ERROR'){ - return new GPGME_Error(code, info.msg); + return new GPGME_Error(code, info); } else { return new GPGME_Error('GENERIC_ERROR'); diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 9475b2b0..c1a01377 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -170,18 +170,19 @@ function putData(message, data){ if (!data){ return gpgme_error('PARAM_WRONG'); } else if (data instanceof Uint8Array){ - let decoder = new TextDecoder('utf8'); message.setParameter('base64', true); - message.setParameter ('data', decoder.decode(data)); + message.setParameter ('data', btoa(data)); } else if (typeof(data) === 'string') { message.setParameter('base64', false); message.setParameter('data', data); - } else if ( typeof(data) === 'object' && data.hasOwnProperty(getText)){ + } else if ( typeof(data) === 'object' && data.hasOwnProperty('getText')){ let txt = data.getText(); if (txt instanceof Uint8Array){ - let decoder = new TextDecoder('utf8'); message.setParameter('base64', true); - message.setParameter ('data', decoder.decode(txt)); + message.setParameter ('data', btoa(txt)); + } + else { + return gpgme_error('PARAM_WRONG'); } } else { return gpgme_error('PARAM_WRONG'); -- cgit From c92326cc257cf7c8b6c0ddc43ec81573c409bc64 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 9 May 2018 19:40:57 +0200 Subject: js: more testing of nativeMessaging connection -- * There were some inconsistencies between utf-8, transfer and browsers' utf16, which broke characters that were split between individual messages. src/Connection now contains a workaround that reassembles javascripts' format from passed base64 strings. This needs someone more experienced looking. * Added several new tests which were failing during initial debugging of this issue * reorganized BrowsertestExtension to avoid cluttering. --- lang/js/BrowserTestExtension/browsertest.html | 3 - lang/js/BrowserTestExtension/index.html | 40 +++++ lang/js/BrowserTestExtension/longTests.html | 22 +++ lang/js/BrowserTestExtension/popup.js | 2 +- lang/js/BrowserTestExtension/runbrowsertest.js | 1 - lang/js/BrowserTestExtension/rununittests.js | 21 +++ .../tests/encryptDecryptTest.js | 191 +++++---------------- lang/js/BrowserTestExtension/tests/encryptTest.js | 2 +- lang/js/BrowserTestExtension/tests/inputvalues.js | 119 ++++++++++++- .../BrowserTestExtension/tests/longRunningTests.js | 53 ++++++ lang/js/BrowserTestExtension/unittests.html | 17 ++ lang/js/src/Connection.js | 19 +- 12 files changed, 328 insertions(+), 162 deletions(-) create mode 100644 lang/js/BrowserTestExtension/index.html create mode 100644 lang/js/BrowserTestExtension/longTests.html create mode 100644 lang/js/BrowserTestExtension/rununittests.js create mode 100644 lang/js/BrowserTestExtension/tests/longRunningTests.js create mode 100644 lang/js/BrowserTestExtension/unittests.html (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index d12e03cf..c379ef53 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -12,14 +12,11 @@ - - - diff --git a/lang/js/BrowserTestExtension/index.html b/lang/js/BrowserTestExtension/index.html new file mode 100644 index 00000000..05d413ba --- /dev/null +++ b/lang/js/BrowserTestExtension/index.html @@ -0,0 +1,40 @@ + + + + + + + +

gpgmejs - Tests

+

+ The unittests rely on a separately packaged version of gpgmejs, + with the different classes and functions exposed. These tests and their + input values can be found in gpgme/lang/js/test. They do not test the + overall functionality, but the individual behaviour of the components. +

+

+

+ The functionality tests, to be found in + gpgme/lang/js/BrowserTestExtension, check the overall functionality of + the standard packaged version of gpgmejs. +

+

+ + diff --git a/lang/js/BrowserTestExtension/longTests.html b/lang/js/BrowserTestExtension/longTests.html new file mode 100644 index 00000000..8ff969b7 --- /dev/null +++ b/lang/js/BrowserTestExtension/longTests.html @@ -0,0 +1,22 @@ + + + + + + + +

Browsertest

+
+ + + + + + + + + + + + + diff --git a/lang/js/BrowserTestExtension/popup.js b/lang/js/BrowserTestExtension/popup.js index 4764df55..12beb1eb 100644 --- a/lang/js/BrowserTestExtension/popup.js +++ b/lang/js/BrowserTestExtension/popup.js @@ -39,6 +39,6 @@ document.addEventListener('DOMContentLoaded', function() { chrome.tabs.create({ - url: './browsertest.html' + url: './index.html' }); }); diff --git a/lang/js/BrowserTestExtension/runbrowsertest.js b/lang/js/BrowserTestExtension/runbrowsertest.js index 308c716d..39bc3fb9 100644 --- a/lang/js/BrowserTestExtension/runbrowsertest.js +++ b/lang/js/BrowserTestExtension/runbrowsertest.js @@ -19,4 +19,3 @@ */ mocha.run(); -Gpgmejs_test.unittests(); diff --git a/lang/js/BrowserTestExtension/rununittests.js b/lang/js/BrowserTestExtension/rununittests.js new file mode 100644 index 00000000..f85ed8b5 --- /dev/null +++ b/lang/js/BrowserTestExtension/rununittests.js @@ -0,0 +1,21 @@ +/* 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+ + */ +Gpgmejs_test.unittests(); +mocha.run(); diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index e28dd66b..a66e1534 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -19,7 +19,7 @@ */ describe('Encryption and Decryption', function () { - it('Successful encrypt and decrypt', function (done) { + it('Successful encrypt and decrypt simple string', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( @@ -39,54 +39,6 @@ describe('Encryption and Decryption', function () { }); }); }); - - /** - * Fails with random data! Some bytes (up to 100) of the original are missing in - * the result -*/ -/** - for (let j = 0; j < 10; j++){ - it('Successful encrypt and decrypt specific sets: ', - function (done) { - let prm = Gpgmejs.init(); - let data = bigBoringString(5); //see ./inputvalues.js - expect(Object.prototype.toString.call(data)).to.equal("[object String]"); - prm.then(function (context) { - context.encrypt(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'); - context.decrypt(answer.data).then( - function (result) { - if (data.length !== result.data.length) { - - for (let k = 0; k < data.length; k++) { - if (data[k] !== result.data[k]) { - console.log(k); - console.log(data[k - 2] + data[k - 1] + data[k] + data[k + 1]); - console.log(result.data[k - 2] + result.data[k - 1] + result.data[k] + result.data[k + 1]); - break; - } - } - } - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - context.connection.disconnect(); - done(); - - }); - }); - }); - }).timeout(5000); - } - - it('Roundtrip does not destroy trailing whitespace', function (done) { let prm = Gpgmejs.init(); @@ -112,88 +64,22 @@ describe('Encryption and Decryption', function () { }); }); }); - }).timeout(3000); - - it('Test with simple non-ascii input', - function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = ''; - for (let i=0; i < 1024 * 1024 * 0.1; i++){ - data += inputvalues.encrypt.good.data_nonascii; - } - context.encrypt(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'); - console.log(answer); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - if (data.length !== result.data.length) { - - for (let k = 0; k < data.length; k++) { - if (data[k] !== result.data[k]) { - console.log(k); - console.log(data[k - 2] + data[k - 1] + data[k] + data[k + 1]); - console.log(result.data[k - 2] + result.data[k - 1] + result.data[k] + result.data[k + 1]); - break; - } - } - } - console.log(data.length - result.data.length); - expect(result.data).to.equal(data); - context.connection.disconnect(); - done(); + }).timeout(5000); - }); - }); - }); - }).timeout(3000); -*/ -/** - for (let i=0; i< 100; i++) { - it('Successful encrypt random data '+ (i+1) + '/100', function (done) { - let prm = Gpgmejs.init(); - let data = bigString(0.2); // << set source data here + for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ + it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + (j + 1) + '/' + inputvalues.encrypt.good.data_nonascii_32.length + ')', + function (done) { + let input = inputvalues.encrypt.good.data_nonascii_32[j]; + expect(input).to.have.length(32); + let prm = Gpgmejs.init(); prm.then(function (context) { + let data = ''; + for (let i=0; i < 34 * 1024; i++){ + data += input; + } context.encrypt(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'); - context.decrypt(answer.data).then( - function(result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - context.connection.disconnect(); - done(); - }); - }); - }); - }).timeout(5000); - }; -*/ - -/** still fails - it('Successful encrypt 0.8 MB Uint8Array', function (done) { - let prm = Gpgmejs.init(); - let data = bigUint8(0.8); - prm.then(function (context) { - context.encrypt(data, - inputvalues.encrypt.good.fingerprint).then( - function (answer){ + function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a("string"); expect(answer.data).to.include( @@ -201,38 +87,39 @@ describe('Encryption and Decryption', function () { expect(answer.data).to.include( 'END PGP MESSAGE'); context.decrypt(answer.data).then( - function(result){ + function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); - done(); - }); - }); - }); - }).timeout(5000); -*/ - - it('Decrypt simple non-ascii', - function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - data = encryptedData; - context.decrypt(data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(inputvalues.encrypt.good.data_nonascii); - context.encrypt(inputvalues.encrypt.good.data_nonascii, inputvalues.encrypt.good.fingerprint).then( - function(result){ - context.decrypt(result.data).then(function(answer){ - expect(answer.data).to.equal(inputvalues.encrypt.good.data_nonascii); context.connection.disconnect(); done(); }); + }); + }); + }).timeout(5000); + }; + + it('Encrypt-decrypt simple non-ascii', function (done) { + //FAILS TODO: Check newline at the end + let prm = Gpgmejs.init(); + prm.then(function (context) { + data = encryptedData; + context.decrypt(data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(inputvalues.encrypt.good.data_nonascii); + context.encrypt(inputvalues.encrypt.good.data_nonascii, inputvalues.encrypt.good.fingerprint).then( + function(result){ + context.decrypt(result.data).then(function(answer){ + expect(answer.data).to.equal('¡Äußerste µ€ før ñoquis@hóme! Добрый день'); + context.connection.disconnect(); + done(); }); }); + }); - }); - }).timeout(8000); + }); + }).timeout(6000); -}); \ No newline at end of file +}); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 2e95151b..5ef68a32 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -49,7 +49,7 @@ describe('Encryption', function () { done(); }); }); - }).timeout(5000); + }).timeout(10000); /** it('Successful encrypt 20 MB', function (done) { diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index bc8c97bb..e23b7786 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -23,7 +23,23 @@ var inputvalues = { good:{ data : 'Hello World.', fingerprint : 'D41735B91236FDB882048C5A2301635EEFF0CB05', - data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n' + data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день', + data_nonascii_32: [ + 'K€K€K€K€K€K€K€K€K€K€K€K€K€K€K€K€', + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€', //fails result has 3 chars more + '€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€', //fails 3 chars + '²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³', + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€A€µ€µ€µ€µ€', //fails 2 chars + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µAµ€µ€µ€µ€', //is okay if 2 chunksizes. + 'üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü', + 'µAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA€', + 'µAAAAµAAAAAAAAAAAAAAAAAAAAAAAAA€', + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAµ€', + 'µAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA°', + '€AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA€', + 'µ||||||||||||||||||||||||||||||€', + 'æſæſ³¼„¬“³³¬“¬½”æſæſ³¼„¬“³³¬“¬½”' + ] }, bad: { fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' @@ -56,7 +72,7 @@ function bigUint8(megabytes){ function bigBoringString(megabytes){ let maxlength = 1024 * 1024 * megabytes; let string = ''; - let chars = ' ä0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let chars = ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; for (let i= 0; i < maxlength; i++){ string = string + chars[Math.floor(Math.random() * chars.length)]; } @@ -101,4 +117,101 @@ var encryptedData = 'isGL7jOlDCBKwep67ted0cTRPLWkk3NSuLIlvD5xs6L4z3rPu92gXYgbZoMMdP0N\n' + 'kSAQYOHplfA7YJWkrlRm\n' + '=zap6\n' + - '-----END PGP MESSAGE-----\n'; \ No newline at end of file + '-----END PGP MESSAGE-----\n'; +var encryptedBroken = '-----BEGIN PGP MESSAGE-----\n' + +'\n' + +'hQEMA6B8jfIUScGEAQf/bUYF70KRCHWITfNH7zaYaLa8P+QoCo+NpFzc3U9J4mty\n' + +'FxjIpoNwxEvQ9UUEMi6LgHhvURYCbWrCV5XYjo/sE66CRXsEuNirfYkAzXVNcUf7\n' + +'BaAzio/QzyyvBfzwHHqMLSxAcNggs+f5lob+TcBnBghwpn1lh5BgNUuhDKVq21/F\n' + +'wWK4rqjmmjrpoR3tKcl916+/Z0VI5SAkPG4IrWUfumxG0xbePB9IFT8uGMmXy2qr\n' + +'ICmEfPakLUIo7NLrdMNInnVQaAeNS/5u5TbpZpRxZWtRP7m4EyUoEA+TgSkp+hG8\n' + +'Um7hmbFsB99H0yiyCSLicN5AxzmgCrL3D77Fqh7LaNLsAYjcyVZm+R7te4vwpv9P\n' + +'F/MCAEUFKGfNYHqyVjBhBlm4/PMC+YtOE9jF920hwtDckT/V3L2POk1Kr78+nVjw\n' + +'1HXTfK/Tk6QMGrzCd2ril5aB2RCi+Fr41B2ftS8SLwcrnrFkP2enH6VYBserx5l8\n' + +'qZlgRR53QNnLvqnn7h/NO1ZNN5cnD2pf0PWBkSHmr5ph82JQ+XyB0h4eV1kwX80K\n' + +'8IkBAq6hFpfm7TU4gy5x1VNTeVoCRdlzESkzVwbvjNZ+OU6+vcpfCaHMbuVBUmYz\n' + +'xjTKYlenevSzwfF1RY7noDTrPUQrBrVor2cPjN3ROLCbFpARrQf44BfzGaq5XdWc\n' + +'NZWFgiRKVGVJQeBQjRyqHAv4e8rkcr5qwnY8kyZpLYAKIVBgtqnh7GExaW5efWRG\n' + +'tyJMgUuP+dF/+HymhlEmMKZabLf5W8J3p8+uBOkU359OX/HOS8mPr6a7bnI4895W\n' + +'7Dt5vkpHRR81V1Le0+Mtcj7G46hsvFMA0dgw29mBbaOA8fhOrumqTBOh01lZliwI\n' + +'6/OF6iqAeBAH3hJQlodCACf1yTxHynF6Ro/SnIa/3BN4CN4PPRHdLMHBJevRm3Ih\n' + +'CbqXVmSdtrihHsViPKjc8+u+7g2n/lt9LHrMyOmptyVX8vT9B/AQYHxf0FDmv4Vg\n' + +'62Mo+eDRWZF+XmKPQYedM6nF5hcyxc/1aCM4yXtu8qQir/GDvyghPbfnKkium5kk\n' + +'+XOb+aIUsxbNzhdLowp2mZcy1MYMPHIJNjIXmVjPnc/GwB8S2SX/gHn1quz52ENq\n' + +'l12ome7rfAp9JkrVbHOK11iDPbd3UdHSTfFNO8wQrxtqnZhUwqLhZwteOi4EGSSh\n' + +'OrWihjdonqL0qcfiS6N9QemJz2w40fR8ZwDuGvPgl6LeNtKjihyqsWvh+zJzwmwM\n' + +'R2Y50wNyvQnXGH4RJJUQVAKO/vMp63K2j3DnHsyz/XLbmp25QGn9f1QIjfplY64D\n' + +'q3lp2W6GvhpYWLRzBfIo6ebwLtqHTsTgON9TA4CD+1QbOXMIxQKAb9hhzEtp/5zN\n' + +'+gJhF4pOvEu5Cg1j9CtXh93iE0J9rwrjyMujzBSiaoqxHabXtRarv8d2v/w75AKh\n' + +'6Avt+WFYRdSLKCstdHeuREXEibIaM55nUUIEO0v9kcb0Y7LyH/vFVGAo0QFh3u+t\n' + +'zMupQwywjeuuUwM18KeWjKrhGuRf1WWCDRnnH1yEztDPLx5kyxadsC31/XyqLjYl\n' + +'zt+vUSm+JrXujhba9VaYO3DSB9hL0qdrA3gaK2DAl2nvFGRn0fjtw0xfa9VJlafN\n' + +'JLosw7MDDEFx962vHbx5XfjJRGaEdDnsco5E5VUkQ+RjhWWrzMHpIPYWYacXiUKr\n' + +'TcNTAg1jR5M2FRz/QOk7qsTl98RyNCYXTUmuPh/pLJI0kJ5rtTPrlzFNgVjwiYEJ\n' + +'+iNITXhqx5KJ5ifY89BXeNVavIb1Tp0xc1+637U/ztH9D0Jp6m0w/VIHW+881Ik3\n' + +'fMKw8A/RuEdTil/PU0bjVRNYLS/KCQCqrlYdItYh57IAkt+sQNxvw0xg46QN+OkO\n' + +'QHKnIazexhGAqyBe6c2KYuRLW46h9grGbCJnqvmoThBRrqL7twmp00O846tvRms8\n' + +'3QEXL3oXqBTH1d6bRd/E6m++X/n9I6VaKMgYe6GNQEqwvtSySFi65VK5cH1jnEGw\n' + +'wr2ZkXUrVbNTfXci6SdNqh+W8DRnFvlRyKzG1jnibsOW5FwGSMT3kVRUvnnJbzlc\n' + +'wj1cJC/NMvkoQtGHppHkMjE23byjBhJlZXBTbGc3kSOfXKAMAT7I9Dm/GgEpbbpD\n' + +'4fgzqNEeWucrCWgbXviXt1pWOyNtudb9rHWgvIQlE9JeykPgvmg+pl4Av42lQTYp\n' + +'kyNFjq46niWT9VsYlsW52x4jCQifT7HkxTuSaD9JyVqjQWS11rci9UM/NuoXfqrv\n' + +'vJYMBJGhzTxFzzFCzSRSERbjN0iXJ2E8vFKkpd5nCZxRMz6XBMk1NVyrE956BMum\n' + +'yNaSy5mwR+ekS3xM7oUdbqyyDwFEDxpPhtIRqRfFugpIn8tRy7jwDZB9mctFGfKo\n' + +'th5dCzcaU0qPfUJWPVQVh2LCPneLGhLENgFUhoNZ+rzaf5SltLeB4vuVjZMLe+PW\n' + +'KqtT9l6QFQajbe7pj99BScteaI8lpiQiNTvQq/LZRFWr9eb5z0Xk5Wc3aYZgymkp\n' + +'EYxyVqwomyz4wPf2BrgsSdKk0OZKIkAxfA3i73tHvCsCQOHeriRMSfLzFN3J54nf\n' + +'+MOuUm1hKLsLbPLQxOfzPiymVGp6DjYCkrRmafvZUJHkvGubvVVR5Yq0txznM1Vg\n' + +'yZq4HoF3RGgKzJtk8N4me5YsVaM2/q+2B2ziVa/HeEFt/cZfcH/byY3ooW3OnAum\n' + +'KTe/+T2BEjXfipmbIMA6iK3IKIoguuVwvSJz+5QfjMH1o8HIUdDOhnrbBBHmkvNK\n' + +'MG+dV+oDijC2rL3n0qRURu4VWdk/bqKcaaLoZC5iDGLThZ20q+9jlFKahmlKe1WH\n' + +'2Rch+JJfqSHtNYVKxZU0CC0I9Wg/Ws6TQJREKCiJf0/aTvxWRSHZtecFiZK7q+zn\n' + +'NyRdWnqAv+HKRjN/tVZcf8I0CERswxmixF9uWMTjH+hq0u/h4It3I3tOObNyAQO3\n' + +'iY9uSZEZbrKBSM3DqFF75toLjooWXU8yaC9so3mQVf5MnSZpG3PA5klwusLmi0QU\n' + +'HD1eZ2aXUnTx7TbHuovWLjI40SIUKnaMAf0TCUHfBvJ5rLUPYez35QwrYRx0Qixn\n' + +'Pcj7KCCXrT5cqwH64vGTiW6JCZJlLzneiE+dmnAT+wnNRNxbVooi6ejWce5HYbYd\n' + +'c2SyBHJstGn0zuNN/248qhV+r5AMBgZ+vDilV8Bmdh3N/xlXBIgLIocegL6Kc+S0\n' + +'Pr60DHKLcnZIunQwZOwyRb8wG9jV6I718CmbSw94gKNCi99B8BSDZ7z2ai+0yv44\n' + +'ErR4Qp/gnCp9/6NXNmafluYn5Pgl9vZCozcJ8EN8mzD4szZBL19btecoT6Wcnve2\n' + +'fYDRuYPWpT79QyRDSMSSzrQoFpezIOtPS2nrN+II81TxyTgOMY+jzR4TRJyMt185\n' + +'7OG4t8Q+WOgzNS4clmPHnmgBBhsueWob72SvIgRtq5pQYB0fStx9qUDMZPnePdhS\n' + +'rI+K82k1/eY5vTQ/eDXMN7UUfdLriuK0UXnJFu5CQSwrMD1u5nFVbQYC9PEwgdUc\n' + +'XEASt9/jh2wDgSXAGegc6mLRI+Zu5H5ygpCIAMs8pNwFJ5DhCsve5RbalGEbYbuL\n' + +'NwB1rRExCCUBjnAkpwNU0TL991y1Gn+gpN2lNvITq/BroE3HLjXbnEACTN+hwNPB\n' + +'KJi38zKSb6/k27/zpTMuEKRXkSz4QuuviQbGJTmCbub+l2aVBQhVNwooGI92Gt8n\n' + +'EQjGOzqeS4J0KQGZmhYRGVc7DdwjBYLV5pi1WkCIt1a1PDK9VZ4vzz978gLaxSZM\n' + +'yozdL97g9wo0IJcAj+36b1Wewj+hL81t0SgIShEO0aIGSNDlFZM4mKQNmCUhvWuO\n' + +'M1CpniR8cBN4MHUaQdBIlW2ua9Ba8JM7LNwcD8JddGvmUBwzFr5w4Hu4ylweacXP\n' + +'5zUfZpJyFZKoxJe1cPY47NmXemOLuBVJRlThnUazvhM/KRxfyu2q4WOz6VSm6LEq\n' + +'PFfr/NYH1AxIda/Z4tLLAs0nLbV+HrqRFMJOBGdY6dMxuvaiUutY3MZCMCKupz8f\n' + +'yHh2p2lFy2jQvZs4HAKN6hTx8X7at1ue0RYw3hdjoPHa/NBKDzrkKjGInfraTVr6\n' + +'qrxqW09/yNuiatISi+KxuBM4o9L/w85Zf01RNEZTS5zCKX0ml33JHgNxQgPosp+7\n' + +'R0TUK2lANdKVTXJe8V/IT4tGUD4mg0EjMVRmFV2CL3LgBbW3ScOC15D4mzD14Yyb\n' + +'KTUHwfX189GHKjJhHnSuZ3QgVKynoSII+0x4fiDHsdhdXdMj/qvVdZIMlABWKRD0\n' + +'JVmrkFpzFtt4yXupl62+9ZYZehSKNKurlO4A8OBeg6xKDUKuvrI7Ug/2s5Q0pCxp\n' + +'EgtxwOhhYrAhd8mN2ilKeB++JCAmZ2KwnwCGFF8kZ/5TOwWZHm/RNKEchTRC5kws\n' + +'KsDUxq/19ORifzCA19f6Tc5s9HcPwxvnrscvb6LLTGGiROp3BlcitHjmPsH5bRUX\n' + +'OAqV069l1JKeiCkGgQmlRviBGG0yO2zIcAeoDIPhaO4O0K6/VHo4p6kAlZAzWJuT\n' + +'QmHI0ETyO+2m0jySoxW0EUU1FB3eQ4KBocneYqJUgCbOCeXf14TO8HekDtkfoKOK\n' + +'bded3iCtnSAH6I9ERtPebqiWdR2tVCO4Yyqkf2f3vzCWrtyXHUWtZtC1I08HNLin\n' + +'zGhEdQZ/VFCLP8CWmbtLU8BPeu88VTpw7i8G76QuHq5+0DY9eBgHWxcBYiwRisT/\n' + +'DHXH0TvjuPedJ4F/sNmlktTXLLMqVu+J8i/qJ48E1r9wXkHTICnFy8jvm5MpQ4gu\n' + +'rwzpyjSFLJZpzDMAxcPSXYGi1kchW+CDg/N/cdeYlVLCoBrUn6dEq6CC05Y6JmDW\n' + +'t46R6lFHbQoq1WsMWZSKomB4WlxWP+hYDsssQOUR9Y7wwI4KXPtf6Ar9W2T9cSfO\n' + +'mtDpgfeOVq/vE01TQGlZc4zwF5dcXBV3OLYBSXlv4JFIreOlKDi/IbPc6TYw0mbV\n' + +'wFuzPi8VpHip3YoGdM7XUDvO1sE07FX8/xrEQVkJfzgl/v+mQ66TCb+/g13QPgZI\n' + +'UftRS6hLeKNTd0pZc8+CTbNzgrCDGqbYn5ZpyPFYF+fVGZnqqLUid5NTjkwI1IoD\n' + +'PgOSHQEo+pIlNfTtR2DCYgqOiMaBSZ4bc4b6SohAKGJkPhNmlMJ61MwGN2J8pFpl\n' + +'1uG2MO3TUo6MxQAkCcKe4twwy1bQh4kO3kReUqTDW/VTnp6HfZhqtYc1tBGLcahu\n' + +'C0ZX7B/8Wbu1PWN4Y34F7ouuSu2l6ASnoAc/Ek1S9R1uyiwLtaPuK58oUbVisDh3\n' + +'cYmnjP0DelYq8FpJPWPrSGwqlERotf3KU3L1k84SHYUB1pHFYPF46KAKYH5qTrsO\n' + +'T3id3CO3mt1gtgWAEGRkEQ+qVmvWtINBOwyFYVAD9ZqXflzF83ZGvdmvdJ6kzRZ7\n' + +'fY5ACZGMghb3f4mfLlbF81WluDbk2k+t186qmRFrJFtJPvAl3VxXczo8pw5bSAdK\n' + +'R6c7cagA6ql4QaYqtbIHpFbgz7iQ9ESe23Q2+o82lkTbUFdG+GDhnZFOL+ldWf/g\n' + +'ufSCqY7IlNxj3hYxgTpaXb2lWvVVdo7C4VhPHyIDbQUCdUE80t2cDgJqPFABe3la\n' + +'Y+UsW9W787mGGuuNSF/iI0tANw5twlQjdRQtqxnF1yETh/hFA4bgD9bmBOBFd+GT\n' + +'+ECxkqI4/UYMgYfVMFja/e6+dQTWLblzuNaZh6wHASeNqpFmeQSBawBVV7qK3nC7\n' + +'CDY9r6Aq9JYMiJTE/TzyfBmBhnxtL1aKTu6EHy3siDlID7EjQx1Xyr/EtbJCmsVl\n' + +'E14StpggdK8=\n' + +'=enm3\n' + +'-----END PGP MESSAGE-----\n'; \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js new file mode 100644 index 00000000..0f32ca92 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -0,0 +1,53 @@ +describe('Long running Encryption/Decryption', function () { + for (let i=0; i< 100; i++) { + it('Successful encrypt/decrypt completely random data ' + (i+1) + '/100', function (done) { + let prm = Gpgmejs.init(); + let data = bigString(2); + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + }); + }); + }); + }).timeout(5000); + }; + + it('Successful encrypt 1 MB Uint8Array', function (done) { + let prm = Gpgmejs.init(); + let data = bigUint8(1); + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }); + }).timeout(5000); + +}); diff --git a/lang/js/BrowserTestExtension/unittests.html b/lang/js/BrowserTestExtension/unittests.html new file mode 100644 index 00000000..6f7da3f1 --- /dev/null +++ b/lang/js/BrowserTestExtension/unittests.html @@ -0,0 +1,17 @@ + + + + + + + + +

Unit tests

+
+ + + + + + + diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 2c8792d6..64621f60 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -181,7 +181,8 @@ class Answer{ if (!this._response.hasOwnProperty(key)){ this._response[key] = ''; } - this._response[key] = this._response[key].concat(msg[key]); + // console.log(msg[key]); + this._response[key] += msg[key]; } //params should not change through the message else if (poa.params.indexOf(key) >= 0){ @@ -214,6 +215,22 @@ class Answer{ * TODO: does not care yet if completed. */ get message(){ + let keys = Object.keys(this._response); + let poa = permittedOperations[this.operation].answer; + for (let i=0; i < keys.length; i++) { + if (poa.data.indexOf(keys[i]) >= 0){ + if (this._response.base64 == true){ + let respatob = atob(this._response[keys[i]]); + + let result = decodeURIComponent( + respatob.split('').map(function(c) { + return '%' + + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + this._response[keys[i]] = result; + } + } + } return this._response; } } -- cgit From 987b31746809dfe04966e37edd759a448a28d975 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 14 May 2018 16:23:24 +0200 Subject: js: Tests and improvements for openpgp mode -- * Added openpgp - Mode tests to the browsertest Extension. These tests require openpgp, which should not be a hard dependency for the main project. Packing openpgpjs into the extension is still TODO * Fixes: - openpgp mode API now correctly handles parameters as an object, similar to openpgpjs - proper check and parsing of openpgpjs Message Objects --- lang/js/BrowserTestExtension/index.html | 7 + lang/js/BrowserTestExtension/openpgpModeTest.html | 23 +++ .../tests/encryptDecryptTest.js | 21 +-- .../tests/inputValues_openpgpjs.js | 32 ++++ lang/js/BrowserTestExtension/tests/inputvalues.js | 131 +++----------- .../BrowserTestExtension/tests/longRunningTests.js | 1 + .../BrowserTestExtension/tests/openpgpModeTest.js | 196 +++++++++++++++++++++ lang/js/src/Connection.js | 1 - lang/js/src/gpgmejs.js | 18 +- lang/js/src/gpgmejs_openpgpjs.js | 77 ++++---- 10 files changed, 346 insertions(+), 161 deletions(-) create mode 100644 lang/js/BrowserTestExtension/openpgpModeTest.html create mode 100644 lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js create mode 100644 lang/js/BrowserTestExtension/tests/openpgpModeTest.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/index.html b/lang/js/BrowserTestExtension/index.html index 05d413ba..c49aedae 100644 --- a/lang/js/BrowserTestExtension/index.html +++ b/lang/js/BrowserTestExtension/index.html @@ -34,6 +34,13 @@ Functionality tests with larger/longer running data sets. +
  • + + Testing openPGP mode. + - Please notice that, due to comparing + the inputs and outputs with openpgpjs objects, this test + requires a copy of openpgpjs in libs. +
  • diff --git a/lang/js/BrowserTestExtension/openpgpModeTest.html b/lang/js/BrowserTestExtension/openpgpModeTest.html new file mode 100644 index 00000000..e7a12be9 --- /dev/null +++ b/lang/js/BrowserTestExtension/openpgpModeTest.html @@ -0,0 +1,23 @@ + + + + + + + +

    Openpgp mode test

    +
    + + + + + + + + + + + + + + diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index a66e1534..5c534039 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -99,8 +99,7 @@ describe('Encryption and Decryption', function () { }).timeout(5000); }; - it('Encrypt-decrypt simple non-ascii', function (done) { - //FAILS TODO: Check newline at the end + it('Decrypt simple non-ascii', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { data = encryptedData; @@ -108,18 +107,10 @@ describe('Encryption and Decryption', function () { function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); - expect(result.data).to.equal(inputvalues.encrypt.good.data_nonascii); - context.encrypt(inputvalues.encrypt.good.data_nonascii, inputvalues.encrypt.good.fingerprint).then( - function(result){ - context.decrypt(result.data).then(function(answer){ - expect(answer.data).to.equal('¡Äußerste µ€ før ñoquis@hóme! Добрый день'); - context.connection.disconnect(); - done(); - }); - }); - }); - + expect(result.data).to.equal( + '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); + done(); + }); }); - }).timeout(6000); - + }).timeout(3000); }); diff --git a/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js b/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js new file mode 100644 index 00000000..945955be --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js @@ -0,0 +1,32 @@ +const openpgpInputs = { + pubKeyArmored: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + '\n' + + 'mQENBFrsKEkBCADKw4Wt8J6M/88qD8PO6lSMCxH1cpwH8iK0uPaFFYsJkkXo7kWf\n' + + 'PTAtrV+REqF/o80dvYcdLvRsV21pvncZz/HXLu1yQ18mC3XObrKokbdgrTTKA5XE\n' + + 'BZkNsqyaMMJauT18H4hYkSg62/tTdO1cu/zWv/LFf7Xyn6+uA74ovXCJlO1s0N2c\n' + + 'PShtr98QRzPMf2owgVk37JnDNp4gGVDGHxSZOuUwxgYAZYnA8SFc+c+3ZrQfY870\n' + + '+O4j3Mz4p7yD13AwP4buQLBsb/icxekeQCqpRJhLH9f7MdEcGXa1x36RcEkHdu+M\n' + + 'yJ392eMgD+dKNfRCtyTPhjZTxvbNELIBYICfABEBAAG0EHRlc3RAZXhhbXBsZS5v\n' + + 'cmeJAVQEEwEIAD4WIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbAwUJA8Jn\n' + + 'AAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAjAWNe7/DLBf9kB/wOQ/S60HGw\n' + + 'Fq07W9N01HWULyhHKoMmcHL6rfZ64oDqLxolPSasz7WAMW1jN4qtWJ0mFzwO83V6\n' + + 'kaBe+wF6Kqir6udFSBW9rPcFg6/VZXPltT0a6uacIHq6DyQ5iMW4YQWbVy9OR2rN\n' + + 'GkYo1JCBR0XdRJYCSX3yB4TWv/eXnZ37/WjmiTOIZh35rjs+NuU/S5JPDfAp2/k7\n' + + '0DevQeBsv+UjVXjWpNTZmPbvDnd995uSmC6UY4hzyP84ORYMYn9n1QAR0goxDN6U\n' + + 'unOf9Rlp1oMzdxMool/d1MlCxg2h3jheuhv7lgUF4KpvHOuEPXQ7UO417E0TYcDZ\n' + + '1J8Nsv87SZeEuQENBFrsKEkBCADjoEBhG/QPqZHg8VyoD1xYRAWGxyDJkX/GrSs6\n' + + 'yE+x2hk5FoQCajxKa/d4AVxOnJpdwhAfeXeSNaql5Ejgzax+Tdj9BV6vtGVJVv0p\n' + + 'O7bgAiZxkA6RHxtNqhpPnPQoXvUzkzpRgpuL+Nj4yIg7z1ITH6KQH4u5SI9vd+j/\n' + + '8i9Taz67pdZwuJjac8qBuJHjzAo1bjYctFYUSG5pbmMQyNLySzgiNkFa4DajODlt\n' + + '3RuqVGP316Fk+Sy2+60tC/HlX8jgMyMONfOGBQx6jk8tvAphS/LAqrrNepnagIyL\n' + + 'UGKU+L8cB2g1PGGp2biBFWqZbudZoyRBet/0yH/zirBdQJw1ABEBAAGJATwEGAEI\n' + + 'ACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAKCRAjAWNe\n' + + '7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ5F32NDJ9\n' + + 'PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7Jq3e/4Iy\n' + + '0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02Lkr+2Cc/Q\n' + + 'k6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe23nntMSD\n' + + 'A+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t9Mmd7bM1\n' + + '+UyPgbPEr0iWMeyctYsuOLeUyQKMscDT\n' + + '=QyY6\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n' +}; diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index e23b7786..38ee6aad 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -22,15 +22,18 @@ var inputvalues = { encrypt: { good:{ data : 'Hello World.', + // Fingerprint of a key that has been imported to gnupg (i.e. see testkey.pub; testkey.sec) fingerprint : 'D41735B91236FDB882048C5A2301635EEFF0CB05', data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день', + + // used for checking encoding consistency in > 2MB messages. data_nonascii_32: [ 'K€K€K€K€K€K€K€K€K€K€K€K€K€K€K€K€', - 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€', //fails result has 3 chars more - '€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€', //fails 3 chars + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€', + '€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€', '²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³', - 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€A€µ€µ€µ€µ€', //fails 2 chars - 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µAµ€µ€µ€µ€', //is okay if 2 chunksizes. + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€A€µ€µ€µ€µ€', + 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µAµ€µ€µ€µ€', 'üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü', 'µAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA€', 'µAAAAµAAAAAAAAAAAAAAAAAAAAAAAAA€', @@ -42,15 +45,21 @@ var inputvalues = { ] }, bad: { + // valid Hex value, but not usable (not imported to gnupg, or bogus fingerprint) fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } }, init: { - invalid_startups: [{all_passwords: true}, 'openpgpmode', {api_style:"frankenstein"}] + // some parameters + invalid_startups: [ + {all_passwords: true}, + 'openpgpmode', + {api_style:"frankenstein"} + ] } - }; +// (Pseudo-)Random String from a Uint8Array, given approx. size in Megabytes function bigString(megabytes){ let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); @@ -60,6 +69,7 @@ function bigString(megabytes){ return new TextDecoder('utf-8').decode(uint); } +// (Pseudo-)Random Uint8Array, given size in Megabytes function bigUint8(megabytes){ let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); @@ -69,6 +79,7 @@ function bigUint8(megabytes){ return uint; } +// (Pseudo-)Random string with very limited charset (ascii only, no control chars) function bigBoringString(megabytes){ let maxlength = 1024 * 1024 * megabytes; let string = ''; @@ -79,24 +90,22 @@ function bigBoringString(megabytes){ return string; } +// Some String with simple chars, with different characteristics, but still +// expected to occur in an averag message function slightlyLessBoringString(megabytes, set){ let maxlength = 1024 * 1024 * megabytes; let string = ''; let chars = ''; - if (!set){ - - } else if (set ===1 ) { + if (set ===1 ) { chars = '\n\"\r \''; } else if (set === 2 ) { chars = '()=?`#+-{}[]'; } else if (set === 3){ chars = '^°/'; - //'*<>\\^°/'; } else if (set ===4) { chars = 'äüßµüþÖ~ɁÑ||@'; } else { - chars = '*<>\n\"\r§$%&/()=?`#+-{}[] \''; //fails! - + chars = '*<>\n\"\r§$%&/()=?`#+-{}[] \''; } for (let i= 0; i < maxlength; i++){ string = string + chars[Math.floor(Math.random() * chars.length)]; @@ -104,6 +113,7 @@ function slightlyLessBoringString(megabytes, set){ return string; } +// Data encrypted with testKey var encryptedData = '-----BEGIN PGP MESSAGE-----\n' + '\n' + @@ -118,100 +128,3 @@ var encryptedData = 'kSAQYOHplfA7YJWkrlRm\n' + '=zap6\n' + '-----END PGP MESSAGE-----\n'; -var encryptedBroken = '-----BEGIN PGP MESSAGE-----\n' + -'\n' + -'hQEMA6B8jfIUScGEAQf/bUYF70KRCHWITfNH7zaYaLa8P+QoCo+NpFzc3U9J4mty\n' + -'FxjIpoNwxEvQ9UUEMi6LgHhvURYCbWrCV5XYjo/sE66CRXsEuNirfYkAzXVNcUf7\n' + -'BaAzio/QzyyvBfzwHHqMLSxAcNggs+f5lob+TcBnBghwpn1lh5BgNUuhDKVq21/F\n' + -'wWK4rqjmmjrpoR3tKcl916+/Z0VI5SAkPG4IrWUfumxG0xbePB9IFT8uGMmXy2qr\n' + -'ICmEfPakLUIo7NLrdMNInnVQaAeNS/5u5TbpZpRxZWtRP7m4EyUoEA+TgSkp+hG8\n' + -'Um7hmbFsB99H0yiyCSLicN5AxzmgCrL3D77Fqh7LaNLsAYjcyVZm+R7te4vwpv9P\n' + -'F/MCAEUFKGfNYHqyVjBhBlm4/PMC+YtOE9jF920hwtDckT/V3L2POk1Kr78+nVjw\n' + -'1HXTfK/Tk6QMGrzCd2ril5aB2RCi+Fr41B2ftS8SLwcrnrFkP2enH6VYBserx5l8\n' + -'qZlgRR53QNnLvqnn7h/NO1ZNN5cnD2pf0PWBkSHmr5ph82JQ+XyB0h4eV1kwX80K\n' + -'8IkBAq6hFpfm7TU4gy5x1VNTeVoCRdlzESkzVwbvjNZ+OU6+vcpfCaHMbuVBUmYz\n' + -'xjTKYlenevSzwfF1RY7noDTrPUQrBrVor2cPjN3ROLCbFpARrQf44BfzGaq5XdWc\n' + -'NZWFgiRKVGVJQeBQjRyqHAv4e8rkcr5qwnY8kyZpLYAKIVBgtqnh7GExaW5efWRG\n' + -'tyJMgUuP+dF/+HymhlEmMKZabLf5W8J3p8+uBOkU359OX/HOS8mPr6a7bnI4895W\n' + -'7Dt5vkpHRR81V1Le0+Mtcj7G46hsvFMA0dgw29mBbaOA8fhOrumqTBOh01lZliwI\n' + -'6/OF6iqAeBAH3hJQlodCACf1yTxHynF6Ro/SnIa/3BN4CN4PPRHdLMHBJevRm3Ih\n' + -'CbqXVmSdtrihHsViPKjc8+u+7g2n/lt9LHrMyOmptyVX8vT9B/AQYHxf0FDmv4Vg\n' + -'62Mo+eDRWZF+XmKPQYedM6nF5hcyxc/1aCM4yXtu8qQir/GDvyghPbfnKkium5kk\n' + -'+XOb+aIUsxbNzhdLowp2mZcy1MYMPHIJNjIXmVjPnc/GwB8S2SX/gHn1quz52ENq\n' + -'l12ome7rfAp9JkrVbHOK11iDPbd3UdHSTfFNO8wQrxtqnZhUwqLhZwteOi4EGSSh\n' + -'OrWihjdonqL0qcfiS6N9QemJz2w40fR8ZwDuGvPgl6LeNtKjihyqsWvh+zJzwmwM\n' + -'R2Y50wNyvQnXGH4RJJUQVAKO/vMp63K2j3DnHsyz/XLbmp25QGn9f1QIjfplY64D\n' + -'q3lp2W6GvhpYWLRzBfIo6ebwLtqHTsTgON9TA4CD+1QbOXMIxQKAb9hhzEtp/5zN\n' + -'+gJhF4pOvEu5Cg1j9CtXh93iE0J9rwrjyMujzBSiaoqxHabXtRarv8d2v/w75AKh\n' + -'6Avt+WFYRdSLKCstdHeuREXEibIaM55nUUIEO0v9kcb0Y7LyH/vFVGAo0QFh3u+t\n' + -'zMupQwywjeuuUwM18KeWjKrhGuRf1WWCDRnnH1yEztDPLx5kyxadsC31/XyqLjYl\n' + -'zt+vUSm+JrXujhba9VaYO3DSB9hL0qdrA3gaK2DAl2nvFGRn0fjtw0xfa9VJlafN\n' + -'JLosw7MDDEFx962vHbx5XfjJRGaEdDnsco5E5VUkQ+RjhWWrzMHpIPYWYacXiUKr\n' + -'TcNTAg1jR5M2FRz/QOk7qsTl98RyNCYXTUmuPh/pLJI0kJ5rtTPrlzFNgVjwiYEJ\n' + -'+iNITXhqx5KJ5ifY89BXeNVavIb1Tp0xc1+637U/ztH9D0Jp6m0w/VIHW+881Ik3\n' + -'fMKw8A/RuEdTil/PU0bjVRNYLS/KCQCqrlYdItYh57IAkt+sQNxvw0xg46QN+OkO\n' + -'QHKnIazexhGAqyBe6c2KYuRLW46h9grGbCJnqvmoThBRrqL7twmp00O846tvRms8\n' + -'3QEXL3oXqBTH1d6bRd/E6m++X/n9I6VaKMgYe6GNQEqwvtSySFi65VK5cH1jnEGw\n' + -'wr2ZkXUrVbNTfXci6SdNqh+W8DRnFvlRyKzG1jnibsOW5FwGSMT3kVRUvnnJbzlc\n' + -'wj1cJC/NMvkoQtGHppHkMjE23byjBhJlZXBTbGc3kSOfXKAMAT7I9Dm/GgEpbbpD\n' + -'4fgzqNEeWucrCWgbXviXt1pWOyNtudb9rHWgvIQlE9JeykPgvmg+pl4Av42lQTYp\n' + -'kyNFjq46niWT9VsYlsW52x4jCQifT7HkxTuSaD9JyVqjQWS11rci9UM/NuoXfqrv\n' + -'vJYMBJGhzTxFzzFCzSRSERbjN0iXJ2E8vFKkpd5nCZxRMz6XBMk1NVyrE956BMum\n' + -'yNaSy5mwR+ekS3xM7oUdbqyyDwFEDxpPhtIRqRfFugpIn8tRy7jwDZB9mctFGfKo\n' + -'th5dCzcaU0qPfUJWPVQVh2LCPneLGhLENgFUhoNZ+rzaf5SltLeB4vuVjZMLe+PW\n' + -'KqtT9l6QFQajbe7pj99BScteaI8lpiQiNTvQq/LZRFWr9eb5z0Xk5Wc3aYZgymkp\n' + -'EYxyVqwomyz4wPf2BrgsSdKk0OZKIkAxfA3i73tHvCsCQOHeriRMSfLzFN3J54nf\n' + -'+MOuUm1hKLsLbPLQxOfzPiymVGp6DjYCkrRmafvZUJHkvGubvVVR5Yq0txznM1Vg\n' + -'yZq4HoF3RGgKzJtk8N4me5YsVaM2/q+2B2ziVa/HeEFt/cZfcH/byY3ooW3OnAum\n' + -'KTe/+T2BEjXfipmbIMA6iK3IKIoguuVwvSJz+5QfjMH1o8HIUdDOhnrbBBHmkvNK\n' + -'MG+dV+oDijC2rL3n0qRURu4VWdk/bqKcaaLoZC5iDGLThZ20q+9jlFKahmlKe1WH\n' + -'2Rch+JJfqSHtNYVKxZU0CC0I9Wg/Ws6TQJREKCiJf0/aTvxWRSHZtecFiZK7q+zn\n' + -'NyRdWnqAv+HKRjN/tVZcf8I0CERswxmixF9uWMTjH+hq0u/h4It3I3tOObNyAQO3\n' + -'iY9uSZEZbrKBSM3DqFF75toLjooWXU8yaC9so3mQVf5MnSZpG3PA5klwusLmi0QU\n' + -'HD1eZ2aXUnTx7TbHuovWLjI40SIUKnaMAf0TCUHfBvJ5rLUPYez35QwrYRx0Qixn\n' + -'Pcj7KCCXrT5cqwH64vGTiW6JCZJlLzneiE+dmnAT+wnNRNxbVooi6ejWce5HYbYd\n' + -'c2SyBHJstGn0zuNN/248qhV+r5AMBgZ+vDilV8Bmdh3N/xlXBIgLIocegL6Kc+S0\n' + -'Pr60DHKLcnZIunQwZOwyRb8wG9jV6I718CmbSw94gKNCi99B8BSDZ7z2ai+0yv44\n' + -'ErR4Qp/gnCp9/6NXNmafluYn5Pgl9vZCozcJ8EN8mzD4szZBL19btecoT6Wcnve2\n' + -'fYDRuYPWpT79QyRDSMSSzrQoFpezIOtPS2nrN+II81TxyTgOMY+jzR4TRJyMt185\n' + -'7OG4t8Q+WOgzNS4clmPHnmgBBhsueWob72SvIgRtq5pQYB0fStx9qUDMZPnePdhS\n' + -'rI+K82k1/eY5vTQ/eDXMN7UUfdLriuK0UXnJFu5CQSwrMD1u5nFVbQYC9PEwgdUc\n' + -'XEASt9/jh2wDgSXAGegc6mLRI+Zu5H5ygpCIAMs8pNwFJ5DhCsve5RbalGEbYbuL\n' + -'NwB1rRExCCUBjnAkpwNU0TL991y1Gn+gpN2lNvITq/BroE3HLjXbnEACTN+hwNPB\n' + -'KJi38zKSb6/k27/zpTMuEKRXkSz4QuuviQbGJTmCbub+l2aVBQhVNwooGI92Gt8n\n' + -'EQjGOzqeS4J0KQGZmhYRGVc7DdwjBYLV5pi1WkCIt1a1PDK9VZ4vzz978gLaxSZM\n' + -'yozdL97g9wo0IJcAj+36b1Wewj+hL81t0SgIShEO0aIGSNDlFZM4mKQNmCUhvWuO\n' + -'M1CpniR8cBN4MHUaQdBIlW2ua9Ba8JM7LNwcD8JddGvmUBwzFr5w4Hu4ylweacXP\n' + -'5zUfZpJyFZKoxJe1cPY47NmXemOLuBVJRlThnUazvhM/KRxfyu2q4WOz6VSm6LEq\n' + -'PFfr/NYH1AxIda/Z4tLLAs0nLbV+HrqRFMJOBGdY6dMxuvaiUutY3MZCMCKupz8f\n' + -'yHh2p2lFy2jQvZs4HAKN6hTx8X7at1ue0RYw3hdjoPHa/NBKDzrkKjGInfraTVr6\n' + -'qrxqW09/yNuiatISi+KxuBM4o9L/w85Zf01RNEZTS5zCKX0ml33JHgNxQgPosp+7\n' + -'R0TUK2lANdKVTXJe8V/IT4tGUD4mg0EjMVRmFV2CL3LgBbW3ScOC15D4mzD14Yyb\n' + -'KTUHwfX189GHKjJhHnSuZ3QgVKynoSII+0x4fiDHsdhdXdMj/qvVdZIMlABWKRD0\n' + -'JVmrkFpzFtt4yXupl62+9ZYZehSKNKurlO4A8OBeg6xKDUKuvrI7Ug/2s5Q0pCxp\n' + -'EgtxwOhhYrAhd8mN2ilKeB++JCAmZ2KwnwCGFF8kZ/5TOwWZHm/RNKEchTRC5kws\n' + -'KsDUxq/19ORifzCA19f6Tc5s9HcPwxvnrscvb6LLTGGiROp3BlcitHjmPsH5bRUX\n' + -'OAqV069l1JKeiCkGgQmlRviBGG0yO2zIcAeoDIPhaO4O0K6/VHo4p6kAlZAzWJuT\n' + -'QmHI0ETyO+2m0jySoxW0EUU1FB3eQ4KBocneYqJUgCbOCeXf14TO8HekDtkfoKOK\n' + -'bded3iCtnSAH6I9ERtPebqiWdR2tVCO4Yyqkf2f3vzCWrtyXHUWtZtC1I08HNLin\n' + -'zGhEdQZ/VFCLP8CWmbtLU8BPeu88VTpw7i8G76QuHq5+0DY9eBgHWxcBYiwRisT/\n' + -'DHXH0TvjuPedJ4F/sNmlktTXLLMqVu+J8i/qJ48E1r9wXkHTICnFy8jvm5MpQ4gu\n' + -'rwzpyjSFLJZpzDMAxcPSXYGi1kchW+CDg/N/cdeYlVLCoBrUn6dEq6CC05Y6JmDW\n' + -'t46R6lFHbQoq1WsMWZSKomB4WlxWP+hYDsssQOUR9Y7wwI4KXPtf6Ar9W2T9cSfO\n' + -'mtDpgfeOVq/vE01TQGlZc4zwF5dcXBV3OLYBSXlv4JFIreOlKDi/IbPc6TYw0mbV\n' + -'wFuzPi8VpHip3YoGdM7XUDvO1sE07FX8/xrEQVkJfzgl/v+mQ66TCb+/g13QPgZI\n' + -'UftRS6hLeKNTd0pZc8+CTbNzgrCDGqbYn5ZpyPFYF+fVGZnqqLUid5NTjkwI1IoD\n' + -'PgOSHQEo+pIlNfTtR2DCYgqOiMaBSZ4bc4b6SohAKGJkPhNmlMJ61MwGN2J8pFpl\n' + -'1uG2MO3TUo6MxQAkCcKe4twwy1bQh4kO3kReUqTDW/VTnp6HfZhqtYc1tBGLcahu\n' + -'C0ZX7B/8Wbu1PWN4Y34F7ouuSu2l6ASnoAc/Ek1S9R1uyiwLtaPuK58oUbVisDh3\n' + -'cYmnjP0DelYq8FpJPWPrSGwqlERotf3KU3L1k84SHYUB1pHFYPF46KAKYH5qTrsO\n' + -'T3id3CO3mt1gtgWAEGRkEQ+qVmvWtINBOwyFYVAD9ZqXflzF83ZGvdmvdJ6kzRZ7\n' + -'fY5ACZGMghb3f4mfLlbF81WluDbk2k+t186qmRFrJFtJPvAl3VxXczo8pw5bSAdK\n' + -'R6c7cagA6ql4QaYqtbIHpFbgz7iQ9ESe23Q2+o82lkTbUFdG+GDhnZFOL+ldWf/g\n' + -'ufSCqY7IlNxj3hYxgTpaXb2lWvVVdo7C4VhPHyIDbQUCdUE80t2cDgJqPFABe3la\n' + -'Y+UsW9W787mGGuuNSF/iI0tANw5twlQjdRQtqxnF1yETh/hFA4bgD9bmBOBFd+GT\n' + -'+ECxkqI4/UYMgYfVMFja/e6+dQTWLblzuNaZh6wHASeNqpFmeQSBawBVV7qK3nC7\n' + -'CDY9r6Aq9JYMiJTE/TzyfBmBhnxtL1aKTu6EHy3siDlID7EjQx1Xyr/EtbJCmsVl\n' + -'E14StpggdK8=\n' + -'=enm3\n' + -'-----END PGP MESSAGE-----\n'; \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index 0f32ca92..f67cbdf1 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -27,6 +27,7 @@ describe('Long running Encryption/Decryption', function () { }; it('Successful encrypt 1 MB Uint8Array', function (done) { + //TODO: this succeeds, but result may be bogus (String with byte values as numbers) let prm = Gpgmejs.init(); let data = bigUint8(1); prm.then(function (context) { diff --git a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js new file mode 100644 index 00000000..98b6e1d8 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js @@ -0,0 +1,196 @@ +/* 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('Encrypting-Decrypting in openpgp mode, using a Message object', function () { + it('Simple Encrypt-Decrypt', function (done) { + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + prm.then(function (context) { + context.encrypt({ + data: openpgp.message.fromText(inputvalues.encrypt.good.data), + publicKeys: inputvalues.encrypt.good.fingerprint} + ).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer).to.be.an("object"); + expect(answer.data).to.include('BEGIN PGP MESSAGE'); + expect(answer.data).to.include('END PGP MESSAGE'); + let msg = openpgp.message.fromText(answer.data); + context.decrypt({message:msg}).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(inputvalues.encrypt.good.data); + context._GpgME.connection.disconnect(); + done(); + }); + }); + }); + }); + it('Encrypt-Decrypt, sending Uint8Array as data', function (done) { + //TODO! fails. Reason is that atob<->btoa destroys the uint8Array, + // resulting in a string of constituyent numbers + // (error already occurs in encryption) + + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + prm.then(function (context) { + let input = bigUint8(0.3); + expect(input).to.be.an.instanceof(Uint8Array); + context.encrypt({ + data: input, + publicKeys: 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'); + context.decrypt({message:answer.data}).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.an.instanceof(Uint8Array); + expect(result.data).to.equal(input); + context._GpgME.connection.disconnect(); + done(); + }); + }); + }); + }); + it('Keys as Fingerprints', function(done){ + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + let input = inputvalues.encrypt.good.data_nonascii; + prm.then(function (context) { + context.encrypt({ + data: input, + publicKeys: 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'); + context.decrypt({message:answer.data}).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(input); + context._GpgME.connection.disconnect(); + done(); + }); + }); + }); + }); + it('Keys as openpgp Keys', function(){ + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + let data = inputvalues.encrypt.good.data_nonascii; + let key = openpgp.key.readArmored(openpgpInputs.pubKeyArmored); + expect(key).to.be.an('object'); + prm.then(function (context) { + context.encrypt({ + data: data, + publicKeys: [key]} + ).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'); + context.decrypt({message:answer.data}).then( function (result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context._GpgME.connection.disconnect(); + done(); + }); + }); + }); + }); + it('Trying to send non-implemented parameters: passwords', function(done){ + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + let data = 'Hello World'; + let key = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.encrypt({ + data: data, + publicKeys: [key], + passwords: 'My secret password'} + ).then( function(){}, + function(error){ + expect(error).to.be.an.instanceof(Error); + expect(error.code).equal('NOT_IMPLEMENTED'); + done(); + }); + }); + }); + it('Trying to send non-implemented parameters: signature', function(done){ + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + let data = 'Hello World'; + let key = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.encrypt({ + data: data, + publicKeys: [key], + signature: {any: 'value'} + }).then( + function(){}, + function(error){ + expect(error).to.be.an.instanceof(Error); + expect(error.code).equal('NOT_IMPLEMENTED'); + done(); + }); + }); + }); +}); + +describe('Keyring in openpgp mode', function(){ + it('Check Existence and structure of Keyring after init', function(done){ + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + prm.then(function (context) { + expect(context.Keyring).to.be.an('object'); + expect(context.Keyring.getPublicKeys).to.be.a('function'); + expect(context.Keyring.deleteKey).to.be.a('function'); + expect(context.Keyring.getDefaultKey).to.be.a('function'); + done(); + }); + }); + // TODO: gpgme key interface not yet there +}); + +describe('Decrypting and verification in openpgp mode', function(){ + it('Decrypt', function(){ + let msg = openpgp.message.fromText(inputvalues.encryptedData); + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + prm.then(function (context) { + context.decrypt({message: msg}) + .then(function(answer){ + expect(answer.data).to.be.a('string'); + expect(result.data).to.equal('¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); + done(); + }); + }); + }); + it('Decryption attempt with bad data returns gnupg error', function(done){ + let msg = openpgp.message.fromText(bigString(0.1)); + let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); + prm.then(function (context) { + context.decrypt({message: msg}) + .then( function(){}, + function(error){ + expect(error).to.be.an.instanceof(Error); + expect(error.code).to.equal('GNUPG_ERROR'); + expect(error.message).to.be.a('string'); + // TBD: Type of error + done(); + }); + }); + }).timeout(4000); +}); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 64621f60..1931a55b 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -181,7 +181,6 @@ class Answer{ if (!this._response.hasOwnProperty(key)){ this._response[key] = ''; } - // console.log(msg[key]); this._response[key] += msg[key]; } //params should not change through the message diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c1a01377..d106f4f7 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -80,7 +80,6 @@ export class GpgME { let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); - putData(msg, data); if (wildcard === true){msg.setParameter('throw-keyids', true); }; @@ -171,19 +170,32 @@ function putData(message, data){ return gpgme_error('PARAM_WRONG'); } else if (data instanceof Uint8Array){ message.setParameter('base64', true); + // TODO: btoa turns the array into a string + // of comma separated of numbers + // atob(data).split(',') would result in a "normal" array of numbers + // atob(btoa(data)).split(',') would result in a "normal" array of numbers + // would result in a "normal" array of numbers message.setParameter ('data', btoa(data)); + } else if (typeof(data) === 'string') { message.setParameter('base64', false); message.setParameter('data', data); - } else if ( typeof(data) === 'object' && data.hasOwnProperty('getText')){ + } else if ( + typeof(data) === 'object' && + typeof(data.getText) === 'function' + ){ let txt = data.getText(); if (txt instanceof Uint8Array){ message.setParameter('base64', true); message.setParameter ('data', btoa(txt)); } - else { + else if (typeof(txt) === 'string'){ + message.setParameter('base64', false); + message.setParameter ('data', txt); + } else { return gpgme_error('PARAM_WRONG'); } + } else { return gpgme_error('PARAM_WRONG'); } diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js index b233f0fa..9c8cd2cc 100644 --- a/lang/js/src/gpgmejs_openpgpjs.js +++ b/lang/js/src/gpgmejs_openpgpjs.js @@ -25,10 +25,10 @@ */ import { GpgME } from "./gpgmejs"; - import {GPGME_Keyring} from "./Keyring" + import {GPGME_Keyring} from "./Keyring"; import { GPGME_Key, createKey } from "./Key"; - import { isFingerprint } from "./Helpers" - import { gpgme_error } from "./Errors" + import { isFingerprint } from "./Helpers"; + import { gpgme_error } from "./Errors"; import { Connection } from "./Connection"; @@ -60,8 +60,8 @@ import { Connection } from "./Connection"; /** * Encrypt Message * Supported: - * @param {String|Uint8Array} data - * //an openpgp Message also accepted here. TODO: is this wanted? + * @param {String|Message} data + * an openpgp Message is accepted here. * @param {Key|Array} publicKeys * //Strings of Fingerprints * @param {Boolean} wildcard @@ -86,36 +86,39 @@ import { Connection } from "./Connection"; * @async * @static */ - encrypt({data = '', publicKeys = '', privateKeys, passwords=null, - sessionKey = null, filename, compression, armor=true, detached=false, - signature=null, returnSessionKey=null, wildcard=false, date=null}) { - if (passwords !== null - || sessionKey !== null - || signature !== null - || returnSessionKey !== null - || date !== null + encrypt(options) { + if (!options || typeof(options) !== 'object'){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } + if (options.passwords + || options.sessionKey + || options.signature + || options.returnSessionKey + || (options.hasOwnProperty('date') && options.date !== null) ){ - return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); + return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); } - if ( privateKeys - || compression - || armor === false - || detached == true){ - return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); + if ( options.privateKeys + || options.compression + || (options.hasOwnProperty('armor') && options.armor === false) + || (options.hasOwnProperty('detached') && options.detached == true) + ){ + return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); } - if (filename){ + if (options.filename){ if (this._config.unconsidered_params === 'warn'){ - GPMGEJS_Error('PARAM_IGNORED'); + gpgme_error('PARAM_IGNORED'); } else if (this._config.unconsidered_params === 'error'){ - return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); + return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); } } - return this._GpgME.encrypt(data, translateKeys(publicKeys), wildcard); + return this._GpgME.encrypt( + options.data, options.publicKeys, options.wildcard); } /** Decrypt Message * supported openpgpjs parameters: - * @param {Message|Uint8Array|String} message Message object from openpgpjs + * @param {Message|String} message Message object from openpgpjs * Unsupported: * @param {String|Array} passwords * @param {Key|Array} privateKeys @@ -128,26 +131,33 @@ import { Connection } from "./Connection"; * @param {Key|Array} publicKeys * * @returns {Promise} decrypted and verified message in the form: - * { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] } + * { data:String, filename:String, signatures:[{ keyid:String, valid:Boolean }] } * @async * @static */ - decrypt({ message, privateKeys, passwords=null, sessionKeys, - publicKeys, format='utf8', signature=null, date= null}) { - if (passwords !== null || sessionKeys || privateKeys){ + decrypt(options) { + if (options.passwords + || options.sessionKeys + || options.privateKeys + ){ return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); } - if ( format !== 'utf8' || signature){ + if ((options.hasOwnProperty('format') && options.format !== 'utf8') + || options.signature + ){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); } - if (date !== null || publicKeys){ + if ((options.hasOwnProperty('date') && options.date !== null) + || options.publicKeys + ){ if (this._config.unconsidered_params === 'warn'){ GPMGEJS_Error('PARAM_IGNORED'); } else if (this._config.unconsidered_params === 'reject'){ return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); } } - return this._GpgME.decrypt(message); + return this._GpgME.decrypt(options.message); + // TODO: translate between: // openpgp: // { data:Uint8Array|String, @@ -276,14 +286,15 @@ class GPGME_Key_openpgpmode { * @returns {Array} */ function translateKeys(input){ + //TODO: does not check if inpout is okay! if (!input){ return null; } if (!Array.isArray(input)){ input = [input]; } - let resultset; - for (let i=0; i< input.length; i++){ + let resultset = []; + for (let i=0; i< input.length; i++) { resultset.push(new GPGME_Key_openpgpmode(input[i])); } return resultset; -- cgit From 6b4caee039af6fd97912426aff143745bf7e191a Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 14 May 2018 19:02:49 +0200 Subject: js: Testing lare messages -- * Some assumption on messages were wrong. Now the tests use more reasonable sizes. * bigString now uses the full utf8-extent, with the exception of U+0000. This code gets dropped during the encryption-decryption process. --- lang/js/BrowserTestExtension/tests/encryptTest.js | 26 +++++++-------- lang/js/BrowserTestExtension/tests/inputvalues.js | 37 +++++++++++++++------- .../BrowserTestExtension/tests/longRunningTests.js | 17 ++++++++-- 3 files changed, 51 insertions(+), 29 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 5ef68a32..521ed276 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -36,7 +36,7 @@ describe('Encryption', function () { it('Successful encrypt 5 MB', function (done) { let prm = Gpgmejs.init(); - let data = bigString(5); + let data = fixedLengthString(5); prm.then(function (context) { context.encrypt( data, @@ -51,10 +51,9 @@ describe('Encryption', function () { }); }).timeout(10000); -/** it('Successful encrypt 20 MB', function (done) { let prm = Gpgmejs.init(); - let data = bigString(20); + let data = fixedLengthString(20); prm.then(function (context) { context.encrypt( data, @@ -68,12 +67,10 @@ describe('Encryption', function () { }); }); }).timeout(20000); -*/ -/** - it('Successful encrypt 30 MB', function (done) { - // TODO: There seems to be a limit imposed at least by chrome at about 21 MB + + it('Successful encrypt 50 MB', function (done) { let prm = Gpgmejs.init(); - let data = bigString(30); + let data = fixedLengthString(50); prm.then(function (context) { context.encrypt( data, @@ -87,7 +84,6 @@ describe('Encryption', function () { }); }); }).timeout(20000); -*/ it('Sending encryption without keys fails', function (done) { let prm = Gpgmejs.init(); @@ -120,7 +116,6 @@ describe('Encryption', function () { }); }); - it('Sending encryption with non existing keys fails', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { @@ -138,21 +133,24 @@ describe('Encryption', function () { }); }).timeout(5000);; - it('Overly large message ( >= 48MB) is rejected', function (done) { + it('Overly large message ( > 65MB) is rejected', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( - bigString(48), + fixedLengthString(65), inputvalues.encrypt.good.fingerprint).then(function (answer) { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an.instanceof(Error); - // TODO who is throwing the error here? - // It is not a GPGME_Error! + // expect(error.code).to.equal('GNUPG_ERROR'); + // TODO: there is a 64 MB hard limit at least in chrome at: + // chromium//extensions/renderer/messaging_util.cc: + // kMaxMessageLength context.connection.disconnect(); done(); }); }); }).timeout(8000); + // TODO check different valid parameter }); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 38ee6aad..52e3a7b0 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -59,14 +59,27 @@ var inputvalues = { } }; -// (Pseudo-)Random String from a Uint8Array, given approx. size in Megabytes -function bigString(megabytes){ - let maxlength = 1024 * 1024 * megabytes; +// (Pseudo-)Random String covering all of utf8. +function bigString(length){ + var uint = ''; + let arr = []; + for (let i= 0; i < length; i++){ + arr.push(String.fromCharCode( + Math.floor(Math.random() * 10174) + 1) + ); + } + return arr.join(''); +} + +function fixedLengthString(megabytes){ + let maxlength = 1024 * 1024 * megabytes / 2; let uint = new Uint8Array(maxlength); - for (let i= 0; i < maxlength; i++){ - uint[i] = Math.random() * Math.floor(256); + for (let i = 0; i < maxlength; i++){ + uint[i] = Math.floor(Math.random()* 256); } - return new TextDecoder('utf-8').decode(uint); + let td = new TextDecoder('ascii'); + let result = td.decode(uint); + return result; } // (Pseudo-)Random Uint8Array, given size in Megabytes @@ -82,19 +95,19 @@ function bigUint8(megabytes){ // (Pseudo-)Random string with very limited charset (ascii only, no control chars) function bigBoringString(megabytes){ let maxlength = 1024 * 1024 * megabytes; - let string = ''; + let string = []; let chars = ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; for (let i= 0; i < maxlength; i++){ - string = string + chars[Math.floor(Math.random() * chars.length)]; + string.push(chars[Math.floor(Math.random() * chars.length)]); } - return string; + return string.join(''); } // Some String with simple chars, with different characteristics, but still // expected to occur in an averag message function slightlyLessBoringString(megabytes, set){ let maxlength = 1024 * 1024 * megabytes; - let string = ''; + let string = []; let chars = ''; if (set ===1 ) { chars = '\n\"\r \''; @@ -108,9 +121,9 @@ function slightlyLessBoringString(megabytes, set){ chars = '*<>\n\"\r§$%&/()=?`#+-{}[] \''; } for (let i= 0; i < maxlength; i++){ - string = string + chars[Math.floor(Math.random() * chars.length)]; + string.push(chars[Math.floor(Math.random() * chars.length)]); } - return string; + return string.join(''); } // Data encrypted with testKey diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index f67cbdf1..c95bebda 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -1,8 +1,8 @@ describe('Long running Encryption/Decryption', function () { - for (let i=0; i< 100; i++) { + for (let i=0; i < 100; i++) { it('Successful encrypt/decrypt completely random data ' + (i+1) + '/100', function (done) { let prm = Gpgmejs.init(); - let data = bigString(2); + let data = bigString(2*1024*1024); prm.then(function (context) { context.encrypt(data, inputvalues.encrypt.good.fingerprint).then( @@ -17,13 +17,24 @@ describe('Long running Encryption/Decryption', function () { function(result){ expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); + if (result.data.length !== data.length) { + console.log('diff: ' + (result.data.length - data.length)); + for (let i=0; i < result.data.length; i++){ + if (result.data[i] !== data[i]){ + console.log('position: ' + i); + console.log('result : '+ result.data.charCodeAt(i) + result.data[i-2] + result.data[i-1] + result.data[i] + result.data[i+1] + result.data[i+2]); + console.log('original: ' + data.charCodeAt(i) + data[i-2] + data[i-1] + data[i] + data[i+1] + data[i+2]); + break; + } + } + } expect(result.data).to.equal(data); context.connection.disconnect(); done(); }); }); }); - }).timeout(5000); + }).timeout(8000); }; it('Successful encrypt 1 MB Uint8Array', function (done) { -- cgit From ecad77263585cd5954758f797327d98232d880dc Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 22 May 2018 14:24:16 +0200 Subject: js: transfer encoding changes -- * Uint8Arrays are not supported for now there are unsolved issues in conversion, and they are lower priority * encrypt gains a new option to indicate that input values are base64 encoded * as decrypted values are always base64 encoded, the option base64 will not try to decode the result into utf, but leave it as it is --- .../tests/encryptDecryptTest.js | 133 +++++++++++++++++++-- .../BrowserTestExtension/tests/longRunningTests.js | 25 ---- .../BrowserTestExtension/tests/openpgpModeTest.js | 27 ----- lang/js/src/Connection.js | 34 +++--- lang/js/src/Message.js | 14 +++ lang/js/src/gpgmejs.js | 42 +++---- lang/js/src/permittedOperations.js | 4 +- 7 files changed, 173 insertions(+), 106 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index 5c534039..2fe955e6 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -1,3 +1,4 @@ + /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * @@ -39,6 +40,22 @@ describe('Encryption and Decryption', function () { }); }); }); + + it('Decrypt simple non-ascii', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = encryptedData; + context.decrypt(data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal( + '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); + done(); + }); + }); + }).timeout(3000); + it('Roundtrip does not destroy trailing whitespace', function (done) { let prm = Gpgmejs.init(); @@ -64,7 +81,7 @@ describe('Encryption and Decryption', function () { }); }); }); - }).timeout(5000); + }).timeout(5000); for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + (j + 1) + '/' + inputvalues.encrypt.good.data_nonascii_32.length + ')', @@ -96,21 +113,113 @@ describe('Encryption and Decryption', function () { }); }); }); - }).timeout(5000); + }).timeout(3000); }; - it('Decrypt simple non-ascii', function (done) { + it('Random data, as string', function (done) { + let data = bigString(1000); let prm = Gpgmejs.init(); prm.then(function (context) { - data = encryptedData; - context.decrypt(data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal( - '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); - done(); - }); + context.encrypt(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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + }); + }); }); }).timeout(3000); + + it('Data, input as base64', function (done) { + let data = inputvalues.encrypt.good.data; + let b64data = btoa(data); + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt(b64data, + 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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(data).to.equal(data); + context.connection.disconnect(); + done(); + }); + }); + }); + }).timeout(3000); + + it('Random data, input as base64', function (done) { + //TODO fails. The result is + let data = bigBoringString(0.001); + let b64data = btoa(data); + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt(b64data, + inputvalues.encrypt.good.fingerprint, true).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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + context.connection.disconnect(); + done(); + }); + }); + }); + }).timeout(3000); + + it('Random data, input and output as base64', function (done) { + let data = bigBoringString(0.0001); + let b64data = btoa(data); + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt(b64data, + 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'); + context.decrypt(answer.data, true).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(b64data); + context.connection.disconnect(); + done(); + }); + }); + }); + }).timeout(3000); + + }); diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index c95bebda..4e55fd26 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -37,29 +37,4 @@ describe('Long running Encryption/Decryption', function () { }).timeout(8000); }; - it('Successful encrypt 1 MB Uint8Array', function (done) { - //TODO: this succeeds, but result may be bogus (String with byte values as numbers) - let prm = Gpgmejs.init(); - let data = bigUint8(1); - prm.then(function (context) { - context.encrypt(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'); - context.decrypt(answer.data).then( - function(result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); - }); - }).timeout(5000); - }); diff --git a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js index 98b6e1d8..cccaf604 100644 --- a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js +++ b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js @@ -41,33 +41,6 @@ describe('Encrypting-Decrypting in openpgp mode, using a Message object', functi }); }); }); - it('Encrypt-Decrypt, sending Uint8Array as data', function (done) { - //TODO! fails. Reason is that atob<->btoa destroys the uint8Array, - // resulting in a string of constituyent numbers - // (error already occurs in encryption) - - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - prm.then(function (context) { - let input = bigUint8(0.3); - expect(input).to.be.an.instanceof(Uint8Array); - context.encrypt({ - data: input, - publicKeys: 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'); - context.decrypt({message:answer.data}).then(function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.an.instanceof(Uint8Array); - expect(result.data).to.equal(input); - context._GpgME.connection.disconnect(); - done(); - }); - }); - }); - }); it('Keys as Fingerprints', function(done){ let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); let input = inputvalues.encrypt.good.data_nonascii; diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 1931a55b..9c2a6428 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -93,7 +93,7 @@ export class Connection{ } let me = this; return new Promise(function(resolve, reject){ - let answer = new Answer(message.operation); + let answer = new Answer(message); let listener = function(msg) { if (!msg){ me._connection.onMessage.removeListener(listener) @@ -147,8 +147,9 @@ export class Connection{ */ class Answer{ - constructor(operation){ - this.operation = operation; + constructor(message){ + this.operation = message.operation; + this.expected = message.expected; } /** @@ -210,26 +211,31 @@ class Answer{ } /** - * @returns {Object} the assembled message. - * TODO: does not care yet if completed. + * @returns {Object} the assembled message, original data assumed to be + * (javascript-) strings */ get message(){ let keys = Object.keys(this._response); + let msg = {}; let poa = permittedOperations[this.operation].answer; for (let i=0; i < keys.length; i++) { - if (poa.data.indexOf(keys[i]) >= 0){ - if (this._response.base64 == true){ - let respatob = atob(this._response[keys[i]]); - - let result = decodeURIComponent( - respatob.split('').map(function(c) { + if (poa.data.indexOf(keys[i]) >= 0 + && this._response.base64 === true + ) { + msg[keys[i]] = atob(this._response[keys[i]]); + if (this.expected === 'base64'){ + msg[keys[i]] = this._response[keys[i]]; + } else { + msg[keys[i]] = decodeURIComponent( + atob(this._response[keys[i]]).split('').map(function(c) { return '%' + - ('00' + c.charCodeAt(0).toString(16)).slice(-2); + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); - this._response[keys[i]] = result; } + } else { + msg[keys[i]] = this._response[keys[i]]; } } - return this._response; + return msg; } } diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 6a59c3e0..932212a6 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -41,6 +41,7 @@ export class GPGME_Message { constructor(operation){ this.operation = operation; + this._expected = 'string'; } set operation (op){ @@ -58,6 +59,19 @@ export class GPGME_Message { return this._msg.op; } + set expected(string){ + if (string === 'base64'){ + this._expected = 'base64'; + } + } + + get expected() { + if (this._expected === "base64"){ + return this._expected; + } + return "string"; + } + /** * Sets a parameter for the message. Note that the operation has to be set * first, to be able to check if the parameter is permittted diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index d106f4f7..01cb92c3 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -64,11 +64,11 @@ export class GpgME { } /** - * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array + * @param {String} data text/data to be encrypted as String * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message */ - encrypt(data, publicKeys, wildcard=false){ + encrypt(data, publicKeys, base64=false, wildcard=false){ let msg = createMessage('encrypt'); if (msg instanceof Error){ @@ -77,11 +77,14 @@ export class GpgME { // TODO temporary msg.setParameter('armor', true); msg.setParameter('always-trust', true); - + if (base64 === true) { + msg.setParameter('base64', true); + } let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); putData(msg, data); - if (wildcard === true){msg.setParameter('throw-keyids', true); + if (wildcard === true){ + msg.setParameter('throw-keyids', true); }; if (msg.isComplete === true){ return this.connection.post(msg); @@ -91,7 +94,8 @@ export class GpgME { } /** - * @param {String} data TODO Format: base64? String? Message with the encrypted data + * @param {String} data TODO base64? Message with the encrypted data + * @param {Boolean} base64 (optional) Response should stay base64 * @returns {Promise} decrypted message: data: The decrypted data. This may be base64 encoded. base64: Boolean indicating whether data is base64 encoded. @@ -100,11 +104,14 @@ export class GpgME { * @async */ - decrypt(data){ + decrypt(data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); + if (base64 === true){ + msg.expected = 'base64'; + } if (msg instanceof Error){ return Promise.reject(msg); } @@ -156,11 +163,9 @@ export class GpgME { } /** - * Sets the data of the message, converting Uint8Array to base64 and setting - * the base64 flag + * Sets the data of the message * @param {GPGME_Message} message The message where this data will be set * @param {*} data The data to enter - * @param {String} propertyname // TODO unchecked still */ function putData(message, data){ if (!message || !message instanceof GPGME_Message ) { @@ -168,30 +173,15 @@ function putData(message, data){ } if (!data){ return gpgme_error('PARAM_WRONG'); - } else if (data instanceof Uint8Array){ - message.setParameter('base64', true); - // TODO: btoa turns the array into a string - // of comma separated of numbers - // atob(data).split(',') would result in a "normal" array of numbers - // atob(btoa(data)).split(',') would result in a "normal" array of numbers - // would result in a "normal" array of numbers - message.setParameter ('data', btoa(data)); - } else if (typeof(data) === 'string') { - message.setParameter('base64', false); message.setParameter('data', data); } else if ( typeof(data) === 'object' && typeof(data.getText) === 'function' ){ let txt = data.getText(); - if (txt instanceof Uint8Array){ - message.setParameter('base64', true); - message.setParameter ('data', btoa(txt)); - } - else if (typeof(txt) === 'string'){ - message.setParameter('base64', false); - message.setParameter ('data', txt); + if (typeof(txt) === 'string'){ + message.setParameter('data', txt); } else { return gpgme_error('PARAM_WRONG'); } diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 59597aaf..da46a1fd 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -51,7 +51,7 @@ export const permittedOperations = { array_allowed: true }, 'data': { - allowed: ['string', 'Uint8Array'] + allowed: ['string'] } }, optional: { @@ -103,7 +103,7 @@ export const permittedOperations = { pinentry: true, required: { 'data': { - allowed: ['string', 'Uint8Array'] + allowed: ['string'] } }, optional: { -- cgit From f7ed80ff6a66f2c5ee6f1c3daebd597f4592733d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 23 May 2018 12:56:23 +0200 Subject: js: remove openpgp mode -- * After discussion, that mode is not required, and can result in being quite misleading and a maintenance hassle later on. --- lang/js/BrowserTestExtension/index.html | 7 - lang/js/BrowserTestExtension/openpgpModeTest.html | 23 -- .../tests/inputValues_openpgpjs.js | 32 --- .../BrowserTestExtension/tests/openpgpModeTest.js | 169 ------------ lang/js/BrowserTestExtension/tests/startup.js | 16 -- lang/js/CHECKLIST | 7 +- lang/js/README | 5 - lang/js/src/Config.js | 8 +- lang/js/src/Errors.js | 8 - lang/js/src/gpgmejs.js | 4 +- lang/js/src/gpgmejs_openpgpjs.js | 301 --------------------- lang/js/src/index.js | 7 +- 12 files changed, 9 insertions(+), 578 deletions(-) delete mode 100644 lang/js/BrowserTestExtension/openpgpModeTest.html delete mode 100644 lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js delete mode 100644 lang/js/BrowserTestExtension/tests/openpgpModeTest.js delete mode 100644 lang/js/src/gpgmejs_openpgpjs.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/index.html b/lang/js/BrowserTestExtension/index.html index c49aedae..05d413ba 100644 --- a/lang/js/BrowserTestExtension/index.html +++ b/lang/js/BrowserTestExtension/index.html @@ -34,13 +34,6 @@ Functionality tests with larger/longer running data sets. -
  • - - Testing openPGP mode. - - Please notice that, due to comparing - the inputs and outputs with openpgpjs objects, this test - requires a copy of openpgpjs in libs. -
  • diff --git a/lang/js/BrowserTestExtension/openpgpModeTest.html b/lang/js/BrowserTestExtension/openpgpModeTest.html deleted file mode 100644 index e7a12be9..00000000 --- a/lang/js/BrowserTestExtension/openpgpModeTest.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - -

    Openpgp mode test

    -
    - - - - - - - - - - - - - - diff --git a/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js b/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js deleted file mode 100644 index 945955be..00000000 --- a/lang/js/BrowserTestExtension/tests/inputValues_openpgpjs.js +++ /dev/null @@ -1,32 +0,0 @@ -const openpgpInputs = { - pubKeyArmored: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' - + '\n' - + 'mQENBFrsKEkBCADKw4Wt8J6M/88qD8PO6lSMCxH1cpwH8iK0uPaFFYsJkkXo7kWf\n' - + 'PTAtrV+REqF/o80dvYcdLvRsV21pvncZz/HXLu1yQ18mC3XObrKokbdgrTTKA5XE\n' - + 'BZkNsqyaMMJauT18H4hYkSg62/tTdO1cu/zWv/LFf7Xyn6+uA74ovXCJlO1s0N2c\n' - + 'PShtr98QRzPMf2owgVk37JnDNp4gGVDGHxSZOuUwxgYAZYnA8SFc+c+3ZrQfY870\n' - + '+O4j3Mz4p7yD13AwP4buQLBsb/icxekeQCqpRJhLH9f7MdEcGXa1x36RcEkHdu+M\n' - + 'yJ392eMgD+dKNfRCtyTPhjZTxvbNELIBYICfABEBAAG0EHRlc3RAZXhhbXBsZS5v\n' - + 'cmeJAVQEEwEIAD4WIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbAwUJA8Jn\n' - + 'AAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAjAWNe7/DLBf9kB/wOQ/S60HGw\n' - + 'Fq07W9N01HWULyhHKoMmcHL6rfZ64oDqLxolPSasz7WAMW1jN4qtWJ0mFzwO83V6\n' - + 'kaBe+wF6Kqir6udFSBW9rPcFg6/VZXPltT0a6uacIHq6DyQ5iMW4YQWbVy9OR2rN\n' - + 'GkYo1JCBR0XdRJYCSX3yB4TWv/eXnZ37/WjmiTOIZh35rjs+NuU/S5JPDfAp2/k7\n' - + '0DevQeBsv+UjVXjWpNTZmPbvDnd995uSmC6UY4hzyP84ORYMYn9n1QAR0goxDN6U\n' - + 'unOf9Rlp1oMzdxMool/d1MlCxg2h3jheuhv7lgUF4KpvHOuEPXQ7UO417E0TYcDZ\n' - + '1J8Nsv87SZeEuQENBFrsKEkBCADjoEBhG/QPqZHg8VyoD1xYRAWGxyDJkX/GrSs6\n' - + 'yE+x2hk5FoQCajxKa/d4AVxOnJpdwhAfeXeSNaql5Ejgzax+Tdj9BV6vtGVJVv0p\n' - + 'O7bgAiZxkA6RHxtNqhpPnPQoXvUzkzpRgpuL+Nj4yIg7z1ITH6KQH4u5SI9vd+j/\n' - + '8i9Taz67pdZwuJjac8qBuJHjzAo1bjYctFYUSG5pbmMQyNLySzgiNkFa4DajODlt\n' - + '3RuqVGP316Fk+Sy2+60tC/HlX8jgMyMONfOGBQx6jk8tvAphS/LAqrrNepnagIyL\n' - + 'UGKU+L8cB2g1PGGp2biBFWqZbudZoyRBet/0yH/zirBdQJw1ABEBAAGJATwEGAEI\n' - + 'ACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAKCRAjAWNe\n' - + '7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ5F32NDJ9\n' - + 'PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7Jq3e/4Iy\n' - + '0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02Lkr+2Cc/Q\n' - + 'k6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe23nntMSD\n' - + 'A+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t9Mmd7bM1\n' - + '+UyPgbPEr0iWMeyctYsuOLeUyQKMscDT\n' - + '=QyY6\n' - + '-----END PGP PUBLIC KEY BLOCK-----\n' -}; diff --git a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js deleted file mode 100644 index cccaf604..00000000 --- a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js +++ /dev/null @@ -1,169 +0,0 @@ -/* 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('Encrypting-Decrypting in openpgp mode, using a Message object', function () { - it('Simple Encrypt-Decrypt', function (done) { - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - prm.then(function (context) { - context.encrypt({ - data: openpgp.message.fromText(inputvalues.encrypt.good.data), - publicKeys: inputvalues.encrypt.good.fingerprint} - ).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer).to.be.an("object"); - expect(answer.data).to.include('BEGIN PGP MESSAGE'); - expect(answer.data).to.include('END PGP MESSAGE'); - let msg = openpgp.message.fromText(answer.data); - context.decrypt({message:msg}).then(function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(inputvalues.encrypt.good.data); - context._GpgME.connection.disconnect(); - done(); - }); - }); - }); - }); - it('Keys as Fingerprints', function(done){ - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - let input = inputvalues.encrypt.good.data_nonascii; - prm.then(function (context) { - context.encrypt({ - data: input, - publicKeys: 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'); - context.decrypt({message:answer.data}).then(function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(input); - context._GpgME.connection.disconnect(); - done(); - }); - }); - }); - }); - it('Keys as openpgp Keys', function(){ - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - let data = inputvalues.encrypt.good.data_nonascii; - let key = openpgp.key.readArmored(openpgpInputs.pubKeyArmored); - expect(key).to.be.an('object'); - prm.then(function (context) { - context.encrypt({ - data: data, - publicKeys: [key]} - ).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'); - context.decrypt({message:answer.data}).then( function (result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - context._GpgME.connection.disconnect(); - done(); - }); - }); - }); - }); - it('Trying to send non-implemented parameters: passwords', function(done){ - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - let data = 'Hello World'; - let key = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { - context.encrypt({ - data: data, - publicKeys: [key], - passwords: 'My secret password'} - ).then( function(){}, - function(error){ - expect(error).to.be.an.instanceof(Error); - expect(error.code).equal('NOT_IMPLEMENTED'); - done(); - }); - }); - }); - it('Trying to send non-implemented parameters: signature', function(done){ - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - let data = 'Hello World'; - let key = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { - context.encrypt({ - data: data, - publicKeys: [key], - signature: {any: 'value'} - }).then( - function(){}, - function(error){ - expect(error).to.be.an.instanceof(Error); - expect(error.code).equal('NOT_IMPLEMENTED'); - done(); - }); - }); - }); -}); - -describe('Keyring in openpgp mode', function(){ - it('Check Existence and structure of Keyring after init', function(done){ - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - prm.then(function (context) { - expect(context.Keyring).to.be.an('object'); - expect(context.Keyring.getPublicKeys).to.be.a('function'); - expect(context.Keyring.deleteKey).to.be.a('function'); - expect(context.Keyring.getDefaultKey).to.be.a('function'); - done(); - }); - }); - // TODO: gpgme key interface not yet there -}); - -describe('Decrypting and verification in openpgp mode', function(){ - it('Decrypt', function(){ - let msg = openpgp.message.fromText(inputvalues.encryptedData); - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - prm.then(function (context) { - context.decrypt({message: msg}) - .then(function(answer){ - expect(answer.data).to.be.a('string'); - expect(result.data).to.equal('¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); - done(); - }); - }); - }); - it('Decryption attempt with bad data returns gnupg error', function(done){ - let msg = openpgp.message.fromText(bigString(0.1)); - let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'}); - prm.then(function (context) { - context.decrypt({message: msg}) - .then( function(){}, - function(error){ - expect(error).to.be.an.instanceof(Error); - expect(error.code).to.equal('GNUPG_ERROR'); - expect(error.message).to.be.a('string'); - // TBD: Type of error - done(); - }); - }); - }).timeout(4000); -}); diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index a5614a83..5de70a6b 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -36,22 +36,6 @@ }); }); }); -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++){ diff --git a/lang/js/CHECKLIST b/lang/js/CHECKLIST index 75664ae5..278f39dd 100644 --- a/lang/js/CHECKLIST +++ b/lang/js/CHECKLIST @@ -4,18 +4,15 @@ NativeConnection: receiving an answer [X] nativeConnection successfull on Chromium, chrome and firefox [*] nativeConnection successfull on Windows, macOS, Linux - [*] nativeConnection with delayed, multipart (> 1MB) answer - -replicating Openpgpjs API: + [X] nativeConnection with delayed, multipart (> 1MB) answer [*] Message handling (encrypt, decrypt verify, sign) [x] encrypt, decrypt [ ] verify [ ] sign [*] Key handling (import/export, modifying, status queries) - [ ] Configuration handling + [*] Configuration handling [ ] check for completeness - [*] handling of differences to openpgpjs Communication with other implementations diff --git a/lang/js/README b/lang/js/README index 5dc3f50b..b597adb2 100644 --- a/lang/js/README +++ b/lang/js/README @@ -12,11 +12,6 @@ To create a current version of the package, the command is If you want a more debuggable (i.e. not minified) build, just change the mode in webpack.conf.js. -TODO: gpgme_openpgpjs aims to offer an API similar to openpgpjs, throwing errors -if some part of the API is not implemented, 'translating' objects if possible. -This will be incorporated into the build process later, for now it is a line to -uncomment in src/index.js - Demo WebExtension: As soon as a bundled webpack is in dist/ the gpgmejs folder can just be included in the extensions tab of the browser in diff --git a/lang/js/src/Config.js b/lang/js/src/Config.js index e18728de..e85bbb82 100644 --- a/lang/js/src/Config.js +++ b/lang/js/src/Config.js @@ -19,13 +19,13 @@ */ export const availableConf = { - api_style: ['gpgme', 'gpgme_openpgpjs'], null_expire_is_never: [true, false], - unconsidered_params: ['warn','reject', 'ignore'], + // cachedKeys: Some Key info will not be queried on each invocation, + // manual refresh by Key.refresh() + cachedKeys: [true, false] }; export const defaultConf = { - api_style: 'gpgme', null_expire_is_never: false, - unconsidered_params: 'reject', + cachedKeys: false }; \ No newline at end of file diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index b71004a5..bfe3a2f4 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -80,14 +80,6 @@ const err_list = { msg: 'An parameter was set that has no effect in gpgmejs', type: 'warning' }, - 'NOT_IMPLEMENTED': { - msg: 'A openpgpjs parameter was submitted that is not implemented', - type: 'error' - }, - 'NOT_YET_IMPLEMENTED': { - msg: 'Support of this is probable, but it is not implemented yet', - type: 'error' - }, 'GENERIC_ERROR': { msg: 'Unspecified error', type: 'error' diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 01cb92c3..3aa5957a 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -54,8 +54,8 @@ export class GpgME { } set Keyring(keyring){ - if (ring && ring instanceof GPGME_Keyring){ - this._Keyring = ring; + if (keyring && keyring instanceof GPGME_Keyring){ + this._Keyring = keyring; } } diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js deleted file mode 100644 index 9c8cd2cc..00000000 --- a/lang/js/src/gpgmejs_openpgpjs.js +++ /dev/null @@ -1,301 +0,0 @@ -/* 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+ - */ - -/** - * This is a compatibility API to be used as openpgpjs syntax. - * Non-implemented options will throw an error if set (not null or undefined) - * TODO Some info about differences - */ - - import { GpgME } from "./gpgmejs"; - import {GPGME_Keyring} from "./Keyring"; - import { GPGME_Key, createKey } from "./Key"; - import { isFingerprint } from "./Helpers"; - import { gpgme_error } from "./Errors"; -import { Connection } from "./Connection"; - - - export class GpgME_openpgpmode { - - constructor(connection, config = {}){ - this.initGpgME(connection, config); - } - - get Keyring(){ - if (this._keyring){ - return this._keyring; - } - return undefined; - } - - initGpgME(connection, config = {}){ - if (connection && typeof(config) ==='object'){ - this._config = config; - if (!this._GpgME){ - this._GpgME = new GpgME(connection, config); - } - if (!this._keyring){ - this._keyring = new GPGME_Keyring_openpgpmode(connection); - } - } - } - - /** - * Encrypt Message - * Supported: - * @param {String|Message} data - * an openpgp Message is accepted here. - * @param {Key|Array} publicKeys - * //Strings of Fingerprints - * @param {Boolean} wildcard - * TODO: - * @param {Key|Array} privateKeys // -> encryptsign - * @param {module:enums.compression} compression //TODO accepts integer, if 0 (no compression) it won't compress - * @param {Boolean} armor // TODO base64 switch - * @param {Boolean} detached // --> encryptsign - * unsupported: - * @param {String|Array} passwords - * @param {Object} sessionKey - * @param {Signature} signature - * @param {Boolean} returnSessionKey - * @param {String} filename - * - * Can be set, but will be ignored: - * - * @returns {Promise} - * {data: ASCII armored message, - * signature: detached signature if 'detached' is true - * } - * @async - * @static - */ - encrypt(options) { - if (!options || typeof(options) !== 'object'){ - return Promise.reject(gpgme_error('PARAM_WRONG')); - } - if (options.passwords - || options.sessionKey - || options.signature - || options.returnSessionKey - || (options.hasOwnProperty('date') && options.date !== null) - ){ - return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); - } - if ( options.privateKeys - || options.compression - || (options.hasOwnProperty('armor') && options.armor === false) - || (options.hasOwnProperty('detached') && options.detached == true) - ){ - return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); - } - if (options.filename){ - if (this._config.unconsidered_params === 'warn'){ - gpgme_error('PARAM_IGNORED'); - } else if (this._config.unconsidered_params === 'error'){ - return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); - } - } - return this._GpgME.encrypt( - options.data, options.publicKeys, options.wildcard); - } - - /** Decrypt Message - * supported openpgpjs parameters: - * @param {Message|String} message Message object from openpgpjs - * Unsupported: - * @param {String|Array} passwords - * @param {Key|Array} privateKeys - * @param {Object|Array} sessionKeys - * Not yet supported, but planned - * @param {String} format (optional) return data format either as 'utf8' or 'binary' - * @param {Signature} signature (optional) detached signature for verification - * Ignored values: can be safely set, but have no effect - * @param {Date} date - * @param {Key|Array} publicKeys - * - * @returns {Promise} decrypted and verified message in the form: - * { data:String, filename:String, signatures:[{ keyid:String, valid:Boolean }] } - * @async - * @static - */ - decrypt(options) { - if (options.passwords - || options.sessionKeys - || options.privateKeys - ){ - return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); - } - if ((options.hasOwnProperty('format') && options.format !== 'utf8') - || options.signature - ){ - return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); - } - if ((options.hasOwnProperty('date') && options.date !== null) - || options.publicKeys - ){ - if (this._config.unconsidered_params === 'warn'){ - GPMGEJS_Error('PARAM_IGNORED'); - } else if (this._config.unconsidered_params === 'reject'){ - return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); - } - } - return this._GpgME.decrypt(options.message); - - // TODO: translate between: - // openpgp: - // { data:Uint8Array|String, - // filename:String, - // signatures:[{ keyid:String, valid:Boolean }] } - // and gnupg: - // data: The decrypted data. This may be base64 encoded. - // base64: Boolean indicating whether data is base64 encoded. - // mime: A Boolean indicating whether the data is a MIME object. - // info: An optional object with extra information. - } -} - -/** - * Translation layer offering basic Keyring API to be used in Mailvelope. - * It may still be changed/expanded/merged with GPGME_Keyring - */ -class GPGME_Keyring_openpgpmode { - constructor(connection){ - this._gpgme_keyring = new GPGME_Keyring(connection); - } - - /** - * Returns a GPGME_Key Object for each Key in the gnupg Keyring. This - * includes keys openpgpjs considers 'private' (usable for signing), with - * the difference that Key.armored will NOT contain any secret information. - * Please also note that a GPGME_Key does not offer full openpgpjs- Key - * compatibility. - * @returns {Array} - * //TODO: Check if IsDefault is also always hasSecret - * TODO Check if async is required - */ - getPublicKeys(){ - return translateKeys( - this._gpgme_keyring.getKeys(null, true)); - } - - /** - * Returns the Default Key used for crypto operation in gnupg. - * Please note that the armored property does not contained secret key blocks, - * despite secret blocks being part of the key itself. - * @returns {Promise } - */ - getDefaultKey(){ - this._gpgme_keyring.getSubset({defaultKey: true}).then(function(result){ - if (result.length === 1){ - return Promise.resolve( - translateKeys(result)[0]); - } - else { - // TODO: Can there be "no default key"? - // TODO: Can there be several default keys? - return gpgme_error('TODO'); - } - }, function(error){ - //TODO - }); - } - - /** - * Deletes a Key - * @param {Object} Object identifying key - * @param {String} key.fingerprint - fingerprint of the to be deleted key - * @param {Boolean} key.secret - indicator if private key should be deleted as well - - * @returns {Promise., Error>} TBD: Not sure what is wanted - TODO @throws {Error} error.code = ‘KEY_NOT_EXIST’ - there is no key for the given fingerprint - TODO @throws {Error} error.code = ‘NO_SECRET_KEY’ - secret indicator set, but no secret key exists - */ - deleteKey(key){ - if (typeof(key) !== "object"){ - return Promise.reject(gpgme_error('PARAM_WRONG')); - } - if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){ - return Promise.reject(gpgme_error('PARAM_WRONG')); - } - let key_to_delete = createKey(key.fingerprint, this._gpgme_keyring_GpgME); - return key_to_delete.deleteKey(key.secret); - } -} - -/** - * TODO error handling. - * Offers the Key information as the openpgpmode wants - */ -class GPGME_Key_openpgpmode { - constructor(value, connection){ - this.init(value, connection); - } - - /** - * Can be either constructed using an existing GPGME_Key, or a fingerprint - * and a connection - * @param {String|GPGME_Key} value - * @param {Connection} connection - */ - init (value, connection){ - if (!this._GPGME_Key && value instanceof GPGME_Key){ - this._GPGME_Key = value; - } else if (!this._GPGME_Key && isFingerprint(value) && - connection instanceof Connection){ - this._GPGME_Key = createKey(value, connection); - } - } - - get fingerprint(){ - return this._GPGME_Key.fingerprint; - } - - get armor(){ - return this._GPGME_Key.armored; - } - - get secret(){ - return this._GPGME_Key.hasSecret; - } - - get default(){ - return this._GPGME_Key.isDefault; - } -} - -/** - * creates GPGME_Key_openpgpmode from GPGME_Keys - * @param {GPGME_Key|Array} input keys - * @returns {Array} - */ -function translateKeys(input){ - //TODO: does not check if inpout is okay! - if (!input){ - return null; - } - if (!Array.isArray(input)){ - input = [input]; - } - let resultset = []; - for (let i=0; i< input.length; i++) { - resultset.push(new GPGME_Key_openpgpmode(input[i])); - } - return resultset; -} \ No newline at end of file diff --git a/lang/js/src/index.js b/lang/js/src/index.js index fc406c66..8527b3f3 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -20,7 +20,6 @@ import { GpgME } from "./gpgmejs"; import { gpgme_error } from "./Errors"; -import { GpgME_openpgpmode } from "./gpgmejs_openpgpjs"; import { Connection } from "./Connection"; import { defaultConf, availableConf } from "./Config"; @@ -43,11 +42,7 @@ function init(config){ reject(gpgme_error('CONN_NO_CONNECT')); } if (connection.isConnected === true){ - if (_conf.api_style && _conf.api_style === 'gpgme_openpgpjs'){ - resolve(new GpgME_openpgpmode(connection, _conf)); - } else { - resolve(new GpgME(connection)); - } + resolve(new GpgME(connection, _conf)); } else { reject(gpgme_error('CONN_NO_CONNECT')); } -- cgit From a4ba80c553c2ac42f9e311344302c04ec9aa715b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 24 May 2018 15:16:18 +0200 Subject: js: adding sign method -- * src/gpgmejs.js: method, update in src/permittedOperations * basic testing in BrowsertestExtension --- lang/js/BrowserTestExtension/browsertest.html | 1 + lang/js/src/gpgmejs.js | 38 +++++++++++++++++++++++ lang/js/src/permittedOperations.js | 44 ++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 1 deletion(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index c379ef53..3d81a9ec 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -17,6 +17,7 @@ + diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 3aa5957a..1e76655e 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -120,6 +120,44 @@ export class GpgME { } + sign(data, keys, mode='clearsign', base64=false) { //sender + if (data === undefined){ + return Promise.reject(gpgme_error('MSG_EMPTY')); + } + let key_arr = toKeyIdArray(keys); + if (key_arr.length === 0){ + return Promise.reject(gpgme_error('MSG_NO_KEYS')); + } + let msg = createMessage('sign'); + + msg.setParameter('keys', key_arr); + if (base64 === true){ + msg.setParameter('base64', true); + } + msg.setParameter('mode', mode); + putData(msg, data); + if (mode === 'detached') { + msg.expected = 'base64'; + } + let me = this; + return new Promise(function(resolve,reject) { + me.connection.post(msg).then( function(message) { + if (mode === 'clearsign'){ + resolve({ + data: message.data} + ); + } else if (mode === 'detached') { + resolve({ + data: data, + signature: message.data + }); + } + }, function(error){ + reject(error); + }) + }); + } + deleteKey(key, delete_secret = false, no_confirm = false){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); let msg = createMessage('deletekey'); diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index da46a1fd..aa02a8bc 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -130,6 +130,49 @@ export const permittedOperations = { // }] } }, + + sign: { + pinentry: true, + required: { + 'data': { + allowed: ['string']}, + 'keys': { + allowed: ['string'], + array_allowed: true + } + }, + optional: { + 'protocol': { + allowed: ['string'], + allowed_data: ['cms', 'openpgp'] + }, + 'chunksize': { + allowed: ['number'], + }, + 'sender': { + allowed: ['string'], + }, + 'mode': { + allowed: ['string'], + allowed_data: ['detached', 'clearsign'] // TODO 'opaque' not used + }, + 'base64': { + allowed: ['boolean'] + }, + 'armor': { + allowed: ['boolean'] + }, + }, + answer: { + type: ['signature', 'ciphertext'], + data: ['data'], // Unless armor mode is used a Base64 encoded binary + // signature. In armor mode a string with an armored + // OpenPGP or a PEM message. + params: ['base64'] + } + }, + + /** TBD: querying the Key's information (keyinfo) TBD name: { required: { @@ -212,6 +255,5 @@ export const permittedOperations = { *TBD get armored secret different treatment from keyinfo! * TBD key modification? * encryptsign: TBD - * verify: TBD */ } -- cgit From eff27d6387b1cad2ef9901fa03dbee2ea86c786a Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 25 May 2018 11:53:24 +0200 Subject: js: use version operation for connection checks -- * src/Connection.js: isConnected was renamed to checkConnection, that returns a promise with either version information or Boolean * Connection checks have been adapted to reflect that checkConnection returns a Promise * BrowsertestExtension: tests/signTest.js was missing from my last commit --- lang/js/BrowserTestExtension/tests/signTest.js | 58 +++++++++++++++++++++++++ lang/js/BrowserTestExtension/tests/startup.js | 3 -- lang/js/src/Connection.js | 60 ++++++++++++++++---------- lang/js/src/Errors.js | 4 -- lang/js/src/Keyring.js | 58 ++++++++++++------------- lang/js/src/gpgmejs.js | 8 +--- lang/js/src/index.js | 22 ++++------ lang/js/unittests.js | 57 ++++++++++++------------ 8 files changed, 162 insertions(+), 108 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/signTest.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js new file mode 100644 index 00000000..e3323721 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -0,0 +1,58 @@ +/* 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('Signing', function () { + it('Sign a message', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = bigString(100); + context.sign( + 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 SIGNATURE'); + expect(answer.data).to.include('END PGP SIGNATURE'); + expect(answer.data).to.include(data); + context.connection.disconnect(); + done(); + }); + }); + }); + it('Detached sign a message', function (done) { + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = bigString(100); + context.sign( + data, + inputvalues.encrypt.good.fingerprint, + 'detached' + ).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include(data); + expect(answer.signature).to.be.a('string'); + expect(answer.signature).to.be.a('string'); + context.connection.disconnect(); + done(); + }); + }); + }); + +}); diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index 5de70a6b..ebecf4fb 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -30,9 +30,6 @@ expect(context.encrypt).to.be.a('function'); expect(context.decrypt).to.be.a('function'); done(); - }, function(errorr){ - expect(error).to.be.undefined; - done(); }); }); }); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 9c2a6428..07df5def 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -25,7 +25,7 @@ */ import { permittedOperations } from './permittedOperations' import { gpgme_error } from "./Errors" -import { GPGME_Message } from "./Message"; +import { GPGME_Message, createMessage } from "./Message"; /** * A Connection handles the nativeMessaging interaction. @@ -34,18 +34,42 @@ export class Connection{ constructor(){ this.connect(); - let me = this; } /** - * (Simple) Connection check. - * @returns {Boolean} true if the onDisconnect event has not been fired. - * Please note that the event listener of the port takes some time - * (5 ms seems enough) to react after the port is created. Then this will - * return undefined + * Retrieves the information about the backend. + * @param {Boolean} details (optional) If set to false, the promise will + * just return a connection status + * @returns {Promise} + * {String} The property 'gpgme': Version number of gpgme + * {Array} 'info' Further information about the backends. + * Example: + * "protocol": "OpenPGP", + * "fname": "/usr/bin/gpg", + * "version": "2.2.6", + * "req_version": "1.4.0", + * "homedir": "default" */ - get isConnected(){ - return this._isConnected; + checkConnection(details = true){ + if (details === true) { + return this.post(createMessage('version')); + } else { + let me = this; + return new Promise(function(resolve,reject) { + Promise.race([ + me.post(createMessage('version')), + new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(gpgme_error('CONN_TIMEOUT')); + }, 500); + }) + ]).then(function(result){ + resolve(true); + }, function(reject){ + resolve(false); + }); + }); + } } /** @@ -54,6 +78,7 @@ export class Connection{ disconnect() { if (this._connection){ this._connection.disconnect(); + this._connection = null; } } @@ -61,17 +86,8 @@ export class Connection{ * Opens a nativeMessaging port. */ connect(){ - if (this._isConnected === true){ - gpgme_error('CONN_ALREADY_CONNECTED'); - } else { - this._isConnected = true; + if (!this._connection){ this._connection = chrome.runtime.connectNative('gpgmejson'); - let me = this; - this._connection.onDisconnect.addListener( - function(){ - me._isConnected = false; - } - ); } } @@ -82,8 +98,8 @@ export class Connection{ * information. */ post(message){ - if (!this.isConnected){ - return Promise.reject(gpgme_error('CONN_DISCONNECTED')); + if (!this._connection) { + } if (!message || !message instanceof GPGME_Message){ return Promise.reject(gpgme_error('PARAM_WRONG'), message); @@ -199,7 +215,7 @@ class Answer{ if (!this._response.hasOwnProperty(key)){ this._response[key] = []; } - this._response.push(msg[key]); + this._response[key].push(msg[key]); } else { return gpgme_error('CONN_UNEXPECTED_ANSWER'); diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index bfe3a2f4..7e98f319 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -25,10 +25,6 @@ const err_list = { + ' established.', type: 'error' }, - 'CONN_DISCONNECTED': { - msg:'Connection with the nativeMessaging host was lost.', - type: 'error' - }, 'CONN_EMPTY_GPG_ANSWER':{ msg: 'The nativeMessaging answer was empty.', type: 'error' diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 4596035a..80792f77 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -36,10 +36,7 @@ export class GPGME_Keyring { } get connection(){ if (this._connection instanceof Connection){ - if (this._connection.isConnected){ - return this._connection; - } - return gpgme_error('CONN_DISCONNECTED'); + return this._connection; } return gpgme_error('CONN_NO_CONNECT'); } @@ -51,36 +48,35 @@ export class GPGME_Keyring { * */ getKeys(pattern, include_secret){ - let msg = createMessage('listkeys'); - if (msg instanceof Error){ - return Promise.reject(msg); - } - if (pattern && typeof(pattern) === 'string'){ - msg.setParameter('pattern', pattern); - } - if (include_secret){ - msg.setParameter('with-secret', true); - } let me = this; - - this.connection.post(msg).then(function(result){ - let fpr_list = []; - let resultset = []; - if (!Array.isArray(result.keys)){ - //TODO check assumption keys = Array - fpr_list = [result.keys]; - } else { - fpr_list = result.keys; + return new Promise(function(resolve, reject) { + let msg; + msg = createMessage('listkeys'); + if (pattern && typeof(pattern) === 'string'){ + msg.setParameter('pattern', pattern); } - for (let i=0; i < fpr_list.length; i++){ - let newKey = new GPGME_Key(fpr_list[i], me._connection); - if (newKey instanceof GPGME_Key){ - resultset.push(newKey); - } + if (include_secret){ + msg.setParameter('with-secret', true); } - return Promise.resolve(resultset); - }, function(error){ - //TODO error handling + me.connection.post(msg).then(function(result){ + let fpr_list = []; + let resultset = []; + if (!Array.isArray(result.keys)){ + //TODO check assumption keys = Array + fpr_list = [result.keys]; + } else { + fpr_list = result.keys; + } + for (let i=0; i < fpr_list.length; i++){ + let newKey = new GPGME_Key(fpr_list[i], me._connection); + if (newKey instanceof GPGME_Key){ + resultset.push(newKey); + } + } + resolve(resultset); + }, function(error){ + reject(error); + }); }); } diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 1e76655e..c182c175 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -44,13 +44,7 @@ export class GpgME { } get connection(){ - if (this._connection){ - if (this._connection.isConnected === true){ - return this._connection; - } - return undefined; - } - return undefined; + return this._connection; } set Keyring(keyring){ diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 8527b3f3..7f969fee 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -34,20 +34,16 @@ function init(config){ } return new Promise(function(resolve, reject){ let connection = new Connection; - // TODO: Delayed reaction is ugly. We need to listen to the port's - // event listener in isConnected, but in some cases this takes some - // time (<5ms) to disconnect if there is no successfull connection. - let delayedreaction = function(){ - if (connection === undefined) { + connection.checkConnection(false).then( + function(result){ + if (result === true) { + resolve(new GpgME(connection, _conf)); + } else { + reject(gpgme_error('CONN_NO_CONNECT')); + } + }, function(error){ reject(gpgme_error('CONN_NO_CONNECT')); - } - if (connection.isConnected === true){ - resolve(new GpgME(connection, _conf)); - } else { - reject(gpgme_error('CONN_NO_CONNECT')); - } - }; - setTimeout(delayedreaction, 5); + }); }); } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index c437d599..06b2b23a 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -39,34 +39,29 @@ function unittests (){ it('Connecting', function(done) { let conn0 = new Connection; - let delayed = function(){ - expect(conn0.isConnected).to.be.true; - expect(conn0.connect).to.be.a('function'); + conn0.checkConnection().then(function(answer) { + expect(answer).to.not.be.empty; + expect(answer.gpgme).to.not.be.undefined; + expect(answer.gpgme).to.be.a('string'); + expect(answer.info).to.be.an('Array'); expect(conn0.disconnect).to.be.a('function'); expect(conn0.post).to.be.a('function'); done(); - }; - setTimeout(delayed, 5); + }); }); it('Disconnecting', function(done) { let conn0 = new Connection; - let delayed = function(){ - conn0.disconnect(); // TODO fails! - expect(conn0.isConnected).to.be.false; - done(); - }; - setTimeout(delayed, 5); + conn0.checkConnection(false).then(function(answer) { + expect(answer).to.be.true; + conn0.disconnect(); + conn0.checkConnection(false).then(function(result) { + expect(result).to.be.false; + done(); + }); + }); }); - - // broken - // it('Connect info still only available after a delay', function(done){ - // // if false, all delayed connections can be refactored - // let conn0 = new Connection; - // expect(conn0.isConnected).to.be.undefined; - // // - // }) }); describe('Error Object handling', function(){ @@ -181,14 +176,17 @@ function unittests (){ // TODO not implemented yet: Further Key functionality }); - it('Key can use the connection', function(){ + it('Key can use the connection', function(done){ let conn = new Connection; let key = createKey(hp.validFingerprint, conn); - - expect(key.connection.isConnected).to.be.true; - - key.connection.disconnect(); - expect(key.connection.isConnected).to.be.false; + key.connection.checkConnection(false).then(function(result){ + expect(result).to.be.true; + key.connection.disconnect(); + key.connection.checkConnection(false).then(function(result2){ + expect(result2).to.be.false; + done(); + }); + }); }); it('createKey returns error if parameters are wrong', function(){ @@ -232,12 +230,15 @@ function unittests (){ it('Keyring should return errors if not connected', function(){ let keyring = new GPGME_Keyring; - expect(keyring).to.be.an.instanceof(GPGME_Keyring); expect(keyring.connection).to.be.an.instanceof(Error); expect(keyring.connection.code).to.equal('CONN_NO_CONNECT'); - expect(keyring.getKeys).to.be.an.instanceof(Error); - expect(keyring.getkeys.code).to.equal('CONN_NO_CONNECT'); + // not yet implemented: + // keyring.getKeys().then( + // function(result){}, + //function(reject){ + // expect(reject).to.be.an.instanceof(Error); + // done(); }); //TODO not yet implemented: // getKeys(pattern, include_secret) //note: pattern can be null -- cgit From d4adbf453d39659eee378b2be1d7125315d76083 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 28 May 2018 16:52:50 +0200 Subject: js: Treat a connection as a gpgme Context -- * After an operation a connection should be disconnected again. The "end of operation" is now assumed to be either an error as answer, or a message not including a "more" * GPGME, GPGME_Key, GPGME_Keyring don't require a connection anymore * Message.js: The Message.post() method will open a connection as required --- .../tests/encryptDecryptTest.js | 7 --- lang/js/BrowserTestExtension/tests/encryptTest.js | 8 --- .../BrowserTestExtension/tests/longRunningTests.js | 1 - lang/js/BrowserTestExtension/tests/signTest.js | 2 - lang/js/BrowserTestExtension/tests/startup.js | 3 - lang/js/src/Connection.js | 14 +++-- lang/js/src/Key.js | 42 ++----------- lang/js/src/Keyring.js | 20 +------ lang/js/src/Message.js | 18 ++++++ lang/js/src/gpgmejs.js | 45 ++++---------- lang/js/src/index.js | 2 +- lang/js/unittests.js | 68 ++++------------------ 12 files changed, 59 insertions(+), 171 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index 2fe955e6..f5d2be16 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -34,7 +34,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(inputvalues.encrypt.good.data); - context.connection.disconnect(); done(); }); }); @@ -75,7 +74,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); - context.connection.disconnect(); done(); }); @@ -108,7 +106,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); - context.connection.disconnect(); done(); }); }); @@ -134,7 +131,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); - context.connection.disconnect(); done(); }); }); @@ -160,7 +156,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(data).to.equal(data); - context.connection.disconnect(); done(); }); }); @@ -187,7 +182,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); - context.connection.disconnect(); done(); }); }); @@ -214,7 +208,6 @@ describe('Encryption and Decryption', function () { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(b64data); - context.connection.disconnect(); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 521ed276..a16f993c 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -28,7 +28,6 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); - context.connection.disconnect(); done(); }); }); @@ -45,7 +44,6 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); - context.connection.disconnect(); done(); }); }); @@ -62,7 +60,6 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); - context.connection.disconnect(); done(); }); }); @@ -79,7 +76,6 @@ describe('Encryption', function () { expect(answer.data).to.be.a("string"); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); - context.connection.disconnect(); done(); }); }); @@ -95,7 +91,6 @@ describe('Encryption', function () { }, function(error){ expect(error).to.be.an('Error'); expect(error.code).to.equal('MSG_INCOMPLETE'); - context.connection.disconnect(); done(); }); }); @@ -110,7 +105,6 @@ describe('Encryption', function () { }, function (error) { expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('MSG_INCOMPLETE'); - context.connection.disconnect(); done(); }); }); @@ -127,7 +121,6 @@ describe('Encryption', function () { expect(error).to.be.an('Error'); expect(error.code).to.not.be.undefined; expect(error.code).to.equal('GNUPG_ERROR'); - context.connection.disconnect(); done(); }); }); @@ -146,7 +139,6 @@ describe('Encryption', function () { // TODO: there is a 64 MB hard limit at least in chrome at: // chromium//extensions/renderer/messaging_util.cc: // kMaxMessageLength - context.connection.disconnect(); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index 4e55fd26..5c588f27 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -29,7 +29,6 @@ describe('Long running Encryption/Decryption', function () { } } expect(result.data).to.equal(data); - context.connection.disconnect(); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js index e3323721..2e5edb30 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -30,7 +30,6 @@ describe('Signing', function () { expect(answer.data).to.include('BEGIN PGP SIGNATURE'); expect(answer.data).to.include('END PGP SIGNATURE'); expect(answer.data).to.include(data); - context.connection.disconnect(); done(); }); }); @@ -49,7 +48,6 @@ describe('Signing', function () { expect(answer.data).to.include(data); expect(answer.signature).to.be.a('string'); expect(answer.signature).to.be.a('string'); - context.connection.disconnect(); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index ebecf4fb..7d13ea47 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -23,10 +23,7 @@ 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(); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 3b442622..3480d811 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -102,9 +102,11 @@ export class Connection{ } if (!message || !message instanceof GPGME_Message){ + this.disconnect(); return Promise.reject(gpgme_error('PARAM_WRONG'), message); } if (message.isComplete !== true){ + this.disconnect(); return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } let me = this; @@ -113,25 +115,27 @@ export class Connection{ let listener = function(msg) { if (!msg){ me._connection.onMessage.removeListener(listener) + me._connection.disconnect(); reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); } else if (msg.type === "error"){ me._connection.onMessage.removeListener(listener); + me._connection.disconnect(); reject(gpgme_error('GNUPG_ERROR', msg.msg)); } else { let answer_result = answer.add(msg); if (answer_result !== true){ me._connection.onMessage.removeListener(listener); + me._connection.disconnect(); reject(answer_result); - } - if (msg.more === true){ + } else if (msg.more === true){ me._connection.postMessage({'op': 'getmore'}); } else { me._connection.onMessage.removeListener(listener) + me._connection.disconnect(); resolve(answer.message); } } }; - me._connection.onMessage.addListener(listener); if (permittedOperations[message.operation].pinentry){ return me._connection.postMessage(message.message); @@ -140,12 +144,14 @@ export class Connection{ me._connection.postMessage(message.message), function(resolve, reject){ setTimeout(function(){ + me._connection.disconnect(); reject(gpgme_error('CONN_TIMEOUT')); }, 5000); }]).then(function(result){ - return result; + return result; }, function(reject){ if(!reject instanceof Error) { + me._connection.disconnect(); return gpgme_error('GNUPG_ERROR', reject); } else { return reject; diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 7d3d82b1..13c99542 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -30,27 +30,16 @@ import { isFingerprint, isLongId } from './Helpers' import { gpgme_error } from './Errors' import { createMessage } from './Message'; import { permittedOperations } from './permittedOperations'; -import { Connection } from './Connection'; /** - * Validates the fingerprint, and checks for tha availability of a connection. - * If both are available, a Key will be returned. + * Validates the fingerprint. * @param {String} fingerprint - * @param {Object} parent Either a Connection, or the invoking object with a - * Connection (e.g. Keyring) */ -export function createKey(fingerprint, parent){ +export function createKey(fingerprint){ if (!isFingerprint(fingerprint)){ return gpgme_error('PARAM_WRONG'); } - if ( parent instanceof Connection){ - return new GPGME_Key(fingerprint, parent); - } else if ( parent.hasOwnProperty('connection') && - parent.connection instanceof Connection){ - return new GPGME_Key(fingerprint, parent.connection); - } else { - return gpgme_error('PARAM_WRONG'); - } + else return new GPGME_Key(fingerprint); } /** @@ -58,28 +47,8 @@ export function createKey(fingerprint, parent){ */ export class GPGME_Key { - constructor(fingerprint, connection){ + constructor(fingerprint){ this.fingerprint = fingerprint; - this.connection = connection; - } - - set connection(conn){ - if (this._connection instanceof Connection) { - gpgme_error('CONN_ALREADY_CONNECTED'); - } else if (conn instanceof Connection ) { - this._connection = conn; - } - } - - get connection(){ - if (!this._data.fingerprint){ - return gpgme_error('KEY_INVALID'); - } - if (!this._connection instanceof Connection){ - return gpgme_error('CONN_NO_CONNECT'); - } else { - return this._connection; - } } set fingerprint(fpr){ @@ -219,7 +188,8 @@ export class GPGME_Key { let msg = createMessage('keylist'); msg.setParameter('sigs', true); msg.setParameter('keys', me._data.fingerprint); - me.connection.post(msg).then(function(result){ + console.log(msg); + msg.post().then(function(result){ if (result.keys.length === 1){ me.setKeydata(result.keys[0]); resolve(me); diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 80792f77..9abb9ec3 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -22,23 +22,9 @@ import {createMessage} from './Message' import {GPGME_Key} from './Key' import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; -import { Connection } from './Connection'; export class GPGME_Keyring { - constructor(connection){ - this.connection = connection; - } - - set connection(connection){ - if (!this._connection && connection instanceof Connection){ - this._connection = connection; - } - } - get connection(){ - if (this._connection instanceof Connection){ - return this._connection; - } - return gpgme_error('CONN_NO_CONNECT'); + constructor(){ } /** @@ -58,7 +44,7 @@ export class GPGME_Keyring { if (include_secret){ msg.setParameter('with-secret', true); } - me.connection.post(msg).then(function(result){ + msg.post().then(function(result){ let fpr_list = []; let resultset = []; if (!Array.isArray(result.keys)){ @@ -68,7 +54,7 @@ export class GPGME_Keyring { fpr_list = result.keys; } for (let i=0; i < fpr_list.length; i++){ - let newKey = new GPGME_Key(fpr_list[i], me._connection); + let newKey = new GPGME_Key(fpr_list[i]); if (newKey instanceof GPGME_Key){ resultset.push(newKey); } diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 932212a6..5664f723 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -19,6 +19,7 @@ */ import { permittedOperations } from './permittedOperations' import { gpgme_error } from './Errors' +import { Connection } from './Connection'; export function createMessage(operation){ if (typeof(operation) !== 'string'){ @@ -193,4 +194,21 @@ export class GPGME_Message { } } + + post(){ + let me = this; + return new Promise(function(resolve, reject) { + if (me.isComplete === true) { + let conn = new Connection; + conn.post(me).then(function(response) { + resolve(response); + }, function(reason) { + reject(gpgme_error('GNUPG_ERROR', reason)); + }); + } + else { + reject(gpgme_error('MSG_INCOMPLETE')); + } + }); + } } diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c182c175..88a91a60 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -18,7 +18,6 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -import {Connection} from "./Connection" import {GPGME_Message, createMessage} from './Message' import {toKeyIdArray} from "./Helpers" import { gpgme_error } from "./Errors" @@ -29,31 +28,20 @@ export class GpgME { * initializes GpgME by opening a nativeMessaging port * TODO: add configuration */ - constructor(connection){ - this.connection = connection; + constructor(config){ //TODO config not parsed + this._config = config; } - set connection(conn){ - if (this._connection instanceof Connection){ - gpgme_error('CONN_ALREADY_CONNECTED'); - } else if (conn instanceof Connection){ - this._connection = conn; - } else { - gpgme_error('PARAM_WRONG'); - } - } - - get connection(){ - return this._connection; - } - - set Keyring(keyring){ + set Keyring(keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } } get Keyring(){ + if (!this._Keyring){ + this._Keyring = new GPGME_Keyring; + } return this._Keyring; } @@ -81,7 +69,7 @@ export class GpgME { msg.setParameter('throw-keyids', true); }; if (msg.isComplete === true){ - return this.connection.post(msg); + return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } @@ -110,7 +98,7 @@ export class GpgME { return Promise.reject(msg); } putData(msg, data); - return this.connection.post(msg); + return msg.post(); } @@ -135,7 +123,7 @@ export class GpgME { } let me = this; return new Promise(function(resolve,reject) { - me.connection.post(msg).then( function(message) { + msg.post().then( function(message) { if (mode === 'clearsign'){ resolve({ data: message.data} @@ -174,20 +162,7 @@ export class GpgME { // TBD } 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 - } - }); + return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 7f969fee..220a6984 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -37,7 +37,7 @@ function init(config){ connection.checkConnection(false).then( function(result){ if (result === true) { - resolve(new GpgME(connection, _conf)); + resolve(new GpgME(_conf)); } else { reject(gpgme_error('CONN_NO_CONNECT')); } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index bb06309d..9830a2c5 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -47,7 +47,6 @@ function unittests (){ expect(answer.info).to.be.an('Array'); expect(conn0.disconnect).to.be.a('function'); expect(conn0.post).to.be.a('function'); - conn0.disconnect(); done(); }); @@ -170,15 +169,11 @@ function unittests (){ describe('GPGME_Key', function(){ it('correct Key initialization', function(){ - let conn = new Connection; - let key = createKey(kp.validKeyFingerprint, conn); + let key = createKey(kp.validKeyFingerprint); expect(key).to.be.an.instanceof(GPGME_Key); - expect(key.connection).to.be.an.instanceof(Connection); - conn.disconnect(); }); it('Key has data after a first refresh', function(done) { - let conn = new Connection; - let key = createKey(kp.validKeyFingerprint, conn); + let key = createKey(kp.validKeyFingerprint); key.refreshKey().then(function(key2){ expect(key2).to.be.an.instanceof(GPGME_Key); expect(key2.get).to.be.a('function'); @@ -192,74 +187,42 @@ function unittests (){ key2.get('fingerprint')).to.equal(kp.validKeyFingerprint); expect( key2.get('fingerprint')).to.equal(key.fingerprint); - conn.disconnect(); done(); }); }); it('Non-cached key async data retrieval', function (done){ - let conn = new Connection; - let key = createKey(kp.validKeyFingerprint, conn); + let key = createKey(kp.validKeyFingerprint); key.get('can_authenticate',false).then(function(result){ expect(result).to.be.a('boolean'); - conn.disconnect(); done(); }); }) it('Querying non-existing Key returns an error', function(done) { - let conn = new Connection; - let key = createKey(kp.invalidKeyFingerprint, conn); + let key = createKey(kp.invalidKeyFingerprint); key.refreshKey().then(function(){}, function(error){ expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('KEY_NOKEY'); - conn.disconnect(); - done(); - }); - }); - - - it('Key can use the connection', function(done){ - let conn = new Connection; - let key = createKey(hp.validFingerprint, conn); - key.connection.checkConnection(false).then(function(result){ - expect(result).to.be.true; - key.connection.disconnect(); - key.connection.checkConnection(false).then(function(result2){ - expect(result2).to.be.false; - conn.disconnect(); done(); - }); }); }); it('createKey returns error if parameters are wrong', function(){ - let conn = new Connection; for (let i=0; i< 4; i++){ - let key0 = createKey(wp.four_invalid_params[i], conn); - + let key0 = createKey(wp.four_invalid_params[i]); expect(key0).to.be.an.instanceof(Error); expect(key0.code).to.equal('PARAM_WRONG'); } - for (let i=0; i< 4; i++){ - let key0 = createKey( - hp.validFingerprint, wp.four_invalid_params[i]); - - expect(key0).to.be.an.instanceof(Error); - expect(key0.code).to.equal('PARAM_WRONG'); - } - conn.disconnect(); }); it('malformed GPGME_Key cannot be used', function(){ - let conn = new Connection; for (let i=0; i < 4; i++){ - let key = new GPGME_Key(wp.four_invalid_params[i], conn); + let key = new GPGME_Key(wp.four_invalid_params[i]); expect(key.fingerprint).to.be.an.instanceof(Error); expect(key.fingerprint.code).to.equal('KEY_INVALID'); } - conn.disconnect(); }); // TODO: tests for subkeys @@ -269,27 +232,18 @@ function unittests (){ describe('GPGME_Keyring', function(){ - it('correct initialization', function(){ - let conn = new Connection; - let keyring = new GPGME_Keyring(conn); - + it('correct Keyring initialization', function(){ + let keyring = new GPGME_Keyring; expect(keyring).to.be.an.instanceof(GPGME_Keyring); - expect(keyring.connection).to.be.an.instanceof(Connection); expect(keyring.getKeys).to.be.a('function'); expect(keyring.getSubset).to.be.a('function'); }); - it('Keyring should return errors if not connected', function(){ + it('correct initialization', function(){ let keyring = new GPGME_Keyring; expect(keyring).to.be.an.instanceof(GPGME_Keyring); - expect(keyring.connection).to.be.an.instanceof(Error); - expect(keyring.connection.code).to.equal('CONN_NO_CONNECT'); - // not yet implemented: - // keyring.getKeys().then( - // function(result){}, - //function(reject){ - // expect(reject).to.be.an.instanceof(Error); - // done(); + expect(keyring.getKeys).to.be.a('function'); + expect(keyring.getSubset).to.be.a('function'); }); //TODO not yet implemented: // getKeys(pattern, include_secret) //note: pattern can be null -- cgit From 53ce2b94bc35243710dec9b7972c7aaaa79dbc75 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 28 May 2018 17:26:56 +0200 Subject: js: Keyring listing keys -- * implementing Keyring methods: - Keyring.getKeys: has an additional option that retrieves the armor and secret state once at the beginning. This is power hungry, but allows for Keys to be used directly (without querying gpgme-json each call) * permittedOperations.js: reflect recent changes in the native counterpart, adding more options * Key: adding two methods for retrieving the armored Key block and for finding out if the Key includes a secret subkey. --- lang/js/BrowserTestExtension/testkey2.pub | 30 ++++++ lang/js/src/Key.js | 86 ++++++++++++--- lang/js/src/Keyring.js | 129 ++++++---------------- lang/js/src/permittedOperations.js | 174 +++++++++++++++++++----------- lang/js/unittest_inputvalues.js | 4 + lang/js/unittests.js | 48 +++++++-- 6 files changed, 286 insertions(+), 185 deletions(-) create mode 100644 lang/js/BrowserTestExtension/testkey2.pub (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/testkey2.pub b/lang/js/BrowserTestExtension/testkey2.pub new file mode 100644 index 00000000..557bd5be --- /dev/null +++ b/lang/js/BrowserTestExtension/testkey2.pub @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFsMHecBCACqdJgqa+CeNYwPCK+MpOwAV6uFVjDyO2LmOs6+XfDWRBU/Zjtz +8zdYNKSbLjkWN4ujV5aiyA7MtEofszzYLEoKUt1wiDScHMpW8qmEFDvl9g26MeAV +rTno9D5KodHvEIs8wnrqBs8ix0WLbh6J1Dtt8HQgIbN+v3gaRQrgBFe6z2ZYpHHx +ZfOu3iFKlm2WE/NekRkvvFIo3ApGvRhGIYw6JMmugBlo7s5xosJK0I9dkPGlEEtt +aF1RkcMj8sWG9vHAXcjlGgFfXSN9YLppydXpkuZGm4+gjLB2a3rbQCZVFnxCyG4O +ybjkP8Jw6Udm89bK2ucYFfjdrmYn/nJqRxeNABEBAAG0I1Rlc3QgTm9Qcml2S2V5 +IDxub2JvZHlAZXhhbXBsZS5vcmc+iQFOBBMBCAA4FiEE4Fmh4IZtMa4TEXCITZou +EzBBU9EFAlsMHecCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQTZouEzBB +U9F+qwf/SHj4uRnTWgyJ71FBxQDYCBq3jbi6e7hMkRPbJyJdnPIMAb2p0PJjBgjW +0pp4+kDPZans3UDHbma1u/SFI4/y6isJiK94Bk5xp5YliLGnUceTjgDFe6lBhfQ1 +zVWZC/NF3tPgbziIxXQTNt34nS+9dbV/QFDLW0POcN7C0jR/hgkBjMEH2PezWhSj +mL/yLfLfUYAoxVpXjfC5aPJKqw0tR7m5ibznjCphE+FUMRg8EOmJcg6soeJ5QspU +k2dPN3+Y0zCTNRgAHEI+yIQbM6pio6v2c+UCtT1QhW4xSI38/kcEG8QiM55r1TUy +FcWAY5n5t1nNZtMxxse3LqEon3rKiLkBDQRbDB3nAQgAqfAjSjcngERtM+ZYOwN0 +QF2v2FuEuMe8mhju7Met7SN2zGv1LnjhTNshEa9IABEfjZirE2Tqx4xCWDwDedK4 +u1ToFvcnuAMnq2O47Sh+eTypsf6WPFtPBWf6ctKY31hFXjgoyDBULBvl43XU/D9C +Mt7nsKDPYHVrrnge/qWPYVcb+cO0sSwNImMcwQSdTQ3VBq7MeNS9ZeBcXi+XCjhN +kjNum2AQqpkHHDQV7871yQ8RIILvZSSfkLb0/SNDU+bGaw2G3lcyKdIfZi2EWWZT +oCbH38I/+LV7nAEe4zFpHwW8X0Dkx2aLgxe6UszDH9L3eGhTLpJhOSiaanG+zZKm ++QARAQABiQE2BBgBCAAgFiEE4Fmh4IZtMa4TEXCITZouEzBBU9EFAlsMHecCGwwA +CgkQTZouEzBBU9H5TQgAolWvIsez/WW8N2tmZEnX0LOFNB+1S4L4X983njwNdoVI +w19pbj+8RIHF/H9kcPGi7jK96gvlykQn3uez/95D2AiRFW5KYdOouFisKgHpv8Ay +BrhclHv11yK+X/0iTD0scYaG7np5162xLkaxSO9hsz2fGv20RKaXCWkI69fWw0BR +XlI5pZh2YFei2ZhH/tIMIW65h3w0gtgaZBBdpZTOOW4zvghyN+0MSObqkI1BvUJu +caDFI4d6ZTmp5SY+pZyktZ4bg/vMH5VFxdIKgbLx9uVeTvOupvbAW0TNulYGUBQE +nm+S0zr3W18t64e4sS3oHse8zCqo1iiImpba6F1Oaw== +=y6DD +-----END PGP PUBLIC KEY BLOCK----- diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 13c99542..f2a16b42 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -77,7 +77,7 @@ export class GPGME_Key { * @returns {GPGME_Key|GPGME_Error} The Key object itself after values have * been set */ - setKeydata(data){ + setKeyData(data){ if (this._data === undefined) { this._data = {}; } @@ -161,11 +161,17 @@ export class GPGME_Key { if (cached === false) { let me = this; return new Promise(function(resolve, reject) { - me.refreshKey().then(function(key){ - resolve(key.get(property, true)); - }, function(error){ - reject(error); - }); + if (property === 'armor'){ + resolve(me.getArmor()); + } else if (property === 'hasSecret'){ + resolve(me.getHasSecret()); + } else { + me.refreshKey().then(function(key){ + resolve(key.get(property, true)); + }, function(error){ + reject(error); + }); + } }); } else { if (!this._data.hasOwnProperty(property)){ @@ -188,10 +194,9 @@ export class GPGME_Key { let msg = createMessage('keylist'); msg.setParameter('sigs', true); msg.setParameter('keys', me._data.fingerprint); - console.log(msg); msg.post().then(function(result){ if (result.keys.length === 1){ - me.setKeydata(result.keys[0]); + me.setKeyData(result.keys[0]); resolve(me); } else { reject(gpgme_error('KEY_NOKEY')); @@ -202,25 +207,78 @@ export class GPGME_Key { }); } - //TODO: /** * Get the armored block of the non- secret parts of the Key. * @returns {String} the armored Key block. * Notice that this may be outdated cached info. Use the async getArmor if * you need the most current info */ + // get armor(){ TODO } /** * Query the armored block of the non- secret parts of the Key directly * from gpg. - * Async, returns Promise + * @returns {Promise} */ - // getArmor(){ TODO } - // + getArmor(){ + let me = this; + return new Promise(function(resolve, reject) { + if (!me._data.fingerprint){ + reject(gpgme_error('KEY_INVALID')); + } + let msg = createMessage('export'); + msg.setParameter('armor', true); + msg.setParameter('keys', me._data.fingerprint); + msg.post().then(function(result){ + me._data.armor = result.data; + resolve(result.data); + }, function(error){ + reject(error); + }); + }); + } - // get hasSecret(){TODO} // confusing difference to Key.get('secret')! - // getHasSecret(){TODO async version} + getHasSecret(){ + let me = this; + return new Promise(function(resolve, reject) { + if (!me._data.fingerprint){ + reject(gpgme_error('KEY_INVALID')); + } + let msg = createMessage('keylist'); + msg.setParameter('keys', me._data.fingerprint); + msg.setParameter('secret', true); + msg.post().then(function(result){ + me._data.hasSecret = null; + if (result.keys === undefined || result.keys.length < 1) { + me._data.hasSecret = false; + resolve(false); + } + else if (result.keys.length === 1){ + let key = result.keys[0]; + if (!key.subkeys){ + me._data.hasSecret = false; + resolve(false); + } else { + for (let i=0; i < key.subkeys.length; i++) { + if (key.subkeys[i].secret === true) { + me._data.hasSecret = true; + resolve(true); + break; + } + if (i === (key.subkeys.length -1)) { + me._data.hasSecret = false; + resolve(false); + } + } + } + } else { + reject(gpgme_error('CONN_UNEXPECTED_ANSWER')) + } + }, function(error){ + }) + }); + } } /** diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 9abb9ec3..7e13dfe2 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -19,7 +19,7 @@ */ import {createMessage} from './Message' -import {GPGME_Key} from './Key' +import {GPGME_Key, createKey} from './Key' import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; @@ -28,117 +28,54 @@ export class GPGME_Keyring { } /** - * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds - * @param {Boolean} (optional) Include listing of secret keys + * @param {String} pattern (optional) pattern A pattern to search for, + * in userIds or KeyIds + * @param {Boolean} prepare_sync (optional, default true) if set to true, + * Key.armor and Key.hasSecret will be called, so they can be used + * inmediately. This allows for full synchronous use. If set to false, + * these will initially only be available as Promises in getArmor() and + * getHasSecret() * @returns {Promise.>} * */ - getKeys(pattern, include_secret){ + getKeys(pattern, prepare_sync){ let me = this; return new Promise(function(resolve, reject) { let msg; - msg = createMessage('listkeys'); + msg = createMessage('keylist'); if (pattern && typeof(pattern) === 'string'){ - msg.setParameter('pattern', pattern); - } - if (include_secret){ - msg.setParameter('with-secret', true); + msg.setParameter('keys', pattern); } + msg.setParameter('sigs', true); //TODO do we need this? msg.post().then(function(result){ - let fpr_list = []; let resultset = []; - if (!Array.isArray(result.keys)){ - //TODO check assumption keys = Array - fpr_list = [result.keys]; - } else { - fpr_list = result.keys; - } - for (let i=0; i < fpr_list.length; i++){ - let newKey = new GPGME_Key(fpr_list[i]); - if (newKey instanceof GPGME_Key){ - resultset.push(newKey); + let promises = []; + // TODO check if result.key is not empty + for (let i=0; i< result.keys.length; i++){ + let k = createKey(result.keys[i].fingerprint, me); + k.setKeyData(result.keys[i]); + if (prepare_sync === true){ + promises.push(k.getArmor()); + promises.push(k.getHasSecret()); } + resultset.push(k); + } + if (promises.length > 0) { + Promise.all(promises).then(function (res){ + resolve(resultset); + }, function(error){ + reject(error); + }); } - resolve(resultset); }, function(error){ reject(error); }); }); } - - /** - * @param {Object} flags subset filter expecting at least one of the - * filters described below. True will filter on the condition, False will - * reverse the filter, if not present or undefined, the filter will not be - * considered. Please note that some combination may not make sense - * @param {Boolean} flags.secret Only Keys containing a secret part. - * @param {Boolean} flags.revoked revoked Keys only - * @param {Boolean} flags.expired Expired Keys only - * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds - * @returns {Promise Array} - * - */ - getSubset(flags, pattern){ - if (flags === undefined) { - throw('ERR_WRONG_PARAM'); - }; - let secretflag = false; - if (flags.hasOwnProperty(secret) && flags.secret){ - secretflag = true; - } - this.getKeys(pattern, secretflag).then(function(queryset){ - let resultset = []; - for (let i=0; i < queryset.length; i++ ){ - let conditions = []; - let anticonditions = []; - if (secretflag === true){ - conditions.push('hasSecret'); - } else if (secretflag === false){ - anticonditions.push('hasSecret'); - } - /** - if (flags.defaultKey === true){ - conditions.push('isDefault'); - } else if (flags.defaultKey === false){ - anticonditions.push('isDefault'); - } - */ - /** - * if (flags.valid === true){ - anticonditions.push('isInvalid'); - } else if (flags.valid === false){ - conditions.push('isInvalid'); - } - */ - if (flags.revoked === true){ - conditions.push('isRevoked'); - } else if (flags.revoked === false){ - anticonditions.push('isRevoked'); - } - if (flags.expired === true){ - conditions.push('isExpired'); - } else if (flags.expired === false){ - anticonditions.push('isExpired'); - } - let decision = undefined; - for (let con = 0; con < conditions.length; con ++){ - if (queryset[i][conditions[con]] !== true){ - decision = false; - } - } - for (let acon = 0; acon < anticonditions.length; acon ++){ - if (queryset[i][anticonditions[acon]] === true){ - decision = false; - } - } - if (decision !== false){ - resultset.push(queryset[i]); - } - } - return Promise.resolve(resultset); - }, function(error){ - //TODO error handling - }); - } +// TODO: + // deleteKey(key, include_secret=false) + // getKeysArmored(pattern) //just dump all armored keys + // getDefaultKey() Big TODO + // importKeys(armoredKeys) }; diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 42213ec3..e4f9bd22 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -45,6 +45,7 @@ export const permittedOperations = { encrypt: { + pinentry: true, //TODO only with signing_keys required: { 'keys': { allowed: ['string'], @@ -59,38 +60,42 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - 'chunksize': { + 'signing_keys': { + allowed: ['string'], + array_allowed: true + }, + 'chunksize': { allowed: ['number'] - }, - 'base64': { - allowed: ['boolean'] - }, - 'mime': { - allowed: ['boolean'] - }, - 'armor': { - allowed: ['boolean'] - }, - 'always-trust': { - allowed: ['boolean'] - }, - 'no-encrypt-to': { - allowed: ['string'], - array_allowed: true - }, - 'no-compress': { - allowed: ['boolean'] - }, - 'throw-keyids': { - allowed: ['boolean'] - }, - 'want-address': { - allowed: ['boolean'] - }, - 'wrap': { - allowed: ['boolean'] - }, }, + 'base64': { + allowed: ['boolean'] + }, + 'mime': { + allowed: ['boolean'] + }, + 'armor': { + allowed: ['boolean'] + }, + 'always-trust': { + allowed: ['boolean'] + }, + 'no-encrypt-to': { + allowed: ['string'], + array_allowed: true + }, + 'no-compress': { + allowed: ['boolean'] + }, + 'throw-keyids': { + allowed: ['boolean'] + }, + 'want-address': { + allowed: ['boolean'] + }, + 'wrap': { + allowed: ['boolean'] + } + }, answer: { type: ['ciphertext'], data: ['data'], @@ -122,12 +127,7 @@ export const permittedOperations = { type: ['plaintext'], data: ['data'], params: ['base64', 'mime'], - infos: [] // TODO pending. Info about signatures and validity - //{ - //signatures: [{ - //Key : Fingerprint, - //valid: - // }] + infos: ['signatures'] } }, @@ -208,61 +208,107 @@ export const permittedOperations = { 'validate': { allowed: ['boolean'] }, - // 'pattern': { TODO - // allowed: ['string'] - // }, 'keys': { allowed: ['string'], array_allowed: true } }, answer: { - type: [], + type: ['keys'], data: [], - params: [], + params: ['base64'], infos: ['keys'] } }, - /** - importkey: { + export: { + required: {}, + optional: { + 'protocol': { + allowed: ['string'], + allowed_data: ['cms', 'openpgp'] + }, + 'chunksize': { + allowed: ['number'], + }, + 'keys': { + allowed: ['string'], + array_allowed: true + }, + 'armor': { + allowed: ['boolean'] + }, + 'extern': { + allowed: ['boolean'] + }, + 'minimal': { + allowed: ['boolean'] + }, + 'raw': { + allowed: ['boolean'] + }, + 'pkcs12':{ + allowed: ['boolean'] + } + // secret: not yet implemented + }, + answer: { + type: ['keys'], + data: ['data'], + params: ['base64'] + } + }, + + import: { required: { - 'keyarmored': { + 'data': { allowed: ['string'] } }, + optional: { + 'protocol': { + allowed: ['string'], + allowed_data: ['cms', 'openpgp'] + }, + 'base64': { + allowed: ['boolean'] + }, + }, answer: { - type: ['TBD'], - infos: ['TBD'], - // for each key if import was a success, - // and if it was an update of preexisting key + infos: ['result'], + type: [], + data: [], + params: [] } }, - */ - /** - deletekey: { + delete: { pinentry: true, - required: { - 'fingerprint': { + required:{ + 'key': { + allowed: ['string'] + } + }, + optional: { + 'protocol': { allowed: ['string'], - // array_allowed: TBD Allow several Keys to be deleted at once? + allowed_data: ['cms', 'openpgp'] }, - optional: { - 'TBD' //Flag to delete secret Key ? - } + // 'secret': { not yet implemented + // allowed: ['boolean'] + // } + + }, answer: { - type ['TBD'], - infos: [''] - // TBD (optional) Some kind of 'ok' if delete was successful. + data: [], + params:['success'], + infos: [] } - } - */ - + }, /** *TBD get armored secret different treatment from keyinfo! * TBD key modification? - * encryptsign: TBD + */ version: { diff --git a/lang/js/unittest_inputvalues.js b/lang/js/unittest_inputvalues.js index ca51f4ae..2a21a6ae 100644 --- a/lang/js/unittest_inputvalues.js +++ b/lang/js/unittest_inputvalues.js @@ -44,7 +44,11 @@ export const whatever_params = { four_invalid_params: ['<(((-<', '>°;==;~~', '^^', '{{{{o}}}}'], } export const key_params = { +// A Key you own (= having a secret Key) in GPG. See testkey.pub/testkey.sec validKeyFingerprint: 'D41735B91236FDB882048C5A2301635EEFF0CB05', +// A Key you do not own (= having no secret Key) in GPG. See testkey2.pub + validFingerprintNoSecret: 'E059A1E0866D31AE131170884D9A2E13304153D1', +// A Key not in your Keyring. This is just a random hex string. invalidKeyFingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A', validKeyProperties: ['expired', 'disabled','invalid','can_encrypt', 'can_sign','can_certify','can_authenticate','secret','is_qualified'] diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 9830a2c5..443aa685 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -197,7 +197,34 @@ function unittests (){ expect(result).to.be.a('boolean'); done(); }); - }) + }); + + it('Non-cached key async armored Key', function (done){ + let key = createKey(kp.validKeyFingerprint); + key.get('armor', false).then(function(result){ + expect(result).to.be.a('string'); + expect(result).to.include('KEY BLOCK-----'); + done(); + }); + }); + + it('Non-cached key async hasSecret', function (done){ + let key = createKey(kp.validKeyFingerprint); + key.get('hasSecret', false).then(function(result){ + expect(result).to.be.a('boolean'); + done(); + }); + }); + + it('Non-cached key async hasSecret (no secret in Key)', function (done){ + let key = createKey(kp.validFingerprintNoSecret); + expect(key).to.be.an.instanceof(GPGME_Key); + key.get('hasSecret', false).then(function(result){ + expect(result).to.be.a('boolean'); + expect(result).to.equal(false); + done(); + }); + }); it('Querying non-existing Key returns an error', function(done) { let key = createKey(kp.invalidKeyFingerprint); @@ -224,7 +251,6 @@ function unittests (){ expect(key.fingerprint.code).to.equal('KEY_INVALID'); } }); - // TODO: tests for subkeys // TODO: tests for userids // TODO: some invalid tests for key/keyring @@ -236,19 +262,19 @@ function unittests (){ let keyring = new GPGME_Keyring; expect(keyring).to.be.an.instanceof(GPGME_Keyring); expect(keyring.getKeys).to.be.a('function'); - expect(keyring.getSubset).to.be.a('function'); }); - it('correct initialization', function(){ + it('Loading Keys from Keyring, to be used synchronously', function(done){ let keyring = new GPGME_Keyring; - expect(keyring).to.be.an.instanceof(GPGME_Keyring); - expect(keyring.getKeys).to.be.a('function'); - expect(keyring.getSubset).to.be.a('function'); + keyring.getKeys(null, true).then(function(result){ + expect(result).to.be.an('array'); + expect(result[0]).to.be.an.instanceof(GPGME_Key); + expect(result[0].get('armor')).to.be.a('string'); + expect(result[0].get('armor')).to.include( + '-----END PGP PUBLIC KEY BLOCK-----'); + done(); + }); }); - //TODO not yet implemented: - // getKeys(pattern, include_secret) //note: pattern can be null - // getSubset(flags, pattern) - // available Boolean flags: secret revoked expired }); describe('GPGME_Message', function(){ -- cgit From 0356a667c5a8b4fdb4404cebb57475ed3f39ade9 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 6 Jun 2018 11:57:41 +0200 Subject: js: implement import/delete Key, some fixes -- * Keyring.js - implemented importKey: importing one or more armored public key blocks. - implemented deleteKey: deleting a public Key from gpg. * Key.js renamed property Key.armor to Key.armored * Helpers.js: toKeyIDArray does not complain anymore if there are no keys. Not having Keys in e.g. signing keys in encrypt is legitimate and common, the complaints were getting spammy * Errors.js: gpgme_errors now always pass an optional additional message, for easier debugging in minified code * Connection.js: Fix in gpgme-json responses containing objects * eslintrc.json: Start using eslint. A cleanup to conform to it is not done yet * Added further tests for the new functionality --- lang/js/.eslintrc.json | 29 +++++ lang/js/BrowserTestExtension/browsertest.html | 1 + .../BrowserTestExtension/tests/KeyImportExport.js | 83 ++++++++++++ .../tests/encryptDecryptTest.js | 5 +- lang/js/BrowserTestExtension/tests/inputvalues.js | 105 +++++++++++++-- lang/js/src/Connection.js | 5 +- lang/js/src/Errors.js | 8 +- lang/js/src/Helpers.js | 2 - lang/js/src/Key.js | 4 +- lang/js/src/Keyring.js | 144 +++++++++++++++++---- lang/js/unittest_inputvalues.js | 93 +++++++++++-- lang/js/unittests.js | 126 +++++++++++++----- 12 files changed, 511 insertions(+), 94 deletions(-) create mode 100644 lang/js/.eslintrc.json create mode 100644 lang/js/BrowserTestExtension/tests/KeyImportExport.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/.eslintrc.json b/lang/js/.eslintrc.json new file mode 100644 index 00000000..65253cf3 --- /dev/null +++ b/lang/js/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "indent": [ + "warn", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ], + "max-len": 1 + } +} \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index 3d81a9ec..f3d7a406 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -18,6 +18,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js new file mode 100644 index 00000000..e6eb5a30 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -0,0 +1,83 @@ +/* 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+ + */ + +/* global describe, it, expect, Gpgmejs, ImportablePublicKey */ + +describe('Key importing', function () { + it('Prepare test Key (deleting it from gnupg, if present)', function(done){ + let prm = Gpgmejs.init(); + prm.then(function (context) { + expect(context.Keyring.getKeys).to.be.a('function'); + context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + function(result){ + if (result.length === 1) { + result[0].delete().then(function(result){ + expect(result).to.be.true; + done(); + }); + } else { + done(); + } + }); + }); + }); + + it('importing, updating, then deleting public Key', function (done) { + //This test runs in one large step, to ensure the proper state of the + // key in all stages. + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + context.Keyring.importKey(ImportablePublicKey.key, true) + .then(function(result){ + expect(result[0]).to.not.be.undefined; + expect(result[0].key).to.be.an('object'); + expect(result[0].key.fingerprint).to.equal( + ImportablePublicKey.fingerprint); + expect(result[0].status).to.equal('newkey'); + context.Keyring.importKey( + ImportablePublicKey.keyChangedUserId,true) + .then(function(res){ + expect(res[0]).to.not.be.undefined; + expect(res[0].key).to.be.an('object'); + expect(res[0].key.fingerprint).to.equal( + ImportablePublicKey.fingerprint); + expect(res[0].status).to.equal( + 'change'); + expect( + res[0].changes.userId).to.be.true; + expect( + res[0].changes.subkey).to.be.false; + expect( + res[0].changes.signature).to.be.true; + res[0].key.delete().then(function(result){ + expect(result).to.be.true; + done(); + }); + }); + }); + }); + }); + }); + +}); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index f5d2be16..e5c2f749 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -163,7 +163,6 @@ describe('Encryption and Decryption', function () { }).timeout(3000); it('Random data, input as base64', function (done) { - //TODO fails. The result is let data = bigBoringString(0.001); let b64data = btoa(data); let prm = Gpgmejs.init(); @@ -177,11 +176,11 @@ describe('Encryption and Decryption', function () { 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( 'END PGP MESSAGE'); - context.decrypt(answer.data).then( + context.decrypt(answer.data, true).then( function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); + expect(result.data).to.equal(b64data); done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 52e3a7b0..9dc13324 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -18,11 +18,12 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -var inputvalues = { +var inputvalues = {// eslint-disable-line no-unused-vars encrypt: { good:{ data : 'Hello World.', - // Fingerprint of a key that has been imported to gnupg (i.e. see testkey.pub; testkey.sec) + // Fingerprint of a key that has been imported to gnupg + // (i.e. see testkey.pub; testkey.sec) fingerprint : 'D41735B91236FDB882048C5A2301635EEFF0CB05', data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день', @@ -45,7 +46,8 @@ var inputvalues = { ] }, bad: { - // valid Hex value, but not usable (not imported to gnupg, or bogus fingerprint) + // valid Hex value, but not usable (not imported to gnupg, or + // bogus fingerprint) fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } }, @@ -54,14 +56,13 @@ var inputvalues = { invalid_startups: [ {all_passwords: true}, 'openpgpmode', - {api_style:"frankenstein"} + {api_style:'frankenstein'} ] } }; // (Pseudo-)Random String covering all of utf8. -function bigString(length){ - var uint = ''; +function bigString(length){// eslint-disable-line no-unused-vars let arr = []; for (let i= 0; i < length; i++){ arr.push(String.fromCharCode( @@ -71,7 +72,7 @@ function bigString(length){ return arr.join(''); } -function fixedLengthString(megabytes){ +function fixedLengthString(megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes / 2; let uint = new Uint8Array(maxlength); for (let i = 0; i < maxlength; i++){ @@ -83,7 +84,7 @@ function fixedLengthString(megabytes){ } // (Pseudo-)Random Uint8Array, given size in Megabytes -function bigUint8(megabytes){ +function bigUint8(megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); for (let i= 0; i < maxlength; i++){ @@ -92,11 +93,13 @@ function bigUint8(megabytes){ return uint; } -// (Pseudo-)Random string with very limited charset (ascii only, no control chars) -function bigBoringString(megabytes){ +// (Pseudo-)Random string with very limited charset +// (ascii only, no control chars) +function bigBoringString(megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let string = []; - let chars = ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let chars = + ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; for (let i= 0; i < maxlength; i++){ string.push(chars[Math.floor(Math.random() * chars.length)]); } @@ -105,12 +108,13 @@ function bigBoringString(megabytes){ // Some String with simple chars, with different characteristics, but still // expected to occur in an averag message +// eslint-disable-next-line no-unused-vars function slightlyLessBoringString(megabytes, set){ let maxlength = 1024 * 1024 * megabytes; let string = []; let chars = ''; if (set ===1 ) { - chars = '\n\"\r \''; + chars = '\n"\r \''; } else if (set === 2 ) { chars = '()=?`#+-{}[]'; } else if (set === 3){ @@ -118,7 +122,7 @@ function slightlyLessBoringString(megabytes, set){ } else if (set ===4) { chars = 'äüßµüþÖ~ɁÑ||@'; } else { - chars = '*<>\n\"\r§$%&/()=?`#+-{}[] \''; + chars = '*<>\n"\r§$%&/()=?`#+-{}[] \''; } for (let i= 0; i < maxlength; i++){ string.push(chars[Math.floor(Math.random() * chars.length)]); @@ -127,7 +131,7 @@ function slightlyLessBoringString(megabytes, set){ } // Data encrypted with testKey -var encryptedData = +var encryptedData =// eslint-disable-line no-unused-vars '-----BEGIN PGP MESSAGE-----\n' + '\n' + 'hQEMA6B8jfIUScGEAQgAlANd3uyhmhYLzVcfz4LEqA8tgUC3n719YH0iuKEzG/dv\n' + @@ -141,3 +145,76 @@ var encryptedData = 'kSAQYOHplfA7YJWkrlRm\n' + '=zap6\n' + '-----END PGP MESSAGE-----\n'; + +var ImportablePublicKey = {// eslint-disable-line no-unused-vars + fingerprint: '78034948BA7F5D0E9BDB67E4F63790C11E60278A', + key:'-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + '\n' + + 'mQENBFsPvK0BCACaIgoIN+3g05mrTITULK/YDTrfg4W7RdzIZBxch5CM0zdu/dby\n' + + 'esFwaJbVQIqu54CRz5xKAiWmRrQCaRvhvjY0na5r5UUIpbeQiOVrl65JtNbRmlik\n' + + 'd9Prn1kZDUOZiCPIKn+/M2ecJ92YedM7I4/BbpiaFB11cVrPFg4thepn0LB3+Whp\n' + + '9HDm4orH9rjy6IUr6yjWNIr+LYRY6/Ip2vWcMVjleEpTFznXrm83hrJ0n0INtyox\n' + + 'Nass4eDWkgo6ItxDFFLOORSmpfrToxZymSosWqgux/qG6sxHvLqlqy6Xe3ZYRFbG\n' + + '+JcA1oGdwOg/c0ndr6BYYiXTh8+uUJfEoZvzABEBAAG0HEJsYSBCbGEgPGJsYWJs\n' + + 'YUBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUC\n' + + 'Ww+8rQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD2N5DBHmAn\n' + + 'igwIB/9K3E3Yev9taZP4KnXPhk1oMQRW1MWAsFGUr+70N85VwedpUawymW4vXi1+\n' + + 'hMeTc39QjmZ0+VqHkJttkqEN6bLcEvgmU/mOlOgKdzy6eUcasYAzgoAKUqSX1SPs\n' + + '0Imo7Tj04wnfnVwvKxaeadi0VmdqIYaW75UlrzIaltsBctyeYH8sBrvaTLscb4ON\n' + + '46OM3Yw2G9+dBF0P+4UYFHP3EYZMlzNxfwF+i2HsYcNDHlcLfjENr9GwKn5FJqpY\n' + + 'Iq3qmI37w1hVasHDxXdz1X06dpsa6Im4ACk6LXa7xIQlXxTgPAQV0sz2yB5eY+Md\n' + + 'uzEXPGW+sq0WRp3hynn7kVP6QQYvuQENBFsPvK0BCACwvBcmbnGJk8XhEBRu2QN3\n' + + 'jKgVs3CG5nE2Xh20JipZwAuGHugDLv6/jlizzz5jtj3SAHVtJB8lJW8I0cNSEIX8\n' + + 'bRYH4C7lP2DTb9CgMcGErQIyK480+HIsbsZhJSNHdjUUl6IPEEVfSQzWaufmuswe\n' + + 'e+giqHiTsaiW20ytXilwVGpjlHBaxn/bpskZ0YRasgnPqKgJD3d5kunNqWoyCpMc\n' + + 'FYgDERvPbhhceFbvFE9G/u3gbcuV15mx53dDX0ImvPcvJnDOyJS9yr7ApdOV312p\n' + + 'A1MLbxfPnbnVu+dGXn7D/VCDd5aBYVPm+5ANrk6z9lYKH9aO5wgXpLAdJvutCOL5\n' + + 'ABEBAAGJATwEGAEIACYWIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUCWw+8rQIbDAUJ\n' + + 'A8JnAAAKCRD2N5DBHmAnigMVB/484G2+3R0cAaj3V/z4gW3MRSMhcYqEMyJ/ACdo\n' + + '7y8eoreYW843JWWVDRY6/YcYYGuBBP47WO4JuP2wIlVn17XOCSgnNjmmjsIYiAzk\n' + + 'op772TB27o0VeiFX5iWcawy0EI7JCb23xpI+QP31ksL2yyRYFXCtXSUfcOrLpCY8\n' + + 'aEQMQbAGtkag1wHTo/Tf/Vip8q0ZEQ4xOKTR2/ll6+inP8kzGyzadElUnH1Q1OUX\n' + + 'd2Lj/7BpBHE2++hAjBQRgnyaONF7mpUNEuw64iBNs0Ce6Ki4RV2+EBLnFubnFNRx\n' + + 'fFJcYXcijhuf3YCdWzqYmPpU/CtF4TgDlfSsdxHxVOmnZkY3\n' + + '=qP6s\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n', + + keyChangedUserId: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + '\n' + + 'mQENBFsPvK0BCACaIgoIN+3g05mrTITULK/YDTrfg4W7RdzIZBxch5CM0zdu/dby\n' + + 'esFwaJbVQIqu54CRz5xKAiWmRrQCaRvhvjY0na5r5UUIpbeQiOVrl65JtNbRmlik\n' + + 'd9Prn1kZDUOZiCPIKn+/M2ecJ92YedM7I4/BbpiaFB11cVrPFg4thepn0LB3+Whp\n' + + '9HDm4orH9rjy6IUr6yjWNIr+LYRY6/Ip2vWcMVjleEpTFznXrm83hrJ0n0INtyox\n' + + 'Nass4eDWkgo6ItxDFFLOORSmpfrToxZymSosWqgux/qG6sxHvLqlqy6Xe3ZYRFbG\n' + + '+JcA1oGdwOg/c0ndr6BYYiXTh8+uUJfEoZvzABEBAAG0HEJsYSBCbGEgPGJsYWJs\n' + + 'YUBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUC\n' + + 'Ww+8rQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD2N5DBHmAn\n' + + 'igwIB/9K3E3Yev9taZP4KnXPhk1oMQRW1MWAsFGUr+70N85VwedpUawymW4vXi1+\n' + + 'hMeTc39QjmZ0+VqHkJttkqEN6bLcEvgmU/mOlOgKdzy6eUcasYAzgoAKUqSX1SPs\n' + + '0Imo7Tj04wnfnVwvKxaeadi0VmdqIYaW75UlrzIaltsBctyeYH8sBrvaTLscb4ON\n' + + '46OM3Yw2G9+dBF0P+4UYFHP3EYZMlzNxfwF+i2HsYcNDHlcLfjENr9GwKn5FJqpY\n' + + 'Iq3qmI37w1hVasHDxXdz1X06dpsa6Im4ACk6LXa7xIQlXxTgPAQV0sz2yB5eY+Md\n' + + 'uzEXPGW+sq0WRp3hynn7kVP6QQYvtCZTb21lb25lIEVsc2UgPHNvbWVvbmVlbHNl\n' + + 'QGV4YW1wbGUub3JnPokBVAQTAQgAPhYhBHgDSUi6f10Om9tn5PY3kMEeYCeKBQJb\n' + + 'D705AhsDBQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPY3kMEeYCeK\n' + + 'aIUH/2o+Ra+GzxgZrVexXLL+FCSmcu0cxeWfMhL8jd96c6uXIT21qQMRU2jgvnUp\n' + + 'Wdi/BeLKp5lYwywm04PFhmRVxWXLuLArCsDu+CFys+aPeybnjikPBZov6P8/cZV3\n' + + 'cd6zxFvqB9J15HjDMcl/r5v6d4CgSLKlFebrO5WKxHa6zGK9TRMQrqTu1heKHRf6\n' + + '4+Wj+MZmYnPzEQePjiBw/VkJ1Nm37Dd24gKdcN/qJFwEOqvbI5RIjB7xqoDslZk9\n' + + 'sAivBXwF0E9HKqvh4WZZeA7uaWNdGo/cQkD5rab5SdHGNPHLbzoRWScsM8WYtsME\n' + + 'dEMp5iPuG9M63+TD7losAkJ/TlS5AQ0EWw+8rQEIALC8FyZucYmTxeEQFG7ZA3eM\n' + + 'qBWzcIbmcTZeHbQmKlnAC4Ye6AMu/r+OWLPPPmO2PdIAdW0kHyUlbwjRw1IQhfxt\n' + + 'FgfgLuU/YNNv0KAxwYStAjIrjzT4cixuxmElI0d2NRSXog8QRV9JDNZq5+a6zB57\n' + + '6CKoeJOxqJbbTK1eKXBUamOUcFrGf9umyRnRhFqyCc+oqAkPd3mS6c2pajIKkxwV\n' + + 'iAMRG89uGFx4Vu8UT0b+7eBty5XXmbHnd0NfQia89y8mcM7IlL3KvsCl05XfXakD\n' + + 'UwtvF8+dudW750ZefsP9UIN3loFhU+b7kA2uTrP2Vgof1o7nCBeksB0m+60I4vkA\n' + + 'EQEAAYkBPAQYAQgAJhYhBHgDSUi6f10Om9tn5PY3kMEeYCeKBQJbD7ytAhsMBQkD\n' + + 'wmcAAAoJEPY3kMEeYCeKAxUH/jzgbb7dHRwBqPdX/PiBbcxFIyFxioQzIn8AJ2jv\n' + + 'Lx6it5hbzjclZZUNFjr9hxhga4EE/jtY7gm4/bAiVWfXtc4JKCc2OaaOwhiIDOSi\n' + + 'nvvZMHbujRV6IVfmJZxrDLQQjskJvbfGkj5A/fWSwvbLJFgVcK1dJR9w6sukJjxo\n' + + 'RAxBsAa2RqDXAdOj9N/9WKnyrRkRDjE4pNHb+WXr6Kc/yTMbLNp0SVScfVDU5Rd3\n' + + 'YuP/sGkEcTb76ECMFBGCfJo40XualQ0S7DriIE2zQJ7oqLhFXb4QEucW5ucU1HF8\n' + + 'UlxhdyKOG5/dgJ1bOpiY+lT8K0XhOAOV9Kx3EfFU6admRjc=\n' + + '=9WZ7\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n' +}; diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 3480d811..8c4cba7c 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -103,7 +103,7 @@ export class Connection{ } if (!message || !message instanceof GPGME_Message){ this.disconnect(); - return Promise.reject(gpgme_error('PARAM_WRONG'), message); + return Promise.reject(gpgme_error('PARAM_WRONG', 'Connection.post')); } if (message.isComplete !== true){ this.disconnect(); @@ -221,12 +221,13 @@ class Answer{ if (!this._response.hasOwnProperty(key)){ this._response[key] = []; } + if (Array.isArray(msg[key])) { for (let i=0; i< msg[key].length; i++) { this._response[key].push(msg[key][i]); } } else { - this._response[key].push(msg[key][i]); + this._response[key].push(msg[key]); } } else { diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index 3b53eeb4..2f2bfd5c 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -74,7 +74,7 @@ const err_list = { 'KEY_NO_INIT': { msg:'This property has not been retrieved yet from GPG', type: 'error' - } + }, // generic 'PARAM_WRONG':{ msg: 'Invalid parameter was found', @@ -118,7 +118,11 @@ class GPGME_Error extends Error{ if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){ super(msg); } else if (err_list.hasOwnProperty(code)){ - super(err_list[code].msg); + if (msg){ + super(err_list[code].msg + "--" + msg); + } else { + super(err_list[code].msg); + } } else { super(err_list['GENERIC_ERROR'].msg); } diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js index b26f40fb..5064d03e 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -29,7 +29,6 @@ import { GPGME_Key } from "./Key"; export function toKeyIdArray(input){ if (!input){ - gpgme_error('MSG_NO_KEYS'); return []; } if (!Array.isArray(input)){ @@ -61,7 +60,6 @@ export function toKeyIdArray(input){ } } if (result.length === 0){ - gpgme_error('MSG_NO_KEYS'); return []; } else { return result; diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 454b1912..d85c8b6e 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -207,7 +207,7 @@ export class GPGME_Key { msg.setParameter('armor', true); msg.setParameter('keys', me._data.fingerprint); msg.post().then(function(result){ - me._data.armor = result.data; + me._data.armored = result.data; resolve(result.data); }, function(error){ reject(error); @@ -280,7 +280,7 @@ export class GPGME_Key { /** * Deletes the public Key from the GPG Keyring. Note that a deletion of a * secret key is not supported by the native backend. - * @returns {Boolean} Success if key was deleted, rejects with a GPG error + * @returns {Promise} Success if key was deleted, rejects with a GPG error * otherwise */ delete(){ diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 9081cbe9..c5e613ec 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -18,9 +18,9 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -import {createMessage} from './Message' -import {GPGME_Key, createKey} from './Key' -import { isFingerprint, toKeyIdArray } from './Helpers'; +import {createMessage} from './Message'; +import {createKey} from './Key'; +import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; export class GPGME_Keyring { @@ -39,10 +39,8 @@ export class GPGME_Keyring { * */ getKeys(pattern, prepare_sync){ - let me = this; return new Promise(function(resolve, reject) { - let msg; - msg = createMessage('keylist'); + let msg = createMessage('keylist'); if (pattern !== undefined){ msg.setParameter('keys', pattern); } @@ -50,25 +48,28 @@ export class GPGME_Keyring { msg.post().then(function(result){ let resultset = []; let promises = []; - // TODO check if result.key is not empty - for (let i=0; i< result.keys.length; i++){ - let k = createKey(result.keys[i].fingerprint, me); - k.setKeyData(result.keys[i]); - if (prepare_sync === true){ - promises.push(k.getArmor()); - promises.push(k.getHasSecret()); + if (result.keys.length === 0){ + resolve([]); + } else { + for (let i=0; i< result.keys.length; i++){ + let k = createKey(result.keys[i].fingerprint); + k.setKeyData(result.keys[i]); + if (prepare_sync === true){ + promises.push(k.getArmor()); + promises.push(k.getHasSecret()); + } + resultset.push(k); } - resultset.push(k); - } - if (promises.length > 0) { - Promise.all(promises).then(function (res){ + if (promises.length > 0) { + Promise.all(promises).then(function() { + resolve(resultset); + }, function(error){ + reject(error); + }); + } else { resolve(resultset); - }, function(error){ - reject(error); - }); + } } - }, function(error){ - reject(error); }); }); } @@ -80,7 +81,6 @@ export class GPGME_Keyring { * @returns {Promise} Armored Key blocks */ getKeysArmored(pattern) { - if (pattern) return new Promise(function(resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); @@ -92,10 +92,102 @@ export class GPGME_Keyring { }, function(error){ reject(error); }); + }); } // getDefaultKey() Big TODO - // importKeys(armoredKeys) - // generateKey --> TODO (Andre noch anfragen!) -}; + /** + * + * @param {String} armored Armored Key block of the Kex(s) to be imported into gnupg + * @param {Boolean} prepare_sync prepare the keys for synched use (see getKeys()). + * @returns {Promise>} An array of objects for the Keys considered. + * Key.key The key itself as a GPGME_Key + * Key.status String: + * 'nochange' if the Key was not changed, + * 'newkey' if the Key was imported in gpg, and did not exist previously, + * 'change' if the key existed, but details were updated. For details, + * Key.changes is available. + * Key.changes.userId: Boolean userIds changed + * Key.changes.signature: Boolean signatures changed + * Key.changes.subkey: Boolean subkeys changed + * // TODO: not yet implemented: Information about Keys that failed + * (e.g. malformed Keys, secretKeys are not accepted) + */ + importKey(armored, prepare_sync) { + if (!armored || typeof(armored) !== 'string'){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } + let me = this; + return new Promise(function(resolve, reject){ + let msg = createMessage('import'); + msg.setParameter('data', armored); + msg.post().then(function(response){ + let infos = {}; + let fprs = []; + for (var res=0; res < response.result[0].imports.length; res++) { + let result = response.result[0].imports[res]; + let status = ''; + if (result.status === 0){ + status = 'nochange'; + } else if ((result.status & 1) === 1){ + status = 'newkey'; + } else { + status = 'change'; + } + let changes = {}; + changes.userId = (result.status & 2) === 2; + changes.signature = (result.status & 4) === 4; + changes.subkey = (result.status & 8) === 8; + //16 new secret key: not implemented + + fprs.push(result.fingerprint); + infos[result.fingerprint] = { + changes: changes, + status: status + }; + } + let resultset = []; + if (prepare_sync === true){ + me.getKeys(fprs, true).then(function(result){ + for (let i=0; i < result.length; i++) { + resultset.push({ + key: result[i], + changes: infos[result[i].fingerprint].changes, + status: infos[result[i].fingerprint].status + }); + } + resolve(resultset); + }, function(error){ + reject(error); + }); + } else { + for (let i=0; i < fprs.length; i++) { + resultset.push({ + key: createKey(fprs[i]), + changes: infos[fprs[i]].changes, + status: infos[fprs[i]].status + }); + } + resolve(resultset); + } + + }, function(error){ + reject(error); + }); + + + }); + + + } + + deleteKey(fingerprint){ + if (isFingerprint(fingerprint) === true) { + let key = createKey(fingerprint); + key.delete(); + } + } + + // generateKey +} diff --git a/lang/js/unittest_inputvalues.js b/lang/js/unittest_inputvalues.js index 2a21a6ae..07147bac 100644 --- a/lang/js/unittest_inputvalues.js +++ b/lang/js/unittest_inputvalues.js @@ -1,5 +1,5 @@ -import {Connection} from "./src/Connection"; -import {createKey} from "./src/Key"; +import {Connection} from './src/Connection'; +import {createKey} from './src/Key'; let conn = new Connection; @@ -23,14 +23,14 @@ export const helper_params = { valid_openpgplike: { primaryKey: { getFingerprint: function(){ return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';} - } } -} + } +}; export const message_params = { invalid_op_action : 'dance', invalid_op_type : [234, 34, '<>'], - valid_encrypt_data: "مرحبا بالعالم", + valid_encrypt_data: 'مرحبا بالعالم', invalid_param_test: { valid_op: 'encrypt', invalid_param_names: [22,'dance', {}], @@ -38,18 +38,89 @@ export const message_params = { invalid_values_0: [2134, 'All your passwords', createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), null] } -} +}; export const whatever_params = { four_invalid_params: ['<(((-<', '>°;==;~~', '^^', '{{{{o}}}}'], -} +}; export const key_params = { // A Key you own (= having a secret Key) in GPG. See testkey.pub/testkey.sec validKeyFingerprint: 'D41735B91236FDB882048C5A2301635EEFF0CB05', -// A Key you do not own (= having no secret Key) in GPG. See testkey2.pub + // A Key you do not own (= having no secret Key) in GPG. See testkey2.pub validFingerprintNoSecret: 'E059A1E0866D31AE131170884D9A2E13304153D1', -// A Key not in your Keyring. This is just a random hex string. + // A Key not in your Keyring. This is just a random hex string. invalidKeyFingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A', validKeyProperties: ['expired', 'disabled','invalid','can_encrypt', - 'can_sign','can_certify','can_authenticate','secret','is_qualified'] -} + 'can_sign','can_certify','can_authenticate','secret','is_qualified'] +}; +export const armoredKey = { + fingerprint: '78034948BA7F5D0E9BDB67E4F63790C11E60278A', + key:'-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + '\n' + + 'mQENBFsPvK0BCACaIgoIN+3g05mrTITULK/YDTrfg4W7RdzIZBxch5CM0zdu/dby\n' + + 'esFwaJbVQIqu54CRz5xKAiWmRrQCaRvhvjY0na5r5UUIpbeQiOVrl65JtNbRmlik\n' + + 'd9Prn1kZDUOZiCPIKn+/M2ecJ92YedM7I4/BbpiaFB11cVrPFg4thepn0LB3+Whp\n' + + '9HDm4orH9rjy6IUr6yjWNIr+LYRY6/Ip2vWcMVjleEpTFznXrm83hrJ0n0INtyox\n' + + 'Nass4eDWkgo6ItxDFFLOORSmpfrToxZymSosWqgux/qG6sxHvLqlqy6Xe3ZYRFbG\n' + + '+JcA1oGdwOg/c0ndr6BYYiXTh8+uUJfEoZvzABEBAAG0HEJsYSBCbGEgPGJsYWJs\n' + + 'YUBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUC\n' + + 'Ww+8rQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD2N5DBHmAn\n' + + 'igwIB/9K3E3Yev9taZP4KnXPhk1oMQRW1MWAsFGUr+70N85VwedpUawymW4vXi1+\n' + + 'hMeTc39QjmZ0+VqHkJttkqEN6bLcEvgmU/mOlOgKdzy6eUcasYAzgoAKUqSX1SPs\n' + + '0Imo7Tj04wnfnVwvKxaeadi0VmdqIYaW75UlrzIaltsBctyeYH8sBrvaTLscb4ON\n' + + '46OM3Yw2G9+dBF0P+4UYFHP3EYZMlzNxfwF+i2HsYcNDHlcLfjENr9GwKn5FJqpY\n' + + 'Iq3qmI37w1hVasHDxXdz1X06dpsa6Im4ACk6LXa7xIQlXxTgPAQV0sz2yB5eY+Md\n' + + 'uzEXPGW+sq0WRp3hynn7kVP6QQYvuQENBFsPvK0BCACwvBcmbnGJk8XhEBRu2QN3\n' + + 'jKgVs3CG5nE2Xh20JipZwAuGHugDLv6/jlizzz5jtj3SAHVtJB8lJW8I0cNSEIX8\n' + + 'bRYH4C7lP2DTb9CgMcGErQIyK480+HIsbsZhJSNHdjUUl6IPEEVfSQzWaufmuswe\n' + + 'e+giqHiTsaiW20ytXilwVGpjlHBaxn/bpskZ0YRasgnPqKgJD3d5kunNqWoyCpMc\n' + + 'FYgDERvPbhhceFbvFE9G/u3gbcuV15mx53dDX0ImvPcvJnDOyJS9yr7ApdOV312p\n' + + 'A1MLbxfPnbnVu+dGXn7D/VCDd5aBYVPm+5ANrk6z9lYKH9aO5wgXpLAdJvutCOL5\n' + + 'ABEBAAGJATwEGAEIACYWIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUCWw+8rQIbDAUJ\n' + + 'A8JnAAAKCRD2N5DBHmAnigMVB/484G2+3R0cAaj3V/z4gW3MRSMhcYqEMyJ/ACdo\n' + + '7y8eoreYW843JWWVDRY6/YcYYGuBBP47WO4JuP2wIlVn17XOCSgnNjmmjsIYiAzk\n' + + 'op772TB27o0VeiFX5iWcawy0EI7JCb23xpI+QP31ksL2yyRYFXCtXSUfcOrLpCY8\n' + + 'aEQMQbAGtkag1wHTo/Tf/Vip8q0ZEQ4xOKTR2/ll6+inP8kzGyzadElUnH1Q1OUX\n' + + 'd2Lj/7BpBHE2++hAjBQRgnyaONF7mpUNEuw64iBNs0Ce6Ki4RV2+EBLnFubnFNRx\n' + + 'fFJcYXcijhuf3YCdWzqYmPpU/CtF4TgDlfSsdxHxVOmnZkY3\n' + + '=qP6s\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n', + keyChangedUserId: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + '\n' + + 'mQENBFsPvK0BCACaIgoIN+3g05mrTITULK/YDTrfg4W7RdzIZBxch5CM0zdu/dby\n' + + 'esFwaJbVQIqu54CRz5xKAiWmRrQCaRvhvjY0na5r5UUIpbeQiOVrl65JtNbRmlik\n' + + 'd9Prn1kZDUOZiCPIKn+/M2ecJ92YedM7I4/BbpiaFB11cVrPFg4thepn0LB3+Whp\n' + + '9HDm4orH9rjy6IUr6yjWNIr+LYRY6/Ip2vWcMVjleEpTFznXrm83hrJ0n0INtyox\n' + + 'Nass4eDWkgo6ItxDFFLOORSmpfrToxZymSosWqgux/qG6sxHvLqlqy6Xe3ZYRFbG\n' + + '+JcA1oGdwOg/c0ndr6BYYiXTh8+uUJfEoZvzABEBAAG0HEJsYSBCbGEgPGJsYWJs\n' + + 'YUBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQR4A0lIun9dDpvbZ+T2N5DBHmAnigUC\n' + + 'Ww+8rQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRD2N5DBHmAn\n' + + 'igwIB/9K3E3Yev9taZP4KnXPhk1oMQRW1MWAsFGUr+70N85VwedpUawymW4vXi1+\n' + + 'hMeTc39QjmZ0+VqHkJttkqEN6bLcEvgmU/mOlOgKdzy6eUcasYAzgoAKUqSX1SPs\n' + + '0Imo7Tj04wnfnVwvKxaeadi0VmdqIYaW75UlrzIaltsBctyeYH8sBrvaTLscb4ON\n' + + '46OM3Yw2G9+dBF0P+4UYFHP3EYZMlzNxfwF+i2HsYcNDHlcLfjENr9GwKn5FJqpY\n' + + 'Iq3qmI37w1hVasHDxXdz1X06dpsa6Im4ACk6LXa7xIQlXxTgPAQV0sz2yB5eY+Md\n' + + 'uzEXPGW+sq0WRp3hynn7kVP6QQYvtCZTb21lb25lIEVsc2UgPHNvbWVvbmVlbHNl\n' + + 'QGV4YW1wbGUub3JnPokBVAQTAQgAPhYhBHgDSUi6f10Om9tn5PY3kMEeYCeKBQJb\n' + + 'D705AhsDBQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPY3kMEeYCeK\n' + + 'aIUH/2o+Ra+GzxgZrVexXLL+FCSmcu0cxeWfMhL8jd96c6uXIT21qQMRU2jgvnUp\n' + + 'Wdi/BeLKp5lYwywm04PFhmRVxWXLuLArCsDu+CFys+aPeybnjikPBZov6P8/cZV3\n' + + 'cd6zxFvqB9J15HjDMcl/r5v6d4CgSLKlFebrO5WKxHa6zGK9TRMQrqTu1heKHRf6\n' + + '4+Wj+MZmYnPzEQePjiBw/VkJ1Nm37Dd24gKdcN/qJFwEOqvbI5RIjB7xqoDslZk9\n' + + 'sAivBXwF0E9HKqvh4WZZeA7uaWNdGo/cQkD5rab5SdHGNPHLbzoRWScsM8WYtsME\n' + + 'dEMp5iPuG9M63+TD7losAkJ/TlS5AQ0EWw+8rQEIALC8FyZucYmTxeEQFG7ZA3eM\n' + + 'qBWzcIbmcTZeHbQmKlnAC4Ye6AMu/r+OWLPPPmO2PdIAdW0kHyUlbwjRw1IQhfxt\n' + + 'FgfgLuU/YNNv0KAxwYStAjIrjzT4cixuxmElI0d2NRSXog8QRV9JDNZq5+a6zB57\n' + + '6CKoeJOxqJbbTK1eKXBUamOUcFrGf9umyRnRhFqyCc+oqAkPd3mS6c2pajIKkxwV\n' + + 'iAMRG89uGFx4Vu8UT0b+7eBty5XXmbHnd0NfQia89y8mcM7IlL3KvsCl05XfXakD\n' + + 'UwtvF8+dudW750ZefsP9UIN3loFhU+b7kA2uTrP2Vgof1o7nCBeksB0m+60I4vkA\n' + + 'EQEAAYkBPAQYAQgAJhYhBHgDSUi6f10Om9tn5PY3kMEeYCeKBQJbD7ytAhsMBQkD\n' + + 'wmcAAAoJEPY3kMEeYCeKAxUH/jzgbb7dHRwBqPdX/PiBbcxFIyFxioQzIn8AJ2jv\n' + + 'Lx6it5hbzjclZZUNFjr9hxhga4EE/jtY7gm4/bAiVWfXtc4JKCc2OaaOwhiIDOSi\n' + + 'nvvZMHbujRV6IVfmJZxrDLQQjskJvbfGkj5A/fWSwvbLJFgVcK1dJR9w6sukJjxo\n' + + 'RAxBsAa2RqDXAdOj9N/9WKnyrRkRDjE4pNHb+WXr6Kc/yTMbLNp0SVScfVDU5Rd3\n' + + 'YuP/sGkEcTb76ECMFBGCfJo40XualQ0S7DriIE2zQJ7oqLhFXb4QEucW5ucU1HF8\n' + + 'UlxhdyKOG5/dgJ1bOpiY+lT8K0XhOAOV9Kx3EfFU6admRjc=\n' + + '=9WZ7\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n' +}; \ No newline at end of file diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 443aa685..d1118448 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -17,19 +17,19 @@ * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ -import "./node_modules/mocha/mocha"; -import "./node_modules/chai/chai"; -import { helper_params as hp } from "./unittest_inputvalues"; -import { message_params as mp } from "./unittest_inputvalues"; -import { whatever_params as wp } from "./unittest_inputvalues"; -import { key_params as kp } from "./unittest_inputvalues"; -import { Connection } from "./src/Connection"; -import { gpgme_error } from "./src/Errors"; -import { toKeyIdArray , isFingerprint } from "./src/Helpers"; -import { GPGME_Key , createKey } from "./src/Key"; -import { GPGME_Keyring } from "./src/Keyring"; -import {GPGME_Message, createMessage} from "./src/Message"; -import { setTimeout } from "timers"; + +import './node_modules/mocha/mocha'; /*global mocha, it, describe*/ +import './node_modules/chai/chai';/*global chai*/ +import { helper_params as hp } from './unittest_inputvalues'; +import { message_params as mp } from './unittest_inputvalues'; +import { whatever_params as wp } from './unittest_inputvalues'; +import { key_params as kp } from './unittest_inputvalues'; +import { Connection } from './src/Connection'; +import { gpgme_error } from './src/Errors'; +import { toKeyIdArray , isFingerprint } from './src/Helpers'; +import { GPGME_Key , createKey } from './src/Key'; +import { GPGME_Keyring } from './src/Keyring'; +import {GPGME_Message, createMessage} from './src/Message'; mocha.setup('bdd'); var expect = chai.expect; @@ -74,12 +74,14 @@ function unittests (){ expect(test0.code).to.equal('CONN_TIMEOUT'); }); - it('Error Object returns generic code if code is not listed', function(){ - let test0 = gpgme_error(hp.invalidErrorCode); + it('Error Object returns generic code if code is not listed', + function(){ + let test0 = gpgme_error(hp.invalidErrorCode); - expect(test0).to.be.an.instanceof(Error); - expect(test0.code).to.equal('GENERIC_ERROR'); - }); + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('GENERIC_ERROR'); + } + ); it('Warnings like PARAM_IGNORED should not return errors', function(){ let test0 = gpgme_error('PARAM_IGNORED'); @@ -201,7 +203,7 @@ function unittests (){ it('Non-cached key async armored Key', function (done){ let key = createKey(kp.validKeyFingerprint); - key.get('armor', false).then(function(result){ + key.get('armored', false).then(function(result){ expect(result).to.be.a('string'); expect(result).to.include('KEY BLOCK-----'); done(); @@ -233,7 +235,7 @@ function unittests (){ expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('KEY_NOKEY'); done(); - }); + }); }); it('createKey returns error if parameters are wrong', function(){ @@ -269,14 +271,74 @@ function unittests (){ keyring.getKeys(null, true).then(function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armor')).to.be.a('string'); - expect(result[0].get('armor')).to.include( + expect(result[0].get('armored')).to.be.a('string'); + expect(result[0].get('armored')).to.include( '-----END PGP PUBLIC KEY BLOCK-----'); done(); }); }); + + it('Loading specific Key from Keyring, to be used synchronously', function(done){ + let keyring = new GPGME_Keyring; + keyring.getKeys(kp.validKeyFingerprint, true).then(function(result){ + expect(result).to.be.an('array'); + expect(result[0]).to.be.an.instanceof(GPGME_Key); + expect(result[0].get('armored')).to.be.a('string'); + expect(result[0].get('armored')).to.include( + '-----END PGP PUBLIC KEY BLOCK-----'); + done(); + }); + }); + + it('Querying non-existing Key from Keyring', function(done){ + let keyring = new GPGME_Keyring; + keyring.getKeys(kp.invalidKeyFingerprint, true).then(function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + done(); + }); + }); }); + // describe('Keyring import/export', function(){ + // before(function(done) { + // let keyring = new GPGME_Keyring; + + // keyring.getKeys(ak.fingerprint, false).then(function(result){ + // if (result.length === 1){ + // result[0].delete().then(function(delete_result){ + // if (delete_result === true){ + // done(); + // } + // }); + // } else { + // done(); + // } + // }); + // }); + // it('Import Public Key', function(done){ + // keyring.importKey(ak.key).then(function(result){ + // expect(result).to.be.an('array'); + // expect(result[0].key).to.be.an.instanceof(GPGME_Key); + // expect(result[0].changed).to.equal('newkey'); + // expect(result[0].key.keyring).to.equal(ak.fingerprint); + // done(); + // }); + // }); + + // it('Update Public Key', function(done){ + // keyring.importKey(ak.key).then(function(result){ + // expect(result).to.be.an('array'); + // expect(result[0].key).to.be.an.instanceof(GPGME_Key); + // expect(result[0].changed).to.equal('change'); + // expect(result[0].changes.userId).to.be.true; + // expect(result[0].changes.subkeys).to.be.false; + // expect(result[0].key.keyring).to.equal(ak.fingerprint); + // done(); + // }); + // }); + // }); + describe('GPGME_Message', function(){ it('creating encrypt Message', function(){ @@ -330,12 +392,12 @@ function unittests (){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let i=0; i < mp.invalid_param_test.invalid_param_names.length; i++){ - let ret = test0.setParameter( - mp.invalid_param_test.invalid_param_names[i], - 'Somevalue'); + let ret = test0.setParameter( + mp.invalid_param_test.invalid_param_names[i], + 'Somevalue'); - expect(ret).to.be.an.instanceof(Error); - expect(ret.code).to.equal('PARAM_WRONG'); + expect(ret).to.be.an.instanceof(Error); + expect(ret.code).to.equal('PARAM_WRONG'); } }); @@ -343,12 +405,12 @@ function unittests (){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let j=0; j < mp.invalid_param_test.invalid_values_0.length; j++){ - let ret = test0.setParameter( - mp.invalid_param_test.validparam_name_0, - mp.invalid_param_test.invalid_values_0[j]); + let ret = test0.setParameter( + mp.invalid_param_test.validparam_name_0, + mp.invalid_param_test.invalid_values_0[j]); - expect(ret).to.be.an.instanceof(Error); - expect(ret.code).to.equal('PARAM_WRONG'); + expect(ret).to.be.an.instanceof(Error); + expect(ret.code).to.equal('PARAM_WRONG'); } }); }); -- cgit From bfd3799d39df265882deedeee083fd5246a2f35d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 6 Jun 2018 13:05:53 +0200 Subject: js: code cleanup (eslint) -- * trying to stick to eslint from now on for readability * As some attribution was lost in previous git confusions, I added my name into some of the licence headers --- lang/js/.eslintrc.json | 3 + lang/js/BrowserTestExtension/popup.js | 22 +--- lang/js/BrowserTestExtension/runbrowsertest.js | 5 + lang/js/BrowserTestExtension/rununittests.js | 6 + lang/js/BrowserTestExtension/setup_testing.js | 8 +- .../BrowserTestExtension/tests/KeyImportExport.js | 3 + .../tests/encryptDecryptTest.js | 91 ++++++++------- lang/js/BrowserTestExtension/tests/encryptTest.js | 113 +++++++++--------- lang/js/BrowserTestExtension/tests/inputvalues.js | 9 +- .../BrowserTestExtension/tests/longRunningTests.js | 101 +++++++++++----- lang/js/BrowserTestExtension/tests/signTest.js | 31 +++-- lang/js/BrowserTestExtension/tests/startup.js | 24 ++-- lang/js/CHECKLIST | 19 +-- lang/js/DemoExtension/entry.js | 5 + lang/js/DemoExtension/maindemo.js | 40 ++++--- lang/js/package.json | 4 +- lang/js/src/Config.js | 3 + lang/js/src/Connection.js | 130 ++++++++++----------- lang/js/src/Errors.js | 6 +- lang/js/src/Helpers.js | 29 +++-- lang/js/src/Key.js | 93 +++++++-------- lang/js/src/Keyring.js | 32 +++-- lang/js/src/Message.js | 95 +++++++-------- lang/js/src/gpgmejs.js | 57 +++++---- lang/js/src/index.js | 25 ++-- lang/js/src/permittedOperations.js | 35 +++--- lang/js/unittests.js | 104 ++++++----------- 27 files changed, 595 insertions(+), 498 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/.eslintrc.json b/lang/js/.eslintrc.json index 65253cf3..ad82400b 100644 --- a/lang/js/.eslintrc.json +++ b/lang/js/.eslintrc.json @@ -24,6 +24,9 @@ "error", "always" ], + "no-var": [ + "warn" + ], "max-len": 1 } } \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/popup.js b/lang/js/BrowserTestExtension/popup.js index 12beb1eb..794620b6 100644 --- a/lang/js/BrowserTestExtension/popup.js +++ b/lang/js/BrowserTestExtension/popup.js @@ -16,27 +16,13 @@ * 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+ - */ -/* 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+ + * Author(s): + * Maximilian Krambach */ +/* global chrome */ + document.addEventListener('DOMContentLoaded', function() { chrome.tabs.create({ url: './index.html' diff --git a/lang/js/BrowserTestExtension/runbrowsertest.js b/lang/js/BrowserTestExtension/runbrowsertest.js index 39bc3fb9..c46eb120 100644 --- a/lang/js/BrowserTestExtension/runbrowsertest.js +++ b/lang/js/BrowserTestExtension/runbrowsertest.js @@ -16,6 +16,11 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ +/* global mocha */ + mocha.run(); diff --git a/lang/js/BrowserTestExtension/rununittests.js b/lang/js/BrowserTestExtension/rununittests.js index f85ed8b5..df31589e 100644 --- a/lang/js/BrowserTestExtension/rununittests.js +++ b/lang/js/BrowserTestExtension/rununittests.js @@ -16,6 +16,12 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ + +/* global Gpgmejs_test, mocha*/ + Gpgmejs_test.unittests(); mocha.run(); diff --git a/lang/js/BrowserTestExtension/setup_testing.js b/lang/js/BrowserTestExtension/setup_testing.js index 7f70d347..52aeac58 100644 --- a/lang/js/BrowserTestExtension/setup_testing.js +++ b/lang/js/BrowserTestExtension/setup_testing.js @@ -16,7 +16,13 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ + +/* global mocha, chai */ + mocha.setup('bdd'); -var expect = chai.expect; +const expect = chai.expect; //eslint-disable-line no-unused-vars chai.config.includeStack = true; \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index e6eb5a30..6b298049 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -16,6 +16,9 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ /* global describe, it, expect, Gpgmejs, ImportablePublicKey */ diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index e5c2f749..a84be27c 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -1,4 +1,3 @@ - /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * @@ -17,23 +16,31 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ +/* global describe, it, expect, Gpgmejs */ +/* global inputvalues, encryptedData, bigString, bigBoringString */ + describe('Encryption and Decryption', function () { it('Successful encrypt and decrypt simple string', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( inputvalues.encrypt.good.data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { + inputvalues.encrypt.good.fingerprint).then( + function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); context.decrypt(answer.data).then(function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); - expect(result.data).to.equal(inputvalues.encrypt.good.data); + expect(result.data).to.equal( + inputvalues.encrypt.good.data); done(); }); }); @@ -51,7 +58,7 @@ describe('Encryption and Decryption', function () { expect(result.data).to.equal( '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); done(); - }); + }); }); }).timeout(3000); @@ -64,7 +71,7 @@ describe('Encryption and Decryption', function () { inputvalues.encrypt.good.fingerprint).then( function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include( 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( @@ -79,39 +86,41 @@ describe('Encryption and Decryption', function () { }); }); }); - }).timeout(5000); + }).timeout(5000); for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ - it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + (j + 1) + '/' + inputvalues.encrypt.good.data_nonascii_32.length + ')', - function (done) { - let input = inputvalues.encrypt.good.data_nonascii_32[j]; - expect(input).to.have.length(32); - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = ''; - for (let i=0; i < 34 * 1024; i++){ - data += input; - } - context.encrypt(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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); - }); + it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + + (j + 1) + '/' + + inputvalues.encrypt.good.data_nonascii_32.length + ')', + function (done) { + let input = inputvalues.encrypt.good.data_nonascii_32[j]; + expect(input).to.have.length(32); + let prm = Gpgmejs.init(); + prm.then(function (context) { + let data = ''; + for (let i=0; i < 34 * 1024; i++){ + data += input; + } + context.encrypt(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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }); }).timeout(3000); - }; + } it('Random data, as string', function (done) { let data = bigString(1000); @@ -121,7 +130,7 @@ describe('Encryption and Decryption', function () { inputvalues.encrypt.good.fingerprint).then( function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include( 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( @@ -143,10 +152,10 @@ describe('Encryption and Decryption', function () { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint,).then( + inputvalues.encrypt.good.fingerprint).then( function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include( 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( @@ -171,7 +180,7 @@ describe('Encryption and Decryption', function () { inputvalues.encrypt.good.fingerprint, true).then( function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include( 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( @@ -196,7 +205,7 @@ describe('Encryption and Decryption', function () { inputvalues.encrypt.good.fingerprint).then( function (answer) { expect(answer).to.not.be.empty; - expect(answer.data).to.be.a("string"); + expect(answer.data).to.be.a('string'); expect(answer.data).to.include( 'BEGIN PGP MESSAGE'); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index a16f993c..2cb4e58b 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -16,7 +16,14 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ + +/* global describe, it, expect, Gpgmejs */ +/* global inputvalues, fixedLengthString */ + describe('Encryption', function () { it('Successful encrypt', function (done) { let prm = Gpgmejs.init(); @@ -24,12 +31,12 @@ describe('Encryption', function () { 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(); - }); + 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(); + }); }); }); @@ -40,12 +47,12 @@ describe('Encryption', function () { context.encrypt( 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(); - }); + 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(); + }); }); }).timeout(10000); @@ -56,12 +63,12 @@ describe('Encryption', function () { context.encrypt( 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(); - }); + 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(); + }); }); }).timeout(20000); @@ -72,12 +79,12 @@ describe('Encryption', function () { context.encrypt( 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(); - }); + 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(); + }); }); }).timeout(20000); @@ -87,12 +94,12 @@ describe('Encryption', function () { context.encrypt( inputvalues.encrypt.good.data, null).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.equal('MSG_INCOMPLETE'); - done(); - }); + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); + }); }); }); @@ -101,12 +108,12 @@ describe('Encryption', function () { 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(); - }); + expect(answer).to.be.undefined; + }, function (error) { + expect(error).to.be.an.instanceof(Error); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); + }); }); }); @@ -116,15 +123,15 @@ describe('Encryption', function () { context.encrypt( inputvalues.encrypt.good.data, inputvalues.encrypt.bad.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.not.be.undefined; - expect(error.code).to.equal('GNUPG_ERROR'); - done(); - }); + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.not.be.undefined; + expect(error.code).to.equal('GNUPG_ERROR'); + done(); + }); }); - }).timeout(5000);; + }).timeout(5000); it('Overly large message ( > 65MB) is rejected', function (done) { let prm = Gpgmejs.init(); @@ -132,15 +139,15 @@ describe('Encryption', function () { context.encrypt( fixedLengthString(65), inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an.instanceof(Error); - // expect(error.code).to.equal('GNUPG_ERROR'); - // TODO: there is a 64 MB hard limit at least in chrome at: - // chromium//extensions/renderer/messaging_util.cc: - // kMaxMessageLength - done(); - }); + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an.instanceof(Error); + // expect(error.code).to.equal('GNUPG_ERROR'); + // TODO: there is a 64 MB hard limit at least in chrome at: + // chromium//extensions/renderer/messaging_util.cc: + // kMaxMessageLength + done(); + }); }); }).timeout(8000); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 9dc13324..024aad25 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -16,9 +16,12 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -var inputvalues = {// eslint-disable-line no-unused-vars +const inputvalues = {// eslint-disable-line no-unused-vars encrypt: { good:{ data : 'Hello World.', @@ -131,7 +134,7 @@ function slightlyLessBoringString(megabytes, set){ } // Data encrypted with testKey -var encryptedData =// eslint-disable-line no-unused-vars +const encryptedData =// eslint-disable-line no-unused-vars '-----BEGIN PGP MESSAGE-----\n' + '\n' + 'hQEMA6B8jfIUScGEAQgAlANd3uyhmhYLzVcfz4LEqA8tgUC3n719YH0iuKEzG/dv\n' + @@ -146,7 +149,7 @@ var encryptedData =// eslint-disable-line no-unused-vars '=zap6\n' + '-----END PGP MESSAGE-----\n'; -var ImportablePublicKey = {// eslint-disable-line no-unused-vars +const ImportablePublicKey = {// eslint-disable-line no-unused-vars fingerprint: '78034948BA7F5D0E9BDB67E4F63790C11E60278A', key:'-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + '\n' + diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index 5c588f27..eefe126d 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -1,39 +1,78 @@ +/* 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+ + * + * Author(s): + * Maximilian Krambach + */ +/* global describe, it, expect, Gpgmejs */ +/* global bigString, inputvalues */ + describe('Long running Encryption/Decryption', function () { for (let i=0; i < 100; i++) { - it('Successful encrypt/decrypt completely random data ' + (i+1) + '/100', function (done) { + it('Successful encrypt/decrypt completely random data ' + + (i+1) + '/100', function (done) { let prm = Gpgmejs.init(); let data = bigString(2*1024*1024); - prm.then(function (context) { - context.encrypt(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'); - context.decrypt(answer.data).then( - function(result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - if (result.data.length !== data.length) { - console.log('diff: ' + (result.data.length - data.length)); - for (let i=0; i < result.data.length; i++){ - if (result.data[i] !== data[i]){ - console.log('position: ' + i); - console.log('result : '+ result.data.charCodeAt(i) + result.data[i-2] + result.data[i-1] + result.data[i] + result.data[i+1] + result.data[i+2]); - console.log('original: ' + data.charCodeAt(i) + data[i-2] + data[i-1] + data[i] + data[i+1] + data[i+2]); - break; - } - } + prm.then(function (context) { + context.encrypt(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'); + context.decrypt(answer.data).then( + function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + if (result.data.length !== data.length) { + // console.log('diff: ' + + // (result.data.length - data.length)); + for (let i=0; i < result.data.length; i++){ + if (result.data[i] !== data[i]){ + // console.log('position: ' + i); + // console.log('result : ' + + // result.data.charCodeAt(i) + + // result.data[i-2] + + // result.data[i-1] + + // result.data[i] + + // result.data[i+1] + + // result.data[i+2]); + // console.log('original: ' + + // data.charCodeAt(i) + + // data[i-2] + + // data[i-1] + + // data[i] + + // data[i+1] + + // data[i+2]); + break; } - expect(result.data).to.equal(data); - done(); - }); - }); - }); + } + } + expect(result.data).to.equal(data); + done(); + }); + }); + }); }).timeout(8000); - }; + } }); diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js index 2e5edb30..ffd2d5de 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -16,7 +16,14 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ + +/* global describe, it, expect, Gpgmejs */ +/* global bigString, inputvalues */ + describe('Signing', function () { it('Sign a message', function (done) { let prm = Gpgmejs.init(); @@ -25,12 +32,12 @@ describe('Signing', function () { context.sign( 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 SIGNATURE'); - expect(answer.data).to.include('END PGP SIGNATURE'); - expect(answer.data).to.include(data); - done(); + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP SIGNATURE'); + expect(answer.data).to.include('END PGP SIGNATURE'); + expect(answer.data).to.include(data); + done(); }); }); }); @@ -43,12 +50,12 @@ describe('Signing', function () { inputvalues.encrypt.good.fingerprint, 'detached' ).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include(data); - expect(answer.signature).to.be.a('string'); - expect(answer.signature).to.be.a('string'); - done(); + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include(data); + expect(answer.signature).to.be.a('string'); + expect(answer.signature).to.be.a('string'); + done(); }); }); }); diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index 7d13ea47..d434b6d4 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -16,25 +16,31 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ - describe('GPGME context', function(){ +/* global describe, it, expect, Gpgmejs */ +/* global inputvalues */ + +describe('GPGME context', function(){ it('Starting a GpgME instance', function(done){ let prm = Gpgmejs.init(); prm.then( - function(context){ - expect(context).to.be.an('object'); - expect(context.encrypt).to.be.a('function'); - expect(context.decrypt).to.be.a('function'); - done(); - }); + function(context){ + expect(context).to.be.an('object'); + expect(context.encrypt).to.be.a('function'); + expect(context.decrypt).to.be.a('function'); + 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]); + let prm = Gpgmejs.init(inputvalues.init.invalid_startups[i]); prm.then(function(context){ expect(context).to.be.undefined; done(); @@ -43,6 +49,6 @@ describe('GPGME does not start with invalid parameters', function(){ expect(error.code).to.equal('PARAM_WRONG'); done(); }); - }) + }); } }); \ No newline at end of file diff --git a/lang/js/CHECKLIST b/lang/js/CHECKLIST index 278f39dd..fe260187 100644 --- a/lang/js/CHECKLIST +++ b/lang/js/CHECKLIST @@ -6,20 +6,25 @@ receiving an answer [*] nativeConnection successfull on Windows, macOS, Linux [X] nativeConnection with delayed, multipart (> 1MB) answer - [*] Message handling (encrypt, decrypt verify, sign) + [x] Message handling (encrypt, decrypt verify, sign) [x] encrypt, decrypt - [ ] verify - [ ] sign + [x] verify + [x] sign [*] Key handling (import/export, modifying, status queries) + [x] Import (not importing secret) + [x] Export (not exporting secret) + [x] status queries + [ ] key generation + [ ] modification [*] Configuration handling [ ] check for completeness Communication with other implementations - - [ ] option to export SECRET Key into localstore used by e.g. mailvelope - + [-] option to export SECRET Key into localstore used by e.g. mailvelope? + current discussion states that this won't be possible due to security + concerns Management: [*] Define the gpgme interface [x] check Permissions (e.g. csp) for the different envs - [X] agree on license + [x] agree on license [*] tests diff --git a/lang/js/DemoExtension/entry.js b/lang/js/DemoExtension/entry.js index 62583421..77b96f92 100644 --- a/lang/js/DemoExtension/entry.js +++ b/lang/js/DemoExtension/entry.js @@ -17,7 +17,12 @@ * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * + * Author(s): + * Maximilian Krambach */ + +/* global chrome */ + document.addEventListener('DOMContentLoaded', function() { chrome.tabs.create({ url: './mainui.html' diff --git a/lang/js/DemoExtension/maindemo.js b/lang/js/DemoExtension/maindemo.js index b2cb4c23..5cde1ce8 100644 --- a/lang/js/DemoExtension/maindemo.js +++ b/lang/js/DemoExtension/maindemo.js @@ -17,39 +17,41 @@ * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * + * Author(s): + * Maximilian Krambach */ +/* global document, Gpgmejs */ + document.addEventListener('DOMContentLoaded', function() { Gpgmejs.init().then(function(gpgmejs){ - document.getElementById("buttonencrypt").addEventListener("click", + document.getElementById('buttonencrypt').addEventListener('click', function(){ let data = document.getElementById('cleartext').value; let keyId = document.getElementById('pubkey').value; gpgmejs.encrypt(data, keyId).then( function(answer){ - console.log(answer); if (answer.data){ - console.log(answer.data); - document.getElementById('answer').value = answer.data; + document.getElementById( + 'answer').value = answer.data; } }, function(errormsg){ alert( errormsg.code + ' ' + errormsg.msg); - }); + }); }); - document.getElementById("buttondecrypt").addEventListener("click", - function(){ - let data = document.getElementById("ciphertext").value; - gpgmejs.decrypt(data).then( - function(answer){ - console.log(answer); - if (answer.data){ - document.getElementById('answer').value = answer.data; - } - }, function(errormsg){ - alert( errormsg.code + ' ' + errormsg.msg); + document.getElementById('buttondecrypt').addEventListener('click', + function(){ + let data = document.getElementById('ciphertext').value; + gpgmejs.decrypt(data).then( + function(answer){ + if (answer.data){ + document.getElementById( + 'answer').value = answer.data; + } + }, function(errormsg){ + alert( errormsg.code + ' ' + errormsg.msg); + }); }); - }); - }, - function(error){console.log(error)}); + }); }); diff --git a/lang/js/package.json b/lang/js/package.json index be52a554..acf89117 100644 --- a/lang/js/package.json +++ b/lang/js/package.json @@ -1,7 +1,7 @@ { "name": "gpgmejs", - "version": "0.0.1", - "description": "javascript part of a nativeMessaging gnupg integration", + "version": "0.0.1-dev", + "description": "Javascript part of the GPGME nativeMessaging integration", "main": "src/index.js", "private": true, "keywords": [], diff --git a/lang/js/src/Config.js b/lang/js/src/Config.js index e85bbb82..8a3ef491 100644 --- a/lang/js/src/Config.js +++ b/lang/js/src/Config.js @@ -16,6 +16,9 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ export const availableConf = { diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 8c4cba7c..e9c0b213 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -16,16 +16,16 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -/** - * A connection port will be opened for each communication between gpgmejs and - * gnupg. It should be alive as long as there are additional messages to be - * expected. - */ -import { permittedOperations } from './permittedOperations' -import { gpgme_error } from "./Errors" -import { GPGME_Message, createMessage } from "./Message"; +/* global chrome */ + +import { permittedOperations } from './permittedOperations'; +import { gpgme_error } from './Errors'; +import { GPGME_Message, createMessage } from './Message'; /** * A Connection handles the nativeMessaging interaction. @@ -55,7 +55,7 @@ export class Connection{ return this.post(createMessage('version')); } else { let me = this; - return new Promise(function(resolve,reject) { + return new Promise(function(resolve) { Promise.race([ me.post(createMessage('version')), new Promise(function(resolve, reject){ @@ -63,9 +63,9 @@ export class Connection{ reject(gpgme_error('CONN_TIMEOUT')); }, 500); }) - ]).then(function(result){ - resolve(true); - }, function(reject){ + ]).then(function(){ // success + resolve(true); + }, function(){ // failure resolve(false); }); }); @@ -98,12 +98,10 @@ export class Connection{ * information. */ post(message){ - if (!this._connection) { - - } - if (!message || !message instanceof GPGME_Message){ + if (!message || !(message instanceof GPGME_Message)){ this.disconnect(); - return Promise.reject(gpgme_error('PARAM_WRONG', 'Connection.post')); + return Promise.reject(gpgme_error( + 'PARAM_WRONG', 'Connection.post')); } if (message.isComplete !== true){ this.disconnect(); @@ -114,10 +112,10 @@ export class Connection{ let answer = new Answer(message); let listener = function(msg) { if (!msg){ - me._connection.onMessage.removeListener(listener) + me._connection.onMessage.removeListener(listener); me._connection.disconnect(); reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); - } else if (msg.type === "error"){ + } else if (msg.type === 'error'){ me._connection.onMessage.removeListener(listener); me._connection.disconnect(); reject(gpgme_error('GNUPG_ERROR', msg.msg)); @@ -130,7 +128,7 @@ export class Connection{ } else if (msg.more === true){ me._connection.postMessage({'op': 'getmore'}); } else { - me._connection.onMessage.removeListener(listener) + me._connection.onMessage.removeListener(listener); me._connection.disconnect(); resolve(answer.message); } @@ -148,9 +146,9 @@ export class Connection{ reject(gpgme_error('CONN_TIMEOUT')); }, 5000); }]).then(function(result){ - return result; + return result; }, function(reject){ - if(!reject instanceof Error) { + if(!(reject instanceof Error)) { me._connection.disconnect(); return gpgme_error('GNUPG_ERROR', reject); } else { @@ -159,13 +157,14 @@ export class Connection{ }); } }); - } -}; + } +} /** * A class for answer objects, checking and processing the return messages of * the nativeMessaging communication. - * @param {String} operation The operation, to look up validity of returning messages + * @param {String} operation The operation, to look up validity of returning + * messages */ class Answer{ @@ -191,49 +190,49 @@ class 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 gpgme_error('CONN_UNEXPECTED_ANSWER'); + case 'type': + if ( msg.type !== 'error' && poa.type.indexOf(msg.type) < 0){ + return gpgme_error('CONN_UNEXPECTED_ANSWER'); + } + break; + case 'more': + break; + default: + //data should be concatenated + if (poa.data.indexOf(key) >= 0){ + if (!this._response.hasOwnProperty(key)){ + this._response[key] = ''; } - break; - case 'more': - break; - default: - //data should be concatenated - if (poa.data.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = ''; - } - this._response[key] += msg[key]; + this._response[key] += msg[key]; + } + //params should not change through the message + else if (poa.params.indexOf(key) >= 0){ + if (!this._response.hasOwnProperty(key)){ + this._response[key] = msg[key]; } - //params should not change through the message - else if (poa.params.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = msg[key]; - } - else if (this._response[key] !== msg[key]){ - return gpgme_error('CONN_UNEXPECTED_ANSWER',msg[key]); - } + else if (this._response[key] !== msg[key]){ + return gpgme_error('CONN_UNEXPECTED_ANSWER',msg[key]); + } + } + //infos may be json objects etc. Not yet defined. + // Pushing them into arrays for now + else if (poa.infos.indexOf(key) >= 0){ + if (!this._response.hasOwnProperty(key)){ + this._response[key] = []; } - //infos may be json objects etc. Not yet defined. - // Pushing them into arrays for now - else if (poa.infos.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = []; - } - if (Array.isArray(msg[key])) { - for (let i=0; i< msg[key].length; i++) { - this._response[key].push(msg[key][i]); - } - } else { - this._response[key].push(msg[key]); + if (Array.isArray(msg[key])) { + for (let i=0; i< msg[key].length; i++) { + this._response[key].push(msg[key][i]); } + } else { + this._response[key].push(msg[key]); } - else { - return gpgme_error('CONN_UNEXPECTED_ANSWER'); - } - break; + } + else { + return gpgme_error('CONN_UNEXPECTED_ANSWER'); + } + break; } } return true; @@ -256,10 +255,11 @@ class Answer{ msg[keys[i]] = this._response[keys[i]]; } else { msg[keys[i]] = decodeURIComponent( - atob(this._response[keys[i]]).split('').map(function(c) { - return '%' + + atob(this._response[keys[i]]).split('').map( + function(c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + }).join('')); } } else { msg[keys[i]] = this._response[keys[i]]; diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index 2f2bfd5c..dabf6a5c 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -16,6 +16,9 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ const err_list = { @@ -102,6 +105,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ return new GPGME_Error(code); } if (err_list[code].type === 'warning'){ + // eslint-disable-next-line no-console console.warn(code + ': ' + err_list[code].msg); } return null; @@ -119,7 +123,7 @@ class GPGME_Error extends Error{ super(msg); } else if (err_list.hasOwnProperty(code)){ if (msg){ - super(err_list[code].msg + "--" + msg); + super(err_list[code].msg + '--' + msg); } else { super(err_list[code].msg); } diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js index 5064d03e..b01fbc30 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -16,14 +16,18 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -import { gpgme_error } from "./Errors"; -import { GPGME_Key } from "./Key"; + +import { gpgme_error } from './Errors'; +import { GPGME_Key } from './Key'; /** * Tries to return an array of fingerprints, either from input fingerprints or - * from Key objects - * @param {Key |Array| GPGME_Key | Array|String|Array} input + * from Key objects (openpgp Keys or GPGME_Keys are both expected) + * @param {Object |Array| String|Array} input * @returns {Array} Array of fingerprints. */ @@ -48,7 +52,7 @@ export function toKeyIdArray(input){ fpr = input[i].fingerprint; } else if (input[i].hasOwnProperty('primaryKey') && input[i].primaryKey.hasOwnProperty('getFingerprint')){ - fpr = input[i].primaryKey.getFingerprint(); + fpr = input[i].primaryKey.getFingerprint(); } if (isFingerprint(fpr) === true){ result.push(fpr); @@ -64,7 +68,7 @@ export function toKeyIdArray(input){ } else { return result; } -}; +} /** * check if values are valid hexadecimal values of a specified length @@ -72,7 +76,7 @@ export function toKeyIdArray(input){ * @param {int} len the expected length of the value */ function hextest(key, len){ - if (!key || typeof(key) !== "string"){ + if (!key || typeof(key) !== 'string'){ return false; } if (key.length !== len){ @@ -80,23 +84,18 @@ function hextest(key, len){ } let regexp= /^[0-9a-fA-F]*$/i; return regexp.test(key); -}; +} /** * check if the input is a valid Hex string with a length of 40 */ export function isFingerprint(string){ return hextest(string, 40); -}; +} /** * check if the input is a valid Hex string with a length of 16 */ export function isLongId(string){ return hextest(string, 16); -}; - -// TODO still not needed anywhere -function isShortId(string){ - return hextest(string, 8); -}; +} diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index d85c8b6e..8c8726a2 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -16,20 +16,14 @@ * 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+ - */ - -/** - * The key class allows to query the information defined in gpgme Key Objects - * (see https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html) - * - * This is a stub, as the gpgme-json side is not yet implemented * + * Author(s): + * Maximilian Krambach */ -import { isFingerprint, isLongId } from './Helpers' -import { gpgme_error } from './Errors' +import { isFingerprint, isLongId } from './Helpers'; +import { gpgme_error } from './Errors'; import { createMessage } from './Message'; -import { permittedOperations } from './permittedOperations'; /** * Validates the fingerprint. @@ -44,6 +38,11 @@ export function createKey(fingerprint){ /** * Representing the Keys as stored in GPG + * It allows to query almost all information defined in gpgme Key Objects + * Refer to validKeyProperties for available information, and the gpgme + * documentation on their meaning + * (https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html) + * */ export class GPGME_Key { @@ -102,22 +101,22 @@ export class GPGME_Key { return gpgme_error('KEY_INVALID'); } switch (dataKeys[i]){ - case 'subkeys': - this._data.subkeys = []; - for (let i=0; i< data.subkeys.length; i++) { - this._data.subkeys.push( - new GPGME_Subkey(data.subkeys[i])); - } - break; - case 'userids': - this._data.userids = []; - for (let i=0; i< data.userids.length; i++) { - this._data.userids.push( - new GPGME_UserId(data.userids[i])); - } - break; - default: - this._data[dataKeys[i]] = data[dataKeys[i]]; + case 'subkeys': + this._data.subkeys = []; + for (let i=0; i< data.subkeys.length; i++) { + this._data.subkeys.push( + new GPGME_Subkey(data.subkeys[i])); + } + break; + case 'userids': + this._data.userids = []; + for (let i=0; i< data.userids.length; i++) { + this._data.userids.push( + new GPGME_UserId(data.userids[i])); + } + break; + default: + this._data[dataKeys[i]] = data[dataKeys[i]]; } } return this; @@ -162,11 +161,6 @@ export class GPGME_Key { } } - get armored () { - return this.get('armored'); - //TODO exception if empty - } - /** * Reloads the Key from gnupg */ @@ -188,7 +182,7 @@ export class GPGME_Key { } }, function (error) { reject(gpgme_error('GNUPG_ERROR'), error); - }) + }); }); } @@ -197,7 +191,7 @@ export class GPGME_Key { * from gpg. * @returns {Promise} */ - getArmor(){ + getArmor(){ let me = this; return new Promise(function(resolve, reject) { if (!me._data.fingerprint){ @@ -249,15 +243,16 @@ export class GPGME_Key { } } } else { - reject(gpgme_error('CONN_UNEXPECTED_ANSWER')) + reject(gpgme_error('CONN_UNEXPECTED_ANSWER')); } }, function(error){ - }) + reject(error); + }); }); } /** - * Convenience function to be directly used as properties of the Key + * Convenience functions to be directly used as properties of the Key * Notice that these rely on cached info and may be outdated. Use the async * get(property, false) if you need the most current info */ @@ -280,8 +275,8 @@ export class GPGME_Key { /** * Deletes the public Key from the GPG Keyring. Note that a deletion of a * secret key is not supported by the native backend. - * @returns {Promise} Success if key was deleted, rejects with a GPG error - * otherwise + * @returns {Promise} Success if key was deleted, rejects with a + * GPG error otherwise */ delete(){ let me = this; @@ -295,7 +290,7 @@ export class GPGME_Key { resolve(result.success); }, function(error){ reject(error); - }) + }); }); } } @@ -378,37 +373,37 @@ const validUserIdProperties = { }, 'uid': function(value){ if (typeof(value) === 'string' || value === ''){ - return true;; + return true; } return false; }, 'validity': function(value){ if (typeof(value) === 'string'){ - return true;; + return true; } return false; }, 'name': function(value){ if (typeof(value) === 'string' || value === ''){ - return true;; + return true; } return false; }, 'email': function(value){ if (typeof(value) === 'string' || value === ''){ - return true;; + return true; } return false; }, 'address': function(value){ if (typeof(value) === 'string' || value === ''){ - return true;; + return true; } return false; }, 'comment': function(value){ if (typeof(value) === 'string' || value === ''){ - return true;; + return true; } return false; }, @@ -449,8 +444,8 @@ const validSubKeyProperties = { return typeof(value) === 'boolean'; }, 'pubkey_algo_name': function(value){ - return typeof(value) === 'string'; - // TODO: check against list of known?[''] + return typeof(value) === 'string'; + // TODO: check against list of known?[''] }, 'pubkey_algo_string': function(value){ return typeof(value) === 'string'; @@ -471,7 +466,7 @@ const validSubKeyProperties = { 'expires': function(value){ return (Number.isInteger(value) && value > 0); } -} +}; const validKeyProperties = { //TODO better validation? 'fingerprint': function(value){ @@ -546,4 +541,4 @@ const validKeyProperties = { return typeof(value) === 'boolean'; } -} +}; diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index c5e613ec..71585878 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -16,8 +16,12 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ + import {createMessage} from './Message'; import {createKey} from './Key'; import { isFingerprint } from './Helpers'; @@ -99,18 +103,22 @@ export class GPGME_Keyring { /** * - * @param {String} armored Armored Key block of the Kex(s) to be imported into gnupg - * @param {Boolean} prepare_sync prepare the keys for synched use (see getKeys()). - * @returns {Promise>} An array of objects for the Keys considered. - * Key.key The key itself as a GPGME_Key - * Key.status String: + * @param {String} armored Armored Key block of the Kex(s) to be imported + * into gnupg + * @param {Boolean} prepare_sync prepare the keys for synched use + * (see getKeys()). + * @returns {Promise>} An array of objects for the Keys + * considered: + * Key.key : The key itself as a GPGME_Key + * Key.status : * 'nochange' if the Key was not changed, - * 'newkey' if the Key was imported in gpg, and did not exist previously, - * 'change' if the key existed, but details were updated. For details, - * Key.changes is available. - * Key.changes.userId: Boolean userIds changed - * Key.changes.signature: Boolean signatures changed - * Key.changes.subkey: Boolean subkeys changed + * 'newkey' if the Key was imported in gpg, and did not exist + * previously, + * 'change' if the key existed, but details were updated. For + * details, Key.changes is available. + * Key.changes.userId: userIds changed + * Key.changes.signature: signatures changed + * Key.changes.subkey: subkeys changed * // TODO: not yet implemented: Information about Keys that failed * (e.g. malformed Keys, secretKeys are not accepted) */ @@ -125,7 +133,7 @@ export class GPGME_Keyring { msg.post().then(function(response){ let infos = {}; let fprs = []; - for (var res=0; res < response.result[0].imports.length; res++) { + for (let res=0; res < response.result[0].imports.length; res++){ let result = response.result[0].imports[res]; let status = ''; if (result.status === 0){ diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 5664f723..0ddda6c4 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -16,9 +16,13 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -import { permittedOperations } from './permittedOperations' -import { gpgme_error } from './Errors' + +import { permittedOperations } from './permittedOperations'; +import { gpgme_error } from './Errors'; import { Connection } from './Connection'; export function createMessage(operation){ @@ -46,7 +50,7 @@ export class GPGME_Message { } set operation (op){ - if (typeof(op) === "string"){ + if (typeof(op) === 'string'){ if (!this._msg){ this._msg = {}; } @@ -67,10 +71,10 @@ export class GPGME_Message { } get expected() { - if (this._expected === "base64"){ - return this._expected; - } - return "string"; + if (this._expected === 'base64'){ + return this._expected; + } + return 'string'; } /** @@ -98,52 +102,50 @@ export class GPGME_Message { } let checktype = function(val){ switch(typeof(val)){ - case 'string': - if (poparam.allowed.indexOf(typeof(val)) >= 0 + case 'string': + if (poparam.allowed.indexOf(typeof(val)) >= 0 && val.length > 0) { - return true; - } - return gpgme_error('PARAM_WRONG'); - break; - case 'number': - if ( - poparam.allowed.indexOf('number') >= 0 + return true; + } + return gpgme_error('PARAM_WRONG'); + case 'number': + if ( + poparam.allowed.indexOf('number') >= 0 && isNaN(value) === false){ - return true; + return true; + } + return gpgme_error('PARAM_WRONG'); + + case 'boolean': + if (poparam.allowed.indexOf('boolean') >= 0){ + return true; + } + return gpgme_error('PARAM_WRONG'); + case 'object': + if (Array.isArray(val)){ + if (poparam.array_allowed !== true){ + return gpgme_error('PARAM_WRONG'); } - return gpgme_error('PARAM_WRONG'); - break; - case 'boolean': - if (poparam.allowed.indexOf('boolean') >= 0){ + for (let i=0; i < val.length; i++){ + let res = checktype(val[i]); + if (res !== true){ + return res; + } + } + if (val.length > 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; - } - } - if (val.length > 0) { - 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'); + } else if (val instanceof Uint8Array){ + if (poparam.allowed.indexOf('Uint8Array') >= 0){ + return true; } - break; - default: return gpgme_error('PARAM_WRONG'); + } else { + return gpgme_error('PARAM_WRONG'); + } + break; + default: + return gpgme_error('PARAM_WRONG'); } }; let typechecked = checktype(value); @@ -173,7 +175,6 @@ export class GPGME_Message { let msg_params = Object.keys(this._msg); for (let i=0; i < reqParams.length; i++){ 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 39f6a2f0..cbad9021 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -16,12 +16,16 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -import {GPGME_Message, createMessage} from './Message' -import {toKeyIdArray} from "./Helpers" -import { gpgme_error } from "./Errors" -import { GPGME_Keyring } from "./Keyring"; + +import {GPGME_Message, createMessage} from './Message'; +import {toKeyIdArray} from './Helpers'; +import { gpgme_error } from './Errors'; +import { GPGME_Keyring } from './Keyring'; export class GpgME { /** @@ -32,7 +36,7 @@ export class GpgME { this._config = config; } - set Keyring(keyring){ + set Keyring(keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } @@ -47,13 +51,19 @@ export class GpgME { /** * Encrypt (and optionally sign) a Message - * @param {String|Object} data text/data to be encrypted as String. Also accepts Objects with a getText method - * @param {GPGME_Key|String|Array|Array} publicKeys Keys used to encrypt the message - * @param {GPGME_Key|String|Array|Array} secretKeys (optional) Keys used to sign the message - * @param {Boolean} base64 (optional) The data is already considered to be in base64 encoding + * @param {String|Object} data text/data to be encrypted as String. Also + * accepts Objects with a getText method + * @param {GPGME_Key|String|Array|Array} publicKeys + * Keys used to encrypt the message + * @param {GPGME_Key|String|Array|Array} secretKeys + * (optional) Keys used to sign the message + * @param {Boolean} base64 (optional) The data is already considered to be + * in base64 encoding * @param {Boolean} armor (optional) Request the output as armored block - * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message - * @param {Object} additional use additional gpg options (refer to src/permittedOperations) + * @param {Boolean} wildcard (optional) If true, recipient information will + * not be added to the message + * @param {Object} additional use additional gpg options + * (refer to src/permittedOperations) * @returns {Promise} Encrypted message: * data: The encrypted message * base64: Boolean indicating whether data is base64 encoded. @@ -64,7 +74,7 @@ export class GpgME { ){ let msg = createMessage('encrypt'); if (msg instanceof Error){ - return Promise.reject(msg) + return Promise.reject(msg); } msg.setParameter('armor', armor); msg.setParameter('always-trust', true); @@ -80,7 +90,7 @@ export class GpgME { putData(msg, data); if (wildcard === true){ msg.setParameter('throw-keyids', true); - }; + } if (additional){ let additional_Keys = Object.keys(additional); for (let k = 0; k < additional_Keys.length; k++) { @@ -97,14 +107,16 @@ export class GpgME { /** * Decrypt a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a getText method - * @param {Boolean} base64 (optional) Response is expected to be base64 encoded + * @param {String|Object} data text/data to be decrypted. Accepts Strings + * and Objects with a getText method + * @param {Boolean} base64 (optional) Response is expected to be base64 + * encoded * @returns {Promise} decrypted message: data: The decrypted data. This may be base64 encoded. 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 etc. + // should be an object that can tell if all signatures are valid . * @async */ decrypt(data, base64=false){ @@ -124,14 +136,16 @@ export class GpgME { /** * Sign a Message - * @param {String|Object} data text/data to be decrypted. Accepts Strings and Objects with a gettext methos - * @param {GPGME_Key|String|Array|Array} keys The key/keys to use for signing + * @param {String|Object} data text/data to be decrypted. Accepts Strings + * and Objects with a gettext methos + * @param {GPGME_Key|String|Array|Array} keys The + * key/keys to use for signing * @param {*} mode The signing mode. Currently supported: * 'clearsign': (default) The Message is embedded into the signature * 'detached': The signature is stored separately * @param {*} base64 input is considered base64 * @returns {Promise} - * data: The resulting data. In clearsign mode this includes the signature + * data: The resulting data. Includes the signature in clearsign mode * signature: The detached signature (if in detached mode) * @async */ @@ -154,7 +168,6 @@ export class GpgME { if (mode === 'detached') { msg.expected = 'base64'; } - let me = this; return new Promise(function(resolve,reject) { msg.post().then( function(message) { if (mode === 'clearsign'){ @@ -169,7 +182,7 @@ export class GpgME { } }, function(error){ reject(error); - }) + }); }); } } @@ -180,7 +193,7 @@ export class GpgME { * @param {*} data The data to enter */ function putData(message, data){ - if (!message || !message instanceof GPGME_Message ) { + if (!message || !(message instanceof GPGME_Message) ) { return gpgme_error('PARAM_WRONG'); } if (!data){ diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 220a6984..1b13ec4a 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -16,16 +16,21 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ -import { GpgME } from "./gpgmejs"; -import { gpgme_error } from "./Errors"; -import { Connection } from "./Connection"; -import { defaultConf, availableConf } from "./Config"; + +import { GpgME } from './gpgmejs'; +import { gpgme_error } from './Errors'; +import { Connection } from './Connection'; +import { defaultConf, availableConf } from './Config'; /** * Initializes a nativeMessaging Connection and returns a GPGMEjs object - * @param {Object} config Configuration. See Config.js for available parameters. Still TODO + * @param {Object} config Configuration. See Config.js for available parameters. + * Still TODO */ function init(config){ let _conf = parseconfiguration(config); @@ -41,16 +46,16 @@ function init(config){ } else { reject(gpgme_error('CONN_NO_CONNECT')); } - }, function(error){ + }, function(){ //unspecific connection error. Should not happen reject(gpgme_error('CONN_NO_CONNECT')); - }); + }); }); } function parseconfiguration(rawconfig = {}){ if ( typeof(rawconfig) !== 'object'){ return gpgme_error('PARAM_WRONG'); - }; + } let result_config = {}; let conf_keys = Object.keys(rawconfig); @@ -75,8 +80,8 @@ function parseconfiguration(rawconfig = {}){ } } return result_config; -}; +} export default { init: init -} \ No newline at end of file +}; \ No newline at end of file diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index e4f9bd22..445a40cc 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -16,9 +16,12 @@ * 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+ + * + * Author(s): + * Maximilian Krambach */ - /** +/** * Definition of the possible interactions with gpgme-json. * operation: required: Array @@ -41,7 +44,7 @@ infos: Array<*> arbitrary information that may result in a list } } - */ +*/ export const permittedOperations = { encrypt: { @@ -65,7 +68,7 @@ export const permittedOperations = { array_allowed: true }, 'chunksize': { - allowed: ['number'] + allowed: ['number'] }, 'base64': { allowed: ['boolean'] @@ -154,7 +157,8 @@ export const permittedOperations = { }, 'mode': { allowed: ['string'], - allowed_data: ['detached', 'clearsign'] // TODO 'opaque' not used + allowed_data: ['detached', 'clearsign'] + // TODO 'opaque' is not used, but available on native app }, 'base64': { allowed: ['boolean'] @@ -166,14 +170,17 @@ export const permittedOperations = { answer: { type: ['signature', 'ciphertext'], data: ['data'], // Unless armor mode is used a Base64 encoded binary - // signature. In armor mode a string with an armored - // OpenPGP or a PEM message. + // signature. In armor mode a string with an armored + // OpenPGP or a PEM message. params: ['base64'] } }, + // note: For the meaning of the optional keylist flags, refer to + // https://www.gnupg.org/documentation/manuals/gpgme/Key-Listing-Mode.html keylist:{ required: {}, + optional: { 'protocol': { allowed: ['string'], @@ -182,8 +189,6 @@ export const permittedOperations = { 'chunksize': { allowed: ['number'], }, - // note: For the meaning of the flags, refer to - // https://www.gnupg.org/documentation/manuals/gpgme/Key-Listing-Mode.html 'secret': { allowed: ['boolean'] }, @@ -305,11 +310,6 @@ export const permittedOperations = { infos: [] } }, - /** - *TBD get armored secret different treatment from keyinfo! - * TBD key modification? - - */ version: { required: {}, @@ -321,4 +321,11 @@ export const permittedOperations = { params:[] } } -} + + /** + * TBD handling of secrets + * TBD key modification? + * TBD: key generation + */ + +}; diff --git a/lang/js/unittests.js b/lang/js/unittests.js index d1118448..ce1dd0c3 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -32,7 +32,7 @@ import { GPGME_Keyring } from './src/Keyring'; import {GPGME_Message, createMessage} from './src/Message'; mocha.setup('bdd'); -var expect = chai.expect; +const expect = chai.expect; chai.config.includeStack = true; function unittests (){ @@ -266,78 +266,48 @@ function unittests (){ expect(keyring.getKeys).to.be.a('function'); }); - it('Loading Keys from Keyring, to be used synchronously', function(done){ - let keyring = new GPGME_Keyring; - keyring.getKeys(null, true).then(function(result){ - expect(result).to.be.an('array'); - expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); - done(); - }); - }); + it('Loading Keys from Keyring, to be used synchronously', + function(done){ + let keyring = new GPGME_Keyring; + keyring.getKeys(null, true).then(function(result){ + expect(result).to.be.an('array'); + expect(result[0]).to.be.an.instanceof(GPGME_Key); + expect(result[0].get('armored')).to.be.a('string'); + expect(result[0].get('armored')).to.include( + '-----END PGP PUBLIC KEY BLOCK-----'); + done(); + }); + } + ); - it('Loading specific Key from Keyring, to be used synchronously', function(done){ - let keyring = new GPGME_Keyring; - keyring.getKeys(kp.validKeyFingerprint, true).then(function(result){ - expect(result).to.be.an('array'); - expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); - done(); - }); - }); + it('Loading specific Key from Keyring, to be used synchronously', + function(done){ + let keyring = new GPGME_Keyring; + keyring.getKeys(kp.validKeyFingerprint, true).then( + function(result){ + expect(result).to.be.an('array'); + expect(result[0]).to.be.an.instanceof(GPGME_Key); + expect(result[0].get('armored')).to.be.a('string'); + expect(result[0].get('armored')).to.include( + '-----END PGP PUBLIC KEY BLOCK-----'); + done(); + } + ); + } + ); it('Querying non-existing Key from Keyring', function(done){ let keyring = new GPGME_Keyring; - keyring.getKeys(kp.invalidKeyFingerprint, true).then(function(result){ - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - done(); - }); + keyring.getKeys(kp.invalidKeyFingerprint, true).then( + function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + done(); + } + ); }); - }); - // describe('Keyring import/export', function(){ - // before(function(done) { - // let keyring = new GPGME_Keyring; - - // keyring.getKeys(ak.fingerprint, false).then(function(result){ - // if (result.length === 1){ - // result[0].delete().then(function(delete_result){ - // if (delete_result === true){ - // done(); - // } - // }); - // } else { - // done(); - // } - // }); - // }); - // it('Import Public Key', function(done){ - // keyring.importKey(ak.key).then(function(result){ - // expect(result).to.be.an('array'); - // expect(result[0].key).to.be.an.instanceof(GPGME_Key); - // expect(result[0].changed).to.equal('newkey'); - // expect(result[0].key.keyring).to.equal(ak.fingerprint); - // done(); - // }); - // }); - - // it('Update Public Key', function(done){ - // keyring.importKey(ak.key).then(function(result){ - // expect(result).to.be.an('array'); - // expect(result[0].key).to.be.an.instanceof(GPGME_Key); - // expect(result[0].changed).to.equal('change'); - // expect(result[0].changes.userId).to.be.true; - // expect(result[0].changes.subkeys).to.be.false; - // expect(result[0].key.keyring).to.equal(ak.fingerprint); - // done(); - // }); - // }); - // }); + }); describe('GPGME_Message', function(){ -- cgit From c072675f3f2d734297a348c6de810148fb1424a2 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 8 Jun 2018 17:54:58 +0200 Subject: js: change chunksize handling and decoding -- * the nativeApp now sends all data in one base64-encoded string, which needs reassembly, but in a much easier way now. * there are some new performance problems now, especially with decrypting data --- .../tests/encryptDecryptTest.js | 31 +---- .../BrowserTestExtension/tests/longRunningTests.js | 38 +++--- lang/js/src/Connection.js | 143 +++++++++------------ lang/js/src/Message.js | 49 +++++-- lang/js/src/gpgmejs.js | 22 ++-- lang/js/src/permittedOperations.js | 81 ++++++------ lang/js/unittests.js | 3 +- 7 files changed, 170 insertions(+), 197 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index a84be27c..bd72c1d2 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -152,7 +152,7 @@ describe('Encryption and Decryption', function () { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint).then( + inputvalues.encrypt.good.fingerprint, true).then( function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); @@ -185,33 +185,7 @@ describe('Encryption and Decryption', function () { 'BEGIN PGP MESSAGE'); expect(answer.data).to.include( 'END PGP MESSAGE'); - context.decrypt(answer.data, true).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(b64data); - done(); - }); - }); - }); - }).timeout(3000); - - it('Random data, input and output as base64', function (done) { - let data = bigBoringString(0.0001); - let b64data = btoa(data); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(b64data, - 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'); - context.decrypt(answer.data, true).then( + context.decrypt(answer.data).then( function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); @@ -222,5 +196,4 @@ describe('Encryption and Decryption', function () { }); }).timeout(3000); - }); diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index eefe126d..e148d1cf 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -24,7 +24,7 @@ /* global bigString, inputvalues */ describe('Long running Encryption/Decryption', function () { - for (let i=0; i < 100; i++) { + for (let i=0; i < 101; i++) { it('Successful encrypt/decrypt completely random data ' + (i+1) + '/100', function (done) { let prm = Gpgmejs.init(); @@ -43,30 +43,32 @@ describe('Long running Encryption/Decryption', function () { function(result){ expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); + /* if (result.data.length !== data.length) { - // console.log('diff: ' + - // (result.data.length - data.length)); + console.log('diff: ' + + (result.data.length - data.length)); for (let i=0; i < result.data.length; i++){ if (result.data[i] !== data[i]){ - // console.log('position: ' + i); - // console.log('result : ' + - // result.data.charCodeAt(i) + - // result.data[i-2] + - // result.data[i-1] + - // result.data[i] + - // result.data[i+1] + - // result.data[i+2]); - // console.log('original: ' + - // data.charCodeAt(i) + - // data[i-2] + - // data[i-1] + - // data[i] + - // data[i+1] + - // data[i+2]); + console.log('position: ' + i); + console.log('result : ' + + result.data.charCodeAt(i) + + result.data[i-2] + + result.data[i-1] + + result.data[i] + + result.data[i+1] + + result.data[i+2]); + console.log('original: ' + + data.charCodeAt(i) + + data[i-2] + + data[i-1] + + data[i] + + data[i+1] + + data[i+2]); break; } } } + */ expect(result.data).to.equal(data); done(); }); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index e9c0b213..f399b22b 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -108,6 +108,7 @@ export class Connection{ return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } let me = this; + let chunksize = message.chunksize; return new Promise(function(resolve, reject){ let answer = new Answer(message); let listener = function(msg) { @@ -115,22 +116,27 @@ export class Connection{ me._connection.onMessage.removeListener(listener); me._connection.disconnect(); reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); - } else if (msg.type === 'error'){ - me._connection.onMessage.removeListener(listener); - me._connection.disconnect(); - reject(gpgme_error('GNUPG_ERROR', msg.msg)); } else { - let answer_result = answer.add(msg); + let answer_result = answer.collect(msg); if (answer_result !== true){ me._connection.onMessage.removeListener(listener); me._connection.disconnect(); reject(answer_result); - } else if (msg.more === true){ - me._connection.postMessage({'op': 'getmore'}); } else { - me._connection.onMessage.removeListener(listener); - me._connection.disconnect(); - resolve(answer.message); + if (msg.more === true){ + me._connection.postMessage({ + 'op': 'getmore', + 'chunksize': chunksize + }); + } else { + me._connection.onMessage.removeListener(listener); + me._connection.disconnect(); + if (answer.message instanceof Error){ + reject(answer.message); + } else { + resolve(answer.message); + } + } } } }; @@ -170,19 +176,32 @@ class Answer{ constructor(message){ this.operation = message.operation; - this.expected = message.expected; + this.expect = message.expect; } - /** - * Add the information to the answer - * @param {Object} msg The message as received with nativeMessaging - * returns true if successfull, gpgme_error otherwise - */ - add(msg){ - if (this._response === undefined){ - this._response = {}; + collect(msg){ + if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) { + return gpgme_error('CONN_UNEXPECTED_ANSWER'); + } + if (this._responseb64 === undefined){ + //this._responseb64 = [msg.response]; + this._responseb64 = msg.response; + return true; + } else { + //this._responseb64.push(msg.response); + this._responseb64 += msg.response; + return true; } - let messageKeys = Object.keys(msg); + } + + get message(){ + if (this._responseb64 === undefined){ + return gpgme_error('CONN_UNEXPECTED_ANSWER'); + } + // let _decodedResponse = JSON.parse(atob(this._responseb64.join(''))); + let _decodedResponse = JSON.parse(atob(this._responseb64)); + let _response = {}; + let messageKeys = Object.keys(_decodedResponse); let poa = permittedOperations[this.operation].answer; if (messageKeys.length === 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); @@ -191,80 +210,42 @@ class Answer{ let key = messageKeys[i]; switch (key) { case 'type': - if ( msg.type !== 'error' && poa.type.indexOf(msg.type) < 0){ + if (_decodedResponse.type === 'error'){ + return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg)); + } else if (poa.type.indexOf(_decodedResponse.type) < 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } break; - case 'more': + case 'base64': break; - default: - //data should be concatenated - if (poa.data.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = ''; - } - this._response[key] += msg[key]; - } - //params should not change through the message - else if (poa.params.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = msg[key]; - } - else if (this._response[key] !== msg[key]){ - return gpgme_error('CONN_UNEXPECTED_ANSWER',msg[key]); - } + case 'msg': + if (_decodedResponse.type === 'error'){ + return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg)); } - //infos may be json objects etc. Not yet defined. - // Pushing them into arrays for now - else if (poa.infos.indexOf(key) >= 0){ - if (!this._response.hasOwnProperty(key)){ - this._response[key] = []; - } - - if (Array.isArray(msg[key])) { - for (let i=0; i< msg[key].length; i++) { - this._response[key].push(msg[key][i]); - } - } else { - this._response[key].push(msg[key]); - } + break; + default: + if (!poa.data.hasOwnProperty(key)){ + return gpgme_error('CONN_UNEXPECTED_ANSWER'); } - else { + if( typeof(_decodedResponse[key]) !== poa.data[key] ){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } - break; - } - } - return true; - } - - /** - * @returns {Object} the assembled message, original data assumed to be - * (javascript-) strings - */ - get message(){ - let keys = Object.keys(this._response); - let msg = {}; - let poa = permittedOperations[this.operation].answer; - for (let i=0; i < keys.length; i++) { - if (poa.data.indexOf(keys[i]) >= 0 - && this._response.base64 === true - ) { - msg[keys[i]] = atob(this._response[keys[i]]); - if (this.expected === 'base64'){ - msg[keys[i]] = this._response[keys[i]]; - } else { - msg[keys[i]] = decodeURIComponent( - atob(this._response[keys[i]]).split('').map( + if (_decodedResponse.base64 === true + && poa.data[key] === 'string' + && this.expect === undefined + ){ + _response[key] = decodeURIComponent( + atob(_decodedResponse[key]).split('').map( function(c) { return '%' + - ('00' + c.charCodeAt(0).toString(16)).slice(-2); + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); + } else { + _response[key] = _decodedResponse[key]; } - } else { - msg[keys[i]] = this._response[keys[i]]; + break; } } - return msg; + return _response; } } diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 0ddda6c4..7ccf7efc 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -46,7 +46,6 @@ export class GPGME_Message { constructor(operation){ this.operation = operation; - this._expected = 'string'; } set operation (op){ @@ -59,24 +58,50 @@ export class GPGME_Message { } } } - get operation(){ return this._msg.op; } - set expected(string){ - if (string === 'base64'){ - this._expected = 'base64'; + /** + * Set the maximum size of responses from gpgme in bytes. Values allowed + * range from 10kB to 1MB. The lower limit is arbitrary, the upper limit + * fixed by browsers' nativeMessaging specifications + */ + set chunksize(value){ + if ( + Number.isInteger(value) && + value > 10 * 1024 && + value <= 1024 * 1024 + ){ + this._chunksize = value; + } + } + get chunksize(){ + if (this._chunksize === undefined){ + return 1024 * 1023; + } else { + return this._chunksize; } } - get expected() { - if (this._expected === 'base64'){ - return this._expected; + /** + * If expect is set to 'base64', the response is expected to be base64 + * encoded binary + */ + set expect(value){ + if (value ==='base64'){ + this._expect = value; + } + } + + get expect(){ + if ( this._expect === 'base64'){ + return this._expect; } - return 'string'; + return undefined; } + /** * Sets a parameter for the message. Note that the operation has to be set * first, to be able to check if the parameter is permittted @@ -188,6 +213,7 @@ export class GPGME_Message { */ get message(){ if (this.isComplete === true){ + this._msg.chunksize = this.chunksize; return this._msg; } else { @@ -201,10 +227,13 @@ export class GPGME_Message { return new Promise(function(resolve, reject) { if (me.isComplete === true) { let conn = new Connection; + if (me._msg.chunksize === undefined){ + me._msg.chunksize = 1023*1024; + } conn.post(me).then(function(response) { resolve(response); }, function(reason) { - reject(gpgme_error('GNUPG_ERROR', reason)); + reject(reason); }); } else { diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index cbad9021..09bca7f9 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -57,8 +57,8 @@ export class GpgME { * Keys used to encrypt the message * @param {GPGME_Key|String|Array|Array} secretKeys * (optional) Keys used to sign the message - * @param {Boolean} base64 (optional) The data is already considered to be - * in base64 encoding + * @param {Boolean} base64 (optional) The data will be interpreted as + * base64 encoded data * @param {Boolean} armor (optional) Request the output as armored block * @param {Boolean} wildcard (optional) If true, recipient information will * not be added to the message @@ -109,24 +109,20 @@ export class GpgME { * Decrypt a Message * @param {String|Object} data text/data to be decrypted. Accepts Strings * and Objects with a getText method - * @param {Boolean} base64 (optional) Response is expected to be base64 - * encoded * @returns {Promise} decrypted message: - data: The decrypted data. This may be base64 encoded. + 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 . + // should be an object that can tell if all signatures are valid. * @async */ - decrypt(data, base64=false){ + decrypt(data){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); - if (base64 === true){ - msg.expected = 'base64'; - } + if (msg instanceof Error){ return Promise.reject(msg); } @@ -165,10 +161,10 @@ export class GpgME { } msg.setParameter('mode', mode); putData(msg, data); - if (mode === 'detached') { - msg.expected = 'base64'; - } return new Promise(function(resolve,reject) { + if (mode ==='detached'){ + msg.expect= 'base64'; + } msg.post().then( function(message) { if (mode === 'clearsign'){ resolve({ diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 445a40cc..6ac33af9 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -37,11 +37,8 @@ 5000 ms would be too short answer: type: The payload property of the answer. May be - partial and in need of concatenation - params: Array Information that do not change throughout - the message - infos: Array<*> arbitrary information that may result in a list + data: + the properties expected and their type, eg: {'data':'string'} } } */ @@ -67,9 +64,6 @@ export const permittedOperations = { allowed: ['string'], array_allowed: true }, - 'chunksize': { - allowed: ['number'] - }, 'base64': { allowed: ['boolean'] }, @@ -101,9 +95,10 @@ export const permittedOperations = { }, answer: { type: ['ciphertext'], - data: ['data'], - params: ['base64'], - infos: [] + data: { + 'data': 'string', + 'base64':'boolean' + } } }, @@ -119,18 +114,18 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - 'chunksize': { - allowed: ['number'], - }, 'base64': { allowed: ['boolean'] } }, answer: { type: ['plaintext'], - data: ['data'], - params: ['base64', 'mime'], - infos: ['signatures'] + data: { + 'data': 'string', + 'base64': 'boolean', + 'mime': 'boolean', + 'signatures': 'object' + } } }, @@ -149,9 +144,6 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - 'chunksize': { - allowed: ['number'], - }, 'sender': { allowed: ['string'], }, @@ -169,10 +161,11 @@ export const permittedOperations = { }, answer: { type: ['signature', 'ciphertext'], - data: ['data'], // Unless armor mode is used a Base64 encoded binary - // signature. In armor mode a string with an armored - // OpenPGP or a PEM message. - params: ['base64'] + data: { + 'data': 'string', + 'base64':'boolean' + } + } }, @@ -186,9 +179,6 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - 'chunksize': { - allowed: ['number'], - }, 'secret': { allowed: ['boolean'] }, @@ -220,9 +210,10 @@ export const permittedOperations = { }, answer: { type: ['keys'], - data: [], - params: ['base64'], - infos: ['keys'] + data: { + 'base64': 'boolean', + 'keys': 'object' + } } }, @@ -233,9 +224,6 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - 'chunksize': { - allowed: ['number'], - }, 'keys': { allowed: ['string'], array_allowed: true @@ -259,8 +247,10 @@ export const permittedOperations = { }, answer: { type: ['keys'], - data: ['data'], - params: ['base64'] + data: { + 'data': 'string', + 'base64': 'boolean' + } } }, @@ -280,10 +270,10 @@ export const permittedOperations = { }, }, answer: { - infos: ['result'], type: [], - data: [], - params: [] + data: { + 'result': 'Object' + } } }, @@ -299,15 +289,15 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - // 'secret': { not yet implemented + // 'secret': { not implemented // allowed: ['boolean'] // } }, answer: { - data: [], - params:['success'], - infos: [] + data: { + 'success': 'boolean' + } } }, @@ -316,9 +306,10 @@ export const permittedOperations = { optional: {}, answer: { type: [''], - data: ['gpgme'], - infos: ['info'], - params:[] + data: { + 'gpgme': 'string', + 'info': 'object' + } } } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index ce1dd0c3..169e8ebc 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -339,7 +339,8 @@ function unittests (){ test0.setParameter('keys', hp.validFingerprints); expect(test0.message).to.not.be.null; - expect(test0.message).to.have.keys('op', 'data', 'keys'); + expect(test0.message).to.have.keys('op', 'data', 'keys', + 'chunksize'); expect(test0.message.op).to.equal('encrypt'); expect(test0.message.data).to.equal( mp.valid_encrypt_data); -- cgit From e154554e9a48a08219649a58be0b641c561e1748 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 11 Jun 2018 15:10:43 +0200 Subject: js: removed config -- * There is no use for a configuration at the moment, and it seems improbable that this use will arise. --- lang/js/BrowserTestExtension/tests/inputvalues.js | 8 ---- lang/js/BrowserTestExtension/tests/startup.js | 17 --------- lang/js/src/Config.js | 34 ----------------- lang/js/src/gpgmejs.js | 4 +- lang/js/src/index.js | 46 +++-------------------- 5 files changed, 7 insertions(+), 102 deletions(-) delete mode 100644 lang/js/src/Config.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 024aad25..1c701904 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -53,14 +53,6 @@ const inputvalues = {// eslint-disable-line no-unused-vars // bogus fingerprint) fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } - }, - init: { - // some parameters - 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 d434b6d4..dae94025 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -22,7 +22,6 @@ */ /* global describe, it, expect, Gpgmejs */ -/* global inputvalues */ describe('GPGME context', function(){ it('Starting a GpgME instance', function(done){ @@ -36,19 +35,3 @@ describe('GPGME context', function(){ }); }); }); - -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/src/Config.js b/lang/js/src/Config.js deleted file mode 100644 index 8a3ef491..00000000 --- a/lang/js/src/Config.js +++ /dev/null @@ -1,34 +0,0 @@ -/* 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+ - * - * Author(s): - * Maximilian Krambach - */ - -export const availableConf = { - null_expire_is_never: [true, false], - // cachedKeys: Some Key info will not be queried on each invocation, - // manual refresh by Key.refresh() - cachedKeys: [true, false] -}; - -export const defaultConf = { - null_expire_is_never: false, - cachedKeys: false -}; \ No newline at end of file diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 09bca7f9..7fa7643c 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -30,10 +30,8 @@ import { GPGME_Keyring } from './Keyring'; export class GpgME { /** * initializes GpgME by opening a nativeMessaging port - * TODO: add configuration */ - constructor(config){ //TODO config not parsed - this._config = config; + constructor(){ } set Keyring(keyring){ diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 1b13ec4a..6db28733 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -25,24 +25,20 @@ import { GpgME } from './gpgmejs'; import { gpgme_error } from './Errors'; import { Connection } from './Connection'; -import { defaultConf, availableConf } from './Config'; /** - * Initializes a nativeMessaging Connection and returns a GPGMEjs object - * @param {Object} config Configuration. See Config.js for available parameters. - * Still TODO + * Tests nativeMessaging once and returns a GpgME object if successful. + * @returns {GpgME | Error} + * + * @async */ -function init(config){ - let _conf = parseconfiguration(config); - if (_conf instanceof Error){ - return Promise.reject(_conf); - } +function init(){ return new Promise(function(resolve, reject){ let connection = new Connection; connection.checkConnection(false).then( function(result){ if (result === true) { - resolve(new GpgME(_conf)); + resolve(new GpgME()); } else { reject(gpgme_error('CONN_NO_CONNECT')); } @@ -52,36 +48,6 @@ function init(config){ }); } -function parseconfiguration(rawconfig = {}){ - if ( typeof(rawconfig) !== 'object'){ - return gpgme_error('PARAM_WRONG'); - } - 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 = rawconfig[conf_keys[i]]; - if (availableConf[conf_keys[i]].indexOf(value) < 0){ - return gpgme_error('PARAM_WRONG'); - } else { - result_config[conf_keys[i]] = value; - } - } - else { - 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; -} - export default { init: init }; \ No newline at end of file -- cgit From d0fc4ded58f4a6a86c5ee0a36a3d3c669e244d0d Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 13 Jun 2018 11:49:37 +0200 Subject: js: less confusing icons for test/Demo extension -- * The current test icon was just a generic pin. Changed that by the gnupg lock symbol with 'Demo'/'Tests' written on it. Original taken from gnupg artwork/icons/lock-wing.svg. --- lang/js/BrowserTestExtension/testicon.png | Bin 16192 -> 2697 bytes lang/js/DemoExtension/testicon.png | Bin 16192 -> 2670 bytes 2 files changed, 0 insertions(+), 0 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/testicon.png b/lang/js/BrowserTestExtension/testicon.png index 12c3f5df..a98463de 100644 Binary files a/lang/js/BrowserTestExtension/testicon.png and b/lang/js/BrowserTestExtension/testicon.png differ diff --git a/lang/js/DemoExtension/testicon.png b/lang/js/DemoExtension/testicon.png index 12c3f5df..84284e0b 100644 Binary files a/lang/js/DemoExtension/testicon.png and b/lang/js/DemoExtension/testicon.png differ -- cgit From d27703ea4f0eed950cddf0157dc78bcb5d8d1c65 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Tue, 19 Jun 2018 16:40:40 +0200 Subject: Prepare build system for gpgme-js and dist it * configure.ac: Add js as language. * lang/Makefile.am: Add js as dist language. * lang/js/BrowserTestExtension/Makefile.am, lang/js/DemoExtension/Makefile.am, lang/js/Makefile.am, lang/js/src/Makefile.am: Populate EXTRA_DIST variables. -- There is no actual build done yet as there seems to be no way to build it with debian stable tools. This needs clarification. --- configure.ac | 27 +++++++++++++++++++- lang/Makefile.am | 2 +- lang/js/BrowserTestExtension/Makefile.am | 42 ++++++++++++++++++++++++++++++++ lang/js/DemoExtension/Makefile.am | 27 ++++++++++++++++++++ lang/js/Makefile.am | 34 ++++++++++++++++++++++++++ lang/js/src/Makefile.am | 30 +++++++++++++++++++++++ 6 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 lang/js/BrowserTestExtension/Makefile.am create mode 100644 lang/js/DemoExtension/Makefile.am create mode 100644 lang/js/Makefile.am create mode 100644 lang/js/src/Makefile.am (limited to 'lang/js/BrowserTestExtension') diff --git a/configure.ac b/configure.ac index a1da1e3e..69d7132f 100644 --- a/configure.ac +++ b/configure.ac @@ -187,7 +187,7 @@ have_w64_system=no have_macos_system=no build_w32_glib=no build_w32_qt=no -available_languages="cl cpp python python2 python3 qt" +available_languages="cl cpp python python2 python3 qt js" default_languages="cl cpp python qt" case "${host}" in x86_64-*mingw32*) @@ -479,6 +479,28 @@ fi AC_SUBST(ENABLED_LANGUAGES, $enabled_languages) +# The javascript bindings +LIST_MEMBER("js", $enabled_languages) +if test "$found" = "1"; then + AC_CHECK_PROGS([NPX], [npx]) + if test -z "$NPX"; then + if test "$explicit_languages" = "1"; then + AC_MSG_ERROR([[ +*** +*** Node.js (npx) is required for the JavaScript binding. +***]]) + else + AC_MSG_WARN([ +*** +*** Node.js (npx) not found - JavaScript binding will not be built. +***]) + enabled_languages=$(echo $enabled_languages | sed 's/js//') + fi + fi +fi +AM_CONDITIONAL([BUILD_JS_BINDINGS], + [test -n "$NPX"]) + # # Provide information about the build. # @@ -899,6 +921,9 @@ AC_CONFIG_FILES(lang/qt/tests/Makefile) AC_CONFIG_FILES(lang/qt/src/qgpgme_version.h) AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpgme.asd]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([lang/qt/doc/Doxyfile])]) +AC_CONFIG_FILES([lang/js/Makefile lang/js/src/Makefile + lang/js/BrowserTestExtension/Makefile + lang/js/DemoExtension/Makefile]) AC_CONFIG_FILES(lang/qt/doc/Makefile) AC_CONFIG_FILES([lang/python/Makefile lang/python/version.py diff --git a/lang/Makefile.am b/lang/Makefile.am index fd3ce4eb..1bf73316 100644 --- a/lang/Makefile.am +++ b/lang/Makefile.am @@ -18,6 +18,6 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA SUBDIRS = $(ENABLED_LANGUAGES) -DIST_SUBDIRS = cl cpp qt python +DIST_SUBDIRS = cl cpp qt python js EXTRA_DIST = README diff --git a/lang/js/BrowserTestExtension/Makefile.am b/lang/js/BrowserTestExtension/Makefile.am new file mode 100644 index 00000000..340d7ad9 --- /dev/null +++ b/lang/js/BrowserTestExtension/Makefile.am @@ -0,0 +1,42 @@ +# Makefile.am for GPGME-JS. +# Copyright (C) 2018 Intevation GmbH +# +# This file is part of GPGME. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL 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 General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +EXTRA_DIST = browsertest.html \ + index.html \ + longTests.html \ + Makefile.am \ + manifest.json \ + popup.html \ + popup.js \ + runbrowsertest.js \ + rununittests.js \ + setup_testing.js \ + testicon.png \ + testkey2.pub \ + testkey.pub \ + testkey.sec \ + tests/encryptDecryptTest.js \ + tests/encryptTest.js \ + tests/inputvalues.js \ + tests/KeyImportExport.js \ + tests/longRunningTests.js \ + tests/signTest.js \ + tests/startup.js \ + unittests.html diff --git a/lang/js/DemoExtension/Makefile.am b/lang/js/DemoExtension/Makefile.am new file mode 100644 index 00000000..e93d0f66 --- /dev/null +++ b/lang/js/DemoExtension/Makefile.am @@ -0,0 +1,27 @@ +# Makefile.am for GPGME-JS. +# Copyright (C) 2018 Intevation GmbH +# +# This file is part of GPGME-CL. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL 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 General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +EXTRA_DIST = manifest.json \ + popup.html \ + entry.js \ + maindemo.js \ + mainui.html \ + testicon.png \ + ui.css diff --git a/lang/js/Makefile.am b/lang/js/Makefile.am new file mode 100644 index 00000000..4b5c7172 --- /dev/null +++ b/lang/js/Makefile.am @@ -0,0 +1,34 @@ +# Makefile.am for GPGME-JS. +# Copyright (C) 2018 2018 Bundesamt für Sicherheit in der Informationstechnik +# +# This file is part of GPGME-JS. +# +# GPGME-JS is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-JS 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 General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +SUBDIRS = src BrowserTestExtension DemoExtension + +EXTRA_DIST = build_extensions.sh \ + CHECKLIST \ + CHECKLIST_build \ + .eslintrc.json \ + Makefile.am \ + package.json \ + README \ + README_testing \ + unittest_inputvalues.js \ + unittests.js \ + webpack.conf.js \ + webpack.conf_unittests.js diff --git a/lang/js/src/Makefile.am b/lang/js/src/Makefile.am new file mode 100644 index 00000000..dd330d50 --- /dev/null +++ b/lang/js/src/Makefile.am @@ -0,0 +1,30 @@ +# Makefile.am for GPGME-JS. +# Copyright (C) 2018 Intevation GmbH +# +# This file is part of GPGME. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL 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 General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +EXTRA_DIST = Connection.js \ + Errors.js \ + gpgmejs.js \ + Helpers.js \ + index.js \ + Key.js \ + Keyring.js \ + Message.js \ + permittedOperations.js \ + Signature.js -- cgit From a52ec87d406379f1a6acd8d4f34605a4bac8683b Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 3 Jul 2018 12:41:49 +0200 Subject: js: fixing Key import/export test -- * BrowserTestExtension: - The KeyImport/Export test had some errors, which have now been fixed - The secret key used for the test examples is now placed more prominently, and a clarification added that decrypt tests will not work if this key is not imported. * permittedOperations.js: typo Thanks to rrenkert@intevation.de for the fixes --- lang/js/BrowserTestExtension/index.html | 73 ++++++++++++++++++++++ .../BrowserTestExtension/tests/KeyImportExport.js | 25 ++++---- lang/js/src/permittedOperations.js | 2 +- 3 files changed, 87 insertions(+), 13 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/index.html b/lang/js/BrowserTestExtension/index.html index 05d413ba..7f8d97de 100644 --- a/lang/js/BrowserTestExtension/index.html +++ b/lang/js/BrowserTestExtension/index.html @@ -23,6 +23,15 @@ The functionality tests, to be found in gpgme/lang/js/BrowserTestExtension, check the overall functionality of the standard packaged version of gpgmejs. +

    +

    + Most tests rely on a test gpg key to be available in gpg, which can be + found at the bottom of this page, or as "testkey.sec" in the + BrowserTestExtension's directory. Please import this key to your tested + gpg installation, or adapt the input defined in tests/inputvalues.js + if you want to use different values. +

    +

    +
    +

    + + + +

    diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 6b298049..33e6bd29 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -19,6 +19,7 @@ * * Author(s): * Maximilian Krambach + * Raimund Renkert */ /* global describe, it, expect, Gpgmejs, ImportablePublicKey */ @@ -53,27 +54,27 @@ describe('Key importing', function () { expect(result.length).to.equal(0); context.Keyring.importKey(ImportablePublicKey.key, true) .then(function(result){ - expect(result[0]).to.not.be.undefined; - expect(result[0].key).to.be.an('object'); - expect(result[0].key.fingerprint).to.equal( + expect(result.Keys[0]).to.not.be.undefined; + expect(result.Keys[0].key).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal( ImportablePublicKey.fingerprint); - expect(result[0].status).to.equal('newkey'); + expect(result.Keys[0].status).to.equal('newkey'); context.Keyring.importKey( ImportablePublicKey.keyChangedUserId,true) .then(function(res){ - expect(res[0]).to.not.be.undefined; - expect(res[0].key).to.be.an('object'); - expect(res[0].key.fingerprint).to.equal( + expect(res.Keys[0]).to.not.be.undefined; + expect(res.Keys[0].key).to.be.an('object'); + expect(res.Keys[0].key.fingerprint).to.equal( ImportablePublicKey.fingerprint); - expect(res[0].status).to.equal( + expect(res.Keys[0].status).to.equal( 'change'); expect( - res[0].changes.userId).to.be.true; + res.Keys[0].changes.userId).to.be.true; expect( - res[0].changes.subkey).to.be.false; + res.Keys[0].changes.subkey).to.be.false; expect( - res[0].changes.signature).to.be.true; - res[0].key.delete().then(function(result){ + res.Keys[0].changes.signature).to.be.true; + res.Keys[0].key.delete().then(function(result){ expect(result).to.be.true; done(); }); diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 044ae4af..312eaa52 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -272,7 +272,7 @@ export const permittedOperations = { answer: { type: [], data: { - 'result': 'Object' + 'result': 'object' } } }, -- cgit From 67b6fa5a2948deed6a914c638f923fb9ad2eac66 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 9 Jul 2018 11:24:46 +0200 Subject: js: reduce request spam at getKeys() -- * Don't make a secret-Key request for each Key retrieved, use one request for all of them instead, and assemble the info later. This should reduce the traffic with large Keyrings. The bulk retrieval for the public armored Keys for each of these Keys is still up to discussion * unittests: disabled assertion for the armored key (as it currently doesn't work) * encryptTest: clarified the mechanism/reason of rejection for Messages >64 MB. This is still a TODO, as this error comes from a different place (the browser itself) and behaves different from the other errors. --- lang/js/BrowserTestExtension/tests/encryptTest.js | 5 ++- lang/js/src/Keyring.js | 52 +++++++++++++++-------- lang/js/unittests.js | 14 +++--- 3 files changed, 46 insertions(+), 25 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 2cb4e58b..1114125e 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -133,7 +133,7 @@ describe('Encryption', function () { }); }).timeout(5000); - it('Overly large message ( > 65MB) is rejected', function (done) { + it('Overly large message ( > 64MB) is rejected', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( @@ -142,10 +142,11 @@ describe('Encryption', function () { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an.instanceof(Error); - // expect(error.code).to.equal('GNUPG_ERROR'); // TODO: there is a 64 MB hard limit at least in chrome at: // chromium//extensions/renderer/messaging_util.cc: // kMaxMessageLength + // The error will be a browser error, not from gnupg or from + // this library done(); }); }); diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 358757b0..09c43f73 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -56,28 +56,46 @@ export class GPGME_Keyring { } msg.post().then(function(result){ let resultset = []; - let promises = []; if (result.keys.length === 0){ resolve([]); } else { - for (let i=0; i< result.keys.length; i++){ - let k = createKey(result.keys[i].fingerprint); - k.setKeyData(result.keys[i]); - if (prepare_sync === true){ - promises.push(k.getArmor()); - promises.push(k.getHasSecret()); - } - resultset.push(k); - } - if (promises.length > 0) { - Promise.all(promises).then(function() { - resolve(resultset); - }, function(error){ - reject(error); - }); + let secondrequest; + if (prepare_sync === true) { + secondrequest = function() { + msg.setParameter('secret', true); + return msg.post(); + }; } else { - resolve(resultset); + secondrequest = function() { + return Promise.resolve(true); + }; } + secondrequest().then(function(answer) { + for (let i=0; i < result.keys.length; i++){ + if (prepare_sync === true){ + result.keys[i].hasSecret = false; + if (answer && answer.keys) { + for (let j=0; j < answer.keys.length; j++ ){ + if (result.keys[i].fingerprint === + answer.keys[j].fingerprint + ) { + if (answer.keys[j].secret === true){ + result.keys[i].hasSecret = true; + } + break; + } + } + // TODO getArmor() to be used in sync + } + } + let k = createKey(result.keys[i].fingerprint); + k.setKeyData(result.keys[i]); + resultset.push(k); + } + resolve(resultset); + }, function(error){ + reject(error); + }); } }); }); diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 169e8ebc..04e15ef3 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -272,9 +272,9 @@ function unittests (){ keyring.getKeys(null, true).then(function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); }); } @@ -287,9 +287,11 @@ function unittests (){ function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // TODO: preparing sync for armored is still in discussion + // expect(result[0].get('armored')).to.be.a('string'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); } ); -- cgit From 8964627f6ad7c407785a9fa5cb508c7c28be0d60 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 9 Jul 2018 11:57:01 +0200 Subject: js: fix verify result reporting -- * src/Signature.js: searching for overall validity in the "summary" property * BrowsertestExtension: Added two verify tests --- lang/js/BrowserTestExtension/browsertest.html | 1 + lang/js/BrowserTestExtension/tests/verifyTest.js | 86 ++++++++++++++++++++++++ lang/js/src/Signature.js | 3 +- 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/verifyTest.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index f3d7a406..de8cd41a 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -18,6 +18,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js new file mode 100644 index 00000000..bf0f0c0f --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -0,0 +1,86 @@ +/* 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+ + * + * Author(s): + * Maximilian Krambach + */ + +/* global describe, it, expect, bigString, inputvalues, Gpgmejs */ + +let verifyData = { + signedMessage: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige Münsteraner Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE34YHmHCyv9oBiN3shwTx6WpaVdQFAlsqWxYACgkQhwTx6Wpa\n' + + 'VdRaTQf9Fj8agQzbE6DtonewZVGzj1KmjjpyAypnDldY21lrN8zIaQ+aKqRVkVrV\n' + + '5A/MeUfoHh0b/9G1Co4LOuNjGS14GRNlFvPtxeA2mCwlk7kgP2i6ekbHdEXWcG9c\n' + + 'gSbzdJ3EgfVCFNkC/yhldXSLOJZ7oyiGEteDpi8dDSa9dIprT++sQ4kRuR8jPrIi\n' + + 'UUY+DltG3it7PybcTFfQm53I0mtnpFsizzCmgyJAkfG5fwVL3uWwbYGofD049PSu\n' + + '6IEkSY74r8JbAbkCOiF/ln40RYGSwM0Ta5rrb3A3MixZNL/a1r17oljkaWz8e8VT\n' + + 'N7NUgBHwbIQ4e3RLuUU8fF3ICCGDOw==\n' + + '=oGai\n' + + '-----END PGP SIGNATURE-----\n' +}; + +describe('Verify data', function () { + it('Successful verify message', function (done) { + let message = verifyData.signedMessage; + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint) + .to.be.a('string'); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + }); + + it('Encrypt-Sign-Verify random message', function (done) { + let message = bigString(2000); + let fpr = inputvalues.encrypt.good.fingerprint; + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt(message, fpr).then(function(message_enc){ + context.sign(message_enc.data, fpr).then(function(message_encsign){ + context.verify(message_encsign.data).then(function(result){ + expect(result.data).to.equal(message_enc.data); + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint) + .to.equal(fpr); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index a07fc4d1..c3c511a8 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -67,7 +67,6 @@ export function createSignature(sigObject){ } } } - console.log('sig created'); return new GPGME_Signature(sigObject); } @@ -114,7 +113,7 @@ class GPGME_Signature { * additional information */ get valid() { - if (this._rawSigObject.valid === true){ + if (this._rawSigObject.summary.valid === true){ return true; } else { return false; -- cgit From 30bb5490466119b66eeac255d71fb7bdc79149fa Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 12 Jul 2018 11:36:55 +0200 Subject: js: add with-sec-fprs to getKeysArmored -- * Reflects the changes made to gpgme-json in commit 6cc842c9aa76d19448141e5117ac59452d7a1ff3. - getKeysArmored now returns an object with property 'armored' being the exported armored block, and an (optional) array of fingerprint strings for those keys that can be used in sign/encrypt operations as property 'secret_fprs'. With this, extensions such as mailvelope will be able to bulk fetch all necessary key information in one request. --- .../BrowserTestExtension/tests/KeyImportExport.js | 29 ++++++++++++++++-- lang/js/src/Keyring.js | 34 +++++++++++++++++----- lang/js/src/permittedOperations.js | 12 ++++---- 3 files changed, 60 insertions(+), 15 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 33e6bd29..4a53c7a6 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -22,7 +22,7 @@ * Raimund Renkert */ -/* global describe, it, expect, Gpgmejs, ImportablePublicKey */ +/* global describe, it, expect, Gpgmejs, ImportablePublicKey, inputvalues */ describe('Key importing', function () { it('Prepare test Key (deleting it from gnupg, if present)', function(done){ @@ -83,5 +83,30 @@ describe('Key importing', function () { }); }); }); - + it('exporting armored Key with getKeysArmored', function (done) { + let prm = Gpgmejs.init(); + const fpr = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.Keyring.getKeysArmored(fpr).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.undefined; + done(); + }); + }); + }); + it('exporting armored Key (including secret fingerprints) with ' + + 'getKeysArmored', function (done) { + let prm = Gpgmejs.init(); + const fpr = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.Keyring.getKeysArmored(fpr, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.an('array'); + expect(result.secret_fprs[0]).to.equal(fpr); + done(); + }); + }); + }); }); \ No newline at end of file diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index a0bdfcb2..7a33be98 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -107,26 +107,46 @@ export class GPGME_Keyring { }); } + /** + * @typedef {Object} exportResult The result of a getKeysArmored operation. + * @property {String} armored The public Key(s) as armored block. Note that + * the result is one armored block, and not a block per key. + * @property {Array} secret_fprs (optional) list of fingerprints + * for those Keys that also have a secret Key available in gnupg. The + * secret key will not be exported, but the fingerprint can be used in + * operations needing a secret key. + */ + /** * Fetches the armored public Key blocks for all Keys matching the pattern - * (if no pattern is given, fetches all keys known to gnupg). Note that the - * result may be one big armored block, instead of several smaller armored - * blocks + * (if no pattern is given, fetches all keys known to gnupg). * @param {String|Array} pattern (optional) The Pattern to search * for - * @returns {Promise} Armored Key blocks + * @param {Boolean} with_secret_fpr (optional) also return a list of + * fingerprints for the keys that have a secret key available + * @returns {Promise} Object containing the + * armored Key(s) and additional information. * @static * @async */ - getKeysArmored(pattern) { + getKeysArmored(pattern, with_secret_fpr) { return new Promise(function(resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); + if (with_secret_fpr === true) { + msg.setParameter('with-sec-fprs', true); + } if (pattern !== undefined){ msg.setParameter('keys', pattern); } - msg.post().then(function(result){ - resolve(result.data); + msg.post().then(function(answer){ + const result = {armored: answer.data}; + if (with_secret_fpr === true + && answer.hasOwnProperty('sec-fprs') + ) { + result.secret_fprs = answer['sec-fprs']; + } + resolve(result); }, function(error){ reject(error); }); diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 0b9c891f..b5e91579 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -246,7 +246,10 @@ export const permittedOperations = { 'raw': { allowed: ['boolean'] }, - 'pkcs12':{ + 'pkcs12': { + allowed: ['boolean'] + }, + 'with-sec-fprs': { allowed: ['boolean'] } // secret: not yet implemented @@ -255,7 +258,8 @@ export const permittedOperations = { type: ['keys'], data: { 'data': 'string', - 'base64': 'boolean' + 'base64': 'boolean', + 'sec-fprs': 'object' } } }, @@ -295,10 +299,6 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - // 'secret': { not implemented - // allowed: ['boolean'] - // } - }, answer: { data: { -- cgit From a965e3e0b89521ad4f3898a8483161624c2e5848 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 20 Jul 2018 10:59:57 +0200 Subject: js: repair BrowserTextExtension test -- * the signed message to verify was signed by a wrong test key --- lang/js/BrowserTestExtension/tests/verifyTest.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index bf0f0c0f..e8e2c76a 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -30,14 +30,14 @@ let verifyData = { 'Matschige Münsteraner Marshmallows\n' + '-----BEGIN PGP SIGNATURE-----\n' + '\n' + - 'iQEzBAEBCAAdFiEE34YHmHCyv9oBiN3shwTx6WpaVdQFAlsqWxYACgkQhwTx6Wpa\n' + - 'VdRaTQf9Fj8agQzbE6DtonewZVGzj1KmjjpyAypnDldY21lrN8zIaQ+aKqRVkVrV\n' + - '5A/MeUfoHh0b/9G1Co4LOuNjGS14GRNlFvPtxeA2mCwlk7kgP2i6ekbHdEXWcG9c\n' + - 'gSbzdJ3EgfVCFNkC/yhldXSLOJZ7oyiGEteDpi8dDSa9dIprT++sQ4kRuR8jPrIi\n' + - 'UUY+DltG3it7PybcTFfQm53I0mtnpFsizzCmgyJAkfG5fwVL3uWwbYGofD049PSu\n' + - '6IEkSY74r8JbAbkCOiF/ln40RYGSwM0Ta5rrb3A3MixZNL/a1r17oljkaWz8e8VT\n' + - 'N7NUgBHwbIQ4e3RLuUU8fF3ICCGDOw==\n' + - '=oGai\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + '-----END PGP SIGNATURE-----\n' }; -- cgit From 4b343c4e339862a5faf8dd20590a3c4592fb6abb Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 24 Jul 2018 14:56:33 +0200 Subject: js: include armored Key in import callback -- * The import answer now also directly contains the armored Key as Key property, without need to refresh the Key object created in the answer. This allows for direct comparision of input and output. * BrowserTestExtension: added test for that import callback --- .../BrowserTestExtension/tests/KeyImportExport.js | 26 ++++++++++++++++++++++ lang/js/src/Key.js | 9 +++++--- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 4a53c7a6..ed307b32 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -83,6 +83,32 @@ describe('Key importing', function () { }); }); }); + + it('Import result feedback', function(done){ + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + context.Keyring.importKey(ImportablePublicKey.key, true) + .then(function(result){ + expect(result).to.be.an('object'); + expect(result.Keys[0]).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal( + ImportablePublicKey.fingerprint); + expect(result.Keys[0].status).to.equal('newkey'); + result.Keys[0].key.getArmor().then(function(armor){ + expect(armor).to.be.a('string'); + result.Keys[0].key.delete().then(function(){ + done(); + }); + }); + }); + }); + }); + }); + it('exporting armored Key with getKeysArmored', function (done) { let prm = Gpgmejs.init(); const fpr = inputvalues.encrypt.good.fingerprint; diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 30f507c1..b024a77b 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -141,7 +141,7 @@ export class GPGME_Key { * during a session. The key still can be reloaded by invoking * {@link refreshKey}. * @returns {*|Promise<*>} the value (Boolean, String, Array, Object). - * If 'cached' is true, the value will be resolved as a Promise. + * If 'cached' is false, the value will be resolved as a Promise. */ get(property, cached=true) { if (cached === false) { @@ -194,8 +194,11 @@ export class GPGME_Key { if (result.keys.length === 1){ me.setKeyData(result.keys[0]); me.getHasSecret().then(function(){ - //TODO retrieve armored Key - resolve(me); + me.getArmor().then(function(){ + resolve(me); + }, function(error){ + reject(error); + }); }, function(error){ reject(error); }); -- cgit From b18b96fb364711025d1e5fa9f135ee682dd0558a Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Jul 2018 11:20:33 +0200 Subject: js: clean up test extension -- Tests will now run with one instance of gpgmejs each block, which reduces overhead. Readability is (hopefully) improved), some negative tests are added. There is still a performance problem in base64 encoding/decoding, which causes some tests to fail due to time out. --- .../BrowserTestExtension/tests/KeyImportExport.js | 169 +++++++------- .../tests/encryptDecryptTest.js | 255 +++++++++------------ lang/js/BrowserTestExtension/tests/encryptTest.js | 157 +++++-------- lang/js/BrowserTestExtension/tests/inputvalues.js | 56 ++++- .../BrowserTestExtension/tests/longRunningTests.js | 76 +++--- lang/js/BrowserTestExtension/tests/signTest.js | 58 ++--- lang/js/BrowserTestExtension/tests/verifyTest.js | 99 ++++---- 7 files changed, 417 insertions(+), 453 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index ed307b32..d2fa2d38 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -22,18 +22,25 @@ * Raimund Renkert */ -/* global describe, it, expect, Gpgmejs, ImportablePublicKey, inputvalues */ +/* global describe, it, expect, before, afterEach, Gpgmejs*/ +/* global ImportablePublicKey, inputvalues */ describe('Key importing', function () { - it('Prepare test Key (deleting it from gnupg, if present)', function(done){ - let prm = Gpgmejs.init(); - prm.then(function (context) { - expect(context.Keyring.getKeys).to.be.a('function'); - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + const fpr = ImportablePublicKey.fingerprint; + const pubKey = ImportablePublicKey.key; + const changedKey = ImportablePublicKey.keyChangedUserId; + + let context = null; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + context.Keyring.getKeys(fpr).then( function(result){ if (result.length === 1) { - result[0].delete().then(function(result){ - expect(result).to.be.true; + result[0].delete().then(function(){ + done(); + },function(){ done(); }); } else { @@ -43,76 +50,79 @@ describe('Key importing', function () { }); }); - it('importing, updating, then deleting public Key', function (done) { - //This test runs in one large step, to ensure the proper state of the - // key in all stages. - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( - function(result){ - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - context.Keyring.importKey(ImportablePublicKey.key, true) - .then(function(result){ - expect(result.Keys[0]).to.not.be.undefined; - expect(result.Keys[0].key).to.be.an('object'); - expect(result.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(result.Keys[0].status).to.equal('newkey'); - context.Keyring.importKey( - ImportablePublicKey.keyChangedUserId,true) - .then(function(res){ - expect(res.Keys[0]).to.not.be.undefined; - expect(res.Keys[0].key).to.be.an('object'); - expect(res.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(res.Keys[0].status).to.equal( - 'change'); - expect( - res.Keys[0].changes.userId).to.be.true; - expect( - res.Keys[0].changes.subkey).to.be.false; - expect( - res.Keys[0].changes.signature).to.be.true; - res.Keys[0].key.delete().then(function(result){ - expect(result).to.be.true; - done(); - }); - }); - }); + afterEach(function(done){ + // delete the test key if still present + context.Keyring.getKeys(fpr).then( + function(result){ + if (result.length === 1) { + result[0].delete().then(function(){ + done(); + },function(){ + done(); + }); + } else { + done(); + } + }); + }); + + it('Importing Key', function (done) { + context.Keyring.getKeys(fpr).then(function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + context.Keyring.importKey(pubKey).then(function(result){ + expect(result[0]).to.not.be.undefined; + expect(result[0].key).to.be.an('object'); + expect(result[0].key.fingerprint).to.equal(fpr); + expect(result[0].status).to.equal('newkey'); + done(); + }); + }); + }); + + it('Updating Key', function(done){ + context.Keyring.importKey(pubKey) + .then(function(result){ + expect(result[0].key).to.not.be.undefined; + expect(result[0].status).to.equal('newkey'); + context.Keyring.importKey(changedKey).then(function(res){ + expect(res[0].key).to.be.an('object'); + expect(res[0].key.fingerprint).to.equal(fpr); + expect(res[0].status).to.equal('change'); + expect(res[0].changes.userId).to.be.true; + expect(res[0].changes.subkey).to.be.false; + expect(res[0].changes.signature).to.be.true; + done(); }); + }); + }); + + it('Deleting Key', function(done) { + context.Keyring.importKey(pubKey).then(function(result){ + expect(result[0].key).to.be.an('object'); + expect(result[0].key.fingerprint).to.equal(fpr); + result[0].key.delete().then(function(result){ + expect(result).to.be.true; + done(); + }); }); }); it('Import result feedback', function(done){ - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( - function(result){ - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - context.Keyring.importKey(ImportablePublicKey.key, true) - .then(function(result){ - expect(result).to.be.an('object'); - expect(result.Keys[0]).to.be.an('object'); - expect(result.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(result.Keys[0].status).to.equal('newkey'); - result.Keys[0].key.getArmor().then(function(armor){ - expect(armor).to.be.a('string'); - result.Keys[0].key.delete().then(function(){ - done(); - }); - }); - }); - }); + context.Keyring.importKey(pubKey, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.Keys[0]).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal(fpr); + expect(result.Keys[0].status).to.equal('newkey'); + result.Keys[0].key.getArmor().then(function(armor){ + expect(armor).to.be.a('string'); + done(); + }); }); }); it('exporting armored Key with getKeysArmored', function (done) { - let prm = Gpgmejs.init(); - const fpr = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { + context.Keyring.importKey(pubKey).then(function(){ context.Keyring.getKeysArmored(fpr).then(function(result){ expect(result).to.be.an('object'); expect(result.armored).to.be.a('string'); @@ -121,18 +131,15 @@ describe('Key importing', function () { }); }); }); - it('exporting armored Key (including secret fingerprints) with ' - + 'getKeysArmored', function (done) { - let prm = Gpgmejs.init(); - const fpr = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { - context.Keyring.getKeysArmored(fpr, true).then(function(result){ - expect(result).to.be.an('object'); - expect(result.armored).to.be.a('string'); - expect(result.secret_fprs).to.be.an('array'); - expect(result.secret_fprs[0]).to.equal(fpr); - done(); - }); + + it('Exporting Key (including secret fingerprints)', function (done) { + const key_secret = inputvalues.encrypt.good.fingerprint; + context.Keyring.getKeysArmored(key_secret, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.an('array'); + expect(result.secret_fprs[0]).to.equal(key_secret); + done(); }); }); }); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index bd72c1d2..80b293d2 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -21,152 +21,101 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global inputvalues, encryptedData, bigString, bigBoringString */ describe('Encryption and Decryption', function () { + let context = null; + let good_fpr = inputvalues.encrypt.good.fingerprint; + + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + it('Successful encrypt and decrypt simple string', 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'); - context.decrypt(answer.data).then(function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal( - inputvalues.encrypt.good.data); - done(); - }); - }); + let data = inputvalues.encrypt.good.data; + context.encrypt(data, good_fpr).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'); + + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal( + inputvalues.encrypt.good.data); + done(); + }); }); }); it('Decrypt simple non-ascii', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = encryptedData; - context.decrypt(data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal( - '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); - done(); - }); + let data = encryptedData; + context.decrypt(data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal( + '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n'); + done(); }); }).timeout(3000); - it('Roundtrip does not destroy trailing whitespace', - function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = 'Keks. \rKeks \n Keks \r\n'; - context.encrypt(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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - - }); - }); - }); - }).timeout(5000); + it('Trailing whitespace and different line endings', function (done) { + const data = 'Keks. \rKeks \n Keks \r\n'; + context.encrypt(data, good_fpr).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'); - for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ - it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + - (j + 1) + '/' - + inputvalues.encrypt.good.data_nonascii_32.length + ')', - function (done) { - let input = inputvalues.encrypt.good.data_nonascii_32[j]; - expect(input).to.have.length(32); - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = ''; - for (let i=0; i < 34 * 1024; i++){ - data += input; - } - context.encrypt(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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); }); - }).timeout(3000); - } + }); + }).timeout(5000); it('Random data, as string', function (done) { let data = bigString(1000); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); + context.encrypt(data, good_fpr).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'); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); }); }).timeout(3000); it('Data, input as base64', function (done) { let data = inputvalues.encrypt.good.data; let b64data = btoa(data); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint, true).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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(data).to.equal(data); - done(); - }); + context.encrypt(b64data, good_fpr, true).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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(data).to.equal(data); + done(); }); }); }).timeout(3000); @@ -174,26 +123,48 @@ describe('Encryption and Decryption', function () { it('Random data, input as base64', function (done) { let data = bigBoringString(0.001); let b64data = btoa(data); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint, true).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'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(b64data); - done(); - }); + context.encrypt(b64data, good_fpr, true).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'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(b64data); + done(); }); }); }).timeout(3000); + for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ + it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + + (j + 1) + '/' + + inputvalues.encrypt.good.data_nonascii_32.length + ')', + function (done) { + let input = inputvalues.encrypt.good.data_nonascii_32[j]; + expect(input).to.have.length(32); + let data = ''; + for (let i=0; i < 34 * 1024; i++){ + data += input; + } + context.encrypt(data,good_fpr).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'); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }).timeout(5000); + } }); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 1114125e..3ead8153 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -21,134 +21,91 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global inputvalues, fixedLengthString */ describe('Encryption', function () { - it('Successful 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(); - }); + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); }); }); - it('Successful encrypt 5 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(5); - prm.then(function (context) { - context.encrypt( - 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(); - }); - }); - }).timeout(10000); - - it('Successful encrypt 20 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(20); - prm.then(function (context) { - context.encrypt( - 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(); - }); + it('Successful encrypt', function (done) { + const data = inputvalues.encrypt.good.data; + context.encrypt(data, good_fpr).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(); }); - }).timeout(20000); + }); - it('Successful encrypt 50 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(50); - prm.then(function (context) { - context.encrypt( - data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { + const sizes = [5,20,50]; + for (let i=0; i < sizes.length; i++) { + it('Successful encrypt a ' + sizes[i] + 'MB message', function (done) { + const data = fixedLengthString(sizes[i]); + context.encrypt(data, good_fpr).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(); }); - }); - }).timeout(20000); + }).timeout(20000); + } it('Sending encryption without keys fails', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - null).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.equal('MSG_INCOMPLETE'); - done(); - }); + const data = inputvalues.encrypt.good.data; + context.encrypt(data,null).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); }); }); it('Sending encryption without data fails', function (done) { - 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(); - }); + context.encrypt(null, good_fpr).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(); }); }); it('Sending encryption with non existing keys fails', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - inputvalues.encrypt.bad.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.not.be.undefined; - expect(error.code).to.equal('GNUPG_ERROR'); - done(); - }); + const data = inputvalues.encrypt.good.data; + const bad_fpr = inputvalues.encrypt.bad.fingerprint; + context.encrypt(data, bad_fpr).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.not.be.undefined; + expect(error.code).to.equal('GNUPG_ERROR'); + done(); }); }).timeout(5000); it('Overly large message ( > 64MB) is rejected', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - fixedLengthString(65), - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an.instanceof(Error); - // TODO: there is a 64 MB hard limit at least in chrome at: - // chromium//extensions/renderer/messaging_util.cc: - // kMaxMessageLength - // The error will be a browser error, not from gnupg or from - // this library - done(); - }); + const data = fixedLengthString(65); + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an.instanceof(Error); + // TODO: there is a 64 MB hard limit at least in chrome at: + // chromium//extensions/renderer/messaging_util.cc: + // kMaxMessageLength + // The error will be a browser error, not from gnupg or from + // this library + done(); }); }).timeout(8000); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 1c701904..5289eab7 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -53,6 +53,39 @@ const inputvalues = {// eslint-disable-line no-unused-vars // bogus fingerprint) fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } + }, + + signedMessage: { + good: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige Münsteraner Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + + '-----END PGP SIGNATURE-----\n', + bad: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige Münchener Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + + '-----END PGP SIGNATURE-----\n', } }; @@ -83,7 +116,7 @@ function bigUint8(megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); for (let i= 0; i < maxlength; i++){ - uint[i] = Math.random() * Math.floor(256); + uint[i] = Math.floor(Math.random() * 256); } return uint; } @@ -125,6 +158,27 @@ function slightlyLessBoringString(megabytes, set){ return string.join(''); } +// Take a gpg looking string and destroy it a bit by changing random values +// eslint-disable-next-line no-unused-vars +function destroylegitimateGpg(string, mutations=5){ + const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/\n'; + for (let i=0; i < mutations.length; i++){ + // leave the first and last 35 chars (header/footer) intact + let position = Math.floor(Math.random() *(string.length - 70)) + 35; + let str0 = string.substring(0,position - 1); + let str1 = string.substring(position, position + 1); + let str2 = string.substring(position +1); + let success = false; + while (!success){ + let newchar = Math.floor(Math.random() * allowed.length); + if (newchar !== str1){ + string = str0 + newchar + str2; + success = true; + } + } + } +} + // Data encrypted with testKey const encryptedData =// eslint-disable-line no-unused-vars '-----BEGIN PGP MESSAGE-----\n' + diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index e148d1cf..03f0390c 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -20,61 +20,37 @@ * Author(s): * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, before, expect, Gpgmejs */ /* global bigString, inputvalues */ describe('Long running Encryption/Decryption', function () { + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + for (let i=0; i < 101; i++) { - it('Successful encrypt/decrypt completely random data ' + - (i+1) + '/100', function (done) { - let prm = Gpgmejs.init(); - let data = bigString(2*1024*1024); - prm.then(function (context) { - context.encrypt(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'); - context.decrypt(answer.data).then( - function(result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - /* - if (result.data.length !== data.length) { - console.log('diff: ' + - (result.data.length - data.length)); - for (let i=0; i < result.data.length; i++){ - if (result.data[i] !== data[i]){ - console.log('position: ' + i); - console.log('result : ' + - result.data.charCodeAt(i) + - result.data[i-2] + - result.data[i-1] + - result.data[i] + - result.data[i+1] + - result.data[i+2]); - console.log('original: ' + - data.charCodeAt(i) + - data[i-2] + - data[i-1] + - data[i] + - data[i+1] + - data[i+2]); - break; - } - } - } - */ - expect(result.data).to.equal(data); - done(); - }); - }); + it('Successful encrypt/decrypt completely random data ' + + (i+1) + '/100', function (done) { + const data = bigString(2*1024*1024); + context.encrypt(data,good_fpr).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'); + context.decrypt(answer.data).then(function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); }); - }).timeout(8000); + }).timeout(15000); } }); diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js index ffd2d5de..2763dadf 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -21,42 +21,42 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global bigString, inputvalues */ describe('Signing', function () { + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + it('Sign a message', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = bigString(100); - context.sign( - 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 SIGNATURE'); - expect(answer.data).to.include('END PGP SIGNATURE'); - expect(answer.data).to.include(data); - done(); - }); + const data = bigString(100); + context.sign(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP SIGNATURE'); + expect(answer.data).to.include('END PGP SIGNATURE'); + expect(answer.data).to.include(data); + done(); }); }); + it('Detached sign a message', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = bigString(100); - context.sign( - data, - inputvalues.encrypt.good.fingerprint, - 'detached' - ).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include(data); - expect(answer.signature).to.be.a('string'); - expect(answer.signature).to.be.a('string'); - done(); - }); + const data = bigString(100); + context.sign(data,good_fpr, 'detached').then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include(data); + expect(answer.signature).to.be.a('string'); + expect(answer.signature).to.be.a('string'); + done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index e8e2c76a..1617e2dc 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -21,64 +21,63 @@ * Maximilian Krambach */ -/* global describe, it, expect, bigString, inputvalues, Gpgmejs */ +/* global describe, it, expect, before, bigString, inputvalues, Gpgmejs */ -let verifyData = { - signedMessage: '-----BEGIN PGP SIGNED MESSAGE-----\n' + - 'Hash: SHA256\n' + - '\n' + - 'Matschige Münsteraner Marshmallows\n' + - '-----BEGIN PGP SIGNATURE-----\n' + - '\n' + - 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + - 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + - 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + - 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + - 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + - 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + - 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + - '=ioB6\n' + - '-----END PGP SIGNATURE-----\n' -}; -describe('Verify data', function () { + +describe('Verifying data', function () { + let context = null; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); it('Successful verify message', function (done) { - let message = verifyData.signedMessage; - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.verify(message).then(function(result){ - expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect(result.signatures.good[0].fingerprint) - .to.be.a('string'); - expect(result.signatures.good[0].valid).to.be.true; - done(); - }); + const message = inputvalues.signedMessage.good; + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint).to.be.a('string'); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + + it('Successfully recognize changed cleartext', function (done) { + const message = inputvalues.signedMessage.bad; + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.false; + expect(result.count).to.equal(1); + expect(result.signatures.bad).to.be.an('array'); + expect(result.signatures.bad.length).to.equal(1); + expect(result.signatures.bad[0].fingerprint).to.be.a('string'); + expect(result.signatures.bad[0].valid).to.be.false; + done(); }); }); it('Encrypt-Sign-Verify random message', function (done) { - let message = bigString(2000); + const message = bigString(2000); let fpr = inputvalues.encrypt.good.fingerprint; - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(message, fpr).then(function(message_enc){ - context.sign(message_enc.data, fpr).then(function(message_encsign){ - context.verify(message_encsign.data).then(function(result){ - expect(result.data).to.equal(message_enc.data); - expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect(result.signatures.good[0].fingerprint) - .to.equal(fpr); - expect(result.signatures.good[0].valid).to.be.true; - done(); - }); + context.encrypt(message, fpr).then(function(message_enc){ + context.sign(message_enc.data, fpr).then(function(message_encsign){ + context.verify(message_encsign.data).then(function(result){ + expect(result.data).to.equal(message_enc.data); + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect( + result.signatures.good[0].fingerprint).to.equal(fpr); + expect(result.signatures.good[0].valid).to.be.true; + done(); }); }); }); -- cgit From 94ee0988d4eaac27785de6efb7c19ca9976e1e9c Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Fri, 27 Jul 2018 20:36:21 +0200 Subject: js: change the write access for js class methods -- * src/ [Connection, Error, Key, Keyring, MEssage, Signature, gpgmejs]: Functions and values that are not meant to be overwritten are now moved into their constructors, thus eliminating the possibility of overwrites after initialization. * Key: The mode of use (synchronous cached, or async promises) ivs now determined at initialization of that Key. The property Key.isAsync reflects this state. * unittests: fixed old Key syntax for testing. * Message.js isComplete is now a method and not a getter anymore. * Added some startup tests. --- lang/js/BrowserTestExtension/tests/inputvalues.js | 25 +- lang/js/BrowserTestExtension/tests/startup.js | 15 +- lang/js/src/Connection.js | 123 +++++----- lang/js/src/Errors.js | 12 +- lang/js/src/Key.js | 287 ++++++++++------------ lang/js/src/Keyring.js | 26 +- lang/js/src/Message.js | 125 ++++------ lang/js/src/Signature.js | 74 ++++-- lang/js/src/gpgmejs.js | 77 ++++-- lang/js/unittest_inputvalues.js | 11 +- lang/js/unittests.js | 22 +- 11 files changed, 403 insertions(+), 394 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 5289eab7..9d956b69 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -86,7 +86,9 @@ const inputvalues = {// eslint-disable-line no-unused-vars 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + '=ioB6\n' + '-----END PGP SIGNATURE-----\n', - } + }, + + someInputParameter: 'bad string' }; // (Pseudo-)Random String covering all of utf8. @@ -158,27 +160,6 @@ function slightlyLessBoringString(megabytes, set){ return string.join(''); } -// Take a gpg looking string and destroy it a bit by changing random values -// eslint-disable-next-line no-unused-vars -function destroylegitimateGpg(string, mutations=5){ - const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/\n'; - for (let i=0; i < mutations.length; i++){ - // leave the first and last 35 chars (header/footer) intact - let position = Math.floor(Math.random() *(string.length - 70)) + 35; - let str0 = string.substring(0,position - 1); - let str1 = string.substring(position, position + 1); - let str2 = string.substring(position +1); - let success = false; - while (!success){ - let newchar = Math.floor(Math.random() * allowed.length); - if (newchar !== str1){ - string = str0 + newchar + str2; - success = true; - } - } - } -} - // Data encrypted with testKey const encryptedData =// eslint-disable-line no-unused-vars '-----BEGIN PGP MESSAGE-----\n' + diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index dae94025..1e2784d9 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -21,17 +21,28 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, Gpgmejs, inputvalues */ describe('GPGME context', function(){ it('Starting a GpgME instance', function(done){ let prm = Gpgmejs.init(); + const input = inputvalues.someInputParameter; prm.then( function(context){ expect(context).to.be.an('object'); expect(context.encrypt).to.be.a('function'); expect(context.decrypt).to.be.a('function'); + expect(context.sign).to.be.a('function'); + expect(context.verify).to.be.a('function'); + context.Keyring = input; + expect(context.Keyring).to.be.an('object'); + expect(context.Keyring).to.not.equal(input); + expect(context._Keyring).to.equal(context.Keyring); + expect(context.Keyring.getKeys).to.be.a('function'); + expect(context.Keyring.getDefaultKey).to.be.a('function'); + expect(context.Keyring.importKey).to.be.a('function'); + expect(context.Keyring.generateKey).to.be.a('function'); done(); }); }); -}); +}); \ No newline at end of file diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index d89fa724..d482667e 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -38,8 +38,19 @@ import { GPGME_Message, createMessage } from './Message'; export class Connection{ constructor(){ - this.connect(); - } + let _connection = chrome.runtime.connectNative('gpgmejson'); + + + /** + * Immediately closes an open port. + */ + this.disconnect = function () { + if (_connection){ + _connection.disconnect(); + _connection = null; + } + }; + /** * @typedef {Object} backEndDetails @@ -63,14 +74,15 @@ export class Connection{ * backend * @async */ - checkConnection(details = true){ + this.checkConnection = function(details = true){ + const msg = createMessage('version'); if (details === true) { - return this.post(createMessage('version')); + return this.post(msg); } else { let me = this; return new Promise(function(resolve) { Promise.race([ - me.post(createMessage('version')), + me.post(msg), new Promise(function(resolve, reject){ setTimeout(function(){ reject(gpgme_error('CONN_TIMEOUT')); @@ -83,26 +95,7 @@ export class Connection{ }); }); } - } - - /** - * Immediately closes an open port. - */ - disconnect() { - if (this._connection){ - this._connection.disconnect(); - this._connection = null; - } - } - - /** - * Opens a nativeMessaging port. - */ - connect(){ - if (!this._connection){ - this._connection = chrome.runtime.connectNative('gpgmejson'); - } - } + }; /** * Sends a {@link GPGME_Message} via tghe nativeMessaging port. It resolves @@ -113,65 +106,65 @@ export class Connection{ * @returns {Promise} The collected answer * @async */ - post(message){ + this.post = function (message){ if (!message || !(message instanceof GPGME_Message)){ this.disconnect(); return Promise.reject(gpgme_error( 'PARAM_WRONG', 'Connection.post')); } - if (message.isComplete !== true){ + if (message.isComplete() !== true){ this.disconnect(); return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } - let me = this; let chunksize = message.chunksize; return new Promise(function(resolve, reject){ let answer = new Answer(message); let listener = function(msg) { if (!msg){ - me._connection.onMessage.removeListener(listener); - me._connection.disconnect(); + _connection.onMessage.removeListener(listener); + _connection.disconnect(); reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); } else { let answer_result = answer.collect(msg); if (answer_result !== true){ - me._connection.onMessage.removeListener(listener); - me._connection.disconnect(); + _connection.onMessage.removeListener(listener); + _connection.disconnect(); reject(answer_result); } else { if (msg.more === true){ - me._connection.postMessage({ + _connection.postMessage({ 'op': 'getmore', 'chunksize': chunksize }); } else { - me._connection.onMessage.removeListener(listener); - me._connection.disconnect(); - if (answer.message instanceof Error){ - reject(answer.message); + _connection.onMessage.removeListener(listener); + _connection.disconnect(); + const message = answer.getMessage(); + if (message instanceof Error){ + reject(message); } else { - resolve(answer.message); + resolve(message); } } } } }; - me._connection.onMessage.addListener(listener); + _connection.onMessage.addListener(listener); if (permittedOperations[message.operation].pinentry){ - return me._connection.postMessage(message.message); + return _connection.postMessage(message.message); } else { return Promise.race([ - me._connection.postMessage(message.message), + _connection.postMessage(message.message), function(resolve, reject){ setTimeout(function(){ - me._connection.disconnect(); + _connection.disconnect(); reject(gpgme_error('CONN_TIMEOUT')); }, 5000); }]).then(function(result){ return result; }, function(reject){ if(!(reject instanceof Error)) { - me._connection.disconnect(); + _connection.disconnect(); return gpgme_error('GNUPG_ERROR', reject); } else { return reject; @@ -179,7 +172,8 @@ export class Connection{ }); } }); - } + }; +} } /** @@ -193,10 +187,16 @@ class Answer{ * @param {GPGME_Message} message */ constructor(message){ - this.operation = message.operation; - this.expect = message.expect; - } + const operation = message.operation; + const expect = message.expect; + let response_b64 = null; + this.getOperation = function(){ + return operation; + }; + this.getExpect = function(){ + return expect; + }; /** * Adds incoming base64 encoded data to the existing response * @param {*} msg base64 encoded data. @@ -204,34 +204,30 @@ class Answer{ * * @private */ - collect(msg){ + this.collect = function (msg){ if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) { return gpgme_error('CONN_UNEXPECTED_ANSWER'); } - if (this._responseb64 === undefined){ - //this._responseb64 = [msg.response]; - this._responseb64 = msg.response; + if (response_b64 === null){ + response_b64 = msg.response; return true; } else { - //this._responseb64.push(msg.response); - this._responseb64 += msg.response; + response_b64 += msg.response; return true; } - } - - /** + }; + /** * Returns the base64 encoded answer data with the content verified against * {@link permittedOperations}. */ - get message(){ - if (this._responseb64 === undefined){ + this.getMessage = function (){ + if (response_b64 === undefined){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } - // let _decodedResponse = JSON.parse(atob(this._responseb64.join(''))); - let _decodedResponse = JSON.parse(atob(this._responseb64)); + let _decodedResponse = JSON.parse(atob(response_b64)); let _response = {}; let messageKeys = Object.keys(_decodedResponse); - let poa = permittedOperations[this.operation].answer; + let poa = permittedOperations[this.getOperation()].answer; if (messageKeys.length === 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } @@ -262,7 +258,7 @@ class Answer{ } if (_decodedResponse.base64 === true && poa.data[key] === 'string' - && this.expect === undefined + && this.getExpect() === undefined ){ _response[key] = decodeURIComponent( atob(_decodedResponse[key]).split('').map( @@ -277,5 +273,6 @@ class Answer{ } } return _response; - } + }; +} } diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index cb5c94c2..0cf1af19 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -143,7 +143,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ * @extends Error */ class GPGME_Error extends Error{ - constructor(code, msg=''){ + constructor(code = 'GENERIC_ERROR', msg=''){ if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){ super(msg); } else if (err_list.hasOwnProperty(code)){ @@ -155,12 +155,12 @@ class GPGME_Error extends Error{ } else { super(err_list['GENERIC_ERROR'].msg); } - this.code = code || 'GENERIC_ERROR'; - } - set code(value){ - this._code = value; + this.getCode = function(){ + return code; + }; } + get code(){ - return this._code; + return this.getCode(); } } \ No newline at end of file diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index b024a77b..a7f7dd26 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -28,13 +28,16 @@ import { createMessage } from './Message'; /** * Validates the given fingerprint and creates a new {@link GPGME_Key} * @param {String} fingerprint + * @param {Boolean} async If True, Key properties (except fingerprint) will be + * queried from gnupg on each call, making the operation up-to-date, the + * answers will be Promises, and the performance will likely suffer * @returns {GPGME_Key|GPGME_Error} */ -export function createKey(fingerprint){ - if (!isFingerprint(fingerprint)){ +export function createKey(fingerprint, async = false){ + if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){ return gpgme_error('PARAM_WRONG'); } - else return new GPGME_Key(fingerprint); + else return new GPGME_Key(fingerprint, async); } /** @@ -48,31 +51,30 @@ export function createKey(fingerprint){ */ export class GPGME_Key { - constructor(fingerprint){ - this.fingerprint = fingerprint; - } + constructor(fingerprint, async){ - set fingerprint(fpr){ - if (isFingerprint(fpr) === true) { - if (this._data === undefined) { - this._data = {fingerprint: fpr}; - } else { - if (this._data.fingerprint === undefined){ - this._data.fingerprint = fpr; - } + /** + * @property {Boolean} If true, most answers will be asynchronous + */ + this.isAsync = async; + + let _data = {fingerprint: fingerprint}; + this.getFingerprint = function(){ + if (!_data.fingerprint || !isFingerprint(_data.fingerprint)){ + return gpgme_error('KEY_INVALID'); } - } - } + return _data.fingerprint; + }; /** - * @returns {String} The fingerprint defining this Key + * Property indicating if the Key possesses a private/secret part. If this + * information is not yet cached, it returns an {@link GPGME_Error} with + * code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case. + * @returns {Boolean} If the Key has a secret subkey. */ - get fingerprint(){ - if (!this._data || !this._data.fingerprint){ - return gpgme_error('KEY_INVALID'); - } - return this._data.fingerprint; - } + this.hasSecret= function (){ + return this.get('hasSecret', true); + }; /** * @param {Object} data Bulk set the data for this key, with an Object sent @@ -81,97 +83,89 @@ export class GPGME_Key { * error if something went wrong * @private */ - setKeyData(data){ - if (this._data === undefined) { - this._data = {}; + this.setKeyData = function (data){ + if (typeof(data) !== 'object') { + return gpgme_error('KEY_INVALID'); } - if ( - typeof(data) !== 'object') { + if (!data.fingerprint || data.fingerprint !== _data.fingerprint){ return gpgme_error('KEY_INVALID'); } - if (!this._data.fingerprint && isFingerprint(data.fingerprint)){ - if (data.fingerprint !== this.fingerprint){ - return gpgme_error('KEY_INVALID'); - } - this._data.fingerprint = data.fingerprint; - } else if (this._data.fingerprint !== data.fingerprint){ + let keys = Object.keys(data); + for (let i=0; i< keys.length; i++){ + if (!validKeyProperties.hasOwnProperty(keys[i])){ return gpgme_error('KEY_INVALID'); } - let dataKeys = Object.keys(data); - for (let i=0; i< dataKeys.length; i++){ - if (!validKeyProperties.hasOwnProperty(dataKeys[i])){ - return gpgme_error('KEY_INVALID'); - } - if (validKeyProperties[dataKeys[i]](data[dataKeys[i]]) !== true ){ - return gpgme_error('KEY_INVALID'); - } - switch (dataKeys[i]){ + //running the defined validation function + if (validKeyProperties[keys[i]](data[keys[i]]) !== true ){ + return gpgme_error('KEY_INVALID'); + } + switch (keys[i]){ case 'subkeys': - this._data.subkeys = []; + _data.subkeys = []; for (let i=0; i< data.subkeys.length; i++) { - this._data.subkeys.push( + _data.subkeys.push( new GPGME_Subkey(data.subkeys[i])); } break; case 'userids': - this._data.userids = []; + _data.userids = []; for (let i=0; i< data.userids.length; i++) { - this._data.userids.push( + _data.userids.push( new GPGME_UserId(data.userids[i])); } break; case 'last_update': - this._data[dataKeys[i]] = new Date( data[dataKeys[i]] * 1000 ); + _data[keys[i]] = new Date( data[keys[i]] * 1000 ); break; default: - this._data[dataKeys[i]] = data[dataKeys[i]]; + _data[keys[i]] = data[keys[i]]; } } return this; - } + }; /** * Query any property of the Key listed in {@link validKeyProperties} * @param {String} property property to be retreived - * @param {Boolean} cached (optional) if false, the data will be directly - * queried from gnupg, and the operation will be asynchronous. Else, the - * data will be fetched from the state of the initialization of the Key. - * The cached mode may contain outdated information, but can be used as - * synchronous operation, where the backend is not expected to change Keys - * during a session. The key still can be reloaded by invoking - * {@link refreshKey}. * @returns {*|Promise<*>} the value (Boolean, String, Array, Object). * If 'cached' is false, the value will be resolved as a Promise. */ - get(property, cached=true) { - if (cached === false) { + this.get = function(property) { + if (this.isAsync === true) { let me = this; return new Promise(function(resolve, reject) { - if (!validKeyProperties.hasOwnProperty(property)){ - reject('PARAM_WRONG'); - } else if (property === 'armored'){ + if (property === 'armored'){ resolve(me.getArmor()); } else if (property === 'hasSecret'){ resolve(me.getHasSecret()); - } else { - me.refreshKey().then(function(key){ - resolve(key.get(property, true)); + } else if (validKeyProperties.hasOwnProperty(property)){ + let msg = createMessage('keylist'); + msg.setParameter('keys', _data.fingerprint); + msg.post().then(function(result){ + if (result.keys && result.keys.length === 1 && + result.keys[0].hasOwnProperty(property)){ + resolve(result.keys[0][property]); + } else { + reject(gpgme_error('CONN_UNEXPECTED_ANSWER')); + } }, function(error){ - reject(error); + reject(gpgme_error(error)); }); + } else { + reject(gpgme_error('PARAM_WRONG')); } }); } else { if (!validKeyProperties.hasOwnProperty(property)){ return gpgme_error('PARAM_WRONG'); } - if (!this._data.hasOwnProperty(property)){ + if (!_data.hasOwnProperty(property)){ return gpgme_error('KEY_NO_INIT'); } else { - return (this._data[property]); + return (_data[property]); } } - } + }; /** * Reloads the Key information from gnupg. This is only useful if you use @@ -181,15 +175,15 @@ export class GPGME_Key { * @returns {Promise} * @async */ - refreshKey() { + this.refreshKey = function() { let me = this; return new Promise(function(resolve, reject) { - if (!me._data.fingerprint){ + if (!_data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('keylist'); msg.setParameter('sigs', true); - msg.setParameter('keys', me._data.fingerprint); + msg.setParameter('keys', _data.fingerprint); msg.post().then(function(result){ if (result.keys.length === 1){ me.setKeyData(result.keys[0]); @@ -209,7 +203,7 @@ export class GPGME_Key { reject(gpgme_error('GNUPG_ERROR'), error); }); }); - } + }; /** * Query the armored block of the Key directly from gnupg. Please note that @@ -217,23 +211,22 @@ export class GPGME_Key { * @returns {Promise} * @async */ - getArmor(){ - let me = this; + this.getArmor = function(){ return new Promise(function(resolve, reject) { - if (!me._data.fingerprint){ + if (!_data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('export'); msg.setParameter('armor', true); - msg.setParameter('keys', me._data.fingerprint); + msg.setParameter('keys', _data.fingerprint); msg.post().then(function(result){ - me._data.armored = result.data; + _data.armored = result.data; resolve(result.data); }, function(error){ reject(error); }); }); - } + }; /** * Find out if the Key includes a secret part. Note that this is a rather @@ -244,59 +237,32 @@ export class GPGME_Key { * available in the gnupg Keyring * @async */ - getHasSecret(){ - let me = this; + this.getHasSecret = function (){ return new Promise(function(resolve, reject) { - if (!me._data.fingerprint){ + if (!_data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('keylist'); - msg.setParameter('keys', me._data.fingerprint); + msg.setParameter('keys', _data.fingerprint); msg.setParameter('secret', true); msg.post().then(function(result){ - me._data.hasSecret = null; + _data.hasSecret = null; if ( result.keys && result.keys.length === 1 && result.keys[0].secret === true ) { - me._data.hasSecret = true; + _data.hasSecret = true; resolve(true); } else { - me._data.hasSecret = false; + _data.hasSecret = false; resolve(false); } }, function(error){ reject(error); }); }); - } - - /** - * Convenience functions to be directly used as properties of the Key - * Notice that these rely on cached info and may be outdated. Use the async - * get(property, false) if you need the most current info - */ - - /** - * Property for the export of armored Key. If the armored Key is not - * cached, it returns an {@link GPGME_Error} with code 'KEY_NO_INIT'. - * Running {@link refreshKey} may help in this case. - * @returns {String|GPGME_Error} The armored public Key block. - */ - get armored(){ - return this.get('armored', true); - } - - /** - * Property indicating if the Key possesses a private/secret part. If this - * information is not yet cached, it returns an {@link GPGME_Error} with - * code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case. - * @returns {Boolean} If the Key has a secret subkey. - */ - get hasSecret(){ - return this.get('hasSecret', true); - } + }; /** * Deletes the (public) Key from the GPG Keyring. Note that a deletion of a @@ -304,20 +270,37 @@ export class GPGME_Key { * @returns {Promise} Success if key was deleted, * rejects with a GPG error otherwise. */ - delete(){ - let me = this; + this.delete= function (){ return new Promise(function(resolve, reject){ - if (!me._data.fingerprint){ + if (!_data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('delete'); - msg.setParameter('key', me._data.fingerprint); + msg.setParameter('key', _data.fingerprint); msg.post().then(function(result){ resolve(result.success); }, function(error){ reject(error); }); }); + }; + } + + /** + * @returns {String} The fingerprint defining this Key + */ + get fingerprint(){ + return this.getFingerprint(); + } + + /** + * Property for the export of armored Key. If the armored Key is not + * cached, it returns an {@link GPGME_Error} with code 'KEY_NO_INIT'. + * Running {@link refreshKey} may help in this case. + * @returns {String|GPGME_Error} The armored public Key block. + */ + get armored(){ + return this.get('armored', true); } } @@ -334,44 +317,45 @@ class GPGME_Subkey { * @private */ constructor(data){ + let _data = {}; let keys = Object.keys(data); - for (let i=0; i< keys.length; i++) { - this.setProperty(keys[i], data[keys[i]]); - } - } - /** + /** * Validates a subkey property against {@link validSubKeyProperties} and * sets it if validation is successful * @param {String} property * @param {*} value * @param private */ - setProperty(property, value){ - if (!this._data){ - this._data = {}; - } + const setProperty = function (property, value){ if (validSubKeyProperties.hasOwnProperty(property)){ if (validSubKeyProperties[property](value) === true) { if (property === 'timestamp' || property === 'expires'){ - this._data[property] = new Date(value * 1000); + _data[property] = new Date(value * 1000); } else { - this._data[property] = value; + _data[property] = value; } } } + }; + for (let i=0; i< keys.length; i++) { + setProperty(keys[i], data[keys[i]]); } + + /** * Fetches any information about this subkey * @param {String} property Information to request * @returns {String | Number | Date} */ - get(property) { - if (this._data.hasOwnProperty(property)){ - return (this._data[property]); + this.get = function(property) { + if (_data.hasOwnProperty(property)){ + return (_data[property]); } - } + }; +} + } /** @@ -387,11 +371,23 @@ class GPGME_UserId { * @private */ constructor(data){ + let _data = {}; let keys = Object.keys(data); + const setProperty = function(property, value){ + if (validUserIdProperties.hasOwnProperty(property)){ + if (validUserIdProperties[property](value) === true) { + if (property === 'last_update'){ + _data[property] = new Date(value*1000); + } else { + _data[property] = value; + } + } + } + }; for (let i=0; i< keys.length; i++) { - this.setProperty(keys[i], data[keys[i]]); + setProperty(keys[i], data[keys[i]]); } - } + /** * Validates a subkey property against {@link validUserIdProperties} and * sets it if validation is successful @@ -399,34 +395,21 @@ class GPGME_UserId { * @param {*} value * @param private */ - setProperty(property, value){ - if (!this._data){ - this._data = {}; - } - if (validUserIdProperties.hasOwnProperty(property)){ - if (validUserIdProperties[property](value) === true) { - if (property === 'last_update'){ - this._data[property] = new Date(value*1000); - } else { - this._data[property] = value; - } - } - } - } /** * Fetches information about the user * @param {String} property Information to request * @returns {String | Number} */ - get(property) { - if (this._data.hasOwnProperty(property)){ - return (this._data[property]); + this.get = function (property) { + if (_data.hasOwnProperty(property)){ + return (_data[property]); } - } + }; } +} /** * Validation definition for userIds. Each valid userId property is represented * as a key- Value pair, with their value being a validation function to check diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index f2a71389..d863fe73 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -32,7 +32,6 @@ import { gpgme_error } from './Errors'; */ export class GPGME_Keyring { constructor(){ - } /** * Queries Keys (all Keys or a subset) from gnupg. @@ -50,7 +49,7 @@ export class GPGME_Keyring { * @static * @async */ - getKeys(pattern, prepare_sync=false, search=false){ + this.getKeys = function(pattern, prepare_sync=false, search=false){ return new Promise(function(resolve, reject) { let msg = createMessage('keylist'); if (pattern !== undefined && pattern !== null){ @@ -107,7 +106,7 @@ export class GPGME_Keyring { } }); }); - } + }; /** * @typedef {Object} exportResult The result of a getKeysArmored operation. @@ -131,7 +130,7 @@ export class GPGME_Keyring { * @static * @async */ - getKeysArmored(pattern, with_secret_fpr) { + this.getKeysArmored = function(pattern, with_secret_fpr) { return new Promise(function(resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); @@ -153,7 +152,7 @@ export class GPGME_Keyring { reject(error); }); }); - } + }; /** * Returns the Key used by default in gnupg. @@ -165,7 +164,7 @@ export class GPGME_Keyring { * @async * @static */ - getDefaultKey() { + this.getDefaultKey = function() { let me = this; return new Promise(function(resolve, reject){ let msg = createMessage('config_opt'); @@ -206,7 +205,7 @@ export class GPGME_Keyring { reject(error); }); }); - } + }; /** * @typedef {Object} importResult The result of a Key update @@ -244,7 +243,7 @@ export class GPGME_Keyring { * @async * @static */ - importKey(armored, prepare_sync) { + this.importKey = function (armored, prepare_sync) { let feedbackValues = ['considered', 'no_user_id', 'imported', 'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys', 'new_signatures', 'new_revocations', 'secret_read', @@ -323,7 +322,7 @@ export class GPGME_Keyring { }); - } + }; /** * Convenience function for deleting a Key. See {@link Key.delete} for @@ -333,14 +332,14 @@ export class GPGME_Keyring { * @async * @static */ - deleteKey(fingerprint){ + this.deleteKey = function(fingerprint){ if (isFingerprint(fingerprint) === true) { let key = createKey(fingerprint); return key.delete(); } else { return Promise.reject(gpgme_error('KEY_INVALID')); } - } + }; /** * Generates a new Key pair directly in gpg, and returns a GPGME_Key @@ -356,7 +355,7 @@ export class GPGME_Keyring { * @return {Promise} * @async */ - generateKey(userId, algo = 'default', expires){ + this.generateKey = function (userId, algo = 'default', expires){ if ( typeof(userId) !== 'string' || supportedKeyAlgos.indexOf(algo) < 0 || @@ -385,7 +384,8 @@ export class GPGME_Keyring { reject(error); }); }); - } + }; +} } /** diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 2e38142c..cf9f84ef 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -52,22 +52,14 @@ export function createMessage(operation){ export class GPGME_Message { constructor(operation){ - this.operation = operation; - } + let _msg = { + op: operation, + chunksize: 1023* 1024 + }; - set operation (op){ - if (typeof(op) === 'string'){ - if (!this._msg){ - this._msg = {}; - } - if (!this._msg.op & permittedOperations.hasOwnProperty(op)){ - this._msg.op = op; - } - } - } - get operation(){ - return this._msg.op; - } + this.getOperation = function(){ + return _msg.op; + }; /** * The maximum size of responses from gpgme in bytes. As of July 2018, @@ -78,41 +70,23 @@ export class GPGME_Message { * messages will be received in chunks. * If the value is not explicitly specified, 1023 KB is used. */ - set chunksize(value){ + this.setChunksize = function (value){ if ( Number.isInteger(value) && value > 10 * 1024 && value <= 1024 * 1024 ){ - this._chunksize = value; - } - } - get chunksize(){ - if (this._chunksize === undefined){ - return 1024 * 1023; - } else { - return this._chunksize; + _msg.chunksize = value; } - } + }; - /** - * Expect indicates which format data is expected to be in. It currently - * only supports 'base64', indicating that the response data from gnupg are - * expected to be base64 encoded binary - */ - set expect(value){ - if (value ==='base64'){ - this._expect = value; - } - } - - get expect(){ - if ( this._expect === 'base64'){ - return this._expect; - } - return undefined; - } + this.getMsg = function(){ + return _msg; + }; + this.getChunksize= function() { + return _msg.chunksize; + }; /** * Sets a parameter for the message. It validates with @@ -121,11 +95,11 @@ export class GPGME_Message { * @param {any} value Value to set * @returns {Boolean} If the parameter was set successfully */ - setParameter( param,value ){ + this.setParameter = function ( param,value ){ if (!param || typeof(param) !== 'string'){ return gpgme_error('PARAM_WRONG'); } - let po = permittedOperations[this._msg.op]; + let po = permittedOperations[_msg.op]; if (!po){ return gpgme_error('MSG_WRONG_OP'); } @@ -195,59 +169,42 @@ export class GPGME_Message { return gpgme_error('PARAM_WRONG'); } } - this._msg[param] = value; + _msg[param] = value; return true; - } + }; + + /** * Check if the message has the minimum requirements to be sent, that is * all 'required' parameters according to {@link permittedOperations}. * @returns {Boolean} true if message is complete. */ - get isComplete(){ - if (!this._msg.op){ + this.isComplete = function(){ + if (!_msg.op){ return false; } let reqParams = Object.keys( - permittedOperations[this._msg.op].required); - let msg_params = Object.keys(this._msg); + permittedOperations[_msg.op].required); + let msg_params = Object.keys(_msg); for (let i=0; i < reqParams.length; i++){ if (msg_params.indexOf(reqParams[i]) < 0){ return false; } } return true; - } - - /** - * Returns the prepared message with parameters and completeness checked - * @returns {Object|null} Object to be posted to gnupg, or null if - * incomplete - */ - get message(){ - if (this.isComplete === true){ - this._msg.chunksize = this.chunksize; - return this._msg; - } - else { - return null; - } - - } - + }; /** * Sends the Message via nativeMessaging and resolves with the answer. * @returns {Promise} * @async */ - post(){ + this.post = function(){ let me = this; return new Promise(function(resolve, reject) { - if (me.isComplete === true) { + if (me.isComplete() === true) { + let conn = new Connection; - if (me._msg.chunksize === undefined){ - me._msg.chunksize = me.chunksize; - } conn.post(me).then(function(response) { resolve(response); }, function(reason) { @@ -258,5 +215,27 @@ export class GPGME_Message { reject(gpgme_error('MSG_INCOMPLETE')); } }); + }; +} + + /** + * Returns the prepared message with parameters and completeness checked + * @returns {Object|null} Object to be posted to gnupg, or null if + * incomplete + */ + get message(){ + if (this.isComplete() === true){ + return this.getMsg(); + } + else { + return null; + } } + +get operation(){ + return this.getOperation(); +} +get chunksize(){ + return this.getChunksize(); +} } diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index 191e00ab..ff4278ad 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -82,44 +82,47 @@ export function createSignature(sigObject){ class GPGME_Signature { constructor(sigObject){ - this._rawSigObject = sigObject; - } + let _rawSigObject = sigObject; - get fingerprint(){ - return this._rawSigObject.fingerprint; - } + this.getFingerprint = function(){ + if (!_rawSigObject.fingerprint){ + return gpgme_error('SIG_WRONG'); + } else { + return _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){ + this.getExpiration = function(){ + if (!_rawSigObject.exp_timestamp){ return null; } - return new Date(this._rawSigObject.exp_timestamp* 1000); - } + return new Date(_rawSigObject.exp_timestamp* 1000); + }; /** * The creation date of this Signature in Javascript Date * @returns {Date} */ - get timestamp(){ - return new Date(this._rawSigObject.timestamp * 1000); - } + this.getTimestamp= function (){ + return new Date(_rawSigObject.timestamp * 1000); + }; /** * The overall validity of the key. If false, errorDetails may contain * additional information */ - get valid() { - if (this._rawSigObject.summary.valid === true){ + this.getValid= function() { + if (_rawSigObject.summary.valid === true){ return true; } else { return false; } - } + }; /** * gives more information on non-valid signatures. Refer to the gpgme docs @@ -127,19 +130,54 @@ class GPGME_Signature { * details on the values * @returns {Object} Object with boolean properties */ - get errorDetails(){ + this.getErrorDetails = function (){ 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]]; + if ( _rawSigObject.hasOwnProperty(properties[i]) ){ + result[properties[i]] = _rawSigObject[properties[i]]; } } return result; + }; +} + + /** + * Convenience getter for {@link getFingerprint} + */ + get fingerprint(){ + return this.getFingerprint(); } + /** + * Convenience getter for {@link getExpiration} + */ + get expiration(){ + return this.getExpiration(); + } + + /** + * Convenience getter for {@link getTimeStamp} + */ + get timestamp(){ + return this.getTimestamp(); + } + + /** + * Convenience getter for {@link getValid} + */ + get valid(){ + return this.getValid(); + } + + /** + * Convenience getter for {@link getErrorDetails} + */ + get errorDetails(){ + return this.getErrorDetails(); + } } /** diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 3f6dc947..f587e854 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -22,8 +22,8 @@ */ -import {GPGME_Message, createMessage} from './Message'; -import {toKeyIdArray} from './Helpers'; +import { GPGME_Message, createMessage } from './Message'; +import { toKeyIdArray } from './Helpers'; import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; import { createSignature } from './Signature'; @@ -85,23 +85,27 @@ import { createSignature } from './Signature'; export class GpgME { constructor(){ - } + let _Keyring = null; - set Keyring(keyring){ - if (keyring && keyring instanceof GPGME_Keyring){ - this._Keyring = keyring; - } - } + /** + * Sets a new Keyring to be used + * @param {GPGME_Keyring} keyring + */ + this.setKeyring = function(keyring){ + if (keyring && keyring instanceof GPGME_Keyring){ + _Keyring = keyring; + } + }; - /** - * Accesses the {@link GPGME_Keyring}. - */ - get Keyring(){ - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring; - } - return this._Keyring; - } + /** + * Accesses the {@link GPGME_Keyring}. + */ + this.getKeyring = function(){ + if (!_Keyring){ + _Keyring = new GPGME_Keyring; + } + return _Keyring; + }; /** * Encrypt (and optionally sign) data @@ -123,8 +127,8 @@ export class GpgME { * message and additional info. * @async */ - encrypt(data, publicKeys, secretKeys, base64=false, armor=true, - wildcard=false, additional = {} + this.encrypt = function (data, publicKeys, secretKeys, base64=false, + armor=true, wildcard=false, additional = {} ){ let msg = createMessage('encrypt'); if (msg instanceof Error){ @@ -152,12 +156,12 @@ export class GpgME { additional[additional_Keys[k]]); } } - if (msg.isComplete === true){ + if (msg.isComplete() === true){ return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } - } + }; /** * Decrypts a Message @@ -168,7 +172,7 @@ export class GpgME { * @returns {Promise} Decrypted Message and information * @async */ - decrypt(data, base64=false){ + this.decrypt = function (data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -203,7 +207,7 @@ export class GpgME { reject(error); }); }); - } + }; /** * Sign a Message @@ -217,7 +221,7 @@ export class GpgME { * @returns {Promise} * @async */ - sign(data, keys, mode='clearsign', base64=false) { + this.sign = function (data, keys, mode='clearsign', base64=false) { if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } @@ -252,7 +256,7 @@ export class GpgME { reject(error); }); }); - } + }; /** * Verifies data. @@ -264,7 +268,7 @@ export class GpgME { * @returns {Promise} *@async */ - verify(data, signature, base64 = false){ + this.verify= function (data, signature, base64 = false){ let msg = createMessage('verify'); let dt = putData(msg, data); if (dt instanceof Error){ @@ -297,6 +301,25 @@ export class GpgME { reject(error); }); }); + }; +} + + /** + * setter for {@link setKeyring}. + * @param {GPGME_Keyring} keyring A Keyring to use + */ + set Keyring(keyring){ + this.setKeyring(keyring); + } + + /** + * Accesses the {@link GPGME_Keyring}. + */ + get Keyring(){ + if (!this._Keyring){ + this._Keyring = new GPGME_Keyring; + } + return this._Keyring; } } @@ -309,7 +332,7 @@ export class GpgME { * @private */ function putData(message, data){ - if (!message || !(message instanceof GPGME_Message) ) { + if (!message || !message instanceof GPGME_Message) { return gpgme_error('PARAM_WRONG'); } if (!data){ diff --git a/lang/js/unittest_inputvalues.js b/lang/js/unittest_inputvalues.js index 07147bac..02bb5329 100644 --- a/lang/js/unittest_inputvalues.js +++ b/lang/js/unittest_inputvalues.js @@ -1,12 +1,9 @@ -import {Connection} from './src/Connection'; import {createKey} from './src/Key'; -let conn = new Connection; - export const helper_params = { validLongId: '0A0A0A0A0A0A0A0A', validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3', - createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), + createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'), 'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'], validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', @@ -15,11 +12,11 @@ export const helper_params = { invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)], invalidKeyArray: {curiosity:'uncat'}, invalidKeyArray_OneBad: [ - createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), + createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'), 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], invalidErrorCode: 'Please type in all your passwords.', - validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), + validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', true), valid_openpgplike: { primaryKey: { getFingerprint: function(){ return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';} @@ -36,7 +33,7 @@ export const message_params = { invalid_param_names: [22,'dance', {}], validparam_name_0: 'mime', invalid_values_0: [2134, 'All your passwords', - createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), null] + createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null] } }; diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 04e15ef3..6228993b 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -194,16 +194,16 @@ function unittests (){ }); it('Non-cached key async data retrieval', function (done){ - let key = createKey(kp.validKeyFingerprint); - key.get('can_authenticate',false).then(function(result){ + let key = createKey(kp.validKeyFingerprint, true); + key.get('can_authenticate').then(function(result){ expect(result).to.be.a('boolean'); done(); }); }); it('Non-cached key async armored Key', function (done){ - let key = createKey(kp.validKeyFingerprint); - key.get('armored', false).then(function(result){ + let key = createKey(kp.validKeyFingerprint, true); + key.get('armored').then(function(result){ expect(result).to.be.a('string'); expect(result).to.include('KEY BLOCK-----'); done(); @@ -211,17 +211,17 @@ function unittests (){ }); it('Non-cached key async hasSecret', function (done){ - let key = createKey(kp.validKeyFingerprint); - key.get('hasSecret', false).then(function(result){ + let key = createKey(kp.validKeyFingerprint, true); + key.get('hasSecret').then(function(result){ expect(result).to.be.a('boolean'); done(); }); }); it('Non-cached key async hasSecret (no secret in Key)', function (done){ - let key = createKey(kp.validFingerprintNoSecret); + let key = createKey(kp.validFingerprintNoSecret, true); expect(key).to.be.an.instanceof(GPGME_Key); - key.get('hasSecret', false).then(function(result){ + key.get('hasSecret').then(function(result){ expect(result).to.be.a('boolean'); expect(result).to.equal(false); done(); @@ -317,7 +317,7 @@ function unittests (){ let test0 = createMessage('encrypt'); expect(test0).to.be.an.instanceof(GPGME_Message); - expect(test0.isComplete).to.be.false; + expect(test0.isComplete()).to.be.false; }); it('Message is complete after setting mandatory data', function(){ @@ -325,14 +325,14 @@ function unittests (){ test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); - expect(test0.isComplete).to.be.true; + expect(test0.isComplete()).to.be.true; }); it('Message is not complete after mandatory data is empty', function(){ let test0 = createMessage('encrypt'); test0.setParameter('data', ''); test0.setParameter('keys', hp.validFingerprints); - expect(test0.isComplete).to.be.false; + expect(test0.isComplete()).to.be.false; }); it('Complete Message contains the data that was set', function(){ -- cgit From e16a87e83910ebb6bfdc4148369165f121f0997e Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 30 Jul 2018 12:31:27 +0200 Subject: js: Making objects inmutable -- * An Object.freeze should stop any malicious third party from changing objects' methods once the objects are instantiated (see unittest for an approach that would have worked before) - An initialized gpgmejs- object doesn't have a '_Keyring' property anymore (it still has its 'Keyring') - The internal expect='base64' needed to be turned into a method. --- lang/js/BrowserTestExtension/tests/startup.js | 1 - lang/js/src/Connection.js | 9 +++++---- lang/js/src/Errors.js | 6 +++--- lang/js/src/Key.js | 10 +++++----- lang/js/src/Message.js | 14 ++++++++++++-- lang/js/src/Signature.js | 2 +- lang/js/src/gpgmejs.js | 9 +++------ lang/js/src/index.js | 4 ++-- lang/js/unittests.js | 16 ++++++++++++++++ 9 files changed, 47 insertions(+), 24 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index 1e2784d9..63358aa9 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -37,7 +37,6 @@ describe('GPGME context', function(){ context.Keyring = input; expect(context.Keyring).to.be.an('object'); expect(context.Keyring).to.not.equal(input); - expect(context._Keyring).to.equal(context.Keyring); expect(context.Keyring.getKeys).to.be.a('function'); expect(context.Keyring.getDefaultKey).to.be.a('function'); expect(context.Keyring.importKey).to.be.a('function'); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 561a5b70..b0105757 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -118,7 +118,7 @@ export class Connection{ } let chunksize = message.chunksize; return new Promise(function(resolve, reject){ - let answer = new Answer(message); + let answer = Object.freeze(new Answer(message)); let listener = function(msg) { if (!msg){ _connection.onMessage.removeListener(listener); @@ -188,14 +188,15 @@ class Answer{ */ constructor(message){ const operation = message.operation; - const expect = message.expect; + const expected = message.getExpect(); let response_b64 = null; this.getOperation = function(){ return operation; }; + this.getExpect = function(){ - return expect; + return expected; }; /** @@ -260,7 +261,7 @@ class Answer{ } if (_decodedResponse.base64 === true && poa.data[key] === 'string' - && this.getExpect() === undefined + && this.getExpect() !== 'base64' ){ _response[key] = decodeURIComponent( atob(_decodedResponse[key]).split('').map( diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index 0cf1af19..39e3a74a 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -119,7 +119,7 @@ const err_list = { export function gpgme_error(code = 'GENERIC_ERROR', info){ if (err_list.hasOwnProperty(code)){ if (err_list[code].type === 'error'){ - return new GPGME_Error(code); + return Object.freeze(new GPGME_Error(code)); } if (err_list[code].type === 'warning'){ // eslint-disable-next-line no-console @@ -127,10 +127,10 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ } return null; } else if (code === 'GNUPG_ERROR'){ - return new GPGME_Error(code, info); + return Object.freeze(new GPGME_Error(code, info)); } else { - return new GPGME_Error('GENERIC_ERROR'); + return Object.freeze(new GPGME_Error('GENERIC_ERROR')); } } diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index d5873a70..f431a283 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -37,7 +37,7 @@ export function createKey(fingerprint, async = false){ if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){ return gpgme_error('PARAM_WRONG'); } - else return new GPGME_Key(fingerprint, async); + else return Object.freeze(new GPGME_Key(fingerprint, async)); } /** @@ -104,15 +104,15 @@ export class GPGME_Key { case 'subkeys': _data.subkeys = []; for (let i=0; i< data.subkeys.length; i++) { - _data.subkeys.push( - new GPGME_Subkey(data.subkeys[i])); + _data.subkeys.push(Object.freeze( + new GPGME_Subkey(data.subkeys[i]))); } break; case 'userids': _data.userids = []; for (let i=0; i< data.userids.length; i++) { - _data.userids.push( - new GPGME_UserId(data.userids[i])); + _data.userids.push(Object.freeze( + new GPGME_UserId(data.userids[i]))); } break; case 'last_update': diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index c0b6ed57..e2c07344 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -36,7 +36,7 @@ export function createMessage(operation){ return gpgme_error('PARAM_WRONG'); } if (permittedOperations.hasOwnProperty(operation)){ - return new GPGME_Message(operation); + return Object.freeze(new GPGME_Message(operation)); } else { return gpgme_error('MSG_WRONG_OP'); } @@ -56,11 +56,21 @@ export class GPGME_Message { op: operation, chunksize: 1023* 1024 }; + let expected = null; this.getOperation = function(){ return _msg.op; }; + this.setExpect = function(value){ + if (value === 'base64'){ + expected = value; + } + }; + this.getExpect = function(){ + return expected; + }; + /** * The maximum size of responses from gpgme in bytes. As of July 2018, * most browsers will only accept answers up to 1 MB of size. @@ -204,7 +214,7 @@ export class GPGME_Message { return new Promise(function(resolve, reject) { if (me.isComplete() === true) { - let conn = new Connection; + let conn = Object.freeze(new Connection); conn.post(me).then(function(response) { resolve(response); }, function(reason) { diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index 0ee58e94..55131b01 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -66,7 +66,7 @@ export function createSignature(sigObject){ } } } - return new GPGME_Signature(sigObject); + return Object.freeze(new GPGME_Signature(sigObject)); } diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 720490d6..9154979d 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -102,7 +102,7 @@ export class GpgME { */ this.getKeyring = function(){ if (!_Keyring){ - _Keyring = new GPGME_Keyring; + _Keyring = Object.freeze(new GPGME_Keyring); } return _Keyring; }; @@ -241,7 +241,7 @@ export class GpgME { putData(msg, data); return new Promise(function(resolve,reject) { if (mode ==='detached'){ - msg.expect= 'base64'; + msg.setExpect('base64'); } msg.post().then( function(message) { if (mode === 'clearsign'){ @@ -319,10 +319,7 @@ export class GpgME { * Accesses the {@link GPGME_Keyring}. */ get Keyring(){ - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring; - } - return this._Keyring; + return this.getKeyring(); } } diff --git a/lang/js/src/index.js b/lang/js/src/index.js index dc613fc7..2fed95f9 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -34,11 +34,11 @@ import { Connection } from './Connection'; */ function init(){ return new Promise(function(resolve, reject){ - let connection = new Connection; + let connection = Object.freeze(new Connection); connection.checkConnection(false).then( function(result){ if (result === true) { - resolve(new GpgME()); + resolve(Object.freeze(new GpgME())); } else { reject(gpgme_error('CONN_NO_CONNECT')); } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 6228993b..3304b1eb 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -253,6 +253,22 @@ function unittests (){ expect(key.fingerprint.code).to.equal('KEY_INVALID'); } }); + + it('Overwriting getFingerprint does not work', function(){ + const evilFunction = function(){ + return 'bad Data'; + }; + let key = createKey(kp.validKeyFingerprint, true); + expect(key.fingerprint).to.equal(kp.validKeyFingerprint); + try { + key.getFingerprint = evilFunction; + } + catch(e) { + expect(e).to.be.an.instanceof(TypeError); + } + expect(key.fingerprint).to.equal(kp.validKeyFingerprint); + expect(key.getFingerprint).to.not.equal(evilFunction); + }); // TODO: tests for subkeys // TODO: tests for userids // TODO: some invalid tests for key/keyring -- cgit From 68a012deb3b501d7417778be12c88bd475a37cb5 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 1 Aug 2018 12:51:12 +0200 Subject: js: make init export immutable -- * src/index.js: The export now uses a freezed Object, which does not allow for simply overwriting the init method by e.g. a third-party library. * BrowsertestExtension: Added some tests trying if decryption of bad data properly fails --- lang/js/BrowserTestExtension/browsertest.html | 1 + lang/js/BrowserTestExtension/tests/decryptTest.js | 62 +++++++++++++++++++++++ lang/js/BrowserTestExtension/tests/inputvalues.js | 36 +++++++++++++ lang/js/src/index.js | 7 ++- 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/decryptTest.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index de8cd41a..a20cfe19 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -19,6 +19,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/decryptTest.js b/lang/js/BrowserTestExtension/tests/decryptTest.js new file mode 100644 index 00000000..c6b3a3c5 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/decryptTest.js @@ -0,0 +1,62 @@ +/* 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+ + * + * Author(s): + * Maximilian Krambach + */ + +/* global describe, it, before, expect, Gpgmejs */ +/* global bigString, inputvalues, sabotageMsg*/ + +describe('Decryption', function () { + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + + it('Decryption of random string fails', function (done) { + let data = bigString(20 * 1024); + context.decrypt(data).then( + function(){}, + function(error){ + expect(error).to.be.an('error'); + expect(error.code).to.equal('GNUPG_ERROR'); + done(); + }); + }); + + it('Decryption of slightly corrupted message fails', function (done) { + const data = bigString(10000); + context.encrypt(data, good_fpr).then(function(enc){ + context.decrypt(sabotageMsg(enc.data)).then( + function(){}, + function(error){ + expect(error).to.be.an('error'); + expect(error.code).to.equal('GNUPG_ERROR'); + done(); + }); + }); + }).timeout(5000); +}); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 9d956b69..1e8f1544 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -248,3 +248,39 @@ const ImportablePublicKey = {// eslint-disable-line no-unused-vars '=9WZ7\n' + '-----END PGP PUBLIC KEY BLOCK-----\n' }; + +/** + * Changes base64 encoded gpg messages + * @param {String} msg input message + * @param {Number} rate of changes as percentage of message length. + * @param {[Number, Number]} p begin and end of the message left untouched (to + * preserve) header/footer + */ +// eslint-disable-next-line no-unused-vars +function sabotageMsg(msg, rate = 0.01, p= [35,35]){ + const iterations = Math.floor(Math.random() * msg.length * rate) + 1; + const base64_set = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/'; + for (let i=0; i < iterations; i++){ + let str0, str1, str2; + const chosePosition = function(){ + let position = + Math.floor( Math.random() * (msg.length - p[0] + p[1])) + + p[0]; + str1 = msg.substring(position,position+1); + if (str1 === '\n'){ + chosePosition(); + } else { + str0 = msg.substring(0,position); + str2 = msg.substring(position +1); + } + }; + chosePosition(); + let new1 = function(){ + let n = base64_set[Math.floor(Math.random() * 64)]; + return (n === str1) ? new1() : n; + }; + msg = str0.concat(new1()).concat(str2); + } + return msg; +} diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 2fed95f9..51f07538 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -34,7 +34,7 @@ import { Connection } from './Connection'; */ function init(){ return new Promise(function(resolve, reject){ - let connection = Object.freeze(new Connection); + const connection = Object.freeze(new Connection); connection.checkConnection(false).then( function(result){ if (result === true) { @@ -48,6 +48,5 @@ function init(){ }); } -export default { - init: init -}; \ No newline at end of file +const exportvalue = Object.freeze({init:init}); +export default exportvalue; \ No newline at end of file -- cgit From 622db0d1de665dfd93c991cd2d517078b04b3a13 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 16 Aug 2018 11:25:50 +0200 Subject: js: consistently return uppercase fingerprint -- * src/Key.js: the fingerprint returned by a Key is now always upper case hex, even if the constructor had lower case input. This is to be more consistent with gpgme and to be more readable and reliable in comparisions. --- lang/js/BrowserTestExtension/browsertest.html | 1 + lang/js/BrowserTestExtension/tests/KeyInfos.js | 46 +++++++++++++++++++++++ lang/js/BrowserTestExtension/tests/inputvalues.js | 1 + lang/js/src/Key.js | 5 ++- 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/KeyInfos.js (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index a20cfe19..0d3e2936 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -15,6 +15,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/KeyInfos.js b/lang/js/BrowserTestExtension/tests/KeyInfos.js new file mode 100644 index 00000000..03773a44 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/KeyInfos.js @@ -0,0 +1,46 @@ +/* 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+ + * + * Author(s): + * Maximilian Krambach + */ + +/* global describe, it, expect, before, Gpgmejs */ +/* global inputvalues, fixedLengthString */ + +describe('Key information', function () { + let context = null; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + + it('A fingerprint is consistently returned upper case hex', function(done){ + const mixedCase = inputvalues.encrypt.good.fingerprint_mixedcase; + context.Keyring.getKeys(mixedCase).then(function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(1); + expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase()); + done(); + }); + }); +}); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 1e8f1544..7dda47cd 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -28,6 +28,7 @@ const inputvalues = {// eslint-disable-line no-unused-vars // Fingerprint of a key that has been imported to gnupg // (i.e. see testkey.pub; testkey.sec) fingerprint : 'D41735B91236FDB882048C5A2301635EEFF0CB05', + fingerprint_mixedcase: 'D41735B91236fdb882048C5A2301635eeFF0Cb05', data_nonascii: '¡Äußerste µ€ før ñoquis@hóme! Добрый день', // used for checking encoding consistency in > 2MB messages. diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 88c49d3f..eeb27035 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -58,7 +58,7 @@ export class GPGME_Key { */ this.isAsync = async; - let _data = {fingerprint: fingerprint}; + let _data = {fingerprint: fingerprint.toUpperCase()}; this.getFingerprint = function(){ if (!_data.fingerprint || !isFingerprint(_data.fingerprint)){ return gpgme_error('KEY_INVALID'); @@ -88,7 +88,8 @@ export class GPGME_Key { if (typeof(data) !== 'object') { return gpgme_error('KEY_INVALID'); } - if (!data.fingerprint || data.fingerprint !== _data.fingerprint){ + if (!data.fingerprint || + data.fingerprint.toUpperCase() !== _data.fingerprint){ return gpgme_error('KEY_INVALID'); } let keys = Object.keys(data); -- cgit From 90cb4a684211fe5630f209ba61510e8be3129eae Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Thu, 16 Aug 2018 17:58:11 +0200 Subject: js: importKey feedback refactor -- * src/Keyring.js: An empty result should no longer cause an error, the import feedback summary has been refactored slightly * Browsertests to reflect import feedback change --- .../BrowserTestExtension/tests/KeyImportExport.js | 34 ++++++++++++---------- lang/js/src/Keyring.js | 31 +++++++++----------- 2 files changed, 32 insertions(+), 33 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index d2fa2d38..6d0ba106 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -71,10 +71,13 @@ describe('Key importing', function () { expect(result).to.be.an('array'); expect(result.length).to.equal(0); context.Keyring.importKey(pubKey).then(function(result){ - expect(result[0]).to.not.be.undefined; - expect(result[0].key).to.be.an('object'); - expect(result[0].key.fingerprint).to.equal(fpr); - expect(result[0].status).to.equal('newkey'); + expect(result.Keys).to.be.an('array'); + expect(result.Keys[0]).to.not.be.undefined; + expect(result.Keys[0].key).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal(fpr); + expect(result.Keys[0].status).to.equal('newkey'); + expect(result.summary.considered).to.equal(1); + expect(result.summary.imported).to.equal(1); done(); }); }); @@ -83,15 +86,16 @@ describe('Key importing', function () { it('Updating Key', function(done){ context.Keyring.importKey(pubKey) .then(function(result){ - expect(result[0].key).to.not.be.undefined; - expect(result[0].status).to.equal('newkey'); + expect(result.Keys[0].key).to.not.be.undefined; + expect(result.Keys[0].status).to.equal('newkey'); context.Keyring.importKey(changedKey).then(function(res){ - expect(res[0].key).to.be.an('object'); - expect(res[0].key.fingerprint).to.equal(fpr); - expect(res[0].status).to.equal('change'); - expect(res[0].changes.userId).to.be.true; - expect(res[0].changes.subkey).to.be.false; - expect(res[0].changes.signature).to.be.true; + expect(res.Keys[0].key).to.be.an('object'); + expect(res.Keys[0].key.fingerprint).to.equal(fpr); + expect(res.Keys[0].status).to.equal('change'); + expect(res.Keys[0].changes.userId).to.be.true; + expect(res.Keys[0].changes.subkey).to.be.false; + expect(res.Keys[0].changes.signature).to.be.true; + expect(res.summary.considered).to.equal(1); done(); }); }); @@ -99,9 +103,9 @@ describe('Key importing', function () { it('Deleting Key', function(done) { context.Keyring.importKey(pubKey).then(function(result){ - expect(result[0].key).to.be.an('object'); - expect(result[0].key.fingerprint).to.equal(fpr); - result[0].key.delete().then(function(result){ + expect(result.Keys[0].key).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal(fpr); + result.Keys[0].key.delete().then(function(result){ expect(result).to.be.true; done(); }); diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index eb4f60f5..a6787986 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -274,6 +274,17 @@ export class GPGME_Keyring { msg.post().then(function(response){ let infos = {}; let fprs = []; + let summary = {}; + for (let i=0; i < feedbackValues.length; i++ ){ + summary[feedbackValues[i]] = + response.result[feedbackValues[i]]; + } + if (!response.result.hasOwnProperty('imports') || + response.result.imports.length === 0 + ){ + resolve({Keys:[],summary: summary}); + return; + } for (let res=0; res Date: Fri, 17 Aug 2018 19:20:35 +0200 Subject: js: decode arriving gpg message strings -- * Arriving strings (i.e. user id names, error messages) are not always in javascript encoding. This is an attempt to go through the whole gpgme answer (with the exception of payload data) and to fix the encoding of these --- lang/js/BrowserTestExtension/tests/KeyInfos.js | 13 ++++++++- lang/js/BrowserTestExtension/tests/inputvalues.js | 35 ++++++++++++++++++++++- lang/js/src/Connection.js | 5 ++-- lang/js/src/Helpers.js | 27 +++++++++++++++++ 4 files changed, 76 insertions(+), 4 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/KeyInfos.js b/lang/js/BrowserTestExtension/tests/KeyInfos.js index 03773a44..1829f227 100644 --- a/lang/js/BrowserTestExtension/tests/KeyInfos.js +++ b/lang/js/BrowserTestExtension/tests/KeyInfos.js @@ -22,7 +22,7 @@ */ /* global describe, it, expect, before, Gpgmejs */ -/* global inputvalues, fixedLengthString */ +/* global inputvalues*/ describe('Key information', function () { let context = null; @@ -43,4 +43,15 @@ describe('Key information', function () { done(); }); }); + + it('A userId keeps their encoding', function(done){ + context.Keyring.importKey(inputvalues.publicKeyNonAscii.key, true) + .then(function(result){ + expect(result.Keys[0]).to.be.an('object'); + const user = result.Keys[0].key.get('userids')[0]; + expect(user.get('name')).to.equal( + inputvalues.publicKeyNonAscii.userid); + done(); + }); + }); }); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 7dda47cd..b33d985b 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -89,7 +89,40 @@ const inputvalues = {// eslint-disable-line no-unused-vars '-----END PGP SIGNATURE-----\n', }, - someInputParameter: 'bad string' + someInputParameter: 'bad string', + + publicKeyNonAscii: { + userid: 'Müller €uro', + key: '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + '\n' + + 'mQENBFt2/VIBCADIWBIMxExZlHda4XIVnM9nsIfUYLebJSC/krEriyWgzytU8/fQ\n' + + 'S05cfnYx7RXvOOq4k8aa7mu80ovg3q77idXauLreAUwng4Njw0nMxWq/vtoMiZ60\n' + + '9f8EmfthZophhkQF2HIPHyqXMDZzMLWv4oTr2UJ9BKudL1XtbK51y9TbiyfQygBl\n' + + '8bl+zrOo70/dN6aunvuo6Hlu5cEzkj2QrzZlqTdfG5qv6KVEMut1eAbxZAmvSnna\n' + + 'R4wqiRCT3/eRXGJbDL/8GaCEYkwi9FBrimjOTV0MpcLNwAU4aGfDxMUsxML9xJ+/\n' + + '/6GFxzYf7Lmk5UhvoewR58uQkHkTVPjZ9hXZABEBAAG0KE3DvGxsZXIg4oKsdXJv\n' + + 'IDxtdWVsbGVyZXVyb0BleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQQVNixp3XT/DuGT\n' + + 'F4MFmkL4L5UZdAUCW3b9UgIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIX\n' + + 'gAAKCRAFmkL4L5UZdAhiCACowW1aC8DYGtJyAaBO2MqWhyw1wVCbQN9uFsQZPydY\n' + + 'v3BEbCDrRc0HyfV1PVoRQsgkiNMes1S2tz2IMJoEOTMaz3WjPM8yK0dDbo5sfx/o\n' + + '/XaXeKhyYNqRkz2dPzorg1sHyHe0ki/HoQiANEJ8mByMtlwnPWlhnINAX+27eL17\n' + + 'JC8juhBYUchqoIBAl+ajYKSThdLzrUkcL7QfJjZb3pPytJSTTdFc0rD6ERDbfXXc\n' + + '/vnE2SDYme+XXn7H5tNe67tPM8M96vbp+uM+n2t/z96C+Pqb6GJFMBa35PM+/qQO\n' + + 'yr0I2oaQnTecx2AfBXGZvd81wMYikAJ9rAOWyMQZHJWouQENBFt2/VIBCADXCvKD\n' + + '3wRWCOzRWtLTs7hpAjCDxp6niPkwxKuUf9r/sUPmn0pWdZHYlbPDev9psN9bnJ+C\n' + + '+wzzPZ1zgSYKIAN0IMoh0L7BRAoau7VWQ3Q7hP6HIbdzOTEGyklSoh9pIh6IlwZZ\n' + + 'XfPlFlnn7FeH1UeA711E174SUpDRKYSfT+mFObQUuQewGi9QC3gBsz5MPLQQLzML\n' + + 'yimIOT+8i64fHHSKChw5ZDckBffej31/YHPQ7+JsWFV+G/6xDfbwnaFZFAUwo+1L\n' + + '4w9UiMyCNkIWCkulzJ2Hbz66xzFMi/8zMYxr08Af+PpsXaWTQHAa5V4GNJSInDEB\n' + + '7gy/CGLcY90EozoDABEBAAGJATwEGAEIACYWIQQVNixp3XT/DuGTF4MFmkL4L5UZ\n' + + 'dAUCW3b9UgIbDAUJA8JnAAAKCRAFmkL4L5UZdPqoB/9kpqxqa82k7JMcq7UiwQY7\n' + + 'CdqCUPKF88ciOWKBpZmpl8V7zgM7kEXwmM6ocHcznXi8xM7eOfDIJcBeqFVIE4OT\n' + + '63OCMuvZICM9Kiu48wLNAw5W/YGAOBH7ySQzZM2XrtvwfFtJ3lR00t5f4FVtriA5\n' + + '47BjYYG5tTdJc8HwEHs045S99xKCWqwuDgO9qskIi6iPePUkuhpaVBLuEj2Goku6\n' + + 'i8aql/vKYQS67L7UHJiEbjLe+wP9k3FvWUFTx39lAubsDzb4Abhe+qRqs2TKD7Go\n' + + 'k35ZriRIYllmx4c9KyWL7Mvzcp+84Sq9LeMfsN4JstBDJ7jn6g19SjO5dmtxSuP0\n' + + '=zZSJ\n' + + '-----END PGP PUBLIC KEY BLOCK-----\n' + } }; // (Pseudo-)Random String covering all of utf8. diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index b0105757..8d381f15 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -26,6 +26,7 @@ import { permittedOperations } from './permittedOperations'; import { gpgme_error } from './Errors'; import { GPGME_Message, createMessage } from './Message'; +import { decode } from './Helpers'; /** * A Connection handles the nativeMessaging interaction via a port. As the @@ -239,7 +240,7 @@ class Answer{ case 'type': if (_decodedResponse.type === 'error'){ return (gpgme_error('GNUPG_ERROR', - decodeURIComponent(escape(_decodedResponse.msg)))); + decode(_decodedResponse.msg))); } else if (poa.type.indexOf(_decodedResponse.type) < 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } @@ -270,7 +271,7 @@ class Answer{ ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); } else { - _response[key] = _decodedResponse[key]; + _response[key] = decode(_decodedResponse[key]); } break; } diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js index accc2af5..379015f2 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -108,3 +108,30 @@ export function isFingerprint(value){ export function isLongId(value){ return hextest(value, 16); } + +/** + * Recursively decodes input (utf8) to output (utf-16; javascript) strings + * @param {Object | Array | String} property + */ +export function decode(property){ + if (typeof property === 'string'){ + return decodeURIComponent(escape(property)); + } else if (Array.isArray(property)){ + let res = []; + for (let arr=0; arr < property.length; arr++){ + res.push(decode(property[arr])); + } + return res; + } else if (typeof property === 'object'){ + const keys = Object.keys(property); + if (keys.length){ + let res = {}; + for (let k=0; k < keys.length; k++ ){ + res[keys[k]] = decode(property[keys[k]]); + } + return res; + } + return property; + } + return property; +} \ No newline at end of file -- cgit From dd32daad0bb21e3d5567326d0b2e548ff8510431 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Mon, 20 Aug 2018 15:12:01 +0200 Subject: js: add and apply eslint rules -- * mainly spacing, see .eslintrc.json for details --- lang/js/.eslintrc.json | 19 +- .../BrowserTestExtension/tests/KeyImportExport.js | 46 ++-- lang/js/BrowserTestExtension/tests/KeyInfos.js | 12 +- lang/js/BrowserTestExtension/tests/decryptTest.js | 14 +- .../tests/encryptDecryptTest.js | 6 +- lang/js/BrowserTestExtension/tests/encryptTest.js | 10 +- lang/js/BrowserTestExtension/tests/inputvalues.js | 16 +- .../BrowserTestExtension/tests/longRunningTests.js | 6 +- lang/js/BrowserTestExtension/tests/signTest.js | 4 +- lang/js/BrowserTestExtension/tests/startup.js | 6 +- lang/js/BrowserTestExtension/tests/verifyTest.js | 14 +- lang/js/DemoExtension/entry.js | 2 +- lang/js/DemoExtension/maindemo.js | 40 ++-- lang/js/src/Connection.js | 40 ++-- lang/js/src/Errors.js | 8 +- lang/js/src/Helpers.js | 16 +- lang/js/src/Key.js | 243 +++++++++++---------- lang/js/src/Keyring.js | 83 ++++--- lang/js/src/Message.js | 32 +-- lang/js/src/Signature.js | 23 +- lang/js/src/gpgmejs.js | 40 ++-- lang/js/src/index.js | 10 +- lang/js/src/permittedOperations.js | 12 +- lang/js/unittest_inputvalues.js | 8 +- lang/js/unittests.js | 108 ++++----- 25 files changed, 421 insertions(+), 397 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/.eslintrc.json b/lang/js/.eslintrc.json index ad82400b..dc3be2e4 100644 --- a/lang/js/.eslintrc.json +++ b/lang/js/.eslintrc.json @@ -27,6 +27,23 @@ "no-var": [ "warn" ], - "max-len": 1 + "max-len": 1, + "default-case": 2, + "no-invalid-this": 2, + "no-lone-blocks": 1, + "no-self-compare": 2, + "radix": 2, + "no-use-before-define": ["error", { + "functions": false, + "classes": false, + "variables": true + }], + "no-useless-constructor": 1, + "space-before-function-paren": ["error", "always"], + "keyword-spacing": 2, + "spaced-comment": 1, + "space-unary-ops": 2, + "object-curly-spacing": ["error", "always"], + "array-bracket-spacing": ["error", "never"] } } \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 6d0ba106..f52b790a 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -31,16 +31,16 @@ describe('Key importing', function () { const changedKey = ImportablePublicKey.keyChangedUserId; let context = null; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; context.Keyring.getKeys(fpr).then( - function(result){ + function (result){ if (result.length === 1) { - result[0].delete().then(function(){ + result[0].delete().then(function (){ done(); - },function(){ + },function (){ done(); }); } else { @@ -50,14 +50,14 @@ describe('Key importing', function () { }); }); - afterEach(function(done){ + afterEach(function (done){ // delete the test key if still present context.Keyring.getKeys(fpr).then( - function(result){ + function (result){ if (result.length === 1) { - result[0].delete().then(function(){ + result[0].delete().then(function (){ done(); - },function(){ + },function (){ done(); }); } else { @@ -67,10 +67,10 @@ describe('Key importing', function () { }); it('Importing Key', function (done) { - context.Keyring.getKeys(fpr).then(function(result){ + context.Keyring.getKeys(fpr).then(function (result){ expect(result).to.be.an('array'); expect(result.length).to.equal(0); - context.Keyring.importKey(pubKey).then(function(result){ + context.Keyring.importKey(pubKey).then(function (result){ expect(result.Keys).to.be.an('array'); expect(result.Keys[0]).to.not.be.undefined; expect(result.Keys[0].key).to.be.an('object'); @@ -83,12 +83,12 @@ describe('Key importing', function () { }); }); - it('Updating Key', function(done){ + it('Updating Key', function (done){ context.Keyring.importKey(pubKey) - .then(function(result){ + .then(function (result){ expect(result.Keys[0].key).to.not.be.undefined; expect(result.Keys[0].status).to.equal('newkey'); - context.Keyring.importKey(changedKey).then(function(res){ + context.Keyring.importKey(changedKey).then(function (res){ expect(res.Keys[0].key).to.be.an('object'); expect(res.Keys[0].key.fingerprint).to.equal(fpr); expect(res.Keys[0].status).to.equal('change'); @@ -101,24 +101,24 @@ describe('Key importing', function () { }); }); - it('Deleting Key', function(done) { - context.Keyring.importKey(pubKey).then(function(result){ + it('Deleting Key', function (done) { + context.Keyring.importKey(pubKey).then(function (result){ expect(result.Keys[0].key).to.be.an('object'); expect(result.Keys[0].key.fingerprint).to.equal(fpr); - result.Keys[0].key.delete().then(function(result){ + result.Keys[0].key.delete().then(function (result){ expect(result).to.be.true; done(); }); }); }); - it('Import result feedback', function(done){ - context.Keyring.importKey(pubKey, true).then(function(result){ + it('Import result feedback', function (done){ + context.Keyring.importKey(pubKey, true).then(function (result){ expect(result).to.be.an('object'); expect(result.Keys[0]).to.be.an('object'); expect(result.Keys[0].key.fingerprint).to.equal(fpr); expect(result.Keys[0].status).to.equal('newkey'); - result.Keys[0].key.getArmor().then(function(armor){ + result.Keys[0].key.getArmor().then(function (armor){ expect(armor).to.be.a('string'); done(); }); @@ -126,8 +126,8 @@ describe('Key importing', function () { }); it('exporting armored Key with getKeysArmored', function (done) { - context.Keyring.importKey(pubKey).then(function(){ - context.Keyring.getKeysArmored(fpr).then(function(result){ + context.Keyring.importKey(pubKey).then(function (){ + context.Keyring.getKeysArmored(fpr).then(function (result){ expect(result).to.be.an('object'); expect(result.armored).to.be.a('string'); expect(result.secret_fprs).to.be.undefined; @@ -138,7 +138,7 @@ describe('Key importing', function () { it('Exporting Key (including secret fingerprints)', function (done) { const key_secret = inputvalues.encrypt.good.fingerprint; - context.Keyring.getKeysArmored(key_secret, true).then(function(result){ + context.Keyring.getKeysArmored(key_secret, true).then(function (result){ expect(result).to.be.an('object'); expect(result.armored).to.be.a('string'); expect(result.secret_fprs).to.be.an('array'); diff --git a/lang/js/BrowserTestExtension/tests/KeyInfos.js b/lang/js/BrowserTestExtension/tests/KeyInfos.js index 1829f227..e1caabe1 100644 --- a/lang/js/BrowserTestExtension/tests/KeyInfos.js +++ b/lang/js/BrowserTestExtension/tests/KeyInfos.js @@ -26,17 +26,17 @@ describe('Key information', function () { let context = null; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); }); - it('A fingerprint is consistently returned upper case hex', function(done){ + it('A fingerprint is consistently returned upper case hex', function (done){ const mixedCase = inputvalues.encrypt.good.fingerprint_mixedcase; - context.Keyring.getKeys(mixedCase).then(function(result){ + context.Keyring.getKeys(mixedCase).then(function (result){ expect(result).to.be.an('array'); expect(result.length).to.equal(1); expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase()); @@ -44,9 +44,9 @@ describe('Key information', function () { }); }); - it('A userId keeps their encoding', function(done){ + it('A userId keeps their encoding', function (done){ context.Keyring.importKey(inputvalues.publicKeyNonAscii.key, true) - .then(function(result){ + .then(function (result){ expect(result.Keys[0]).to.be.an('object'); const user = result.Keys[0].key.get('userids')[0]; expect(user.get('name')).to.equal( diff --git a/lang/js/BrowserTestExtension/tests/decryptTest.js b/lang/js/BrowserTestExtension/tests/decryptTest.js index c6b3a3c5..a3f48daa 100644 --- a/lang/js/BrowserTestExtension/tests/decryptTest.js +++ b/lang/js/BrowserTestExtension/tests/decryptTest.js @@ -28,9 +28,9 @@ describe('Decryption', function () { let context = null; const good_fpr = inputvalues.encrypt.good.fingerprint; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); @@ -39,8 +39,8 @@ describe('Decryption', function () { it('Decryption of random string fails', function (done) { let data = bigString(20 * 1024); context.decrypt(data).then( - function(){}, - function(error){ + function (){}, + function (error){ expect(error).to.be.an('error'); expect(error.code).to.equal('GNUPG_ERROR'); done(); @@ -49,10 +49,10 @@ describe('Decryption', function () { it('Decryption of slightly corrupted message fails', function (done) { const data = bigString(10000); - context.encrypt(data, good_fpr).then(function(enc){ + context.encrypt(data, good_fpr).then(function (enc){ context.decrypt(sabotageMsg(enc.data)).then( - function(){}, - function(error){ + function (){}, + function (error){ expect(error).to.be.an('error'); expect(error.code).to.equal('GNUPG_ERROR'); done(); diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index 80b293d2..28c98d98 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -24,13 +24,13 @@ /* global describe, it, expect, before, Gpgmejs */ /* global inputvalues, encryptedData, bigString, bigBoringString */ -describe('Encryption and Decryption', function () { +describe('Encryption and Decryption', function (){ let context = null; let good_fpr = inputvalues.encrypt.good.fingerprint; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 3ead8153..a242af5f 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -27,9 +27,9 @@ describe('Encryption', function () { let context = null; const good_fpr = inputvalues.encrypt.good.fingerprint; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); @@ -64,7 +64,7 @@ describe('Encryption', function () { const data = inputvalues.encrypt.good.data; context.encrypt(data,null).then(function (answer) { expect(answer).to.be.undefined; - }, function(error){ + }, function (error){ expect(error).to.be.an('Error'); expect(error.code).to.equal('MSG_INCOMPLETE'); done(); @@ -86,7 +86,7 @@ describe('Encryption', function () { const bad_fpr = inputvalues.encrypt.bad.fingerprint; context.encrypt(data, bad_fpr).then(function (answer) { expect(answer).to.be.undefined; - }, function(error){ + }, function (error){ expect(error).to.be.an('Error'); expect(error.code).to.not.be.undefined; expect(error.code).to.equal('GNUPG_ERROR'); @@ -98,7 +98,7 @@ describe('Encryption', function () { const data = fixedLengthString(65); context.encrypt(data, good_fpr).then(function (answer) { expect(answer).to.be.undefined; - }, function(error){ + }, function (error){ expect(error).to.be.an.instanceof(Error); // TODO: there is a 64 MB hard limit at least in chrome at: // chromium//extensions/renderer/messaging_util.cc: diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index b33d985b..f84ac955 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -126,7 +126,7 @@ const inputvalues = {// eslint-disable-line no-unused-vars }; // (Pseudo-)Random String covering all of utf8. -function bigString(length){// eslint-disable-line no-unused-vars +function bigString (length){// eslint-disable-line no-unused-vars let arr = []; for (let i= 0; i < length; i++){ arr.push(String.fromCharCode( @@ -136,7 +136,7 @@ function bigString(length){// eslint-disable-line no-unused-vars return arr.join(''); } -function fixedLengthString(megabytes){// eslint-disable-line no-unused-vars +function fixedLengthString (megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes / 2; let uint = new Uint8Array(maxlength); for (let i = 0; i < maxlength; i++){ @@ -148,7 +148,7 @@ function fixedLengthString(megabytes){// eslint-disable-line no-unused-vars } // (Pseudo-)Random Uint8Array, given size in Megabytes -function bigUint8(megabytes){// eslint-disable-line no-unused-vars +function bigUint8 (megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); for (let i= 0; i < maxlength; i++){ @@ -159,7 +159,7 @@ function bigUint8(megabytes){// eslint-disable-line no-unused-vars // (Pseudo-)Random string with very limited charset // (ascii only, no control chars) -function bigBoringString(megabytes){// eslint-disable-line no-unused-vars +function bigBoringString (megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let string = []; let chars = @@ -173,7 +173,7 @@ function bigBoringString(megabytes){// eslint-disable-line no-unused-vars // Some String with simple chars, with different characteristics, but still // expected to occur in an averag message // eslint-disable-next-line no-unused-vars -function slightlyLessBoringString(megabytes, set){ +function slightlyLessBoringString (megabytes, set){ let maxlength = 1024 * 1024 * megabytes; let string = []; let chars = ''; @@ -291,13 +291,13 @@ const ImportablePublicKey = {// eslint-disable-line no-unused-vars * preserve) header/footer */ // eslint-disable-next-line no-unused-vars -function sabotageMsg(msg, rate = 0.01, p= [35,35]){ +function sabotageMsg (msg, rate = 0.01, p= [35,35]){ const iterations = Math.floor(Math.random() * msg.length * rate) + 1; const base64_set = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/'; for (let i=0; i < iterations; i++){ let str0, str1, str2; - const chosePosition = function(){ + const chosePosition = function (){ let position = Math.floor( Math.random() * (msg.length - p[0] + p[1])) + p[0]; @@ -310,7 +310,7 @@ function sabotageMsg(msg, rate = 0.01, p= [35,35]){ } }; chosePosition(); - let new1 = function(){ + let new1 = function (){ let n = base64_set[Math.floor(Math.random() * 64)]; return (n === str1) ? new1() : n; }; diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index 03f0390c..240a6b93 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -26,9 +26,9 @@ describe('Long running Encryption/Decryption', function () { let context = null; const good_fpr = inputvalues.encrypt.good.fingerprint; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); @@ -43,7 +43,7 @@ describe('Long running Encryption/Decryption', function () { expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); - context.decrypt(answer.data).then(function(result){ + context.decrypt(answer.data).then(function (result){ expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal(data); diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js index 2763dadf..f5bd9c1d 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -28,9 +28,9 @@ describe('Signing', function () { let context = null; const good_fpr = inputvalues.encrypt.good.fingerprint; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index 63358aa9..cf5b0999 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -23,12 +23,12 @@ /* global describe, it, expect, Gpgmejs, inputvalues */ -describe('GPGME context', function(){ - it('Starting a GpgME instance', function(done){ +describe('GPGME context', function (){ + it('Starting a GpgME instance', function (done){ let prm = Gpgmejs.init(); const input = inputvalues.someInputParameter; prm.then( - function(context){ + function (context){ expect(context).to.be.an('object'); expect(context.encrypt).to.be.a('function'); expect(context.decrypt).to.be.a('function'); diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index 1617e2dc..82aaf564 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -27,16 +27,16 @@ describe('Verifying data', function () { let context = null; - before(function(done){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + prm.then(function (gpgmejs){ context = gpgmejs; done(); }); }); it('Successful verify message', function (done) { const message = inputvalues.signedMessage.good; - context.verify(message).then(function(result){ + context.verify(message).then(function (result){ expect(result.data).to.be.a('string'); expect(result.all_valid).to.be.true; expect(result.count).to.equal(1); @@ -50,7 +50,7 @@ describe('Verifying data', function () { it('Successfully recognize changed cleartext', function (done) { const message = inputvalues.signedMessage.bad; - context.verify(message).then(function(result){ + context.verify(message).then(function (result){ expect(result.data).to.be.a('string'); expect(result.all_valid).to.be.false; expect(result.count).to.equal(1); @@ -65,9 +65,9 @@ describe('Verifying data', function () { it('Encrypt-Sign-Verify random message', function (done) { const message = bigString(2000); let fpr = inputvalues.encrypt.good.fingerprint; - context.encrypt(message, fpr).then(function(message_enc){ - context.sign(message_enc.data, fpr).then(function(message_encsign){ - context.verify(message_encsign.data).then(function(result){ + context.encrypt(message, fpr).then(function (message_enc){ + context.sign(message_enc.data, fpr).then(function (message_encsign){ + context.verify(message_encsign.data).then(function (result){ expect(result.data).to.equal(message_enc.data); expect(result.data).to.be.a('string'); expect(result.all_valid).to.be.true; diff --git a/lang/js/DemoExtension/entry.js b/lang/js/DemoExtension/entry.js index 77b96f92..fd261a0b 100644 --- a/lang/js/DemoExtension/entry.js +++ b/lang/js/DemoExtension/entry.js @@ -23,7 +23,7 @@ /* global chrome */ -document.addEventListener('DOMContentLoaded', function() { +document.addEventListener('DOMContentLoaded', function () { chrome.tabs.create({ url: './mainui.html' }); diff --git a/lang/js/DemoExtension/maindemo.js b/lang/js/DemoExtension/maindemo.js index 4cae934e..8d190852 100644 --- a/lang/js/DemoExtension/maindemo.js +++ b/lang/js/DemoExtension/maindemo.js @@ -23,67 +23,67 @@ /* global document, Gpgmejs */ -document.addEventListener('DOMContentLoaded', function() { - Gpgmejs.init().then(function(gpgmejs){ +document.addEventListener('DOMContentLoaded', function () { + Gpgmejs.init().then(function (gpgmejs){ document.getElementById('buttonencrypt').addEventListener('click', - function(){ + function (){ let data = document.getElementById('inputtext').value; let keyId = document.getElementById('pubkey').value; gpgmejs.encrypt(data, keyId).then( - function(answer){ + function (answer){ if (answer.data){ document.getElementById( 'answer').value = answer.data; } - }, function(errormsg){ + }, function (errormsg){ alert( errormsg.message); }); }); document.getElementById('buttondecrypt').addEventListener('click', - function(){ + function (){ let data = document.getElementById('inputtext').value; gpgmejs.decrypt(data).then( - function(answer){ + function (answer){ if (answer.data){ document.getElementById( 'answer').value = answer.data; } - }, function(errormsg){ + }, function (errormsg){ alert(errormsg.message); }); }); document.getElementById('getdefaultkey').addEventListener('click', - function(){ - gpgmejs.Keyring.getDefaultKey().then(function(answer){ + function (){ + gpgmejs.Keyring.getDefaultKey().then(function (answer){ document.getElementById('pubkey').value = answer.fingerprint; - }, function(errormsg){ + }, function (errormsg){ alert(errormsg.message); }); }); document.getElementById('signtext').addEventListener('click', - function(){ + function (){ let data = document.getElementById('inputtext').value; let keyId = document.getElementById('pubkey').value; gpgmejs.sign(data, keyId).then( - function(answer){ + function (answer){ if (answer.data){ document.getElementById( 'answer').value = answer.data; } - }, function(errormsg){ + }, function (errormsg){ alert( errormsg.message); }); }); document.getElementById('verifytext').addEventListener('click', - function(){ + function (){ let data = document.getElementById('inputtext').value; gpgmejs.verify(data).then( - function(answer){ + function (answer){ let vals = ''; if (answer.all_valid === true){ vals = 'Success! '; @@ -94,14 +94,14 @@ document.addEventListener('DOMContentLoaded', function() { + answer.count + ' signature(s) were successfully ' + 'verified.\n\n' + answer.data; document.getElementById('answer').value = vals; - }, function(errormsg){ + }, function (errormsg){ alert( errormsg.message); }); }); document.getElementById('searchkey').addEventListener('click', - function(){ + function (){ let data = document.getElementById('inputtext').value; - gpgmejs.Keyring.getKeys(data, true, true).then(function(keys){ + gpgmejs.Keyring.getKeys(data, true, true).then(function (keys){ if (keys.length === 1){ document.getElementById( 'pubkey').value = keys[0].fingerprint; @@ -111,7 +111,7 @@ document.addEventListener('DOMContentLoaded', function() { } else { alert('No keys found'); } - }, function(errormsg){ + }, function (errormsg){ alert( errormsg.message); }); }); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index a60fd215..928ac681 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -38,14 +38,14 @@ import { decode } from './Helpers'; */ export class Connection{ - constructor(){ + constructor (){ this._connection = chrome.runtime.connectNative('gpgmejson'); } /** * Immediately closes an open port. */ - disconnect() { + disconnect () { if (this._connection){ this._connection.disconnect(); this._connection = null; @@ -81,17 +81,17 @@ export class Connection{ return this.post(msg); } else { let me = this; - return new Promise(function(resolve) { + return new Promise(function (resolve) { Promise.race([ me.post(msg), - new Promise(function(resolve, reject){ - setTimeout(function(){ + new Promise(function (resolve, reject){ + setTimeout(function (){ reject(gpgme_error('CONN_TIMEOUT')); }, 500); }) - ]).then(function(){ // success + ]).then(function (){ // success resolve(true); - }, function(){ // failure + }, function (){ // failure resolve(false); }); }); @@ -107,7 +107,7 @@ export class Connection{ * @returns {Promise} The collected answer * @async */ - post(message){ + post (message){ if (!message || !(message instanceof GPGME_Message)){ this.disconnect(); return Promise.reject(gpgme_error( @@ -119,9 +119,9 @@ export class Connection{ } let chunksize = message.chunksize; const me = this; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ let answer = new Answer(message); - let listener = function(msg) { + let listener = function (msg) { if (!msg){ me._connection.onMessage.removeListener(listener); me._connection.disconnect(); @@ -157,16 +157,16 @@ export class Connection{ } else { return Promise.race([ me._connection.postMessage(message.message), - function(resolve, reject){ - setTimeout(function(){ + function (resolve, reject){ + setTimeout(function (){ me._connection.disconnect(); reject(gpgme_error('CONN_TIMEOUT')); }, 5000); } - ]).then(function(result){ + ]).then(function (result){ return result; - }, function(reject){ - if(!(reject instanceof Error)) { + }, function (reject){ + if (!(reject instanceof Error)) { me._connection.disconnect(); return gpgme_error('GNUPG_ERROR', reject); } else { @@ -189,7 +189,7 @@ class Answer{ /** * @param {GPGME_Message} message */ - constructor(message){ + constructor (message){ this._operation = message.operation; this._expected = message.expected; this._response_b64 = null; @@ -211,7 +211,7 @@ class Answer{ * @private */ collect (msg){ - if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) { + if (typeof (msg) !== 'object' || !msg.hasOwnProperty('response')) { return gpgme_error('CONN_UNEXPECTED_ANSWER'); } if (!this._response_b64){ @@ -226,7 +226,7 @@ class Answer{ * Returns the base64 encoded answer data with the content verified * against {@link permittedOperations}. */ - getMessage(){ + getMessage (){ if (this._response_b64 === null){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } @@ -259,7 +259,7 @@ class Answer{ if (!poa.data.hasOwnProperty(key)){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } - if( typeof(_decodedResponse[key]) !== poa.data[key] ){ + if ( typeof (_decodedResponse[key]) !== poa.data[key] ){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } if (_decodedResponse.base64 === true @@ -268,7 +268,7 @@ class Answer{ ){ _response[key] = decodeURIComponent( atob(_decodedResponse[key]).split('').map( - function(c) { + function (c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index 2a35bc5e..53e7bcd7 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -120,7 +120,7 @@ const err_list = { * @param {*} info Error message passed through if code is 'GNUPG_ERROR' * @returns {GPGME_Error} */ -export function gpgme_error(code = 'GENERIC_ERROR', info){ +export function gpgme_error (code = 'GENERIC_ERROR', info){ if (err_list.hasOwnProperty(code)){ if (err_list[code].type === 'error'){ return new GPGME_Error(code); @@ -147,9 +147,9 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ * @extends Error */ class GPGME_Error extends Error{ - constructor(code = 'GENERIC_ERROR', msg=''){ + constructor (code = 'GENERIC_ERROR', msg=''){ - if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){ + if (code === 'GNUPG_ERROR' && typeof (msg) === 'string'){ super(msg); } else if (err_list.hasOwnProperty(code)){ if (msg){ @@ -163,7 +163,7 @@ class GPGME_Error extends Error{ this._code = code; } - get code(){ + get code (){ return this._code; } } \ No newline at end of file diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js index 379015f2..ba4277ab 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -30,7 +30,7 @@ import { gpgme_error } from './Errors'; * @param {Object | Array | String | Array} input * @returns {Array} Array of fingerprints, or an empty array */ -export function toKeyIdArray(input){ +export function toKeyIdArray (input){ if (!input){ return []; } @@ -39,7 +39,7 @@ export function toKeyIdArray(input){ } let result = []; for (let i=0; i < input.length; i++){ - if (typeof(input[i]) === 'string'){ + if (typeof (input[i]) === 'string'){ if (isFingerprint(input[i]) === true){ result.push(input[i]); } else { @@ -47,7 +47,7 @@ export function toKeyIdArray(input){ // in src/Errors.js gpgme_error('MSG_NOT_A_FPR'); } - } else if (typeof(input[i]) === 'object'){ + } else if (typeof (input[i]) === 'object'){ let fpr = ''; if (input[i].hasOwnProperty('fingerprint')){ fpr = input[i].fingerprint; @@ -78,8 +78,8 @@ export function toKeyIdArray(input){ * @returns {Boolean} true if value passes test * @private */ -function hextest(key, len){ - if (!key || typeof(key) !== 'string'){ +function hextest (key, len){ + if (!key || typeof (key) !== 'string'){ return false; } if (key.length !== len){ @@ -95,7 +95,7 @@ function hextest(key, len){ * @param {String} value to check * @returns {Boolean} true if value passes test */ -export function isFingerprint(value){ +export function isFingerprint (value){ return hextest(value, 40); } @@ -105,7 +105,7 @@ export function isFingerprint(value){ * @param {String} value to check * @returns {Boolean} true if value passes test */ -export function isLongId(value){ +export function isLongId (value){ return hextest(value, 16); } @@ -113,7 +113,7 @@ export function isLongId(value){ * Recursively decodes input (utf8) to output (utf-16; javascript) strings * @param {Object | Array | String} property */ -export function decode(property){ +export function decode (property){ if (typeof property === 'string'){ return decodeURIComponent(escape(property)); } else if (Array.isArray(property)){ diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 37ec7f9d..2800ae9a 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -35,8 +35,8 @@ import { createMessage } from './Message'; * a full object as delivered by gpgme-json * @returns {Object|GPGME_Error} The verified and updated data */ -export function createKey(fingerprint, async = false, data){ - if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){ +export function createKey (fingerprint, async = false, data){ + if (!isFingerprint(fingerprint) || typeof (async) !== 'boolean'){ return gpgme_error('PARAM_WRONG'); } if (data !== undefined){ @@ -60,14 +60,14 @@ export function createKey(fingerprint, async = false, data){ */ class GPGME_Key { - constructor(fingerprint, async, data){ + constructor (fingerprint, async, data){ /** * @property {Boolean} If true, most answers will be asynchronous */ this._async = async; - this._data = {fingerprint: fingerprint.toUpperCase()}; + this._data = { fingerprint: fingerprint.toUpperCase() }; if (data !== undefined && data.fingerprint.toUpperCase() === this._data.fingerprint ) { @@ -84,7 +84,7 @@ class GPGME_Key { * async, the armored property is not available (it can still be * retrieved asynchronously by {@link Key.getArmor}) */ - get(property) { + get (property) { if (this._async === true) { switch (property){ case 'armored': @@ -98,6 +98,7 @@ class GPGME_Key { if (property === 'armored') { return gpgme_error('KEY_ASYNC_ONLY'); } + // eslint-disable-next-line no-use-before-define if (!validKeyProperties.hasOwnProperty(property)){ return gpgme_error('PARAM_WRONG'); } else { @@ -114,16 +115,16 @@ class GPGME_Key { * @returns {Promise} * @async */ - refreshKey() { + refreshKey () { let me = this; - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (!me._data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('keylist'); msg.setParameter('sigs', true); msg.setParameter('keys', me._data.fingerprint); - msg.post().then(function(result){ + msg.post().then(function (result){ if (result.keys.length === 1){ const newdata = validateKeyData( me._data.fingerprint, result.keys[0]); @@ -131,13 +132,13 @@ class GPGME_Key { reject(gpgme_error('KEY_INVALID')); } else { me._data = newdata; - me.getGnupgSecretState().then(function(){ - me.getArmor().then(function(){ + me.getGnupgSecretState().then(function (){ + me.getArmor().then(function (){ resolve(me); - }, function(error){ + }, function (error){ reject(error); }); - }, function(error){ + }, function (error){ reject(error); }); } @@ -157,18 +158,18 @@ class GPGME_Key { * @returns {Promise} * @async */ - getArmor() { + getArmor () { const me = this; - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (!me._data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('export'); msg.setParameter('armor', true); msg.setParameter('keys', me._data.fingerprint); - msg.post().then(function(result){ + msg.post().then(function (result){ resolve(result.data); - }, function(error){ + }, function (error){ reject(error); }); }); @@ -186,14 +187,14 @@ class GPGME_Key { */ getGnupgSecretState (){ const me = this; - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (!me._data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } else { let msg = createMessage('keylist'); msg.setParameter('keys', me._data.fingerprint); msg.setParameter('secret', true); - msg.post().then(function(result){ + msg.post().then(function (result){ me._data.hasSecret = null; if ( result.keys && @@ -206,7 +207,7 @@ class GPGME_Key { me._data.hasSecret = false; resolve(false); } - }, function(error){ + }, function (error){ reject(error); }); } @@ -219,17 +220,17 @@ class GPGME_Key { * @returns {Promise} Success if key was deleted, * rejects with a GPG error otherwise. */ - delete(){ + delete (){ const me = this; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ if (!me._data.fingerprint){ reject(gpgme_error('KEY_INVALID')); } let msg = createMessage('delete'); msg.setParameter('key', me._data.fingerprint); - msg.post().then(function(result){ + msg.post().then(function (result){ resolve(result.success); - }, function(error){ + }, function (error){ reject(error); }); }); @@ -238,7 +239,7 @@ class GPGME_Key { /** * @returns {String} The fingerprint defining this Key. Convenience getter */ - get fingerprint(){ + get fingerprint (){ return this._data.fingerprint; } } @@ -255,7 +256,7 @@ class GPGME_Subkey { * @param {Object} data * @private */ - constructor(data){ + constructor (data){ this._data = {}; let keys = Object.keys(data); const me = this; @@ -268,7 +269,9 @@ class GPGME_Subkey { * @param private */ const setProperty = function (property, value){ + // eslint-disable-next-line no-use-before-define if (validSubKeyProperties.hasOwnProperty(property)){ + // eslint-disable-next-line no-use-before-define if (validSubKeyProperties[property](value) === true) { if (property === 'timestamp' || property === 'expires'){ me._data[property] = new Date(value * 1000); @@ -288,7 +291,7 @@ class GPGME_Subkey { * @param {String} property Information to request * @returns {String | Number | Date} */ - get(property) { + get (property) { if (this._data.hasOwnProperty(property)){ return (this._data[property]); } @@ -308,12 +311,14 @@ class GPGME_UserId { * @param {Object} data * @private */ - constructor(data){ + constructor (data){ this._data = {}; const me = this; let keys = Object.keys(data); - const setProperty = function(property, value){ + const setProperty = function (property, value){ + // eslint-disable-next-line no-use-before-define if (validUserIdProperties.hasOwnProperty(property)){ + // eslint-disable-next-line no-use-before-define if (validUserIdProperties[property](value) === true) { if (property === 'last_update'){ me._data[property] = new Date(value*1000); @@ -333,7 +338,7 @@ class GPGME_UserId { * @param {String} property Information to request * @returns {String | Number} */ - get(property) { + get (property) { if (this._data.hasOwnProperty(property)){ return (this._data[property]); } @@ -349,52 +354,52 @@ class GPGME_UserId { * @const */ const validUserIdProperties = { - 'revoked': function(value){ - return typeof(value) === 'boolean'; + 'revoked': function (value){ + return typeof (value) === 'boolean'; }, - 'invalid': function(value){ - return typeof(value) === 'boolean'; + 'invalid': function (value){ + return typeof (value) === 'boolean'; }, - 'uid': function(value){ - if (typeof(value) === 'string' || value === ''){ + 'uid': function (value){ + if (typeof (value) === 'string' || value === ''){ return true; } return false; }, - 'validity': function(value){ - if (typeof(value) === 'string'){ + 'validity': function (value){ + if (typeof (value) === 'string'){ return true; } return false; }, - 'name': function(value){ - if (typeof(value) === 'string' || value === ''){ + 'name': function (value){ + if (typeof (value) === 'string' || value === ''){ return true; } return false; }, - 'email': function(value){ - if (typeof(value) === 'string' || value === ''){ + 'email': function (value){ + if (typeof (value) === 'string' || value === ''){ return true; } return false; }, - 'address': function(value){ - if (typeof(value) === 'string' || value === ''){ + 'address': function (value){ + if (typeof (value) === 'string' || value === ''){ return true; } return false; }, - 'comment': function(value){ - if (typeof(value) === 'string' || value === ''){ + 'comment': function (value){ + if (typeof (value) === 'string' || value === ''){ return true; } return false; }, - 'origin': function(value){ + 'origin': function (value){ return Number.isInteger(value); }, - 'last_update': function(value){ + 'last_update': function (value){ return Number.isInteger(value); } }; @@ -406,54 +411,54 @@ const validUserIdProperties = { * @const */ const validSubKeyProperties = { - 'invalid': function(value){ - return typeof(value) === 'boolean'; + 'invalid': function (value){ + return typeof (value) === 'boolean'; }, - 'can_encrypt': function(value){ - return typeof(value) === 'boolean'; + 'can_encrypt': function (value){ + return typeof (value) === 'boolean'; }, - 'can_sign': function(value){ - return typeof(value) === 'boolean'; + 'can_sign': function (value){ + return typeof (value) === 'boolean'; }, - 'can_certify': function(value){ - return typeof(value) === 'boolean'; + 'can_certify': function (value){ + return typeof (value) === 'boolean'; }, - 'can_authenticate': function(value){ - return typeof(value) === 'boolean'; + 'can_authenticate': function (value){ + return typeof (value) === 'boolean'; }, - 'secret': function(value){ - return typeof(value) === 'boolean'; + 'secret': function (value){ + return typeof (value) === 'boolean'; }, - 'is_qualified': function(value){ - return typeof(value) === 'boolean'; + 'is_qualified': function (value){ + return typeof (value) === 'boolean'; }, - 'is_cardkey': function(value){ - return typeof(value) === 'boolean'; + 'is_cardkey': function (value){ + return typeof (value) === 'boolean'; }, - 'is_de_vs': function(value){ - return typeof(value) === 'boolean'; + 'is_de_vs': function (value){ + return typeof (value) === 'boolean'; }, - 'pubkey_algo_name': function(value){ - return typeof(value) === 'string'; + 'pubkey_algo_name': function (value){ + return typeof (value) === 'string'; // TODO: check against list of known?[''] }, - 'pubkey_algo_string': function(value){ - return typeof(value) === 'string'; + 'pubkey_algo_string': function (value){ + return typeof (value) === 'string'; // TODO: check against list of known?[''] }, - 'keyid': function(value){ + 'keyid': function (value){ return isLongId(value); }, - 'pubkey_algo': function(value) { + 'pubkey_algo': function (value) { return (Number.isInteger(value) && value >= 0); }, - 'length': function(value){ + 'length': function (value){ return (Number.isInteger(value) && value > 0); }, - 'timestamp': function(value){ + 'timestamp': function (value){ return (Number.isInteger(value) && value > 0); }, - 'expires': function(value){ + 'expires': function (value){ return (Number.isInteger(value) && value > 0); } }; @@ -489,73 +494,73 @@ const validSubKeyProperties = { * @const */ const validKeyProperties = { - 'fingerprint': function(value){ + 'fingerprint': function (value){ return isFingerprint(value); }, - 'revoked': function(value){ - return typeof(value) === 'boolean'; + 'revoked': function (value){ + return typeof (value) === 'boolean'; }, - 'expired': function(value){ - return typeof(value) === 'boolean'; + 'expired': function (value){ + return typeof (value) === 'boolean'; }, - 'disabled': function(value){ - return typeof(value) === 'boolean'; + 'disabled': function (value){ + return typeof (value) === 'boolean'; }, - 'invalid': function(value){ - return typeof(value) === 'boolean'; + 'invalid': function (value){ + return typeof (value) === 'boolean'; }, - 'can_encrypt': function(value){ - return typeof(value) === 'boolean'; + 'can_encrypt': function (value){ + return typeof (value) === 'boolean'; }, - 'can_sign': function(value){ - return typeof(value) === 'boolean'; + 'can_sign': function (value){ + return typeof (value) === 'boolean'; }, - 'can_certify': function(value){ - return typeof(value) === 'boolean'; + 'can_certify': function (value){ + return typeof (value) === 'boolean'; }, - 'can_authenticate': function(value){ - return typeof(value) === 'boolean'; + 'can_authenticate': function (value){ + return typeof (value) === 'boolean'; }, - 'secret': function(value){ - return typeof(value) === 'boolean'; + 'secret': function (value){ + return typeof (value) === 'boolean'; }, - 'is_qualified': function(value){ - return typeof(value) === 'boolean'; + 'is_qualified': function (value){ + return typeof (value) === 'boolean'; }, - 'protocol': function(value){ - return typeof(value) === 'string'; - //TODO check for implemented ones + 'protocol': function (value){ + return typeof (value) === 'string'; + // TODO check for implemented ones }, - 'issuer_serial': function(value){ - return typeof(value) === 'string'; + 'issuer_serial': function (value){ + return typeof (value) === 'string'; }, - 'issuer_name': function(value){ - return typeof(value) === 'string'; + 'issuer_name': function (value){ + return typeof (value) === 'string'; }, - 'chain_id': function(value){ - return typeof(value) === 'string'; + 'chain_id': function (value){ + return typeof (value) === 'string'; }, - 'owner_trust': function(value){ - return typeof(value) === 'string'; + 'owner_trust': function (value){ + return typeof (value) === 'string'; }, - 'last_update': function(value){ + 'last_update': function (value){ return (Number.isInteger(value)); - //TODO undefined/null possible? + // TODO undefined/null possible? }, - 'origin': function(value){ + 'origin': function (value){ return (Number.isInteger(value)); }, - 'subkeys': function(value){ + 'subkeys': function (value){ return (Array.isArray(value)); }, - 'userids': function(value){ + 'userids': function (value){ return (Array.isArray(value)); }, - 'tofu': function(value){ + 'tofu': function (value){ return (Array.isArray(value)); }, - 'hasSecret': function(value){ - return typeof(value) === 'boolean'; + 'hasSecret': function (value){ + return typeof (value) === 'boolean'; } }; @@ -570,9 +575,9 @@ const validKeyProperties = { * an error if something went wrong. * @private */ -function validateKeyData(fingerprint, data){ +function validateKeyData (fingerprint, data){ const key = {}; - if (!fingerprint || typeof(data) !== 'object' || !data.fingerprint + if (!fingerprint || typeof (data) !== 'object' || !data.fingerprint || fingerprint !== data.fingerprint.toUpperCase() ){ return gpgme_error('KEY_INVALID'); @@ -619,13 +624,13 @@ function validateKeyData(fingerprint, data){ * @async */ function getGnupgState (fingerprint, property){ - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (!isFingerprint(fingerprint)) { reject(gpgme_error('KEY_INVALID')); } else { let msg = createMessage('keylist'); msg.setParameter('keys', fingerprint); - msg.post().then(function(res){ + msg.post().then(function (res){ if (!res.keys || res.keys.length !== 1){ reject(gpgme_error('KEY_INVALID')); } else { @@ -675,7 +680,7 @@ function getGnupgState (fingerprint, property){ break; } } - }, function(error){ + }, function (error){ reject(gpgme_error(error)); }); } diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index de21736e..90d267db 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -22,8 +22,8 @@ */ -import {createMessage} from './Message'; -import {createKey} from './Key'; +import { createMessage } from './Message'; +import { createKey } from './Key'; import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; @@ -31,8 +31,6 @@ import { gpgme_error } from './Errors'; * This class offers access to the gnupg keyring */ export class GPGME_Keyring { - constructor(){ - } /** * Queries Keys (all Keys or a subset) from gnupg. @@ -51,7 +49,7 @@ export class GPGME_Keyring { * @async */ getKeys (pattern, prepare_sync=false, search=false){ - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { let msg = createMessage('keylist'); if (pattern !== undefined && pattern !== null){ msg.setParameter('keys', pattern); @@ -60,25 +58,25 @@ export class GPGME_Keyring { if (search === true){ msg.setParameter('locate', true); } - msg.post().then(function(result){ + msg.post().then(function (result){ let resultset = []; if (result.keys.length === 0){ resolve([]); } else { let secondrequest; if (prepare_sync === true) { - secondrequest = function() { + secondrequest = function () { let msg2 = createMessage('keylist'); msg2.setParameter('keys', pattern); msg2.setParameter('secret', true); return msg2.post(); }; } else { - secondrequest = function() { + secondrequest = function () { return Promise.resolve(true); }; } - secondrequest().then(function(answer) { + secondrequest().then(function (answer) { for (let i=0; i < result.keys.length; i++){ if (prepare_sync === true){ if (answer && answer.keys) { @@ -104,7 +102,7 @@ export class GPGME_Keyring { resultset.push(k); } resolve(resultset); - }, function(error){ + }, function (error){ reject(error); }); } @@ -136,7 +134,7 @@ export class GPGME_Keyring { * @async */ getKeysArmored (pattern, with_secret_fpr) { - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); if (with_secret_fpr === true) { @@ -145,15 +143,15 @@ export class GPGME_Keyring { if (pattern !== undefined && pattern !== null){ msg.setParameter('keys', pattern); } - msg.post().then(function(answer){ - const result = {armored: answer.data}; + msg.post().then(function (answer){ + const result = { armored: answer.data }; if (with_secret_fpr === true && answer.hasOwnProperty('sec-fprs') ) { result.secret_fprs = answer['sec-fprs']; } resolve(result); - }, function(error){ + }, function (error){ reject(error); }); }); @@ -169,32 +167,32 @@ export class GPGME_Keyring { * @async * @static */ - getDefaultKey(prepare_sync = false) { + getDefaultKey (prepare_sync = false) { let me = this; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ let msg = createMessage('config_opt'); msg.setParameter('component', 'gpg'); msg.setParameter('option', 'default-key'); - msg.post().then(function(resp){ + msg.post().then(function (resp){ if (resp.option !== undefined && resp.option.hasOwnProperty('value') && resp.option.value.length === 1 && resp.option.value[0].hasOwnProperty('string') - && typeof(resp.option.value[0].string) === 'string'){ + && typeof (resp.option.value[0].string) === 'string'){ me.getKeys(resp.option.value[0].string, true).then( - function(keys){ - if(keys.length === 1){ + function (keys){ + if (keys.length === 1){ resolve(keys[0]); } else { reject(gpgme_error('KEY_NO_DEFAULT')); } - }, function(error){ + }, function (error){ reject(error); }); } else { let msg = createMessage('keylist'); msg.setParameter('secret', true); - msg.post().then(function(result){ + msg.post().then(function (result){ if (result.keys.length === 0){ reject(gpgme_error('KEY_NO_DEFAULT')); } else { @@ -211,11 +209,11 @@ export class GPGME_Keyring { } } } - }, function(error){ + }, function (error){ reject(error); }); } - }, function(error){ + }, function (error){ reject(error); }); }); @@ -264,14 +262,14 @@ export class GPGME_Keyring { 'new_signatures', 'new_revocations', 'secret_read', 'secret_imported', 'secret_unchanged', 'skipped_new_keys', 'not_imported', 'skipped_v3_keys']; - if (!armored || typeof(armored) !== 'string'){ + if (!armored || typeof (armored) !== 'string'){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let me = this; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ let msg = createMessage('import'); msg.setParameter('data', armored); - msg.post().then(function(response){ + msg.post().then(function (response){ let infos = {}; let fprs = []; let summary = {}; @@ -282,7 +280,7 @@ export class GPGME_Keyring { if (!response.result.hasOwnProperty('imports') || response.result.imports.length === 0 ){ - resolve({Keys:[],summary: summary}); + resolve({ Keys:[],summary: summary }); return; } for (let res=0; res} * @async */ - generateKey(userId, algo = 'default', expires){ + generateKey (userId, algo = 'default', expires){ if ( - typeof(userId) !== 'string' || + typeof (userId) !== 'string' || + // eslint-disable-next-line no-use-before-define supportedKeyAlgos.indexOf(algo) < 0 || (expires && !(expires instanceof Date)) ){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let me = this; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ let msg = createMessage('createkey'); msg.setParameter('userid', userId); msg.setParameter('algo', algo ); @@ -394,15 +393,15 @@ export class GPGME_Keyring { } else { msg.setParameter('expires', 0); } - msg.post().then(function(response){ + msg.post().then(function (response){ me.getKeys(response.fingerprint, true).then( // TODO prepare_sync? - function(result){ + function (result){ resolve(result); - }, function(error){ + }, function (error){ reject(error); }); - }, function(error) { + }, function (error) { reject(error); }); }); diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 2134fe99..1ba2b658 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -31,8 +31,8 @@ import { Connection } from './Connection'; * @param {String} operation * @returns {GPGME_Message|GPGME_Error} The Message object */ -export function createMessage(operation){ - if (typeof(operation) !== 'string'){ +export function createMessage (operation){ + if (typeof (operation) !== 'string'){ return gpgme_error('PARAM_WRONG'); } if (permittedOperations.hasOwnProperty(operation)){ @@ -51,7 +51,7 @@ export function createMessage(operation){ */ export class GPGME_Message { - constructor(operation){ + constructor (operation){ this._msg = { op: operation, chunksize: 1023* 1024 @@ -59,7 +59,7 @@ export class GPGME_Message { this._expected = null; } - get operation(){ + get operation (){ return this._msg.op; } @@ -69,7 +69,7 @@ export class GPGME_Message { } } - get expected() { + get expected () { return this._expected; } /** @@ -81,7 +81,7 @@ export class GPGME_Message { * will not encounter problems, larger messages will be received in * chunks. If the value is not explicitly specified, 1023 KB is used. */ - set chunksize(value){ + set chunksize (value){ if ( Number.isInteger(value) && value > 10 * 1024 && @@ -91,7 +91,7 @@ export class GPGME_Message { } } - get chunksize(){ + get chunksize (){ return this._msg.chunksize; } @@ -100,7 +100,7 @@ export class GPGME_Message { * @returns {Object|null} Object to be posted to gnupg, or null if * incomplete */ - get message() { + get message () { if (this.isComplete() === true){ return this._msg; } else { @@ -116,7 +116,7 @@ export class GPGME_Message { * @returns {Boolean} If the parameter was set successfully */ setParameter ( param,value ){ - if (!param || typeof(param) !== 'string'){ + if (!param || typeof (param) !== 'string'){ return gpgme_error('PARAM_WRONG'); } let po = permittedOperations[this._msg.op]; @@ -132,10 +132,10 @@ export class GPGME_Message { return gpgme_error('PARAM_WRONG'); } // check incoming value for correctness - let checktype = function(val){ - switch(typeof(val)){ + let checktype = function (val){ + switch (typeof (val)){ case 'string': - if (poparam.allowed.indexOf(typeof(val)) >= 0 + if (poparam.allowed.indexOf(typeof (val)) >= 0 && val.length > 0) { return true; } @@ -199,7 +199,7 @@ export class GPGME_Message { * all 'required' parameters according to {@link permittedOperations}. * @returns {Boolean} true if message is complete. */ - isComplete(){ + isComplete (){ if (!this._msg.op){ return false; } @@ -220,13 +220,13 @@ export class GPGME_Message { */ post (){ let me = this; - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (me.isComplete() === true) { let conn = new Connection; - conn.post(me).then(function(response) { + conn.post(me).then(function (response) { resolve(response); - }, function(reason) { + }, function (reason) { reject(reason); }); } diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index 65365772..a6539048 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -30,25 +30,27 @@ import { gpgme_error } from './Errors'; * {@link expNote}. * @returns {GPGME_Signature|GPGME_Error} Signature Object */ -export function createSignature(sigObject){ +export function createSignature (sigObject){ if ( - typeof(sigObject) !=='object' || + typeof (sigObject) !=='object' || !sigObject.hasOwnProperty('summary') || !sigObject.hasOwnProperty('fingerprint') || !sigObject.hasOwnProperty('timestamp') - //TODO check if timestamp is mandatory in specification + // 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]] ){ + // eslint-disable-next-line no-use-before-define + 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]] ){ + // eslint-disable-next-line no-use-before-define + if ( typeof (sigObject.summary[sumkeys[i]]) !== expSum[sumkeys[i]] ){ return gpgme_error('SIG_WRONG'); } } @@ -60,7 +62,8 @@ export function createSignature(sigObject){ 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]] ){ + // eslint-disable-next-line no-use-before-define + if ( typeof (notation[notekeys[j]]) !== expNote[notekeys[j]] ){ return gpgme_error('SIG_WRONG'); } } @@ -81,10 +84,10 @@ export function createSignature(sigObject){ */ class GPGME_Signature { - constructor(sigObject){ + constructor (sigObject){ this._rawSigObject = sigObject; } - get fingerprint(){ + get fingerprint (){ if (!this._rawSigObject.fingerprint){ return gpgme_error('SIG_WRONG'); } else { @@ -97,7 +100,7 @@ class GPGME_Signature { * signature does not expire * @returns {Date | null} */ - get expiration(){ + get expiration (){ if (!this._rawSigObject.exp_timestamp){ return null; } @@ -130,7 +133,7 @@ class GPGME_Signature { * for details on the values. * @returns {Object} Object with boolean properties */ - get errorDetails(){ + get errorDetails (){ let properties = ['revoked', 'key-expired', 'sig-expired', 'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy', 'sys-error']; diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 4aa51759..9a0925b0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -84,7 +84,7 @@ import { createSignature } from './Signature'; */ export class GpgME { - constructor(){ + constructor (){ this._Keyring = null; } @@ -92,7 +92,7 @@ export class GpgME { * setter for {@link setKeyring}. * @param {GPGME_Keyring} keyring A Keyring to use */ - set Keyring(keyring){ + set Keyring (keyring){ if (keyring && keyring instanceof GPGME_Keyring){ this._Keyring = keyring; } @@ -100,7 +100,7 @@ export class GpgME { /** * Accesses the {@link GPGME_Keyring}. */ - get Keyring(){ + get Keyring (){ if (!this._Keyring){ this._Keyring = new GPGME_Keyring; } @@ -188,9 +188,9 @@ export class GpgME { if (base64 === true){ msg.setParameter('base64', true); } - return new Promise(function(resolve, reject){ - msg.post().then(function(result){ - let _result = {data: result.data}; + 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.is_mime ? true: false; if (result.file_name){ @@ -206,7 +206,7 @@ export class GpgME { result.signatures); } resolve(_result); - }, function(error){ + }, function (error){ reject(error); }); }); @@ -240,14 +240,14 @@ export class GpgME { } msg.setParameter('mode', mode); putData(msg, data); - return new Promise(function(resolve,reject) { + return new Promise(function (resolve,reject) { if (mode ==='detached'){ msg.expected ='base64'; } - msg.post().then( function(message) { + msg.post().then( function (message) { if (mode === 'clearsign'){ resolve({ - data: message.data} + data: message.data } ); } else if (mode === 'detached') { resolve({ @@ -255,7 +255,7 @@ export class GpgME { signature: message.data }); } - }, function(error){ + }, function (error){ reject(error); }); }); @@ -278,7 +278,7 @@ export class GpgME { return Promise.reject(dt); } if (signature){ - if (typeof(signature)!== 'string'){ + if (typeof (signature)!== 'string'){ return Promise.reject(gpgme_error('PARAM_WRONG')); } else { msg.setParameter('signature', signature); @@ -287,7 +287,7 @@ export class GpgME { if (base64 === true){ msg.setParameter('base64', true); } - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject){ msg.post().then(function (message){ if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); @@ -301,7 +301,7 @@ export class GpgME { _result.data = message.data; resolve(_result); } - }, function(error){ + }, function (error){ reject(error); }); }); @@ -316,20 +316,20 @@ export class GpgME { * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise * @private */ -function putData(message, data){ +function putData (message, data){ if (!message || !(message instanceof GPGME_Message)) { return gpgme_error('PARAM_WRONG'); } if (!data){ return gpgme_error('PARAM_WRONG'); - } else if (typeof(data) === 'string') { + } else if (typeof (data) === 'string') { message.setParameter('data', data); } else if ( - typeof(data) === 'object' && - typeof(data.getText) === 'function' + typeof (data) === 'object' && + typeof (data.getText) === 'function' ){ let txt = data.getText(); - if (typeof(txt) === 'string'){ + if (typeof (txt) === 'string'){ message.setParameter('data', txt); } else { return gpgme_error('PARAM_WRONG'); @@ -345,7 +345,7 @@ function putData(message, data){ * @param {Array} sigs * @returns {signatureDetails} Details about the signatures */ -function collectSignatures(sigs){ +function collectSignatures (sigs){ if (!Array.isArray(sigs)){ return gpgme_error('SIG_NO_SIGS'); } diff --git a/lang/js/src/index.js b/lang/js/src/index.js index ad4b05b0..cf6e2d03 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -32,21 +32,21 @@ import { Connection } from './Connection'; * * @async */ -function init(){ - return new Promise(function(resolve, reject){ +function init (){ + return new Promise(function (resolve, reject){ const connection = new Connection; connection.checkConnection(false).then( - function(result){ + function (result){ if (result === true) { resolve(new GpgME()); } else { reject(gpgme_error('CONN_NO_CONNECT')); } - }, function(){ //unspecific connection error. Should not happen + }, function (){ // unspecific connection error. Should not happen reject(gpgme_error('CONN_NO_CONNECT')); }); }); } -const exportvalue = {init:init}; +const exportvalue = { init:init }; export default exportvalue; \ No newline at end of file diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index f9145dab..48ff7fa7 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -48,7 +48,7 @@ */ export const permittedOperations = { encrypt: { - pinentry: true, //TODO only with signing_keys + pinentry: true, // TODO only with signing_keys required: { 'keys': { allowed: ['string'], @@ -137,7 +137,7 @@ export const permittedOperations = { pinentry: true, required: { 'data': { - allowed: ['string']}, + allowed: ['string'] }, 'keys': { allowed: ['string'], array_allowed: true @@ -337,7 +337,7 @@ export const permittedOperations = { }, answer: { type: [''], - data: {'fingerprint': 'string'} + data: { 'fingerprint': 'string' } } }, @@ -365,9 +365,9 @@ export const permittedOperations = { data: 'string', base64:'boolean', info: 'object' - // file_name: Optional string of the plaintext file name. - // is_mime: Boolean if the messages claims it is MIME. - // signatures: Array of signatures + // info.file_name: Optional string of the plaintext file name. + // info.is_mime: Boolean if the messages claims it is MIME. + // info.signatures: Array of signatures } } }, diff --git a/lang/js/unittest_inputvalues.js b/lang/js/unittest_inputvalues.js index 02bb5329..659ef85c 100644 --- a/lang/js/unittest_inputvalues.js +++ b/lang/js/unittest_inputvalues.js @@ -1,4 +1,4 @@ -import {createKey} from './src/Key'; +import { createKey } from './src/Key'; export const helper_params = { validLongId: '0A0A0A0A0A0A0A0A', @@ -9,8 +9,8 @@ export const helper_params = { validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', '9AAE7A338A9A9A7A7A8A9A9A7A7A8A9A9A7A7DDA'], invalidLongId: '9A9A7A7A8A9A9A7A7A8A', - invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)], - invalidKeyArray: {curiosity:'uncat'}, + invalidFingerprints: [{ hello:'World' }, ['kekekeke'], new Uint32Array(40)], + invalidKeyArray: { curiosity:'uncat' }, invalidKeyArray_OneBad: [ createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'), 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', @@ -18,7 +18,7 @@ export const helper_params = { invalidErrorCode: 'Please type in all your passwords.', validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', true), valid_openpgplike: { primaryKey: { - getFingerprint: function(){ + getFingerprint: function (){ return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';} } } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 47eeabf2..0abc1061 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -18,8 +18,8 @@ * SPDX-License-Identifier: LGPL-2.1+ */ -import './node_modules/mocha/mocha'; /*global mocha, it, describe*/ -import './node_modules/chai/chai';/*global chai*/ +import './node_modules/mocha/mocha'; /* global mocha, it, describe*/ +import './node_modules/chai/chai';/* global chai*/ import { helper_params as hp } from './unittest_inputvalues'; import { message_params as mp } from './unittest_inputvalues'; import { whatever_params as wp } from './unittest_inputvalues'; @@ -29,18 +29,18 @@ import { gpgme_error } from './src/Errors'; import { toKeyIdArray , isFingerprint } from './src/Helpers'; import { createKey } from './src/Key'; import { GPGME_Keyring } from './src/Keyring'; -import {GPGME_Message, createMessage} from './src/Message'; +import { GPGME_Message, createMessage } from './src/Message'; mocha.setup('bdd'); const expect = chai.expect; chai.config.includeStack = true; function unittests (){ - describe('Connection testing', function(){ + describe('Connection testing', function (){ - it('Connecting', function(done) { + it('Connecting', function (done) { let conn0 = new Connection; - conn0.checkConnection().then(function(answer) { + conn0.checkConnection().then(function (answer) { expect(answer).to.not.be.empty; expect(answer.gpgme).to.not.be.undefined; expect(answer.gpgme).to.be.a('string'); @@ -52,12 +52,12 @@ function unittests (){ }); - it('Disconnecting', function(done) { + it('Disconnecting', function (done) { let conn0 = new Connection; - conn0.checkConnection(false).then(function(answer) { + conn0.checkConnection(false).then(function (answer) { expect(answer).to.be.true; conn0.disconnect(); - conn0.checkConnection(false).then(function(result) { + conn0.checkConnection(false).then(function (result) { expect(result).to.be.false; done(); }); @@ -65,9 +65,9 @@ function unittests (){ }); }); - describe('Error Object handling', function(){ + describe('Error Object handling', function (){ // TODO: new GPGME_Error codes - it('check the Timeout error', function(){ + it('check the Timeout error', function (){ let test0 = gpgme_error('CONN_TIMEOUT'); expect(test0).to.be.an.instanceof(Error); @@ -75,7 +75,7 @@ function unittests (){ }); it('Error Object returns generic code if code is not listed', - function(){ + function (){ let test0 = gpgme_error(hp.invalidErrorCode); expect(test0).to.be.an.instanceof(Error); @@ -83,22 +83,22 @@ function unittests (){ } ); - it('Warnings like PARAM_IGNORED should not return errors', function(){ + it('Warnings like PARAM_IGNORED should not return errors', function (){ let test0 = gpgme_error('PARAM_IGNORED'); expect(test0).to.be.null; }); }); - describe('Fingerprint checking', function(){ + describe('Fingerprint checking', function (){ - it('isFingerprint(): valid Fingerprint', function(){ + it('isFingerprint(): valid Fingerprint', function (){ let test0 = isFingerprint(hp.validFingerprint); expect(test0).to.be.true; }); - it('isFingerprint(): invalid Fingerprints', function(){ + it('isFingerprint(): invalid Fingerprints', function (){ for (let i=0; i < hp.invalidFingerprints.length; i++){ let test0 = isFingerprint(hp.invalidFingerprints[i]); @@ -107,16 +107,16 @@ function unittests (){ }); }); - describe('toKeyIdArray() (converting input to fingerprint)', function(){ + describe('toKeyIdArray() (converting input to fingerprint)', function (){ - it('Correct fingerprint string', function(){ + it('Correct fingerprint string', function (){ let test0 = toKeyIdArray(hp.validFingerprint); expect(test0).to.be.an('array'); expect(test0).to.include(hp.validFingerprint); }); - it('openpgpjs-like object', function(){ + it('openpgpjs-like object', function (){ let test0 = toKeyIdArray(hp.valid_openpgplike); expect(test0).to.be.an('array').with.lengthOf(1); @@ -124,33 +124,33 @@ function unittests (){ hp.valid_openpgplike.primaryKey.getFingerprint()); }); - it('Array of valid inputs', function(){ + it('Array of valid inputs', function (){ let test0 = toKeyIdArray(hp.validKeys); expect(test0).to.be.an('array'); expect(test0).to.have.lengthOf(hp.validKeys.length); }); - it('Incorrect inputs', function(){ + it('Incorrect inputs', function (){ - it('valid Long ID', function(){ + it('valid Long ID', function (){ let test0 = toKeyIdArray(hp.validLongId); expect(test0).to.be.empty; }); - it('invalidFingerprint', function(){ + it('invalidFingerprint', function (){ let test0 = toKeyIdArray(hp.invalidFingerprint); expect(test0).to.be.empty; }); - it('invalidKeyArray', function(){ + it('invalidKeyArray', function (){ let test0 = toKeyIdArray(hp.invalidKeyArray); expect(test0).to.be.empty; }); - it('Partially invalid array', function(){ + it('Partially invalid array', function (){ let test0 = toKeyIdArray(hp.invalidKeyArray_OneBad); expect(test0).to.be.an('array'); @@ -160,10 +160,10 @@ function unittests (){ }); }); - describe('GPGME_Key', function(){ - it('Key has data after a first refresh', function(done) { + describe('GPGME_Key', function (){ + it('Key has data after a first refresh', function (done) { let key = createKey(kp.validKeyFingerprint); - key.refreshKey().then(function(key2){ + key.refreshKey().then(function (key2){ expect(key2.get).to.be.a('function'); for (let i=0; i < kp.validKeyProperties.length; i++) { let prop = key2.get(kp.validKeyProperties[i]); @@ -181,7 +181,7 @@ function unittests (){ it('Non-cached key async data retrieval', function (done){ let key = createKey(kp.validKeyFingerprint, true); - key.get('can_authenticate').then(function(result){ + key.get('can_authenticate').then(function (result){ expect(result).to.be.a('boolean'); done(); }); @@ -189,7 +189,7 @@ function unittests (){ it('Non-cached key async armored Key', function (done){ let key = createKey(kp.validKeyFingerprint, true); - key.get('armored').then(function(result){ + key.get('armored').then(function (result){ expect(result).to.be.a('string'); expect(result).to.include('KEY BLOCK-----'); done(); @@ -198,7 +198,7 @@ function unittests (){ it('Non-cached key async hasSecret', function (done){ let key = createKey(kp.validKeyFingerprint, true); - key.get('hasSecret').then(function(result){ + key.get('hasSecret').then(function (result){ expect(result).to.be.a('boolean'); done(); }); @@ -206,24 +206,24 @@ function unittests (){ it('Non-cached key async hasSecret (no secret in Key)', function (done){ let key = createKey(kp.validFingerprintNoSecret, true); - key.get('hasSecret').then(function(result){ + key.get('hasSecret').then(function (result){ expect(result).to.be.a('boolean'); expect(result).to.equal(false); done(); }); }); - it('Querying non-existing Key returns an error', function(done) { + it('Querying non-existing Key returns an error', function (done) { let key = createKey(kp.invalidKeyFingerprint); - key.refreshKey().then(function(){}, - function(error){ + key.refreshKey().then(function (){}, + function (error){ expect(error).to.be.an.instanceof(Error); expect(error.code).to.equal('KEY_NOKEY'); done(); }); }); - it('createKey returns error if parameters are wrong', function(){ + it('createKey returns error if parameters are wrong', function (){ for (let i=0; i< 4; i++){ let key0 = createKey(wp.four_invalid_params[i]); expect(key0).to.be.an.instanceof(Error); @@ -248,18 +248,18 @@ function unittests (){ // }); }); - describe('GPGME_Keyring', function(){ + describe('GPGME_Keyring', function (){ - it('correct Keyring initialization', function(){ + it('correct Keyring initialization', function (){ let keyring = new GPGME_Keyring; expect(keyring).to.be.an.instanceof(GPGME_Keyring); expect(keyring.getKeys).to.be.a('function'); }); it('Loading Keys from Keyring, to be used synchronously', - function(done){ + function (done){ let keyring = new GPGME_Keyring; - keyring.getKeys(null, true).then(function(result){ + keyring.getKeys(null, true).then(function (result){ expect(result).to.be.an('array'); expect(result[0].get('hasSecret')).to.be.a('boolean'); done(); @@ -268,10 +268,10 @@ function unittests (){ ); it('Loading specific Key from Keyring, to be used synchronously', - function(done){ + function (done){ let keyring = new GPGME_Keyring; keyring.getKeys(kp.validKeyFingerprint, true).then( - function(result){ + function (result){ expect(result).to.be.an('array'); expect(result[0].get('hasSecret')).to.be.a('boolean'); done(); @@ -280,10 +280,10 @@ function unittests (){ } ); - it('Querying non-existing Key from Keyring', function(done){ + it('Querying non-existing Key from Keyring', function (done){ let keyring = new GPGME_Keyring; keyring.getKeys(kp.invalidKeyFingerprint, true).then( - function(result){ + function (result){ expect(result).to.be.an('array'); expect(result.length).to.equal(0); done(); @@ -293,16 +293,16 @@ function unittests (){ }); - describe('GPGME_Message', function(){ + describe('GPGME_Message', function (){ - it('creating encrypt Message', function(){ + it('creating encrypt Message', function (){ let test0 = createMessage('encrypt'); expect(test0).to.be.an.instanceof(GPGME_Message); expect(test0.isComplete()).to.be.false; }); - it('Message is complete after setting mandatory data', function(){ + it('Message is complete after setting mandatory data', function (){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); @@ -310,14 +310,14 @@ function unittests (){ expect(test0.isComplete()).to.be.true; }); - it('Message is not complete after mandatory data is empty', function(){ + it('Message is not complete after mandatory data is empty', function (){ let test0 = createMessage('encrypt'); test0.setParameter('data', ''); test0.setParameter('keys', hp.validFingerprints); expect(test0.isComplete()).to.be.false; }); - it('Complete Message contains the data that was set', function(){ + it('Complete Message contains the data that was set', function (){ let test0 = createMessage('encrypt'); test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('keys', hp.validFingerprints); @@ -330,20 +330,20 @@ function unittests (){ mp.valid_encrypt_data); }); - it ('Not accepting non-allowed operation', function(){ + it ('Not accepting non-allowed operation', function (){ let test0 = createMessage(mp.invalid_op_action); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('MSG_WRONG_OP'); }); - it('Not accepting wrong parameter type', function(){ + it('Not accepting wrong parameter type', function (){ let test0 = createMessage(mp.invalid_op_type); expect(test0).to.be.an.instanceof(Error); expect(test0.code).to.equal('PARAM_WRONG'); }); - it('Not accepting wrong parameter name', function(){ + it('Not accepting wrong parameter name', function (){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let i=0; i < mp.invalid_param_test.invalid_param_names.length; i++){ @@ -356,7 +356,7 @@ function unittests (){ } }); - it('Not accepting wrong parameter value', function(){ + it('Not accepting wrong parameter value', function (){ let test0 = createMessage(mp.invalid_param_test.valid_op); for (let j=0; j < mp.invalid_param_test.invalid_values_0.length; j++){ @@ -372,4 +372,4 @@ function unittests (){ } -export default {unittests}; \ No newline at end of file +export default { unittests }; \ No newline at end of file -- cgit From 738a8e6f950af08305c082d59a91d3d5d45800fa Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Tue, 21 Aug 2018 13:56:45 +0200 Subject: js: Update extra_dist files * lang/js/BrowserTestExtension/Makefile.am, lang/js/Makefile.am (EXTRA_DIST): Update. --- lang/js/BrowserTestExtension/Makefile.am | 3 +++ lang/js/Makefile.am | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/Makefile.am b/lang/js/BrowserTestExtension/Makefile.am index 340d7ad9..6153f7d7 100644 --- a/lang/js/BrowserTestExtension/Makefile.am +++ b/lang/js/BrowserTestExtension/Makefile.am @@ -32,11 +32,14 @@ EXTRA_DIST = browsertest.html \ testkey2.pub \ testkey.pub \ testkey.sec \ + tests/decryptTest.js \ tests/encryptDecryptTest.js \ tests/encryptTest.js \ tests/inputvalues.js \ tests/KeyImportExport.js \ + tests/KeyInfos.js \ tests/longRunningTests.js \ tests/signTest.js \ tests/startup.js \ + tests/verifyTest.js \ unittests.html diff --git a/lang/js/Makefile.am b/lang/js/Makefile.am index 4b5c7172..daa3d1ed 100644 --- a/lang/js/Makefile.am +++ b/lang/js/Makefile.am @@ -23,11 +23,10 @@ SUBDIRS = src BrowserTestExtension DemoExtension EXTRA_DIST = build_extensions.sh \ CHECKLIST \ CHECKLIST_build \ + jsdoc.conf \ .eslintrc.json \ - Makefile.am \ package.json \ README \ - README_testing \ unittest_inputvalues.js \ unittests.js \ webpack.conf.js \ -- cgit From 0036b9bc493f0482cc7c4619867649481393163e Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Tue, 21 Aug 2018 13:58:06 +0200 Subject: js: Fix library name mentioned in js Makefiles -- --- lang/js/BrowserTestExtension/Makefile.am | 6 +++--- lang/js/DemoExtension/Makefile.am | 8 ++++---- lang/js/Makefile.am | 10 +++++----- lang/js/src/Makefile.am | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/Makefile.am b/lang/js/BrowserTestExtension/Makefile.am index 6153f7d7..8f0a4f93 100644 --- a/lang/js/BrowserTestExtension/Makefile.am +++ b/lang/js/BrowserTestExtension/Makefile.am @@ -1,14 +1,14 @@ -# Makefile.am for GPGME-JS. +# Makefile.am for gpgme.js. # Copyright (C) 2018 Intevation GmbH # # This file is part of GPGME. # -# GPGME-CL is free software; you can redistribute it and/or modify it +# gpgme.js is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# GPGME-CL is distributed in the hope that it will be useful, +# gpgme.js 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. diff --git a/lang/js/DemoExtension/Makefile.am b/lang/js/DemoExtension/Makefile.am index e93d0f66..d6e87fde 100644 --- a/lang/js/DemoExtension/Makefile.am +++ b/lang/js/DemoExtension/Makefile.am @@ -1,14 +1,14 @@ -# Makefile.am for GPGME-JS. +# Makefile.am for gpgme.js. # Copyright (C) 2018 Intevation GmbH # -# This file is part of GPGME-CL. +# This file is part of gpgme.js. # -# GPGME-CL is free software; you can redistribute it and/or modify it +# gpgme.js is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# GPGME-CL is distributed in the hope that it will be useful, +# gpgme.js 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. diff --git a/lang/js/Makefile.am b/lang/js/Makefile.am index daa3d1ed..40a1c4fd 100644 --- a/lang/js/Makefile.am +++ b/lang/js/Makefile.am @@ -1,14 +1,14 @@ -# Makefile.am for GPGME-JS. -# Copyright (C) 2018 2018 Bundesamt für Sicherheit in der Informationstechnik +# Makefile.am for gpgme.js. +# Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik # -# This file is part of GPGME-JS. +# This file is part of gpgme.js. # -# GPGME-JS is free software; you can redistribute it and/or modify it +# gpgme.js is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# GPGME-JS is distributed in the hope that it will be useful, +# gpgme.js 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. diff --git a/lang/js/src/Makefile.am b/lang/js/src/Makefile.am index dd330d50..dc58fd31 100644 --- a/lang/js/src/Makefile.am +++ b/lang/js/src/Makefile.am @@ -1,14 +1,14 @@ -# Makefile.am for GPGME-JS. +# Makefile.am for gpgme.js. # Copyright (C) 2018 Intevation GmbH # # This file is part of GPGME. # -# GPGME-CL is free software; you can redistribute it and/or modify it +# gpgme.js is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# GPGME-CL is distributed in the hope that it will be useful, +# gpgme.js 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. -- cgit From 6d720137dd9564931bf313a7e7078e63fb00287c Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Tue, 21 Aug 2018 15:26:17 +0200 Subject: js: update decrypt/verify results -- * src/gpgmejs.js: Decrypt now parses additional optional dec_info information, as well as any verify information, if present * src/permittedOperations: Now decrypt also expect the new return object dec_inf (containing info such as is_mime and file_name) --- lang/js/BrowserTestExtension/tests/decryptTest.js | 16 ++++++++++++++++ lang/js/BrowserTestExtension/tests/inputvalues.js | 22 ++++++++++++++++++++-- lang/js/src/gpgmejs.js | 19 +++++++++++-------- lang/js/src/permittedOperations.js | 4 ++-- 4 files changed, 49 insertions(+), 12 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/decryptTest.js b/lang/js/BrowserTestExtension/tests/decryptTest.js index a3f48daa..ea887491 100644 --- a/lang/js/BrowserTestExtension/tests/decryptTest.js +++ b/lang/js/BrowserTestExtension/tests/decryptTest.js @@ -59,4 +59,20 @@ describe('Decryption', function () { }); }); }).timeout(5000); + + + it('decrypt/verify operations return proper information', function (done){ + const data = inputvalues.encryptSignedMessage; + context.decrypt(data).then(function (result){ + expect(result).to.be.an('object'); + expect(result.signatures).to.be.an('object'); + expect(result.signatures.all_valid).to.be.true; + expect(result.signatures.count).to.equal(1); + expect(result.signatures.signatures.good).to.be.an('array'); + expect( + result.signatures.signatures.good[0].fingerprint).to.equal( + good_fpr); + done(); + }); + }); }); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index f84ac955..5c2abf36 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -86,9 +86,27 @@ const inputvalues = {// eslint-disable-line no-unused-vars 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + '=ioB6\n' + - '-----END PGP SIGNATURE-----\n', + '-----END PGP SIGNATURE-----\n' }, - + encryptSignedMessage: '-----BEGIN PGP MESSAGE-----\n'+ + '\n'+ + 'hQEMA6B8jfIUScGEAQf/bmQ+xNMGTjPvQCktkxR4Svt2dVNVdSzKsCmvSv24QOQF\n'+ + 'yBMK5w51S/6DTdiZI12IYD7hjvkr9NqxXXupjrVKwqEVpg4Pkwckac0OcElJIBsL\n'+ + '3htr4iYsr8dhSgSS4BO0azcu4wZQTXy5v2P7yYPECMEagNEXnW+tE7sHLCq8Ysqz\n'+ + 'LVxG0R0IUijKeEd3xQC2Tt20e1Z1j5tnqaPhE/9Smqf5OjSUDqpXxvRnSNRk/zEs\n'+ + 'cGVgCF+cv68nUJM9lwEAbBQChplwL6ebnhunC6DsRCxnjLHVyKm127hmhSiMGC0e\n'+ + 'Ns31mGeP1dxpDv6Gi2/oKmq67vG3i4fKeckj7bt30tLA1wH0Qn5Mn6Tzxzve0W0q\n'+ + 'Ghqn9PY9qNK8EkrkzqaFk9dzu5tfSbaJBLS/uIhX2Wj70EMEBbFSkN0qlgOfLgGw\n'+ + '5mwRvCgj4nvV1ByFhnx7uwgQixvOwLH4JLKvwCQpJm+O2R0eC7M6CzR/b9iL/oaO\n'+ + 'JTkoD9hcLhxF7j+3ZYg7rbNwofuHST097vFjzItsucb0jHOzjlkCqbhdczICILTa\n'+ + 'H76Q6YGdMLyG9a3s4yZUMruaeQyWGeXlryzLDvdEoSgoD5YrolsFOM+Z2apbzVs2\n'+ + 'k5CltwtanjjWGnpAqSyr49C6CSU8G1QHpNygx5frtAS8bojR2ovB9OJp2wUklDvC\n'+ + 'LtU7dLpTY/BIvfB1vzwcW/aNgmPadNHX8mAzlqTQJjeLoo69Wp804t+u36sgfd/J\n'+ + 'ser7vdJJUm+86Q9csefItvFmHhqjMg5XXHoa8WZWJOHIQMxZkaIwKAzcEt/oEOdJ\n'+ + 'rbVNVabhTdbmS5I1ok16wg5jMF07ZDM7nXWMcQNjwT646XKP+pp2N6YQROVidNXj\n'+ + 'COyRyiXE/csr\n'+ + '=Ik7G\n'+ + '-----END PGP MESSAGE-----\n', someInputParameter: 'bad string', publicKeyNonAscii: { diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 9a0925b0..3be5cdd5 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -192,18 +192,21 @@ export class GpgME { msg.post().then(function (result){ let _result = { data: result.data }; _result.base64 = result.base64 ? true: false; - _result.is_mime = result.is_mime ? true: false; - if (result.file_name){ - _result.file_name = result.file_name; - } else { + if (result.hasOwnProperty('dec_info')){ + _result.is_mime = result.dec_info.is_mime ? true: false; + if (result.dec_info.file_name) { + _result.file_name = result.dec_info.file_name; + } + } + if (!result.file_name) { _result.file_name = null; } - if ( - result.hasOwnProperty('signatures') && - Array.isArray(result.signatures) + if (result.hasOwnProperty('info') + && result.info.hasOwnProperty('signatures') + && Array.isArray(result.info.signatures) ) { _result.signatures = collectSignatures( - result.signatures); + result.info.signatures); } resolve(_result); }, function (error){ diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 3142725c..6c05fc6c 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -127,8 +127,8 @@ export const permittedOperations = { 'data': 'string', 'base64': 'boolean', 'mime': 'boolean', - 'signatures': 'object', - 'info': 'object' + 'info': 'object', + 'dec_info': 'object' } } }, -- cgit From d8fd4aad8a93f7745c63814b3779469b610a8db0 Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 22 Aug 2018 12:44:05 +0200 Subject: js: changed verify signature result infos -- * the resulting information of verify now are as documented, and the same as in a decrypt callback --- lang/js/BrowserTestExtension/tests/verifyTest.js | 43 +++++++++++++----------- lang/js/src/gpgmejs.js | 6 ++-- 2 files changed, 28 insertions(+), 21 deletions(-) (limited to 'lang/js/BrowserTestExtension') diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index 82aaf564..5788ed51 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -38,12 +38,12 @@ describe('Verifying data', function () { const message = inputvalues.signedMessage.good; context.verify(message).then(function (result){ expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect(result.signatures.good[0].fingerprint).to.be.a('string'); - expect(result.signatures.good[0].valid).to.be.true; + expect(result.signatures.all_valid).to.be.true; + expect(result.signatures.count).to.equal(1); + expect(result.signatures.signatures.good).to.be.an('array'); + expect(result.signatures.signatures.good.length).to.equal(1); + expect(result.signatures.signatures.good[0].fingerprint).to.be.a('string'); + expect(result.signatures.signatures.good[0].valid).to.be.true; done(); }); }); @@ -52,12 +52,14 @@ describe('Verifying data', function () { const message = inputvalues.signedMessage.bad; context.verify(message).then(function (result){ expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.false; - expect(result.count).to.equal(1); - expect(result.signatures.bad).to.be.an('array'); - expect(result.signatures.bad.length).to.equal(1); - expect(result.signatures.bad[0].fingerprint).to.be.a('string'); - expect(result.signatures.bad[0].valid).to.be.false; + expect(result.signatures.all_valid).to.be.false; + expect(result.signatures.count).to.equal(1); + expect(result.signatures.signatures.bad).to.be.an('array'); + expect(result.signatures.signatures.bad.length).to.equal(1); + expect(result.signatures.signatures.bad[0].fingerprint) + .to.be.a('string'); + expect(result.signatures.signatures.bad[0].valid) + .to.be.false; done(); }); }); @@ -70,13 +72,16 @@ describe('Verifying data', function () { context.verify(message_encsign.data).then(function (result){ expect(result.data).to.equal(message_enc.data); expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect( - result.signatures.good[0].fingerprint).to.equal(fpr); - expect(result.signatures.good[0].valid).to.be.true; + expect(result.signatures.all_valid).to.be.true; + expect(result.signatures.count).to.equal(1); + expect(result.signatures.signatures.good) + .to.be.an('array'); + expect(result.signatures.signatures.good.length) + .to.equal(1); + expect(result.signatures.signatures.good[0].fingerprint) + .to.equal(fpr); + expect(result.signatures.signatures.good[0].valid) + .to.be.true; done(); }); }); diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 2886c6f6..7692298f 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -301,8 +301,10 @@ export class GpgME { if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); } else { - let _result = collectSignatures(message.info.signatures); - if (_result instanceof Error){ + let _result = { + signatures: collectSignatures(message.info.signatures) + }; + if (_result.signatures instanceof Error){ reject(_result.signatures); } else { _result.is_mime = message.info.is_mime? true: false; -- cgit