From f0409bbdafcbd4f8b0be099a6b3ce0d5352c9bcd Mon Sep 17 00:00:00 2001 From: Maximilian Krambach Date: Wed, 22 Aug 2018 18:37:46 +0200 Subject: [PATCH] js: make method parameters objects -- * As requested by using parties, the options to be passed into the methods are now objects, with the objects' properties better describing what they do, and to avoid the need to type several nulls in a method call if one wants the last parameter. - src/Keyring.js, src/gpgme.js: Changed parameters and their validations - BrowserTest/*.js Had to adapt quite some calls to the new format --- .../tests/KeyImportExport.js | 35 ++-- .../js/BrowserTestExtension/tests/KeyInfos.js | 2 +- .../BrowserTestExtension/tests/decryptTest.js | 23 +-- .../tests/encryptDecryptTest.js | 160 +++++++++--------- .../BrowserTestExtension/tests/encryptTest.js | 87 +++++----- .../tests/longRunningTests.js | 24 +-- .../js/BrowserTestExtension/tests/signTest.js | 19 ++- .../BrowserTestExtension/tests/verifyTest.js | 40 ++--- lang/js/DemoExtension/maindemo.js | 14 +- lang/js/src/Keyring.js | 143 +++++++++------- lang/js/src/gpgmejs.js | 147 +++++++++------- 11 files changed, 385 insertions(+), 309 deletions(-) diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index f52b790a..f57877f4 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -35,7 +35,7 @@ describe('Key importing', function () { const prm = Gpgmejs.init(); prm.then(function (gpgmejs){ context = gpgmejs; - context.Keyring.getKeys(fpr).then( + context.Keyring.getKeys({ pattern: fpr }).then( function (result){ if (result.length === 1) { result[0].delete().then(function (){ @@ -52,7 +52,7 @@ describe('Key importing', function () { afterEach(function (done){ // delete the test key if still present - context.Keyring.getKeys(fpr).then( + context.Keyring.getKeys({ pattern: fpr }).then( function (result){ if (result.length === 1) { result[0].delete().then(function (){ @@ -67,7 +67,7 @@ describe('Key importing', function () { }); it('Importing Key', function (done) { - context.Keyring.getKeys(fpr).then(function (result){ + context.Keyring.getKeys({ pattern: fpr }).then(function (result){ expect(result).to.be.an('array'); expect(result.length).to.equal(0); context.Keyring.importKey(pubKey).then(function (result){ @@ -127,23 +127,26 @@ describe('Key importing', function () { it('exporting armored Key with getKeysArmored', function (done) { context.Keyring.importKey(pubKey).then(function (){ - context.Keyring.getKeysArmored(fpr).then(function (result){ - expect(result).to.be.an('object'); - expect(result.armored).to.be.a('string'); - expect(result.secret_fprs).to.be.undefined; - done(); - }); + context.Keyring.getKeysArmored({ pattern: 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(); - }); + context.Keyring.getKeysArmored({ + pattern: key_secret, with_secret_fpr: true }) + .then(function (result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.an('array'); + expect(result.secret_fprs[0]).to.equal(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 e1caabe1..430c83a3 100644 --- a/lang/js/BrowserTestExtension/tests/KeyInfos.js +++ b/lang/js/BrowserTestExtension/tests/KeyInfos.js @@ -36,7 +36,7 @@ describe('Key information', function () { 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({ pattern: mixedCase }).then(function (result){ expect(result).to.be.an('array'); expect(result.length).to.equal(1); expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase()); diff --git a/lang/js/BrowserTestExtension/tests/decryptTest.js b/lang/js/BrowserTestExtension/tests/decryptTest.js index ea887491..8852cb6a 100644 --- a/lang/js/BrowserTestExtension/tests/decryptTest.js +++ b/lang/js/BrowserTestExtension/tests/decryptTest.js @@ -38,7 +38,7 @@ describe('Decryption', function () { it('Decryption of random string fails', function (done) { let data = bigString(20 * 1024); - context.decrypt(data).then( + context.decrypt({ data: data }).then( function (){}, function (error){ expect(error).to.be.an('error'); @@ -49,21 +49,22 @@ describe('Decryption', function () { it('Decryption of slightly corrupted message fails', function (done) { const data = bigString(10000); - context.encrypt(data, good_fpr).then(function (enc){ - context.decrypt(sabotageMsg(enc.data)).then( - function (){}, - function (error){ - expect(error).to.be.an('error'); - expect(error.code).to.equal('GNUPG_ERROR'); - done(); - }); - }); + context.encrypt({ data: data, publicKeys:good_fpr }).then( + function (enc){ + context.decrypt({ data: 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){ + context.decrypt({ data: 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; diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index 28c98d98..1efdf5cf 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -38,25 +38,25 @@ describe('Encryption and Decryption', function (){ 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(); + context.encrypt({ data: data, publicKeys: 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({ data: 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) { + context.decrypt({ data: data }).then(function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); expect(result.data).to.equal( @@ -67,77 +67,81 @@ describe('Encryption and Decryption', function (){ 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.encrypt({ data: data, publicKeys: 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(); + context.decrypt({ data: 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(); + context.encrypt({ data:data, publicKeys: 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({ data: 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) { + context.encrypt({ data: b64data, publicKeys: good_fpr, base64: 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({ data: answer.data }).then(function (result) { expect(result).to.not.be.empty; expect(result.data).to.be.a('string'); - expect(data).to.equal(data); + expect(result.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(); - }); - }); + context.encrypt( + { data: b64data, publicKeys: good_fpr, base64: 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({ data: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); for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ @@ -151,20 +155,22 @@ describe('Encryption and Decryption', function (){ 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(); + context.encrypt({ data: data, publicKeys: 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({ data: 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 a242af5f..ccdb4994 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -37,32 +37,34 @@ describe('Encryption', function () { 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) { + context.encrypt({ data: data, publicKeys: 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: data, publicKeys: 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) { + context.encrypt({ data: data }).then(function (answer) { expect(answer).to.be.undefined; }, function (error){ expect(error).to.be.an('Error'); @@ -72,41 +74,44 @@ describe('Encryption', function () { }); 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(); - }); + context.encrypt({ data: null, publicKeys: 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(); - }); + context.encrypt({ data:data, publicKeys: 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(); - }); + context.encrypt({ data: data, publicKeys: 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/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index 240a6b93..1d710e31 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -38,18 +38,20 @@ describe('Long running Encryption/Decryption', function () { 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(); + context.encrypt({ data: data, publicKeys: 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({ data: 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 f5bd9c1d..bd8db807 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -38,7 +38,7 @@ describe('Signing', function () { it('Sign a message', function (done) { const data = bigString(100); - context.sign(data, good_fpr).then(function (answer) { + context.sign({ data: data, keys: 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'); @@ -50,14 +50,15 @@ describe('Signing', function () { 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(); - }); + context.sign({ data: data, keys: good_fpr, mode: 'detached' }) + .then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include(data); + expect(answer.signature).to.be.a('string'); + expect(answer.signature).to.be.a('string'); + done(); + }); }); }); diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index 5788ed51..04c7a77a 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -36,7 +36,7 @@ describe('Verifying data', function () { }); it('Successful verify message', function (done) { const message = inputvalues.signedMessage.good; - context.verify(message).then(function (result){ + context.verify({ data: 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); @@ -50,7 +50,7 @@ describe('Verifying data', function () { it('Successfully recognize changed cleartext', function (done) { const message = inputvalues.signedMessage.bad; - context.verify(message).then(function (result){ + context.verify({ data: 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); @@ -67,24 +67,24 @@ describe('Verifying data', function () { it('Encrypt-Sign-Verify random message', function (done) { const message = bigString(2000); let fpr = inputvalues.encrypt.good.fingerprint; - context.encrypt(message, fpr).then(function (message_enc){ - context.sign(message_enc.data, fpr).then(function (message_encsign){ - context.verify(message_encsign.data).then(function (result){ - 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(); - }); + context.encrypt({ data: message, publicKeys: fpr }) + .then(function (message_enc){ + context.sign({ data: message_enc.data, keys: fpr }) + .then(function (message_encsign){ + context.verify({ data: 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); + const arr = result.signatures.signatures.good; + expect(arr).to.be.an('array'); + expect(arr.length).to.equal(1); + expect(arr[0].fingerprint).to.equal(fpr); + expect(arr[0].valid).to.be.true; + done(); + }); + }); }); - }); }); }); \ No newline at end of file diff --git a/lang/js/DemoExtension/maindemo.js b/lang/js/DemoExtension/maindemo.js index 8d190852..97a27f60 100644 --- a/lang/js/DemoExtension/maindemo.js +++ b/lang/js/DemoExtension/maindemo.js @@ -29,7 +29,7 @@ document.addEventListener('DOMContentLoaded', function () { function (){ let data = document.getElementById('inputtext').value; let keyId = document.getElementById('pubkey').value; - gpgmejs.encrypt(data, keyId).then( + gpgmejs.encrypt({ data: data, privateKeys: keyId }).then( function (answer){ if (answer.data){ document.getElementById( @@ -43,7 +43,7 @@ document.addEventListener('DOMContentLoaded', function () { document.getElementById('buttondecrypt').addEventListener('click', function (){ let data = document.getElementById('inputtext').value; - gpgmejs.decrypt(data).then( + gpgmejs.decrypt({ data: data }).then( function (answer){ if (answer.data){ document.getElementById( @@ -68,7 +68,7 @@ document.addEventListener('DOMContentLoaded', function () { function (){ let data = document.getElementById('inputtext').value; let keyId = document.getElementById('pubkey').value; - gpgmejs.sign(data, keyId).then( + gpgmejs.sign({ data: data, keys: keyId }).then( function (answer){ if (answer.data){ document.getElementById( @@ -82,7 +82,7 @@ document.addEventListener('DOMContentLoaded', function () { document.getElementById('verifytext').addEventListener('click', function (){ let data = document.getElementById('inputtext').value; - gpgmejs.verify(data).then( + gpgmejs.verify({ data: data }).then( function (answer){ let vals = ''; if (answer.all_valid === true){ @@ -101,7 +101,11 @@ document.addEventListener('DOMContentLoaded', function () { document.getElementById('searchkey').addEventListener('click', function (){ let data = document.getElementById('inputtext').value; - gpgmejs.Keyring.getKeys(data, true, true).then(function (keys){ + gpgmejs.Keyring.getKeys({ + pattern: data, + prepare_sync: true, + search: true } + ).then(function (keys){ if (keys.length === 1){ document.getElementById( 'pubkey').value = keys[0].fingerprint; diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index cb053ba1..d6ba1d6f 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -35,27 +35,38 @@ export class GPGME_Keyring { /** * Queries Keys (all Keys or a subset) from gnupg. * - * @param {String | Array} pattern (optional) A pattern to + * @param {Object} options + * @param {String | Array} options.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 + * @param {Boolean} options.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 + * @param {Boolean} options.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){ + getKeys (options){ + if (options && typeof options !== 'object'){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } return new Promise(function (resolve, reject) { let msg = createMessage('keylist'); - if (pattern !== undefined && pattern !== null){ - msg.setParameter('keys', pattern); + if (options && options.pattern) { + if ( + typeof options.pattern === 'string' + || Array.isArray(options.pattern) + ){ + msg.setParameter('keys', options.pattern); + } else { + reject(gpgme_error('PARAM_WRONG')); + } } msg.setParameter('sigs', true); - if (search === true){ + if (options && options.search === true){ msg.setParameter('locate', true); } msg.post().then(function (result){ @@ -64,11 +75,11 @@ export class GPGME_Keyring { resolve([]); } else { let secondrequest; - if (prepare_sync === true) { + if (options && options.prepare_sync === true) { secondrequest = function () { let msg2 = createMessage('keylist'); - if (pattern){ - msg2.setParameter('keys', pattern); + if (options.pattern){ + msg2.setParameter('keys', options.pattern); } msg2.setParameter('secret', true); return msg2.post(); @@ -80,7 +91,7 @@ export class GPGME_Keyring { } secondrequest().then(function (answer) { for (let i=0; i < result.keys.length; i++){ - if (prepare_sync === true){ + if (options.prepare_sync === true){ if (answer && answer.keys) { for (let j=0; j < answer.keys.length; j++ ){ @@ -100,7 +111,7 @@ export class GPGME_Keyring { } } let k = createKey(result.keys[i].fingerprint, - !prepare_sync, result.keys[i]); + !options.prepare_sync, result.keys[i]); resultset.push(k); } resolve(resultset); @@ -126,31 +137,42 @@ export class GPGME_Keyring { /** * 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 + * @param {Object} options (optional) + * @param {String|Array} options.pattern The Pattern to * search for - * @param {Boolean} with_secret_fpr (optional) also return a list of + * @param {Boolean} options.with_secret_fpr 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) { + getKeysArmored (options) { + if (options && typeof options !== 'object'){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } return new Promise(function (resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); - if (with_secret_fpr === true) { + if (options.with_secret_fpr === true) { msg.setParameter('with-sec-fprs', true); } - if (pattern !== undefined && pattern !== null){ - msg.setParameter('keys', pattern); + if (options.pattern){ + if ( + typeof options.pattern === 'string' + || Array.isArray(options.pattern) + ){ + msg.setParameter('keys', options.pattern); + } } 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']; + if (options.with_secret_fpr === true){ + if (answer.hasOwnProperty('sec-fprs')){ + result.secret_fprs = answer['sec-fprs']; + } else { + result.secret_fprs = []; + } } resolve(result); }, function (error){ @@ -300,7 +322,6 @@ export class GPGME_Keyring { changes.signature = (result.status & 4) === 4; changes.subkey = (result.status & 8) === 8; // 16 new secret key: not implemented - fprs.push(result.fingerprint); infos[result.fingerprint] = { changes: changes, @@ -309,19 +330,20 @@ export class GPGME_Keyring { } let resultset = []; if (prepare_sync === true){ - me.getKeys(fprs, true).then(function (result){ - for (let i=0; i < result.length; i++) { - resultset.push({ - key: result[i], - changes: - infos[result[i].fingerprint].changes, - status: infos[result[i].fingerprint].status - }); - } - resolve({ Keys:resultset,summary: summary }); - }, function (error){ - reject(error); - }); + me.getKeys({ pattern: fprs, prepare_sync: true }) + .then(function (result){ + for (let i=0; i < result.length; i++) { + resultset.push({ + key: result[i], + changes: + infos[result[i].fingerprint].changes, + status: infos[result[i].fingerprint].status + }); + } + resolve({ Keys:resultset,summary: summary }); + }, function (error){ + reject(error); + }); } else { for (let i=0; i < fprs.length; i++) { resultset.push({ @@ -364,42 +386,49 @@ export class GPGME_Keyring { * 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 + * @param {Object} options + * @param {String} option.userId The user Id, e.g. 'Foo Bar ' + * @param {String} option.algo (optional) algorithm (and optionally key + * size) to be used. See {@link supportedKeyAlgos} below for supported * values. If ommitted, 'default' is used. - * @param {Number} expires (optional) Expiration time in seconds from now. - * If not set or set to 0, expiration will be 'never' - * @param {String} subkey_algo (optional) algorithm of the encryption - * subkey. If ommited the same as algo is used. + * @param {Number} option.expires (optional) Expiration time in seconds + * from now. If not set or set to 0, expiration will be 'never' + * @param {String} options.subkey_algo (optional) algorithm of the + * encryption subkey. If ommited the same as algo is used. * * @return {Promise} * @async */ - generateKey (userId, algo = 'default', expires, subkey_algo){ - if ( - typeof (userId) !== 'string' || + generateKey (options){ + if (!options + || typeof options !== 'object' + || typeof options.userId !== 'string' // eslint-disable-next-line no-use-before-define - supportedKeyAlgos.indexOf(algo) < 0 || - (expires && !( Number.isInteger(expires) || expires < 0 )) + || ( options.algo && supportedKeyAlgos.indexOf(options.algo) < 0 ) + || ( options.expires && !( + Number.isInteger(options.expires) || options.expires < 0 ) ) ){ return Promise.reject(gpgme_error('PARAM_WRONG')); } // eslint-disable-next-line no-use-before-define - if (subkey_algo && supportedKeyAlgos.indexOf(subkey_algo) < 0 ){ + if (options.subkey_algo && supportedKeyAlgos.indexOf( + options.subkey_algo) < 0 + ){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let me = this; return new Promise(function (resolve, reject){ let msg = createMessage('createkey'); - msg.setParameter('userid', userId); - msg.setParameter('algo', algo ); - if (subkey_algo) { - msg.setParameter('subkey-algo', subkey_algo ); + msg.setParameter('userid', options.userId); + if (!options.algo){ + options.algo === 'default'; } - if (expires){ - msg.setParameter('expires', expires); + msg.setParameter('algo', options.algo); + if (options.subkey_algo) { + msg.setParameter('subkey-algo', options.subkey_algo ); + } + if (options.expires){ + msg.setParameter('expires', options.expires); } else { msg.setParameter('expires', 0); } diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 513e4a56..e0398423 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -110,52 +110,63 @@ export class GpgME { /** * 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 + * @param {Object} options + * @param {String|Object} options.data text/data to be encrypted as String. + * Also accepts Objects with a getText method + * @param {inputKeys} options.publicKeys * Keys used to encrypt the message - * @param {inputKeys} secretKeys (optional) Keys used to sign the + * @param {inputKeys} opions.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 + * @param {Boolean} options.base64 (optional) The data will be interpreted + * as base64 encoded data. + * @param {Boolean} options.armor (optional) Request the output as armored * block. - * @param {Boolean} wildcard (optional) If true, recipient information - * will not be added to the message. + * @param {Boolean} options.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 = {}){ + encrypt (options){ + if (!options || (typeof options !== 'object')){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } + if (!options.hasOwnProperty('data') + || !options.hasOwnProperty('publicKeys') + ){ + return Promise.reject(gpgme_error('MSG_INCOMPLETE')); + } let msg = createMessage('encrypt'); if (msg instanceof Error){ return Promise.reject(msg); } - msg.setParameter('armor', armor); - msg.setParameter('always-trust', true); - if (base64 === true) { + if (!options.hasOwnProperty('armor')){ + options.armor = true; + } + msg.setParameter('armor', options.armor); + + if (options.base64 === true) { msg.setParameter('base64', true); } - let pubkeys = toKeyIdArray(publicKeys); + let pubkeys = toKeyIdArray(options.publicKeys); msg.setParameter('keys', pubkeys); - let sigkeys = toKeyIdArray(secretKeys); + let sigkeys = toKeyIdArray(options.secretKeys); if (sigkeys.length > 0) { msg.setParameter('signing_keys', sigkeys); } - putData(msg, data); - if (wildcard === true){ + putData(msg, options.data); + if (options.wildcard === true){ msg.setParameter('throw-keyids', true); } - if (additional){ - let additional_Keys = Object.keys(additional); + if (options.additional){ + let additional_Keys = Object.keys(options.additional); for (let k = 0; k < additional_Keys.length; k++) { try { msg.setParameter(additional_Keys[k], - additional[additional_Keys[k]]); + options.additional[additional_Keys[k]]); } catch (error){ return Promise.reject(error); @@ -171,17 +182,21 @@ export class GpgME { /** * Decrypts a Message - * @param {String|Object} data text/data to be decrypted. Accepts + * @param {Object} options + * @param {String|Object} options.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 - * @param {Boolean} binary (optional) if true, treat the decoded data as - * binary, and return the data as Uint8Array + * @param {Boolean} options.base64 (optional) false if the data is an + * armored block, true if it is base64 encoded binary data + * @param {Boolean} options.binary (optional) if true, treat the decoded + * data as binary, and return the data as Uint8Array * @returns {Promise} Decrypted Message and information * @async */ - decrypt (data, base64=false, binary){ - if (data === undefined){ + decrypt (options){ + if (!options || (typeof options !== 'object')){ + return Promise.reject('PARAM_WRONG'); + } + if (!options.data){ return Promise.reject(gpgme_error('MSG_EMPTY')); } let msg = createMessage('decrypt'); @@ -189,13 +204,13 @@ export class GpgME { if (msg instanceof Error){ return Promise.reject(msg); } - if (base64 === true){ + if (options.base64 === true){ msg.setParameter('base64', true); } - if (binary === true){ + if (options.binary === true){ msg.expected = 'binary'; } - putData(msg, data); + putData(msg, options.data); return new Promise(function (resolve, reject){ msg.post().then(function (result){ let _result = { data: result.data }; @@ -229,44 +244,49 @@ export class GpgME { /** * 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: + * @param {Object} options Signing options + * @param {String|Object} options.data text/data to be signed. Accepts + * Strings and Objects with a getText method. + * @param {inputKeys} options.keys The key/keys to use for signing + * @param {String} options.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 + * @param {Boolean} options.base64 input is considered base64 * @returns {Promise} * @async */ - sign (data, keys, mode='clearsign', base64=false) { - if (data === undefined){ + sign (options){ + if ( + !options || (typeof options !== 'object')){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } + if (!options.data){ return Promise.reject(gpgme_error('MSG_EMPTY')); } - let key_arr = toKeyIdArray(keys); + if (!options.mode) { + options.mode = 'clearsign'; + } + let key_arr = toKeyIdArray(options.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){ + if (options.base64 === true){ msg.setParameter('base64', true); } - msg.setParameter('mode', mode); - putData(msg, data); + msg.setParameter('mode', options.mode); + putData(msg, options.data); return new Promise(function (resolve,reject) { - if (mode ==='detached'){ - msg.expected ='binary'; - } msg.post().then( function (message) { - if (mode === 'clearsign'){ + if (options.mode === 'clearsign'){ resolve({ data: message.data } ); - } else if (mode === 'detached') { + } else if (options.mode === 'detached') { resolve({ - data: data, + data: options.data, signature: message.data }); } @@ -278,28 +298,33 @@ export class GpgME { /** * Verifies data. - * @param {String|Object} data text/data to be verified. Accepts Strings - * and Objects with a getText method - * @param {String} (optional) A detached signature. If not present, + * @param {Object} options + * @param {String|Object} options.data text/data to be verified. Accepts + * Strings and Objects with a getText method + * @param {String} options.signature A detached signature. If not present, * opaque mode is assumed - * @param {Boolean} (optional) Data and signature are base64 encoded + * @param {Boolean} options.base64 Indicating that data and signature are + * base64 encoded * @returns {Promise} *@async */ - verify (data, signature, base64 = false){ + verify (options){ + if (!options || (typeof options !== 'object') || !options.data){ + return Promise.reject(gpgme_error('PARAM_WRONG')); + } let msg = createMessage('verify'); - let dt = putData(msg, data); + let dt = putData(msg, options.data); if (dt instanceof Error){ return Promise.reject(dt); } - if (signature){ - if (typeof (signature)!== 'string'){ + if (options.signature){ + if (typeof signature !== 'string'){ return Promise.reject(gpgme_error('PARAM_WRONG')); } else { msg.setParameter('signature', signature); } } - if (base64 === true){ + if (options.base64 === true){ msg.setParameter('base64', true); } return new Promise(function (resolve, reject){ @@ -342,14 +367,14 @@ function putData (message, data){ } 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');