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 @@ -1,32 +1,49 @@ { "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" ], "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 @@ -1,149 +1,149 @@ /* 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 * Raimund Renkert */ /* global describe, it, expect, before, afterEach, Gpgmejs*/ /* global ImportablePublicKey, inputvalues */ describe('Key importing', function () { const fpr = ImportablePublicKey.fingerprint; const pubKey = ImportablePublicKey.key; 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 { done(); } }); }); }); - 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 { done(); } }); }); 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'); 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(); }); }); }); - 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'); 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(); }); }); }); - 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(); }); }); }); 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; 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){ + 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/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 @@ -1,57 +1,57 @@ /* 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*/ 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()); done(); }); }); - 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( inputvalues.publicKeyNonAscii.userid); done(); }); }); }); \ No newline at end of file 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 @@ -1,62 +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){ + before(function (done){ const prm = Gpgmejs.init(); - prm.then(function(gpgmejs){ + 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){ + 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.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(); }); }); }).timeout(5000); }); \ No newline at end of file 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 @@ -1,170 +1,170 @@ /* 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, 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(); }); }); it('Successful encrypt and decrypt simple string', function (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 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('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'); 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('Random data, as string', function (done) { let data = bigString(1000); 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); 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); it('Random data, input as base64', function (done) { let data = bigBoringString(0.001); let b64data = btoa(data); 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 3ead8153..a242af5f 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -1,113 +1,113 @@ /* 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('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(); }); }); 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(); }); }); 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); } it('Sending encryption without keys fails', function (done) { 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(); }); }); it('Sending encryption without data fails', function (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) { 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){ + }, 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) { 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: // kMaxMessageLength // The error will be a browser error, not from gnupg or from // this library 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 b33d985b..f84ac955 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -1,320 +1,320 @@ /* 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 */ const 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 : 'D41735B91236FDB882048C5A2301635EEFF0CB05', fingerprint_mixedcase: '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€', 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€', '€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€', '²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³²³', 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€A€µ€µ€µ€µ€', 'µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µ€µAµ€µ€µ€µ€', 'üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü', 'µAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA€', 'µAAAAµAAAAAAAAAAAAAAAAAAAAAAAAA€', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAµ€', 'µAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA°', '€AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA€', 'µ||||||||||||||||||||||||||||||€', 'æſæſ³¼„¬“³³¬“¬½”æſæſ³¼„¬“³³¬“¬½”' ] }, bad: { // valid Hex value, but not usable (not imported to gnupg, or // 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', }, 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. -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( Math.floor(Math.random() * 10174) + 1) ); } 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++){ uint[i] = Math.floor(Math.random()* 256); } let td = new TextDecoder('ascii'); let result = td.decode(uint); return result; } // (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++){ uint[i] = Math.floor(Math.random() * 256); } return uint; } // (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 = ' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; for (let i= 0; i < maxlength; i++){ string.push(chars[Math.floor(Math.random() * chars.length)]); } return string.join(''); } // 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 = ''; 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§$%&/()=?`#+-{}[] \''; } for (let i= 0; i < maxlength; i++){ string.push(chars[Math.floor(Math.random() * chars.length)]); } return string.join(''); } // Data encrypted with testKey const encryptedData =// eslint-disable-line no-unused-vars '-----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'; const 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' }; /** * 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]){ +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]; 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 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/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 @@ -1,56 +1,56 @@ /* 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 */ 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(); }); }); for (let i=0; i < 101; i++) { 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){ + 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(15000); } }); 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 @@ -1,63 +1,63 @@ /* 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 bigString, inputvalues */ 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(); }); }); it('Sign a message', function (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) { 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/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 @@ -1,47 +1,47 @@ /* 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, 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'); 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.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/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 @@ -1,85 +1,85 @@ /* 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, bigString, inputvalues, Gpgmejs */ 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); 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){ + 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) { 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; 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/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 @@ -1,30 +1,30 @@ /* 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() { +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 @@ -1,119 +1,119 @@ /* 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 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! '; } else { vals = 'Failure! '; } vals = vals + (answer.count - answer.failures) + 'of ' + 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; } else if (keys.length > 1) { alert('The pattern was not unambigious enough for a Key. ' + keys.length + ' Keys were found'); } 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 @@ -1,283 +1,283 @@ /* 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 */ 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 * protocol only allows up to 1MB of message sent from the nativeApp to the * browser, the connection will stay open until all parts of a communication * are finished. For a new request, a new port will open, to avoid mixing * contexts. * @class */ 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; } } /** * @typedef {Object} backEndDetails * @property {String} gpgme Version number of gpgme * @property {Array} info Further information about the backend * and the used applications (Example: * { * "protocol": "OpenPGP", * "fname": "/usr/bin/gpg", * "version": "2.2.6", * "req_version": "1.4.0", * "homedir": "default" * } */ /** * Retrieves the information about the backend. * @param {Boolean} details (optional) If set to false, the promise will * just return if a connection was successful. * @returns {Promise|Promise} Details from the * backend * @async */ checkConnection (details = true){ const msg = createMessage('version'); if (details === true) { 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); }); }); } } /** * Sends a {@link GPGME_Message} via tghe nativeMessaging port. It * resolves with the completed answer after all parts have been * received and reassembled, or rejects with an {@link GPGME_Error}. * * @param {GPGME_Message} message * @returns {Promise} The collected answer * @async */ - post(message){ + post (message){ if (!message || !(message instanceof GPGME_Message)){ this.disconnect(); return Promise.reject(gpgme_error( 'PARAM_WRONG', 'Connection.post')); } if (message.isComplete() !== true){ this.disconnect(); return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } 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(); 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(); reject(answer_result); } else { if (msg.more === true){ me._connection.postMessage({ 'op': 'getmore', 'chunksize': chunksize }); } else { me._connection.onMessage.removeListener(listener); me._connection.disconnect(); const message = answer.getMessage(); if (message instanceof Error){ reject(message); } else { resolve(message); } } } } }; me._connection.onMessage.addListener(listener); if (permittedOperations[message.operation].pinentry){ return me._connection.postMessage(message.message); } 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 { return reject; } }); } }); } } /** * A class for answer objects, checking and processing the return messages of * the nativeMessaging communication. * @protected */ class Answer{ /** * @param {GPGME_Message} message */ - constructor(message){ + constructor (message){ this._operation = message.operation; this._expected = message.expected; this._response_b64 = null; } get operation (){ return this._operation; } get expected (){ return this._expected; } /** * Adds incoming base64 encoded data to the existing response * @param {*} msg base64 encoded data. * @returns {Boolean} * * @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){ this._response_b64 = msg.response; return true; } else { this._response_b64 += msg.response; return true; } } /** * 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'); } let _decodedResponse = JSON.parse(atob(this._response_b64)); let _response = {}; let messageKeys = Object.keys(_decodedResponse); let poa = permittedOperations[this.operation].answer; if (messageKeys.length === 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } for (let i= 0; i < messageKeys.length; i++){ let key = messageKeys[i]; switch (key) { case 'type': if (_decodedResponse.type === 'error'){ return (gpgme_error('GNUPG_ERROR', decode(_decodedResponse.msg))); } else if (poa.type.indexOf(_decodedResponse.type) < 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } break; case 'base64': break; case 'msg': if (_decodedResponse.type === 'error'){ return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg)); } break; default: 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 && poa.data[key] === 'string' && this.expected !== 'base64' ){ _response[key] = decodeURIComponent( atob(_decodedResponse[key]).split('').map( - function(c) { + function (c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); } else { _response[key] = decode(_decodedResponse[key]); } break; } } return _response; } } 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 @@ -1,169 +1,169 @@ /* 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 */ /** * Listing of all possible error codes and messages of a {@link GPGME_Error}. */ const err_list = { // Connection 'CONN_NO_CONNECT': { msg:'Connection with the nativeMessaging host could not be' + ' established.', type: 'error' }, 'CONN_EMPTY_GPG_ANSWER':{ msg: 'The nativeMessaging answer was empty.', type: 'error' }, 'CONN_TIMEOUT': { msg: 'A connection timeout was exceeded.', type: 'error' }, 'CONN_UNEXPECTED_ANSWER': { msg: 'The answer from gnupg was not as expected.', type: 'error' }, 'CONN_ALREADY_CONNECTED':{ msg: 'A connection was already established.', type: 'warning' }, // Message/Data 'MSG_INCOMPLETE': { msg: 'The Message did not match the minimum requirements for' + ' the interaction.', type: 'error' }, 'MSG_EMPTY' : { msg: 'The Message is empty.', type: 'error' }, 'MSG_WRONG_OP': { msg: 'The operation requested could not be found', type: 'error' }, 'MSG_NO_KEYS' : { msg: 'There were no valid keys provided.', type: 'warning' }, 'MSG_NOT_A_FPR': { msg: 'The String is not an accepted fingerprint', type: 'warning' }, 'KEY_INVALID': { msg:'Key object is invalid', type: 'error' }, 'KEY_NOKEY': { msg:'This key does not exist in GPG', type: 'error' }, 'KEY_NO_INIT': { msg:'This property has not been retrieved yet from GPG', type: 'error' }, 'KEY_ASYNC_ONLY': { msg: 'This property cannot be used in synchronous calls', type: 'error' }, 'KEY_NO_DEFAULT': { msg:'A default key could not be established. Please check yout gpg ' + 'configuration', type: 'error' }, 'SIG_WRONG': { msg:'A malformed signature was created', type: 'error' }, 'SIG_NO_SIGS': { msg:'There were no signatures found', type: 'error' }, // generic 'PARAM_WRONG':{ msg: 'Invalid parameter was found', type: 'error' }, 'PARAM_IGNORED': { msg: 'An parameter was set that has no effect in gpgmejs', type: 'warning' }, 'GENERIC_ERROR': { msg: 'Unspecified error', type: 'error' } }; /** * Checks the given error code and returns an {@link GPGME_Error} error object * with some information about meaning and origin * @param {*} code Error code. Should be in err_list or 'GNUPG_ERROR' * @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); } if (err_list[code].type === 'warning'){ // eslint-disable-next-line no-console // console.warn(code + ': ' + err_list[code].msg); } return null; } else if (code === 'GNUPG_ERROR'){ return new GPGME_Error(code, info); } else { return new GPGME_Error('GENERIC_ERROR'); } } /** * An error class with additional info about the origin of the error, as string * @property {String} code Short description of origin and type of the error * @property {String} msg Additional info * @class * @protected * @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){ super(err_list[code].msg + '--' + msg); } else { super(err_list[code].msg); } } else { super(err_list['GENERIC_ERROR'].msg); } 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 @@ -1,137 +1,137 @@ /* 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 */ import { gpgme_error } from './Errors'; /** * Tries to return an array of fingerprints, either from input fingerprints or * from Key objects (openpgp Keys or GPGME_Keys are both accepted). * * @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 []; } if (!Array.isArray(input)){ input = [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 { // MSG_NOT_A_FPR is just a console warning if warning enabled // 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; } else if (input[i].hasOwnProperty('primaryKey') && input[i].primaryKey.hasOwnProperty('getFingerprint')){ fpr = input[i].primaryKey.getFingerprint(); } if (isFingerprint(fpr) === true){ result.push(fpr); } else { gpgme_error('MSG_NOT_A_FPR'); } } else { return gpgme_error('PARAM_WRONG'); } } if (result.length === 0){ return []; } else { return result; } } /** * Check if values are valid hexadecimal values of a specified length * @param {String} key input value. * @param {int} len the expected length of the value * @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){ return false; } let regexp= /^[0-9a-fA-F]*$/i; return regexp.test(key); } /** * check if the input is a valid Fingerprint * (Hex string with a length of 40 characters) * @param {String} value to check * @returns {Boolean} true if value passes test */ -export function isFingerprint(value){ +export function isFingerprint (value){ return hextest(value, 40); } /** * check if the input is a valid gnupg long ID (Hex string with a length of 16 * characters) * @param {String} value to check * @returns {Boolean} true if value passes test */ -export function isLongId(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){ +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 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 @@ -1,683 +1,688 @@ /* 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 */ import { isFingerprint, isLongId } from './Helpers'; import { gpgme_error } from './Errors'; 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 * @param {Object} data additional initial properties this Key will have. Needs * 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){ data = validateKeyData(fingerprint, data); } if (data instanceof Error){ return gpgme_error('KEY_INVALID'); } else { return new GPGME_Key(fingerprint, async, data); } } /** * Represents the Keys as stored in the gnupg backend * It allows to query almost all information defined in gpgme Key Objects * Refer to {@link validKeyProperties} for available information, and the gpgme * documentation on their meaning * (https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html) * * @class */ 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 ) { this._data = data; } } /** * Query any property of the Key listed in {@link validKeyProperties} * @param {String} property property to be retreived * @returns {Boolean| String | Date | Array | Object |GPGME_Error} * the value of the property. If the Key is set to Async, the value * will be fetched from gnupg and resolved as a Promise. If Key is not * 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': return this.getArmor(); case 'hasSecret': return this.getGnupgSecretState(); default: return getGnupgState(this.fingerprint, property); } } else { 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 { return (this._data[property]); } } } /** * Reloads the Key information from gnupg. This is only useful if you * use the GPGME_Keys cached. Note that this is a performance hungry * operation. If you desire more than a few refreshs, it may be * advisable to run {@link Keyring.getKeys} instead. * @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]); if (newdata instanceof Error){ 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); }); } } else { reject(gpgme_error('KEY_NOKEY')); } }, function (error) { reject(gpgme_error('GNUPG_ERROR'), error); }); }); } /** * Query the armored block of the Key directly from gnupg. Please note * that this will not get you any export of the secret/private parts of * a 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); }); }); } /** * Find out if the Key is part of a Key pair including public and * private key(s). If you want this information about more than a few * Keys in synchronous mode, it may be advisable to run * {@link Keyring.getKeys} instead, as it performs faster in bulk * querying this state. * @returns {Promise} True if a private Key is * available in the gnupg Keyring. * @async */ 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 && result.keys.length === 1 && result.keys[0].secret === true ) { me._data.hasSecret = true; resolve(true); } else { me._data.hasSecret = false; resolve(false); } - }, function(error){ + }, function (error){ reject(error); }); } }); } /** * 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. */ - 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); }); }); } /** * @returns {String} The fingerprint defining this Key. Convenience getter */ - get fingerprint(){ + get fingerprint (){ return this._data.fingerprint; } } /** * Representing a subkey of a Key. * @class * @protected */ class GPGME_Subkey { /** * Initializes with the json data sent by gpgme-json * @param {Object} data * @private */ - constructor(data){ + constructor (data){ this._data = {}; let keys = Object.keys(data); const me = this; /** * Validates a subkey property against {@link validSubKeyProperties} and * sets it if validation is successful * @param {String} property * @param {*} value * @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); } else { me._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) { + get (property) { if (this._data.hasOwnProperty(property)){ return (this._data[property]); } } } /** * Representing user attributes associated with a Key or subkey * @class * @protected */ class GPGME_UserId { /** * Initializes with the json data sent by gpgme-json * @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); } else { me._data[property] = value; } } } }; for (let i=0; i< keys.length; i++) { setProperty(keys[i], data[keys[i]]); } } /** * Fetches information about the user * @param {String} property Information to request * @returns {String | Number} */ - get(property) { + get (property) { if (this._data.hasOwnProperty(property)){ return (this._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 * against * @protected * @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); } }; /** * Validation definition for subKeys. Each valid userId property is represented * as a key-value pair, with the value being a validation function * @protected * @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); } }; /** * Validation definition for Keys. Each valid Key property is represented * as a key-value pair, with their value being a validation function. For * details on the meanings, please refer to the gpgme documentation * https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html#Key-objects * @param {String} fingerprint * @param {Boolean} revoked * @param {Boolean} expired * @param {Boolean} disabled * @param {Boolean} invalid * @param {Boolean} can_encrypt * @param {Boolean} can_sign * @param {Boolean} can_certify * @param {Boolean} can_authenticate * @param {Boolean} secret * @param {Boolean}is_qualified * @param {String} protocol * @param {String} issuer_serial * @param {String} issuer_name * @param {Boolean} chain_id * @param {String} owner_trust * @param {Date} last_update * @param {String} origin * @param {Array} subkeys * @param {Array} userids * @param {Array} tofu * @param {Boolean} hasSecret * @protected * @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'; } }; /** * sets the Key data in bulk. It can only be used from inside a Key, either * during construction or on a refresh callback. * @param {Object} key the original internal key data. * @param {Object} data Bulk set the data for this key, with an Object structure * as sent by gpgme-json. * @returns {Object|GPGME_Error} the changed data after values have been set, * 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'); } let props = Object.keys(data); for (let i=0; i< props.length; i++){ if (!validKeyProperties.hasOwnProperty(props[i])){ return gpgme_error('KEY_INVALID'); } // running the defined validation function if (validKeyProperties[props[i]](data[props[i]]) !== true ){ return gpgme_error('KEY_INVALID'); } switch (props[i]){ case 'subkeys': key.subkeys = []; for (let i=0; i< data.subkeys.length; i++) { key.subkeys.push( new GPGME_Subkey(data.subkeys[i])); } break; case 'userids': key.userids = []; for (let i=0; i< data.userids.length; i++) { key.userids.push( new GPGME_UserId(data.userids[i])); } break; case 'last_update': key[props[i]] = new Date( data[props[i]] * 1000 ); break; default: key[props[i]] = data[props[i]]; } } return key; } /** * Fetches and sets properties from gnupg * @param {String} fingerprint * @param {String} property to search for. * @private * @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 { const key = res.keys[0]; let result; switch (property){ case 'subkeys': result = []; if (key.subkeys.length){ for (let i=0; i < key.subkeys.length; i++) { result.push( new GPGME_Subkey(key.subkeys[i])); } } resolve(result); break; case 'userids': result = []; if (key.userids.length){ for (let i=0; i< key.userids.length; i++) { result.push( new GPGME_UserId(key.userids[i])); } } resolve(result); break; case 'last_update': if (key.last_update === undefined){ reject(gpgme_error('CONN_UNEXPECTED_ANSWER')); } else if (key.last_update !== null){ resolve(new Date( key.last_update * 1000)); } else { resolve(null); } break; default: if (!validKeyProperties.hasOwnProperty(property)){ reject(gpgme_error('PARAM_WRONG')); } else { if (key.hasOwnProperty(property)){ resolve(key[property]); } else { reject(gpgme_error( 'CONN_UNEXPECTED_ANSWER')); } } break; } } - }, function(error){ + }, function (error){ reject(gpgme_error(error)); }); } }); } \ No newline at end of file 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 @@ -1,426 +1,425 @@ /* 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 */ -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'; /** * This class offers access to the gnupg keyring */ export class GPGME_Keyring { - constructor(){ - } /** * Queries Keys (all Keys or a subset) from gnupg. * * @param {String | Array} pattern (optional) A pattern to * search for in userIds or KeyIds. * @param {Boolean} prepare_sync (optional) if set to true, most data * (with the exception of armored Key blocks) will be cached for the * Keys. This enables direct, synchronous use of these properties for * all keys. It does not check for changes on the backend. The cached * information can be updated with the {@link Key.refresh} method. * @param {Boolean} search (optional) retrieve Keys from external * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup) * @returns {Promise>} * @static * @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); } msg.setParameter('sigs', true); 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) { for (let j=0; j < answer.keys.length; j++ ){ const a = answer.keys[j]; const b = result.keys[i]; if ( a.fingerprint === b.fingerprint ) { if (a.secret === true){ b.hasSecret = true; } else { b.hasSecret = false; } break; } } } } let k = createKey(result.keys[i].fingerprint, !prepare_sync, result.keys[i]); resultset.push(k); } resolve(resultset); - }, function(error){ + }, function (error){ reject(error); }); } }); }); } /** * @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). * @param {String|Array} pattern (optional) The Pattern to * search for * @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, 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) { msg.setParameter('with-sec-fprs', true); } 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); }); }); } /** * Returns the Key used by default in gnupg. * (a.k.a. 'primary Key or 'main key'). * It looks up the gpg configuration if set, or the first key that * contains a secret key. * * @returns {Promise} * @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 { for (let i=0; i< result.keys.length; i++ ) { if (result.keys[i].invalid === false) { let k = createKey( result.keys[i].fingerprint, !prepare_sync, result.keys[i]); resolve(k); break; } else if (i === result.keys.length - 1){ reject(gpgme_error('KEY_NO_DEFAULT')); } } } - }, function(error){ + }, function (error){ reject(error); }); } - }, function(error){ + }, function (error){ reject(error); }); }); } /** * @typedef {Object} importResult The result of a Key update * @property {Object} summary Numerical summary of the result. See the * feedbackValues variable for available Keys values and the gnupg * documentation. * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html * for details on their meaning. * @property {Array} Keys Array of Object containing * GPGME_Keys with additional import information * */ /** * @typedef {Object} importedKeyResult * @property {GPGME_Key} key The resulting key * @property {String} 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. * @property {Boolean} changes.userId Changes in userIds * @property {Boolean} changes.signature Changes in signatures * @property {Boolean} changes.subkey Changes in subkeys */ /** * Import an armored Key block into gnupg. Note that this currently * will not succeed on private Key blocks. * @param {String} armored Armored Key block of the Key(s) to be * imported into gnupg * @param {Boolean} prepare_sync prepare the keys for synched use * (see {@link getKeys}). * @returns {Promise} A summary and Keys considered. * @async * @static */ importKey (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', '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 = {}; 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}); + resolve({ Keys:[],summary: summary }); return; } for (let res=0; res} * @async * @static */ - deleteKey(fingerprint){ + deleteKey (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 * representing that Key. Please note that due to security concerns, * secret Keys can not be deleted or exported from inside gpgme.js. * * @param {String} userId The user Id, e.g. 'Foo Bar ' * @param {String} algo (optional) algorithm (and optionally key size) * to be used. See {@link supportedKeyAlgos} below for supported * values. * @param {Date} expires (optional) Expiration date. If not set, * expiration will be set to 'never' * * @return {Promise} * @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 ); if (expires){ msg.setParameter('expires', Math.floor(expires.valueOf()/1000)); } 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); }); }); } } /** * List of algorithms supported for key generation. Please refer to the gnupg * documentation for details */ const supportedKeyAlgos = [ 'default', 'rsa', 'rsa2048', 'rsa3072', 'rsa4096', 'dsa', 'dsa2048', 'dsa3072', 'dsa4096', 'elg', 'elg2048', 'elg3072', 'elg4096', 'ed25519', 'cv25519', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'NIST P-256', 'NIST P-384', 'NIST P-521' ]; \ No newline at end of file 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 @@ -1,239 +1,239 @@ /* 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 */ import { permittedOperations } from './permittedOperations'; import { gpgme_error } from './Errors'; import { Connection } from './Connection'; /** * Initializes a message for gnupg, validating the message's purpose with * {@link permittedOperations} first * @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)){ return new GPGME_Message(operation); } else { return gpgme_error('MSG_WRONG_OP'); } } /** * A Message collects, validates and handles all information required to * successfully establish a meaningful communication with gpgme-json via * {@link Connection.post}. The definition on which communication is available * can be found in {@link permittedOperations}. * @class */ export class GPGME_Message { - constructor(operation){ + constructor (operation){ this._msg = { op: operation, chunksize: 1023* 1024 }; this._expected = null; } - get operation(){ + get operation (){ return this._msg.op; } set expected (value){ if (value === 'base64'){ this._expected = value; } } - get expected() { + get expected () { return this._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. * Everything above that threshold will not pass through * nativeMessaging; answers that are larger need to be sent in parts. * The lower limit is set to 10 KB. Messages smaller than the threshold * 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 && value <= 1024 * 1024 ){ this._msg.chunksize = value; } } - get chunksize(){ + get chunksize (){ return this._msg.chunksize; } /** * Returns the prepared message with parameters and completeness checked * @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 { return null; } } /** * Sets a parameter for the message. It validates with * {@link permittedOperations} * @param {String} param Parameter to set * @param {any} value Value to set * @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]; if (!po){ return gpgme_error('MSG_WRONG_OP'); } 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'); } // 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; } return gpgme_error('PARAM_WRONG'); case 'number': if ( poparam.allowed.indexOf('number') >= 0 && isNaN(value) === false){ 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'); } 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'); } 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; } /** * 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. */ - isComplete(){ + isComplete (){ if (!this._msg.op){ return false; } 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 (msg_params.indexOf(reqParams[i]) < 0){ return false; } } return true; } /** * Sends the Message via nativeMessaging and resolves with the answer. * @returns {Promise} * @async */ 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); }); } else { reject(gpgme_error('MSG_INCOMPLETE')); } }); } } 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 @@ -1,197 +1,200 @@ /* 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 */ import { gpgme_error } from './Errors'; /** * Validates an object containing a signature, as sent by the nativeMessaging * interface * @param {Object} sigObject Object as returned by gpgme-json. The definition * of the expected values are to be found in {@link expKeys}, {@link expSum}, * {@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'); } } if (sigObject.hasOwnProperty('notations')){ if (!Array.isArray(sigObject.notations)){ return gpgme_error('SIG_WRONG'); } for (let i=0; i < sigObject.notations.length; i++){ let notation = sigObject.notations[i]; let notekeys = Object.keys(notation); for (let j=0; j < notekeys.length; j++){ - if ( typeof(notation[notekeys[j]]) !== expNote[notekeys[j]] ){ + // eslint-disable-next-line no-use-before-define + if ( typeof (notation[notekeys[j]]) !== expNote[notekeys[j]] ){ return gpgme_error('SIG_WRONG'); } } } } return new GPGME_Signature(sigObject); } /** * Representing the details of a signature. The full details as given by * gpgme-json can be read from the _rawSigObject. * * Note to reviewers: This class should be read only except via * {@link createSignature} * @protected * @class */ class GPGME_Signature { - constructor(sigObject){ + constructor (sigObject){ this._rawSigObject = sigObject; } - get fingerprint(){ + get fingerprint (){ if (!this._rawSigObject.fingerprint){ return gpgme_error('SIG_WRONG'); } else { return this._rawSigObject.fingerprint; } } /** * The expiration of this Signature as Javascript date, or null if * signature does not expire * @returns {Date | null} */ - get expiration(){ + get expiration (){ if (!this._rawSigObject.exp_timestamp){ return null; } return new Date(this._rawSigObject.exp_timestamp* 1000); } /** * The creation date of this Signature in Javascript Date * @returns {Date} */ get timestamp (){ return new Date(this._rawSigObject.timestamp * 1000); } /** * The overall validity of the key. If false, errorDetails may contain * additional information. */ get valid () { if (this._rawSigObject.summary.valid === true){ return true; } else { return false; } } /** * gives more information on non-valid signatures. Refer to the gpgme * docs https://www.gnupg.org/documentation/manuals/gpgme/Verify.html * for details on the values. * @returns {Object} Object with boolean properties */ - get errorDetails(){ + get errorDetails (){ let properties = ['revoked', 'key-expired', 'sig-expired', 'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy', 'sys-error']; let result = {}; for (let i=0; i< properties.length; i++){ if ( this._rawSigObject.hasOwnProperty(properties[i]) ){ result[properties[i]] = this._rawSigObject[properties[i]]; } } return result; } } /** * Keys and their value's type for the signature Object */ const expKeys = { 'wrong_key_usage': 'boolean', 'chain_model': 'boolean', 'summary': 'object', 'is_de_vs': 'boolean', 'status_string':'string', 'fingerprint':'string', 'validity_string': 'string', 'pubkey_algo_name':'string', 'hash_algo_name':'string', 'pka_address':'string', 'status_code':'number', 'timestamp':'number', 'exp_timestamp':'number', 'pka_trust':'number', 'validity':'number', 'validity_reason':'number', 'notations': 'object' }; /** * Keys and their value's type for the summary */ const expSum = { 'valid': 'boolean', 'green': 'boolean', 'red': 'boolean', 'revoked': 'boolean', 'key-expired': 'boolean', 'sig-expired': 'boolean', 'key-missing': 'boolean', 'crl-missing': 'boolean', 'crl-too-old': 'boolean', 'bad-policy': 'boolean', 'sys-error': 'boolean', 'sigsum': 'object' }; /** * Keys and their value's type for notations objects */ const expNote = { 'human_readable': 'boolean', 'critical':'boolean', 'name': 'string', 'value': 'string', 'flags': 'number' }; diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 4aa51759..9a0925b0 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -1,377 +1,377 @@ /* 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 */ import { GPGME_Message, createMessage } from './Message'; import { toKeyIdArray } from './Helpers'; import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; import { createSignature } from './Signature'; /** * @typedef {Object} decrypt_result * @property {String} data The decrypted data * @property {Boolean} base64 indicating whether data is base64 encoded. * @property {Boolean} is_mime (optional) the data claims to be a MIME * object. * @property {String} file_name (optional) the original file name * @property {signatureDetails} signatures Verification details for * signatures */ /** * @typedef {Object} signatureDetails * @property {Boolean} all_valid Summary if all signatures are fully valid * @property {Number} count Number of signatures found * @property {Number} failures Number of invalid signatures * @property {Array} signatures.good All valid signatures * @property {Array} signatures.bad All invalid signatures */ /** * @typedef {Object} encrypt_result The result of an encrypt operation * @property {String} data The encrypted message * @property {Boolean} base64 Indicating whether data is base64 encoded. */ /** * @typedef { GPGME_Key | String | Object } inputKeys * Accepts different identifiers of a gnupg Key that can be parsed by * {@link toKeyIdArray}. Expected inputs are: One or an array of * GPGME_Keys; one or an array of fingerprint strings; one or an array of * openpgpjs Key objects. */ /** * @typedef {Object} signResult The result of a signing operation * @property {String} data The resulting data. Includes the signature in * clearsign mode * @property {String} signature The detached signature (if in detached mode) */ /** @typedef {Object} verifyResult The result of a verification * @property {Boolean} data: The verified data * @property {Boolean} is_mime (optional) the data claims to be a MIME * object. * @property {String} file_name (optional) the original file name * @property {signatureDetails} signatures Verification details for * signatures */ /** * The main entry point for gpgme.js. * @class */ export class GpgME { - constructor(){ + constructor (){ this._Keyring = null; } /** * 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; } } /** * Accesses the {@link GPGME_Keyring}. */ - get Keyring(){ + get Keyring (){ if (!this._Keyring){ this._Keyring = new GPGME_Keyring; } return this._Keyring; } /** * Encrypt (and optionally sign) data * @param {String|Object} data text/data to be encrypted as String. Also * accepts Objects with a getText method * @param {inputKeys} publicKeys * Keys used to encrypt the message * @param {inputKeys} secretKeys (optional) Keys used to sign the * message. If Keys are present, the operation requested is assumed * to be 'encrypt and sign' * @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. * @param {Object} additional use additional valid gpg options as * defined in {@link permittedOperations} * @returns {Promise} Object containing the encrypted * message and additional info. * @async */ encrypt (data, publicKeys, secretKeys, base64=false, armor=true, wildcard=false, additional = {}){ let msg = createMessage('encrypt'); if (msg instanceof Error){ return Promise.reject(msg); } msg.setParameter('armor', armor); msg.setParameter('always-trust', true); if (base64 === true) { msg.setParameter('base64', true); } let pubkeys = toKeyIdArray(publicKeys); msg.setParameter('keys', pubkeys); let sigkeys = toKeyIdArray(secretKeys); if (sigkeys.length > 0) { msg.setParameter('signing_keys', sigkeys); } 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++) { msg.setParameter(additional_Keys[k], additional[additional_Keys[k]]); } } if (msg.isComplete() === true){ return msg.post(); } else { return Promise.reject(gpgme_error('MSG_INCOMPLETE')); } } /** * Decrypts a Message * @param {String|Object} data text/data to be decrypted. Accepts * Strings and Objects with a getText method * @param {Boolean} base64 (optional) false if the data is an armored * block, true if it is base64 encoded binary data * @returns {Promise} Decrypted Message and information * @async */ decrypt (data, base64=false){ if (data === undefined){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); if (msg instanceof Error){ return Promise.reject(msg); } if (base64 === true){ msg.setParameter('base64', true); } putData(msg, data); 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){ _result.file_name = result.file_name; } else { _result.file_name = null; } if ( result.hasOwnProperty('signatures') && Array.isArray(result.signatures) ) { _result.signatures = collectSignatures( result.signatures); } resolve(_result); - }, function(error){ + }, function (error){ reject(error); }); }); } /** * Sign a Message * @param {String|Object} data text/data to be signed. Accepts Strings * and Objects with a getText method. * @param {inputKeys} keys The key/keys to use for signing * @param {String} mode The signing mode. Currently supported: * 'clearsign':The Message is embedded into the signature; * 'detached': The signature is stored separately * @param {Boolean} base64 input is considered base64 * @returns {Promise} * @async */ sign (data, keys, mode='clearsign', base64=false) { 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); - 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({ data: data, signature: message.data }); } - }, function(error){ + }, function (error){ reject(error); }); }); } /** * Verifies data. * @param {String|Object} data text/data to be verified. Accepts Strings * and Objects with a getText method * @param {String} (optional) A detached signature. If not present, * opaque mode is assumed * @param {Boolean} (optional) Data and signature are base64 encoded * @returns {Promise} *@async */ verify (data, signature, base64 = false){ let msg = createMessage('verify'); let dt = putData(msg, data); if (dt instanceof Error){ 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); } } 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')); } else { let _result = collectSignatures( message.info.signatures); _result.is_mime = message.info.is_mime? true: false; if (message.info.filename){ _result.file_name = message.info.filename; } _result.data = message.data; resolve(_result); } - }, function(error){ + }, function (error){ reject(error); }); }); } } /** * Sets the data of the message, setting flags according on the data type * @param {GPGME_Message} message The message where this data will be set * @param { String| Object } data The data to enter. Expects either a string of * data, or an object with a getText method * @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'); } } else { return gpgme_error('PARAM_WRONG'); } } /** * Parses, validates and converts incoming objects into signatures. * @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'); } let summary = { all_valid: false, count: sigs.length, failures: 0, signatures: { good: [], bad: [], } }; for (let i=0; i< sigs.length; i++){ let sigObj = createSignature(sigs[i]); if (sigObj instanceof Error){ return gpgme_error(sigObj); } if (sigObj.valid !== true){ summary.failures += 1; summary.signatures.bad.push(sigObj); } else { summary.signatures.good.push(sigObj); } } if (summary.failures === 0){ summary.all_valid = true; } return summary; } \ No newline at end of file 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 @@ -1,52 +1,52 @@ /* 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 */ import { GpgME } from './gpgmejs'; import { gpgme_error } from './Errors'; import { Connection } from './Connection'; /** * Initializes gpgme.js by testing the nativeMessaging connection once. * @returns {Promise | GPGME_Error} * * @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 @@ -1,400 +1,400 @@ /* 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 */ /** * @typedef {Object} messageProperty * A message Property is defined by it's key. * @property {Array} allowed Array of allowed types. * Currently accepted values are 'number', 'string', 'boolean'. * @property {Boolean} array_allowed If the value can be an array of types * defined in allowed * @property {Array<*>} allowed_data (optional) restricts to the given values */ /** * Definition of the possible interactions with gpgme-json. * @param {Object} operation Each operation is named by a key and contains * the following properties: * @property {messageProperty} required An object with all required parameters * @property {messageProperty} optional An object with all optional parameters * @property {Boolean} pinentry (optional) If true, a password dialog is * expected, thus a connection tuimeout is not advisable * @property {Object} answer The definition on what to expect as answer, if the * answer is not an error * @property {Array} answer.type the type(s) as reported by gpgme-json. * @property {Object} answer.data key-value combinations of expected properties * of an answer and their type ('boolean', 'string', object) @const */ export const permittedOperations = { encrypt: { - pinentry: true, //TODO only with signing_keys + pinentry: true, // TODO only with signing_keys required: { 'keys': { allowed: ['string'], array_allowed: true }, 'data': { allowed: ['string'] } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'signing_keys': { allowed: ['string'], array_allowed: true }, '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': 'string', 'base64':'boolean' } } }, decrypt: { pinentry: true, required: { 'data': { allowed: ['string'] } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'base64': { allowed: ['boolean'] } }, answer: { type: ['plaintext'], data: { 'data': 'string', 'base64': 'boolean', 'mime': 'boolean', 'signatures': 'object', 'info': 'object' } } }, sign: { pinentry: true, required: { 'data': { - allowed: ['string']}, + allowed: ['string'] }, 'keys': { allowed: ['string'], array_allowed: true } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'sender': { allowed: ['string'], }, 'mode': { allowed: ['string'], allowed_data: ['detached', 'clearsign'] // TODO 'opaque' is not used, but available on native app }, 'base64': { allowed: ['boolean'] }, 'armor': { allowed: ['boolean'] }, }, answer: { type: ['signature', 'ciphertext'], data: { 'data': 'string', 'base64':'boolean' } } }, // 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'], allowed_data: ['cms', 'openpgp'] }, 'secret': { allowed: ['boolean'] }, 'extern': { allowed: ['boolean'] }, 'local':{ allowed: ['boolean'] }, 'locate': { allowed: ['boolean'] }, 'sigs':{ allowed: ['boolean'] }, 'notations':{ allowed: ['boolean'] }, 'tofu': { allowed: ['boolean'] }, 'ephemeral': { allowed: ['boolean'] }, 'validate': { allowed: ['boolean'] }, 'keys': { allowed: ['string'], array_allowed: true } }, answer: { type: ['keys'], data: { 'base64': 'boolean', 'keys': 'object' } } }, export: { required: {}, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'keys': { allowed: ['string'], array_allowed: true }, 'armor': { allowed: ['boolean'] }, 'extern': { allowed: ['boolean'] }, 'minimal': { allowed: ['boolean'] }, 'raw': { allowed: ['boolean'] }, 'pkcs12': { allowed: ['boolean'] }, 'with-sec-fprs': { allowed: ['boolean'] } // secret: not yet implemented }, answer: { type: ['keys'], data: { 'data': 'string', 'base64': 'boolean', 'sec-fprs': 'object' } } }, import: { required: { 'data': { allowed: ['string'] } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'base64': { allowed: ['boolean'] }, }, answer: { type: [], data: { 'result': 'object' } } }, delete: { pinentry: true, required:{ 'key': { allowed: ['string'] } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, }, answer: { data: { 'success': 'boolean' } } }, version: { required: {}, optional: {}, answer: { type: [''], data: { 'gpgme': 'string', 'info': 'object' } } }, createkey: { pinentry: true, required: { userid: { allowed: ['string'] } }, optional: { algo: { allowed: ['string'] }, expires: { allowed: ['number'], } }, answer: { type: [''], - data: {'fingerprint': 'string'} + data: { 'fingerprint': 'string' } } }, verify: { required: { data: { allowed: ['string'] } }, optional: { 'protocol': { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, 'signature': { allowed: ['string'] }, 'base64':{ allowed: ['boolean'] } }, answer: { type: ['plaintext'], data:{ 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 } } }, config_opt: { required: { 'component':{ allowed: ['string'], // allowed_data: ['gpg'] // TODO check all available }, 'option': { allowed: ['string'], // allowed_data: ['default-key'] // TODO check all available } }, optional: {}, answer: { type: [], data: { option: 'object' } } } /** * TBD handling of secrets * TBD key modification? */ }; 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,123 +1,123 @@ -import {createKey} from './src/Key'; +import { createKey } from './src/Key'; export const helper_params = { validLongId: '0A0A0A0A0A0A0A0A', validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3', createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'), 'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'], validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', 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', '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], invalidErrorCode: 'Please type in all your passwords.', validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', true), valid_openpgplike: { primaryKey: { - getFingerprint: function(){ + 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'), 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 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'] }; 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 47eeabf2..0abc1061 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -1,375 +1,375 @@ /* 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'; /*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'; 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 { 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'); expect(answer.info).to.be.an('Array'); expect(conn0.disconnect).to.be.a('function'); expect(conn0.post).to.be.a('function'); done(); }); }); - 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(); }); }); }); }); - 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); expect(test0.code).to.equal('CONN_TIMEOUT'); }); 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); expect(test0.code).to.equal('GENERIC_ERROR'); } ); - 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]); expect(test0).to.be.false; } }); }); - 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); expect(test0).to.include( 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'); expect(test0).to.have.lengthOf( hp.invalidKeyArray_OneBad.length - 1); }); }); }); - 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]); expect(prop).to.not.be.undefined; expect(prop).to.be.a('boolean'); } expect(isFingerprint(key2.get('fingerprint'))).to.be.true; expect( key2.get('fingerprint')).to.equal(kp.validKeyFingerprint); expect( key2.get('fingerprint')).to.equal(key.fingerprint); done(); }); }); 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(); }); }); 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(); }); }); 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(); }); }); 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); expect(key0.code).to.equal('PARAM_WRONG'); } }); // 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); // }); }); - 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(); }); } ); 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(); } ); } ); - 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(); } ); }); }); - 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); 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); expect(test0.message).to.not.be.null; 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); }); - 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++){ 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(){ + 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'); } }); }); } -export default {unittests}; \ No newline at end of file +export default { unittests }; \ No newline at end of file