+ The unittests rely on a separately packaged version of gpgmejs,
+ with the different classes and functions exposed. These tests and their
+ input values can be found in gpgme/lang/js/test. They do not test the
+ overall functionality, but the individual behaviour of the components.
+
+ The functionality tests, to be found in
+ gpgme/lang/js/BrowserTestExtension, check the overall functionality of
+ the standard packaged version of gpgmejs.
+
+
+ Most tests rely on a test gpg key to be available in gpg, which can be
+ found at the bottom of this page, or as "testkey.sec" in the
+ BrowserTestExtension's directory. Please import this key to your tested
+ gpg installation, or adapt the input defined in tests/inputvalues.js
+ if you want to use different values.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lang/js/BrowserTestExtension/manifest.json b/lang/js/BrowserTestExtension/manifest.json
new file mode 100644
index 00000000..a9e605bc
--- /dev/null
+++ b/lang/js/BrowserTestExtension/manifest.json
@@ -0,0 +1,13 @@
+{
+ "manifest_version": 2,
+
+ "name": "Browsertests for gpgmejs",
+ "description": "Run the browsertests.",
+ "version": "0.1",
+ "content_security_policy": "default-src 'self' filesystem:",
+ "browser_action": {
+ "default_icon": "testicon.png",
+ "default_popup": "popup.html"
+ },
+ "permissions": ["nativeMessaging", "activeTab"]
+ }
diff --git a/lang/js/BrowserTestExtension/popup.html b/lang/js/BrowserTestExtension/popup.html
new file mode 100644
index 00000000..f17f262a
--- /dev/null
+++ b/lang/js/BrowserTestExtension/popup.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lang/js/BrowserTestExtension/popup.js b/lang/js/BrowserTestExtension/popup.js
new file mode 100644
index 00000000..794620b6
--- /dev/null
+++ b/lang/js/BrowserTestExtension/popup.js
@@ -0,0 +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() {
+ chrome.tabs.create({
+ url: './index.html'
+ });
+});
diff --git a/lang/js/BrowserTestExtension/runbrowsertest.js b/lang/js/BrowserTestExtension/runbrowsertest.js
new file mode 100644
index 00000000..c46eb120
--- /dev/null
+++ b/lang/js/BrowserTestExtension/runbrowsertest.js
@@ -0,0 +1,26 @@
+/* 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 mocha */
+
+mocha.run();
diff --git a/lang/js/BrowserTestExtension/rununittests.js b/lang/js/BrowserTestExtension/rununittests.js
new file mode 100644
index 00000000..df31589e
--- /dev/null
+++ b/lang/js/BrowserTestExtension/rununittests.js
@@ -0,0 +1,27 @@
+/* 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 Gpgmejs_test, mocha*/
+
+Gpgmejs_test.unittests();
+mocha.run();
diff --git a/lang/js/BrowserTestExtension/setup_testing.js b/lang/js/BrowserTestExtension/setup_testing.js
new file mode 100644
index 00000000..52aeac58
--- /dev/null
+++ b/lang/js/BrowserTestExtension/setup_testing.js
@@ -0,0 +1,28 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see .
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author(s):
+ * Maximilian Krambach
+ */
+
+/* global mocha, chai */
+
+mocha.setup('bdd');
+const expect = chai.expect; //eslint-disable-line no-unused-vars
+chai.config.includeStack = true;
\ No newline at end of file
diff --git a/lang/js/BrowserTestExtension/testicon.png b/lang/js/BrowserTestExtension/testicon.png
new file mode 100644
index 00000000..a98463de
Binary files /dev/null and b/lang/js/BrowserTestExtension/testicon.png differ
diff --git a/lang/js/BrowserTestExtension/testkey.pub b/lang/js/BrowserTestExtension/testkey.pub
new file mode 100644
index 00000000..cfc329f3
--- /dev/null
+++ b/lang/js/BrowserTestExtension/testkey.pub
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFrsKEkBCADKw4Wt8J6M/88qD8PO6lSMCxH1cpwH8iK0uPaFFYsJkkXo7kWf
+PTAtrV+REqF/o80dvYcdLvRsV21pvncZz/HXLu1yQ18mC3XObrKokbdgrTTKA5XE
+BZkNsqyaMMJauT18H4hYkSg62/tTdO1cu/zWv/LFf7Xyn6+uA74ovXCJlO1s0N2c
+PShtr98QRzPMf2owgVk37JnDNp4gGVDGHxSZOuUwxgYAZYnA8SFc+c+3ZrQfY870
++O4j3Mz4p7yD13AwP4buQLBsb/icxekeQCqpRJhLH9f7MdEcGXa1x36RcEkHdu+M
+yJ392eMgD+dKNfRCtyTPhjZTxvbNELIBYICfABEBAAG0EHRlc3RAZXhhbXBsZS5v
+cmeJAVQEEwEIAD4WIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbAwUJA8Jn
+AAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAjAWNe7/DLBf9kB/wOQ/S60HGw
+Fq07W9N01HWULyhHKoMmcHL6rfZ64oDqLxolPSasz7WAMW1jN4qtWJ0mFzwO83V6
+kaBe+wF6Kqir6udFSBW9rPcFg6/VZXPltT0a6uacIHq6DyQ5iMW4YQWbVy9OR2rN
+GkYo1JCBR0XdRJYCSX3yB4TWv/eXnZ37/WjmiTOIZh35rjs+NuU/S5JPDfAp2/k7
+0DevQeBsv+UjVXjWpNTZmPbvDnd995uSmC6UY4hzyP84ORYMYn9n1QAR0goxDN6U
+unOf9Rlp1oMzdxMool/d1MlCxg2h3jheuhv7lgUF4KpvHOuEPXQ7UO417E0TYcDZ
+1J8Nsv87SZeEuQENBFrsKEkBCADjoEBhG/QPqZHg8VyoD1xYRAWGxyDJkX/GrSs6
+yE+x2hk5FoQCajxKa/d4AVxOnJpdwhAfeXeSNaql5Ejgzax+Tdj9BV6vtGVJVv0p
+O7bgAiZxkA6RHxtNqhpPnPQoXvUzkzpRgpuL+Nj4yIg7z1ITH6KQH4u5SI9vd+j/
+8i9Taz67pdZwuJjac8qBuJHjzAo1bjYctFYUSG5pbmMQyNLySzgiNkFa4DajODlt
+3RuqVGP316Fk+Sy2+60tC/HlX8jgMyMONfOGBQx6jk8tvAphS/LAqrrNepnagIyL
+UGKU+L8cB2g1PGGp2biBFWqZbudZoyRBet/0yH/zirBdQJw1ABEBAAGJATwEGAEI
+ACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAKCRAjAWNe
+7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ5F32NDJ9
+PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7Jq3e/4Iy
+0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02Lkr+2Cc/Q
+k6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe23nntMSD
+A+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t9Mmd7bM1
++UyPgbPEr0iWMeyctYsuOLeUyQKMscDT
+=QyY6
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/lang/js/BrowserTestExtension/testkey.sec b/lang/js/BrowserTestExtension/testkey.sec
new file mode 100644
index 00000000..ced8f3ec
--- /dev/null
+++ b/lang/js/BrowserTestExtension/testkey.sec
@@ -0,0 +1,57 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+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
+07SO8+IACcaQliOto1pndOPwTimCeo58/7rf8I2a5uuJloGrnPwAX65bKDnUALp6
+X3lnXRNMhnB3Uewx4i00LQmjsxhJfQiGLpMv0j58tn64s7GqQzGVV1JKcQm992RV
+jFOydyjZ+K4LGWEOITG/bZrMEVNGCM+OnQQA/Haz8xN0NFSlq7tyfFc0pkx/TiCX
+xGfBqbO0wU2b5GMnZbY/06HENpidIzpa231VQaw5/nPTvfhlLKW1iGAkc148cX1q
+lL9w2ksXuaHR3LXud2VcfVTIdxU/7h7u1dD/85+c0+7jlGObD9cXKxlM6OjpIJz1
+l5/1h3C5S0TuxHkEAL/3BGihkhNfv1Xx0rWu0/732usX/nE/A9C26hGu41FUf3fp
+0ilonKpKZUEwWt5hWSEFCSrznNVekiO0rxvuu3RVegvzThPNU4Pf4JZtJpRVhvUQ
+d9ulxJw7V9rs75uNBatTNC0kXuGoXhehw4Bn93xa67gYGd3LfrH+oT0GCDpTSHCJ
+ATwEGAEIACYWIQTUFzW5Ejb9uIIEjFojAWNe7/DLBQUCWuwoSQIbDAUJA8JnAAAK
+CRAjAWNe7/DLBf0pCACPp5hBuUWngu2Hqvg+tNiujfsiYzId3MffFxEk3CbXeHcJ
+5F32NDJ9PYCnra4L8wSv+NZt9gIa8lFwoFSFQCjzH7KE86XcV3MhfdJTNb/+9CR7
+Jq3e/4Iy0N5ip7PNYMCyakcAsxvsNCJKrSaDuYe/OAoTXRBtgRWE2uyT315em02L
+kr+2Cc/Qk6H+vlNOHGRgnpI/OZZjnUuUfBUvMGHr1phW+y7aeymC9PnUGdViRdJe
+23nntMSDA+0/I7ESO9JsWvJbyBmuiZpu9JjScOjYH9xpQLqRNyw4WHpZriN69F0t
+9Mmd7bM1+UyPgbPEr0iWMeyctYsuOLeUyQKMscDT
+=hkUm
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/lang/js/BrowserTestExtension/testkey2.pub b/lang/js/BrowserTestExtension/testkey2.pub
new file mode 100644
index 00000000..557bd5be
--- /dev/null
+++ b/lang/js/BrowserTestExtension/testkey2.pub
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFsMHecBCACqdJgqa+CeNYwPCK+MpOwAV6uFVjDyO2LmOs6+XfDWRBU/Zjtz
+8zdYNKSbLjkWN4ujV5aiyA7MtEofszzYLEoKUt1wiDScHMpW8qmEFDvl9g26MeAV
+rTno9D5KodHvEIs8wnrqBs8ix0WLbh6J1Dtt8HQgIbN+v3gaRQrgBFe6z2ZYpHHx
+ZfOu3iFKlm2WE/NekRkvvFIo3ApGvRhGIYw6JMmugBlo7s5xosJK0I9dkPGlEEtt
+aF1RkcMj8sWG9vHAXcjlGgFfXSN9YLppydXpkuZGm4+gjLB2a3rbQCZVFnxCyG4O
+ybjkP8Jw6Udm89bK2ucYFfjdrmYn/nJqRxeNABEBAAG0I1Rlc3QgTm9Qcml2S2V5
+IDxub2JvZHlAZXhhbXBsZS5vcmc+iQFOBBMBCAA4FiEE4Fmh4IZtMa4TEXCITZou
+EzBBU9EFAlsMHecCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQTZouEzBB
+U9F+qwf/SHj4uRnTWgyJ71FBxQDYCBq3jbi6e7hMkRPbJyJdnPIMAb2p0PJjBgjW
+0pp4+kDPZans3UDHbma1u/SFI4/y6isJiK94Bk5xp5YliLGnUceTjgDFe6lBhfQ1
+zVWZC/NF3tPgbziIxXQTNt34nS+9dbV/QFDLW0POcN7C0jR/hgkBjMEH2PezWhSj
+mL/yLfLfUYAoxVpXjfC5aPJKqw0tR7m5ibznjCphE+FUMRg8EOmJcg6soeJ5QspU
+k2dPN3+Y0zCTNRgAHEI+yIQbM6pio6v2c+UCtT1QhW4xSI38/kcEG8QiM55r1TUy
+FcWAY5n5t1nNZtMxxse3LqEon3rKiLkBDQRbDB3nAQgAqfAjSjcngERtM+ZYOwN0
+QF2v2FuEuMe8mhju7Met7SN2zGv1LnjhTNshEa9IABEfjZirE2Tqx4xCWDwDedK4
+u1ToFvcnuAMnq2O47Sh+eTypsf6WPFtPBWf6ctKY31hFXjgoyDBULBvl43XU/D9C
+Mt7nsKDPYHVrrnge/qWPYVcb+cO0sSwNImMcwQSdTQ3VBq7MeNS9ZeBcXi+XCjhN
+kjNum2AQqpkHHDQV7871yQ8RIILvZSSfkLb0/SNDU+bGaw2G3lcyKdIfZi2EWWZT
+oCbH38I/+LV7nAEe4zFpHwW8X0Dkx2aLgxe6UszDH9L3eGhTLpJhOSiaanG+zZKm
++QARAQABiQE2BBgBCAAgFiEE4Fmh4IZtMa4TEXCITZouEzBBU9EFAlsMHecCGwwA
+CgkQTZouEzBBU9H5TQgAolWvIsez/WW8N2tmZEnX0LOFNB+1S4L4X983njwNdoVI
+w19pbj+8RIHF/H9kcPGi7jK96gvlykQn3uez/95D2AiRFW5KYdOouFisKgHpv8Ay
+BrhclHv11yK+X/0iTD0scYaG7np5162xLkaxSO9hsz2fGv20RKaXCWkI69fWw0BR
+XlI5pZh2YFei2ZhH/tIMIW65h3w0gtgaZBBdpZTOOW4zvghyN+0MSObqkI1BvUJu
+caDFI4d6ZTmp5SY+pZyktZ4bg/vMH5VFxdIKgbLx9uVeTvOupvbAW0TNulYGUBQE
+nm+S0zr3W18t64e4sS3oHse8zCqo1iiImpba6F1Oaw==
+=y6DD
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js
new file mode 100644
index 00000000..f52b790a
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js
@@ -0,0 +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){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ context.Keyring.getKeys(fpr).then(
+ function (result){
+ if (result.length === 1) {
+ result[0].delete().then(function (){
+ done();
+ },function (){
+ done();
+ });
+ } else {
+ done();
+ }
+ });
+ });
+ });
+
+ afterEach(function (done){
+ // delete the test key if still present
+ context.Keyring.getKeys(fpr).then(
+ function (result){
+ if (result.length === 1) {
+ result[0].delete().then(function (){
+ done();
+ },function (){
+ done();
+ });
+ } else {
+ done();
+ }
+ });
+ });
+
+ it('Importing Key', function (done) {
+ context.Keyring.getKeys(fpr).then(function (result){
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(0);
+ context.Keyring.importKey(pubKey).then(function (result){
+ expect(result.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){
+ context.Keyring.importKey(pubKey)
+ .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){
+ 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){
+ expect(result.Keys[0].key).to.be.an('object');
+ expect(result.Keys[0].key.fingerprint).to.equal(fpr);
+ result.Keys[0].key.delete().then(function (result){
+ expect(result).to.be.true;
+ done();
+ });
+ });
+ });
+
+ 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){
+ 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){
+ 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){
+ 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
new file mode 100644
index 00000000..e1caabe1
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/KeyInfos.js
@@ -0,0 +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){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ done();
+ });
+ });
+
+ it('A fingerprint is consistently returned upper case hex', function (done){
+ const mixedCase = inputvalues.encrypt.good.fingerprint_mixedcase;
+ context.Keyring.getKeys(mixedCase).then(function (result){
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase());
+ done();
+ });
+ });
+
+ it('A userId keeps their encoding', function (done){
+ context.Keyring.importKey(inputvalues.publicKeyNonAscii.key, true)
+ .then(function (result){
+ expect(result.Keys[0]).to.be.an('object');
+ const user = result.Keys[0].key.get('userids')[0];
+ expect(user.get('name')).to.equal(
+ inputvalues.publicKeyNonAscii.userid);
+ done();
+ });
+ });
+});
\ No newline at end of file
diff --git a/lang/js/BrowserTestExtension/tests/decryptTest.js b/lang/js/BrowserTestExtension/tests/decryptTest.js
new file mode 100644
index 00000000..ea887491
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/decryptTest.js
@@ -0,0 +1,78 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see .
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author(s):
+ * Maximilian Krambach
+ */
+
+/* global describe, it, before, expect, Gpgmejs */
+/* global bigString, inputvalues, sabotageMsg*/
+
+describe('Decryption', function () {
+ let context = null;
+ const good_fpr = inputvalues.encrypt.good.fingerprint;
+
+ before(function (done){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ done();
+ });
+ });
+
+ it('Decryption of random string fails', function (done) {
+ let data = bigString(20 * 1024);
+ context.decrypt(data).then(
+ function (){},
+ function (error){
+ expect(error).to.be.an('error');
+ expect(error.code).to.equal('GNUPG_ERROR');
+ done();
+ });
+ });
+
+ it('Decryption of slightly corrupted message fails', function (done) {
+ const data = bigString(10000);
+ context.encrypt(data, good_fpr).then(function (enc){
+ context.decrypt(sabotageMsg(enc.data)).then(
+ function (){},
+ function (error){
+ expect(error).to.be.an('error');
+ expect(error.code).to.equal('GNUPG_ERROR');
+ done();
+ });
+ });
+ }).timeout(5000);
+
+
+ it('decrypt/verify operations return proper information', function (done){
+ const data = inputvalues.encryptSignedMessage;
+ context.decrypt(data).then(function (result){
+ expect(result).to.be.an('object');
+ expect(result.signatures).to.be.an('object');
+ expect(result.signatures.all_valid).to.be.true;
+ expect(result.signatures.count).to.equal(1);
+ expect(result.signatures.signatures.good).to.be.an('array');
+ expect(
+ result.signatures.signatures.good[0].fingerprint).to.equal(
+ good_fpr);
+ done();
+ });
+ });
+});
\ No newline at end of file
diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
new file mode 100644
index 00000000..28c98d98
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
@@ -0,0 +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 (){
+ let context = null;
+ let good_fpr = inputvalues.encrypt.good.fingerprint;
+
+ before(function (done){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ done();
+ });
+ });
+
+ it('Successful encrypt and decrypt simple string', function (done) {
+ let 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
new file mode 100644
index 00000000..a242af5f
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/encryptTest.js
@@ -0,0 +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){
+ const prm = Gpgmejs.init();
+ 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){
+ 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){
+ 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){
+ 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
new file mode 100644
index 00000000..5c2abf36
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/inputvalues.js
@@ -0,0 +1,338 @@
+/* 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'
+ },
+ encryptSignedMessage: '-----BEGIN PGP MESSAGE-----\n'+
+ '\n'+
+ 'hQEMA6B8jfIUScGEAQf/bmQ+xNMGTjPvQCktkxR4Svt2dVNVdSzKsCmvSv24QOQF\n'+
+ 'yBMK5w51S/6DTdiZI12IYD7hjvkr9NqxXXupjrVKwqEVpg4Pkwckac0OcElJIBsL\n'+
+ '3htr4iYsr8dhSgSS4BO0azcu4wZQTXy5v2P7yYPECMEagNEXnW+tE7sHLCq8Ysqz\n'+
+ 'LVxG0R0IUijKeEd3xQC2Tt20e1Z1j5tnqaPhE/9Smqf5OjSUDqpXxvRnSNRk/zEs\n'+
+ 'cGVgCF+cv68nUJM9lwEAbBQChplwL6ebnhunC6DsRCxnjLHVyKm127hmhSiMGC0e\n'+
+ 'Ns31mGeP1dxpDv6Gi2/oKmq67vG3i4fKeckj7bt30tLA1wH0Qn5Mn6Tzxzve0W0q\n'+
+ 'Ghqn9PY9qNK8EkrkzqaFk9dzu5tfSbaJBLS/uIhX2Wj70EMEBbFSkN0qlgOfLgGw\n'+
+ '5mwRvCgj4nvV1ByFhnx7uwgQixvOwLH4JLKvwCQpJm+O2R0eC7M6CzR/b9iL/oaO\n'+
+ 'JTkoD9hcLhxF7j+3ZYg7rbNwofuHST097vFjzItsucb0jHOzjlkCqbhdczICILTa\n'+
+ 'H76Q6YGdMLyG9a3s4yZUMruaeQyWGeXlryzLDvdEoSgoD5YrolsFOM+Z2apbzVs2\n'+
+ 'k5CltwtanjjWGnpAqSyr49C6CSU8G1QHpNygx5frtAS8bojR2ovB9OJp2wUklDvC\n'+
+ 'LtU7dLpTY/BIvfB1vzwcW/aNgmPadNHX8mAzlqTQJjeLoo69Wp804t+u36sgfd/J\n'+
+ 'ser7vdJJUm+86Q9csefItvFmHhqjMg5XXHoa8WZWJOHIQMxZkaIwKAzcEt/oEOdJ\n'+
+ 'rbVNVabhTdbmS5I1ok16wg5jMF07ZDM7nXWMcQNjwT646XKP+pp2N6YQROVidNXj\n'+
+ 'COyRyiXE/csr\n'+
+ '=Ik7G\n'+
+ '-----END PGP MESSAGE-----\n',
+ someInputParameter: 'bad string',
+
+ publicKeyNonAscii: {
+ 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
+ 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
+ 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
+ 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
+ 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){
+ 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' +
+ '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\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]){
+ const iterations = Math.floor(Math.random() * msg.length * rate) + 1;
+ const base64_set =
+ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/';
+ for (let i=0; i < iterations; i++){
+ let str0, str1, str2;
+ const chosePosition = function (){
+ let position =
+ Math.floor( Math.random() * (msg.length - p[0] + p[1]))
+ + p[0];
+ str1 = msg.substring(position,position+1);
+ if (str1 === '\n'){
+ chosePosition();
+ } else {
+ str0 = msg.substring(0,position);
+ str2 = msg.substring(position +1);
+ }
+ };
+ chosePosition();
+ let new1 = function (){
+ let n = base64_set[Math.floor(Math.random() * 64)];
+ return (n === str1) ? new1() : n;
+ };
+ msg = str0.concat(new1()).concat(str2);
+ }
+ return msg;
+}
diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js
new file mode 100644
index 00000000..240a6b93
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js
@@ -0,0 +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){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ done();
+ });
+ });
+
+ for (let i=0; i < 101; i++) {
+ it('Successful encrypt/decrypt completely random data '
+ + (i+1) + '/100', function (done) {
+ const data = bigString(2*1024*1024);
+ context.encrypt(data,good_fpr).then(function (answer){
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a('string');
+ expect(answer.data).to.include('BEGIN PGP MESSAGE');
+ expect(answer.data).to.include('END PGP MESSAGE');
+ context.decrypt(answer.data).then(function (result){
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(result.data).to.equal(data);
+ done();
+ });
+ });
+ }).timeout(15000);
+ }
+
+});
diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js
new file mode 100644
index 00000000..f5bd9c1d
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/signTest.js
@@ -0,0 +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){
+ const prm = Gpgmejs.init();
+ 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
new file mode 100644
index 00000000..cf5b0999
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/startup.js
@@ -0,0 +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){
+ let prm = Gpgmejs.init();
+ const input = inputvalues.someInputParameter;
+ prm.then(
+ function (context){
+ expect(context).to.be.an('object');
+ expect(context.encrypt).to.be.a('function');
+ expect(context.decrypt).to.be.a('function');
+ expect(context.sign).to.be.a('function');
+ expect(context.verify).to.be.a('function');
+ context.Keyring = input;
+ expect(context.Keyring).to.be.an('object');
+ expect(context.Keyring).to.not.equal(input);
+ expect(context.Keyring.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
new file mode 100644
index 00000000..5788ed51
--- /dev/null
+++ b/lang/js/BrowserTestExtension/tests/verifyTest.js
@@ -0,0 +1,90 @@
+/* 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){
+ const prm = Gpgmejs.init();
+ prm.then(function (gpgmejs){
+ context = gpgmejs;
+ done();
+ });
+ });
+ it('Successful verify message', function (done) {
+ const message = inputvalues.signedMessage.good;
+ context.verify(message).then(function (result){
+ expect(result.data).to.be.a('string');
+ expect(result.signatures.all_valid).to.be.true;
+ expect(result.signatures.count).to.equal(1);
+ expect(result.signatures.signatures.good).to.be.an('array');
+ expect(result.signatures.signatures.good.length).to.equal(1);
+ expect(result.signatures.signatures.good[0].fingerprint).to.be.a('string');
+ expect(result.signatures.signatures.good[0].valid).to.be.true;
+ done();
+ });
+ });
+
+ it('Successfully recognize changed cleartext', function (done) {
+ const message = inputvalues.signedMessage.bad;
+ context.verify(message).then(function (result){
+ expect(result.data).to.be.a('string');
+ expect(result.signatures.all_valid).to.be.false;
+ expect(result.signatures.count).to.equal(1);
+ expect(result.signatures.signatures.bad).to.be.an('array');
+ expect(result.signatures.signatures.bad.length).to.equal(1);
+ expect(result.signatures.signatures.bad[0].fingerprint)
+ .to.be.a('string');
+ expect(result.signatures.signatures.bad[0].valid)
+ .to.be.false;
+ done();
+ });
+ });
+
+ 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){
+ expect(result.data).to.equal(message_enc.data);
+ expect(result.data).to.be.a('string');
+ expect(result.signatures.all_valid).to.be.true;
+ expect(result.signatures.count).to.equal(1);
+ expect(result.signatures.signatures.good)
+ .to.be.an('array');
+ expect(result.signatures.signatures.good.length)
+ .to.equal(1);
+ expect(result.signatures.signatures.good[0].fingerprint)
+ .to.equal(fpr);
+ expect(result.signatures.signatures.good[0].valid)
+ .to.be.true;
+ done();
+ });
+ });
+ });
+ });
+});
\ No newline at end of file
diff --git a/lang/js/BrowserTestExtension/unittests.html b/lang/js/BrowserTestExtension/unittests.html
new file mode 100644
index 00000000..6f7da3f1
--- /dev/null
+++ b/lang/js/BrowserTestExtension/unittests.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
Unit tests
+
+
+
+
+
+
+
+
diff --git a/lang/js/DemoExtension/Makefile.am b/lang/js/DemoExtension/Makefile.am
new file mode 100644
index 00000000..d6e87fde
--- /dev/null
+++ b/lang/js/DemoExtension/Makefile.am
@@ -0,0 +1,27 @@
+# Makefile.am for gpgme.js.
+# Copyright (C) 2018 Intevation GmbH
+#
+# This file is part of gpgme.js.
+#
+# gpgme.js is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# gpgme.js is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+EXTRA_DIST = manifest.json \
+ popup.html \
+ entry.js \
+ maindemo.js \
+ mainui.html \
+ testicon.png \
+ ui.css
diff --git a/lang/js/DemoExtension/entry.js b/lang/js/DemoExtension/entry.js
new file mode 100644
index 00000000..fd261a0b
--- /dev/null
+++ b/lang/js/DemoExtension/entry.js
@@ -0,0 +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 () {
+ chrome.tabs.create({
+ url: './mainui.html'
+ });
+});
diff --git a/lang/js/DemoExtension/maindemo.js b/lang/js/DemoExtension/maindemo.js
new file mode 100644
index 00000000..8d190852
--- /dev/null
+++ b/lang/js/DemoExtension/maindemo.js
@@ -0,0 +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.getElementById('buttonencrypt').addEventListener('click',
+ function (){
+ let data = document.getElementById('inputtext').value;
+ let keyId = document.getElementById('pubkey').value;
+ gpgmejs.encrypt(data, keyId).then(
+ function (answer){
+ if (answer.data){
+ document.getElementById(
+ 'answer').value = answer.data;
+ }
+ }, function (errormsg){
+ alert( errormsg.message);
+ });
+ });
+
+ document.getElementById('buttondecrypt').addEventListener('click',
+ function (){
+ let data = document.getElementById('inputtext').value;
+ gpgmejs.decrypt(data).then(
+ function (answer){
+ if (answer.data){
+ document.getElementById(
+ 'answer').value = answer.data;
+ }
+ }, function (errormsg){
+ alert(errormsg.message);
+ });
+ });
+
+ document.getElementById('getdefaultkey').addEventListener('click',
+ function (){
+ gpgmejs.Keyring.getDefaultKey().then(function (answer){
+ document.getElementById('pubkey').value =
+ answer.fingerprint;
+ }, function (errormsg){
+ alert(errormsg.message);
+ });
+ });
+
+ document.getElementById('signtext').addEventListener('click',
+ function (){
+ let data = document.getElementById('inputtext').value;
+ let keyId = document.getElementById('pubkey').value;
+ gpgmejs.sign(data, keyId).then(
+ function (answer){
+ if (answer.data){
+ document.getElementById(
+ 'answer').value = answer.data;
+ }
+ }, function (errormsg){
+ alert( errormsg.message);
+ });
+ });
+
+ document.getElementById('verifytext').addEventListener('click',
+ function (){
+ let data = document.getElementById('inputtext').value;
+ gpgmejs.verify(data).then(
+ 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){
+ alert( errormsg.message);
+ });
+ });
+ document.getElementById('searchkey').addEventListener('click',
+ function (){
+ let data = document.getElementById('inputtext').value;
+ 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){
+ alert( errormsg.message);
+ });
+ });
+ });
+});
diff --git a/lang/js/DemoExtension/mainui.html b/lang/js/DemoExtension/mainui.html
new file mode 100644
index 00000000..c773c9b9
--- /dev/null
+++ b/lang/js/DemoExtension/mainui.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Input
+
+
+
+ Fingerprint of Key to use:
+
+
+
+
+
+
+
+
+
+ Result
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lang/js/DemoExtension/manifest.json b/lang/js/DemoExtension/manifest.json
new file mode 100644
index 00000000..9e057b35
--- /dev/null
+++ b/lang/js/DemoExtension/manifest.json
@@ -0,0 +1,14 @@
+{
+ "manifest_version": 2,
+
+ "name": "gpgme-json with native Messaging",
+ "description": "A simple demo application",
+ "version": "0.1",
+ "content_security_policy": "default-src 'self' filesystem:",
+ "browser_action": {
+ "default_icon": "testicon.png",
+ "default_title": "gpgme.js",
+ "default_popup": "popup.html"
+ },
+ "permissions": ["nativeMessaging", "activeTab"]
+}
diff --git a/lang/js/DemoExtension/popup.html b/lang/js/DemoExtension/popup.html
new file mode 100644
index 00000000..50070311
--- /dev/null
+++ b/lang/js/DemoExtension/popup.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lang/js/DemoExtension/testicon.png b/lang/js/DemoExtension/testicon.png
new file mode 100644
index 00000000..84284e0b
Binary files /dev/null and b/lang/js/DemoExtension/testicon.png differ
diff --git a/lang/js/DemoExtension/ui.css b/lang/js/DemoExtension/ui.css
new file mode 100644
index 00000000..16dfb5ae
--- /dev/null
+++ b/lang/js/DemoExtension/ui.css
@@ -0,0 +1,33 @@
+ul {
+ list-style-type: none;
+ padding-left: 0px;
+}
+
+ul li span {
+ float: left;
+ width: 120px;
+ margin-top: 6px;
+}
+
+div .left {
+ float: left;
+ align-items: stretch;
+ width: 40%;
+}
+div .center {
+ width: 50%;
+ align-content: space-between;
+}
+
+div .center button {
+ align-self: stretch;
+}
+div .right {
+ float: right;
+ align-items: stretch;
+ width: 40%;
+}
+
+div .bottom {
+ clear:both;
+}
\ No newline at end of file
diff --git a/lang/js/Makefile.am b/lang/js/Makefile.am
new file mode 100644
index 00000000..4464730f
--- /dev/null
+++ b/lang/js/Makefile.am
@@ -0,0 +1,31 @@
+# Makefile.am for gpgme.js.
+# Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+#
+# This file is part of gpgme.js.
+#
+# gpgme.js is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# gpgme.js is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+SUBDIRS = src BrowserTestExtension DemoExtension
+
+EXTRA_DIST = build_extensions.sh \
+ jsdoc.conf \
+ .eslintrc.json \
+ package.json \
+ README \
+ unittest_inputvalues.js \
+ unittests.js \
+ webpack.conf.js \
+ webpack.conf_unittests.js
diff --git a/lang/js/README b/lang/js/README
new file mode 100644
index 00000000..fd95cc45
--- /dev/null
+++ b/lang/js/README
@@ -0,0 +1,116 @@
+gpgme.js - JavaScript for GPGME
+-------------------------------
+Initially developed for integration with the Mailvelope Web Extension.
+
+Overview
+--------
+
+gpgme.js is a javascript library for direct use of GnuPG in browsers.
+It interacts with GPGME through nativeMessaging and gpgme-json.
+
+It is meant to be distributed directly by its downstream users in
+their extension package. As such it is not integrated in the
+autotools build system. See build instructions below.
+
+
+gpgme-json
+----------
+
+gpgme-json (see core src/gpgme-json.c) the json to GPGME bridge is
+required as native messaging backend for gpgme.js to work.
+It needs to be installed and registered as native messaging
+backend with the browser.
+
+See gpgme-mozilla.json and gpgme-chrome.json examples in
+the top level doc/examples as example manifests.
+
+Any web extension using gpgme.js will need to be whitelisted in the manifest
+file by its id.
+
+Distributors are encouraged to create manifest packages for their
+distributions.
+
+
+Building gpgme.js
+-----------------
+
+gpgme.js uses webpack, and thus depends on Node.js for building.
+All dependencies will be installed (in a local subdirectory) with the command
+`npm install`.
+
+To create a current version of the package, the command is
+`npx webpack --config webpack.conf.js`.
+If you want a more debuggable (i.e. not minified) build, just change the mode
+in webpack.conf.js.
+
+
+Demo and Test WebExtension:
+---------------------------
+
+The Demo Extension shows simple examples of the usage of gpgme.js.
+
+The BrowsertestExtension runs more intensive tests (using the mocha and chai
+frameworks). Tests from BrowserTestExtension/tests will be run against the
+gpgmejs.bundle.js itself. They aim to test the outward facing functionality
+and API.
+
+Unittests as defined in ./unittests.js will be bundled in
+gpgmejs_unittests.bundle.js, and test the separate components of gpgme.js,
+which mostly are not exported.
+
+The file `build_extension.sh` may serve as a pointer on how to build and
+assemble these two Extensions and their dependencies. It can directly
+be used in most linux systems.
+
+The resulting folders can just be included in the extensions tab of the browser
+in questions (extension debug mode needs to be active). For chrome, selecting
+the folder is sufficient, for firefox, the manifest.json needs to be selected.
+Please note that it is just for demonstration/debug purposes!
+
+For the Extensions to successfully communicate with gpgme-json, a manifest file
+is needed.
+
+- `~/.config/chromium/NativeMessagingHosts/gpgmejson.json`
+
+In the browsers' nativeMessaging configuration folder a file 'gpgmejs.json'
+is needed, with the following content:
+
+- For Chrome/Chromium:
+ ```
+ {
+ "name": "gpgmejson",
+ "description": "This is a test application for gpgme.js",
+ "path": "/usr/bin/gpgme-json",
+ "type": "stdio",
+ "allowed_origins": ["chrome-extension://ExtensionIdentifier/"]
+ }
+ ```
+ The usual path for Linux is similar to:
+ `~/.config/chromium/NativeMessagingHosts/gpgmejson.json` for
+ For Windows, the path to the manifest needs to be placed in
+ `HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\gpgmejson`
+
+ - For firefox:
+ ```
+ {
+ "name": "gpgmejson",
+ "description": "This is a test application for gpgme.js",
+ "path": "/usr/bin/gpgme-json",
+ "type": "stdio",
+ "allowed_extensions": ["ExtensionIdentifier@temporary-addon"]
+ }
+ ```
+
+ The ExtensionIdentifier can be seen as Extension ID on the about:addons page
+ if addon-debugging is active. In firefox, the temporary addon is removed once
+ firefox exits, and the identifier will need to be changed more often.
+
+ The manifest for linux is usually placed at:
+ `~/.mozilla/native-messaging-hosts/gpgmejson.json`
+
+
+Documentation
+-------------
+
+The documentation can be built by jsdoc. It currently uses the command
+`./node_modules/.bin/jsdoc -c jsdoc.conf`.
diff --git a/lang/js/build_extensions.sh b/lang/js/build_extensions.sh
new file mode 100755
index 00000000..91d5479b
--- /dev/null
+++ b/lang/js/build_extensions.sh
@@ -0,0 +1,17 @@
+#/!bin/bash
+
+npx webpack --config webpack.conf.js
+npx webpack --config webpack.conf_unittests.js
+mkdir -p BrowserTestExtension/libs
+cp node_modules/chai/chai.js \
+ node_modules/mocha/mocha.css \
+ node_modules/mocha/mocha.js \
+ build/gpgmejs.bundle.js \
+ build/gpgmejs_unittests.bundle.js BrowserTestExtension/libs
+rm -rf build/extensions
+mkdir -p build/extensions
+zip -r build/extensions/browsertest.zip BrowserTestExtension
+
+mkdir -p DemoExtension/libs
+cp build/gpgmejs.bundle.js DemoExtension/libs
+zip -r build/extensions/demoextension.zip DemoExtension
diff --git a/lang/js/jsdoc.conf b/lang/js/jsdoc.conf
new file mode 100644
index 00000000..12ae35e9
--- /dev/null
+++ b/lang/js/jsdoc.conf
@@ -0,0 +1,24 @@
+{
+ "tags": {
+ "allowUnknownTags": false,
+ "dictionaries": ["jsdoc"]
+ },
+ "source": {
+ "include": ["./src"],
+ "includePattern": ".+\\.js(doc|x)?$",
+ "excludePattern": "(^|\\/|\\\\)_"
+ },
+ "opts":{
+ "destination": "./doc/",
+ "recurse": true
+ },
+ "sourceType": "module",
+ "plugins": [],
+ "templates": {
+ "cleverLinks": false,
+ "monospaceLinks": false,
+ "default": {
+ "outputSourceFiles": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/lang/js/package.json b/lang/js/package.json
new file mode 100644
index 00000000..54af2982
--- /dev/null
+++ b/lang/js/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "gpgmejs",
+ "version": "0.0.1-dev",
+ "description": "Javascript part of the GPGME nativeMessaging integration",
+ "main": "src/index.js",
+ "private": true,
+ "keywords": [],
+ "author": "",
+ "license": "LGPL-2.1+",
+ "devDependencies": {
+ "webpack": "^4.5.0",
+ "webpack-cli": "^3.0.8",
+ "chai": "^4.1.2",
+ "mocha": "^5.1.1",
+ "jsdoc": "^3.5.5"
+ }
+}
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
new file mode 100644
index 00000000..928ac681
--- /dev/null
+++ b/lang/js/src/Connection.js
@@ -0,0 +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 (){
+ this._connection = chrome.runtime.connectNative('gpgmejson');
+ }
+
+ /**
+ * Immediately closes an open port.
+ */
+ disconnect () {
+ if (this._connection){
+ this._connection.disconnect();
+ this._connection = null;
+ }
+ }
+
+
+ /**
+ * @typedef {Object} backEndDetails
+ * @property {String} gpgme Version number of gpgme
+ * @property {Array