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
This commit is contained in:
Maximilian Krambach 2018-08-22 18:37:46 +02:00
parent 129fa919b9
commit f0409bbdaf
11 changed files with 385 additions and 309 deletions

View File

@ -35,7 +35,7 @@ describe('Key importing', function () {
const prm = Gpgmejs.init(); const prm = Gpgmejs.init();
prm.then(function (gpgmejs){ prm.then(function (gpgmejs){
context = gpgmejs; context = gpgmejs;
context.Keyring.getKeys(fpr).then( context.Keyring.getKeys({ pattern: fpr }).then(
function (result){ function (result){
if (result.length === 1) { if (result.length === 1) {
result[0].delete().then(function (){ result[0].delete().then(function (){
@ -52,7 +52,7 @@ describe('Key importing', function () {
afterEach(function (done){ afterEach(function (done){
// delete the test key if still present // delete the test key if still present
context.Keyring.getKeys(fpr).then( context.Keyring.getKeys({ pattern: fpr }).then(
function (result){ function (result){
if (result.length === 1) { if (result.length === 1) {
result[0].delete().then(function (){ result[0].delete().then(function (){
@ -67,7 +67,7 @@ describe('Key importing', function () {
}); });
it('Importing Key', function (done) { 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).to.be.an('array');
expect(result.length).to.equal(0); expect(result.length).to.equal(0);
context.Keyring.importKey(pubKey).then(function (result){ context.Keyring.importKey(pubKey).then(function (result){
@ -127,23 +127,26 @@ describe('Key importing', function () {
it('exporting armored Key with getKeysArmored', function (done) { it('exporting armored Key with getKeysArmored', function (done) {
context.Keyring.importKey(pubKey).then(function (){ context.Keyring.importKey(pubKey).then(function (){
context.Keyring.getKeysArmored(fpr).then(function (result){ context.Keyring.getKeysArmored({ pattern: fpr })
expect(result).to.be.an('object'); .then(function (result){
expect(result.armored).to.be.a('string'); expect(result).to.be.an('object');
expect(result.secret_fprs).to.be.undefined; expect(result.armored).to.be.a('string');
done(); expect(result.secret_fprs).to.be.undefined;
}); done();
});
}); });
}); });
it('Exporting Key (including secret fingerprints)', function (done) { it('Exporting Key (including secret fingerprints)', function (done) {
const key_secret = inputvalues.encrypt.good.fingerprint; const key_secret = inputvalues.encrypt.good.fingerprint;
context.Keyring.getKeysArmored(key_secret, true).then(function (result){ context.Keyring.getKeysArmored({
expect(result).to.be.an('object'); pattern: key_secret, with_secret_fpr: true })
expect(result.armored).to.be.a('string'); .then(function (result){
expect(result.secret_fprs).to.be.an('array'); expect(result).to.be.an('object');
expect(result.secret_fprs[0]).to.equal(key_secret); expect(result.armored).to.be.a('string');
done(); expect(result.secret_fprs).to.be.an('array');
}); expect(result.secret_fprs[0]).to.equal(key_secret);
done();
});
}); });
}); });

View File

@ -36,7 +36,7 @@ describe('Key information', function () {
it('A fingerprint is consistently returned upper case hex', function (done){ it('A fingerprint is consistently returned upper case hex', function (done){
const mixedCase = inputvalues.encrypt.good.fingerprint_mixedcase; 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).to.be.an('array');
expect(result.length).to.equal(1); expect(result.length).to.equal(1);
expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase()); expect(result[0].fingerprint).to.equal(mixedCase.toUpperCase());

View File

@ -38,7 +38,7 @@ describe('Decryption', function () {
it('Decryption of random string fails', function (done) { it('Decryption of random string fails', function (done) {
let data = bigString(20 * 1024); let data = bigString(20 * 1024);
context.decrypt(data).then( context.decrypt({ data: data }).then(
function (){}, function (){},
function (error){ function (error){
expect(error).to.be.an('error'); expect(error).to.be.an('error');
@ -49,21 +49,22 @@ describe('Decryption', function () {
it('Decryption of slightly corrupted message fails', function (done) { it('Decryption of slightly corrupted message fails', function (done) {
const data = bigString(10000); const data = bigString(10000);
context.encrypt(data, good_fpr).then(function (enc){ context.encrypt({ data: data, publicKeys:good_fpr }).then(
context.decrypt(sabotageMsg(enc.data)).then( function (enc){
function (){}, context.decrypt({ data: sabotageMsg(enc.data) }).then(
function (error){ function (){},
expect(error).to.be.an('error'); function (error){
expect(error.code).to.equal('GNUPG_ERROR'); expect(error).to.be.an('error');
done(); expect(error.code).to.equal('GNUPG_ERROR');
}); done();
}); });
});
}).timeout(5000); }).timeout(5000);
it('decrypt/verify operations return proper information', function (done){ it('decrypt/verify operations return proper information', function (done){
const data = inputvalues.encryptSignedMessage; 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).to.be.an('object');
expect(result.signatures).to.be.an('object'); expect(result.signatures).to.be.an('object');
expect(result.signatures.all_valid).to.be.true; expect(result.signatures.all_valid).to.be.true;

View File

@ -38,25 +38,25 @@ describe('Encryption and Decryption', function (){
it('Successful encrypt and decrypt simple string', function (done) { it('Successful encrypt and decrypt simple string', function (done) {
let data = inputvalues.encrypt.good.data; let data = inputvalues.encrypt.good.data;
context.encrypt(data, good_fpr).then(function (answer) { context.encrypt({ data: data, publicKeys: good_fpr }).then(
expect(answer).to.not.be.empty; function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include('END PGP MESSAGE'); expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
context.decrypt(answer.data).then(function (result) { context.decrypt({ data: answer.data }).then(function (result) {
expect(result).to.not.be.empty; expect(result).to.not.be.empty;
expect(result.data).to.be.a('string'); expect(result.data).to.be.a('string');
expect(result.data).to.equal( expect(result.data).to.equal(
inputvalues.encrypt.good.data); inputvalues.encrypt.good.data);
done(); done();
});
}); });
});
}); });
it('Decrypt simple non-ascii', function (done) { it('Decrypt simple non-ascii', function (done) {
let data = encryptedData; let data = encryptedData;
context.decrypt(data).then(function (result) { context.decrypt({ data: data }).then(function (result) {
expect(result).to.not.be.empty; expect(result).to.not.be.empty;
expect(result.data).to.be.a('string'); expect(result.data).to.be.a('string');
expect(result.data).to.equal( expect(result.data).to.equal(
@ -67,77 +67,81 @@ describe('Encryption and Decryption', function (){
it('Trailing whitespace and different line endings', function (done) { it('Trailing whitespace and different line endings', function (done) {
const data = 'Keks. \rKeks \n Keks \r\n'; const data = 'Keks. \rKeks \n Keks \r\n';
context.encrypt(data, good_fpr).then(function (answer) { context.encrypt({ data: data, publicKeys: good_fpr }).then(
expect(answer).to.not.be.empty; function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include('END PGP MESSAGE'); expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
context.decrypt(answer.data).then(function (result) { context.decrypt({ data: answer.data }).then(function (result) {
expect(result).to.not.be.empty; expect(result).to.not.be.empty;
expect(result.data).to.be.a('string'); expect(result.data).to.be.a('string');
expect(result.data).to.equal(data); expect(result.data).to.equal(data);
done(); done();
});
}); });
});
}).timeout(5000); }).timeout(5000);
it('Random data, as string', function (done) { it('Random data, as string', function (done) {
let data = bigString(1000); let data = bigString(1000);
context.encrypt(data, good_fpr).then(function (answer) { context.encrypt({ data:data, publicKeys: good_fpr }).then(
expect(answer).to.not.be.empty; function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include( expect(answer.data).to.be.a('string');
'BEGIN PGP MESSAGE'); expect(answer.data).to.include(
expect(answer.data).to.include( 'BEGIN PGP MESSAGE');
'END PGP MESSAGE'); expect(answer.data).to.include(
context.decrypt(answer.data).then(function (result) { 'END PGP MESSAGE');
expect(result).to.not.be.empty; context.decrypt({ data: answer.data }).then(function (result) {
expect(result.data).to.be.a('string'); expect(result).to.not.be.empty;
expect(result.data).to.equal(data); expect(result.data).to.be.a('string');
done(); expect(result.data).to.equal(data);
done();
});
}); });
});
}).timeout(3000); }).timeout(3000);
it('Data, input as base64', function (done) { it('Data, input as base64', function (done) {
let data = inputvalues.encrypt.good.data; let data = inputvalues.encrypt.good.data;
let b64data = btoa(data); let b64data = btoa(data);
context.encrypt(b64data, good_fpr, true).then(function (answer) { context.encrypt({ data: b64data, publicKeys: good_fpr, base64: true })
expect(answer).to.not.be.empty; .then(function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include( expect(answer.data).to.be.a('string');
'BEGIN PGP MESSAGE'); expect(answer.data).to.include(
expect(answer.data).to.include( 'BEGIN PGP MESSAGE');
'END PGP MESSAGE'); expect(answer.data).to.include(
context.decrypt(answer.data).then( 'END PGP MESSAGE');
function (result) { context.decrypt({ data: answer.data }).then(function (result) {
expect(result).to.not.be.empty; expect(result).to.not.be.empty;
expect(result.data).to.be.a('string'); expect(result.data).to.be.a('string');
expect(data).to.equal(data); expect(result.data).to.equal(data);
done(); done();
}); });
}); });
}).timeout(3000); }).timeout(3000);
it('Random data, input as base64', function (done) { it('Random data, input as base64', function (done) {
let data = bigBoringString(0.001); let data = bigBoringString(0.001);
let b64data = btoa(data); let b64data = btoa(data);
context.encrypt(b64data, good_fpr, true).then(function (answer) { context.encrypt(
expect(answer).to.not.be.empty; { data: b64data, publicKeys: good_fpr, base64: true })
expect(answer.data).to.be.a('string'); .then(function (answer) {
expect(answer.data).to.include( expect(answer).to.not.be.empty;
'BEGIN PGP MESSAGE'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include( expect(answer.data).to.include(
'END PGP MESSAGE'); 'BEGIN PGP MESSAGE');
context.decrypt(answer.data).then( expect(answer.data).to.include(
function (result) { 'END PGP MESSAGE');
expect(result).to.not.be.empty; context.decrypt({ data:answer.data }).then(
expect(result.data).to.be.a('string'); function (result) {
expect(result.data).to.equal(b64data); expect(result).to.not.be.empty;
done(); expect(result.data).to.be.a('string');
}); expect(result.data).to.equal(data);
}); done();
});
});
}).timeout(3000); }).timeout(3000);
for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ 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++){ for (let i=0; i < 34 * 1024; i++){
data += input; data += input;
} }
context.encrypt(data,good_fpr).then(function (answer) { context.encrypt({ data: data, publicKeys: good_fpr })
expect(answer).to.not.be.empty; .then(function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include( expect(answer.data).to.be.a('string');
'BEGIN PGP MESSAGE'); expect(answer.data).to.include(
expect(answer.data).to.include( 'BEGIN PGP MESSAGE');
'END PGP MESSAGE'); expect(answer.data).to.include(
context.decrypt(answer.data).then(function (result) { 'END PGP MESSAGE');
expect(result).to.not.be.empty; context.decrypt({ data: answer.data })
expect(result.data).to.be.a('string'); .then(function (result) {
expect(result.data).to.equal(data); expect(result).to.not.be.empty;
done(); expect(result.data).to.be.a('string');
expect(result.data).to.equal(data);
done();
});
}); });
});
}).timeout(5000); }).timeout(5000);
} }
}); });

View File

@ -37,32 +37,34 @@ describe('Encryption', function () {
it('Successful encrypt', function (done) { it('Successful encrypt', function (done) {
const data = inputvalues.encrypt.good.data; const data = inputvalues.encrypt.good.data;
context.encrypt(data, good_fpr).then(function (answer) { context.encrypt({ data: data, publicKeys: good_fpr })
expect(answer).to.not.be.empty; .then(function (answer) {
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).to.not.be.empty;
expect(answer.data).to.be.a('string'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE');
done(); 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); }).timeout(20000);
} }
it('Sending encryption without keys fails', function (done) { it('Sending encryption without keys fails', function (done) {
const data = inputvalues.encrypt.good.data; 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; expect(answer).to.be.undefined;
}, function (error){ }, function (error){
expect(error).to.be.an('Error'); expect(error).to.be.an('Error');
@ -72,41 +74,44 @@ describe('Encryption', function () {
}); });
it('Sending encryption without data fails', function (done) { it('Sending encryption without data fails', function (done) {
context.encrypt(null, good_fpr).then(function (answer) { context.encrypt({ data: null, publicKeys: good_fpr })
expect(answer).to.be.undefined; .then(function (answer) {
}, function (error) { expect(answer).to.be.undefined;
expect(error).to.be.an.instanceof(Error); }, function (error) {
expect(error.code).to.equal('MSG_INCOMPLETE'); expect(error).to.be.an.instanceof(Error);
done(); expect(error.code).to.equal('MSG_INCOMPLETE');
}); done();
});
}); });
it('Sending encryption with non existing keys fails', function (done) { it('Sending encryption with non existing keys fails', function (done) {
const data = inputvalues.encrypt.good.data; const data = inputvalues.encrypt.good.data;
const bad_fpr = inputvalues.encrypt.bad.fingerprint; const bad_fpr = inputvalues.encrypt.bad.fingerprint;
context.encrypt(data, bad_fpr).then(function (answer) { context.encrypt({ data:data, publicKeys: bad_fpr })
expect(answer).to.be.undefined; .then(function (answer) {
}, function (error){ expect(answer).to.be.undefined;
expect(error).to.be.an('Error'); }, function (error){
expect(error.code).to.not.be.undefined; expect(error).to.be.an('Error');
expect(error.code).to.equal('GNUPG_ERROR'); expect(error.code).to.not.be.undefined;
done(); expect(error.code).to.equal('GNUPG_ERROR');
}); done();
});
}).timeout(5000); }).timeout(5000);
it('Overly large message ( > 64MB) is rejected', function (done) { it('Overly large message ( > 64MB) is rejected', function (done) {
const data = fixedLengthString(65); const data = fixedLengthString(65);
context.encrypt(data, good_fpr).then(function (answer) { context.encrypt({ data: data, publicKeys: good_fpr })
expect(answer).to.be.undefined; .then(function (answer) {
}, function (error){ expect(answer).to.be.undefined;
expect(error).to.be.an.instanceof(Error); }, function (error){
// TODO: there is a 64 MB hard limit at least in chrome at: expect(error).to.be.an.instanceof(Error);
// chromium//extensions/renderer/messaging_util.cc: // TODO: there is a 64 MB hard limit at least in chrome at:
// kMaxMessageLength // chromium//extensions/renderer/messaging_util.cc:
// The error will be a browser error, not from gnupg or from // kMaxMessageLength
// this library // The error will be a browser error, not from gnupg or from
done(); // this library
}); done();
});
}).timeout(8000); }).timeout(8000);
// TODO check different valid parameter // TODO check different valid parameter

View File

@ -38,18 +38,20 @@ describe('Long running Encryption/Decryption', function () {
it('Successful encrypt/decrypt completely random data ' it('Successful encrypt/decrypt completely random data '
+ (i+1) + '/100', function (done) { + (i+1) + '/100', function (done) {
const data = bigString(2*1024*1024); const data = bigString(2*1024*1024);
context.encrypt(data,good_fpr).then(function (answer){ context.encrypt({ data: data, publicKeys: good_fpr })
expect(answer).to.not.be.empty; .then(function (answer){
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include('END PGP MESSAGE'); expect(answer.data).to.include('BEGIN PGP MESSAGE');
context.decrypt(answer.data).then(function (result){ expect(answer.data).to.include('END PGP MESSAGE');
expect(result).to.not.be.empty; context.decrypt({ data: answer.data })
expect(result.data).to.be.a('string'); .then(function (result){
expect(result.data).to.equal(data); expect(result).to.not.be.empty;
done(); expect(result.data).to.be.a('string');
expect(result.data).to.equal(data);
done();
});
}); });
});
}).timeout(15000); }).timeout(15000);
} }

View File

@ -38,7 +38,7 @@ describe('Signing', function () {
it('Sign a message', function (done) { it('Sign a message', function (done) {
const data = bigString(100); 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).to.not.be.empty;
expect(answer.data).to.be.a('string'); expect(answer.data).to.be.a('string');
expect(answer.data).to.include('BEGIN PGP SIGNATURE'); expect(answer.data).to.include('BEGIN PGP SIGNATURE');
@ -50,14 +50,15 @@ describe('Signing', function () {
it('Detached sign a message', function (done) { it('Detached sign a message', function (done) {
const data = bigString(100); const data = bigString(100);
context.sign(data,good_fpr, 'detached').then(function (answer) { context.sign({ data: data, keys: good_fpr, mode: 'detached' })
expect(answer).to.not.be.empty; .then(function (answer) {
expect(answer.data).to.be.a('string'); expect(answer).to.not.be.empty;
expect(answer.data).to.include(data); expect(answer.data).to.be.a('string');
expect(answer.signature).to.be.a('string'); expect(answer.data).to.include(data);
expect(answer.signature).to.be.a('string'); expect(answer.signature).to.be.a('string');
done(); expect(answer.signature).to.be.a('string');
}); done();
});
}); });
}); });

View File

@ -36,7 +36,7 @@ describe('Verifying data', function () {
}); });
it('Successful verify message', function (done) { it('Successful verify message', function (done) {
const message = inputvalues.signedMessage.good; 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.data).to.be.a('string');
expect(result.signatures.all_valid).to.be.true; expect(result.signatures.all_valid).to.be.true;
expect(result.signatures.count).to.equal(1); expect(result.signatures.count).to.equal(1);
@ -50,7 +50,7 @@ describe('Verifying data', function () {
it('Successfully recognize changed cleartext', function (done) { it('Successfully recognize changed cleartext', function (done) {
const message = inputvalues.signedMessage.bad; 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.data).to.be.a('string');
expect(result.signatures.all_valid).to.be.false; expect(result.signatures.all_valid).to.be.false;
expect(result.signatures.count).to.equal(1); expect(result.signatures.count).to.equal(1);
@ -67,24 +67,24 @@ describe('Verifying data', function () {
it('Encrypt-Sign-Verify random message', function (done) { it('Encrypt-Sign-Verify random message', function (done) {
const message = bigString(2000); const message = bigString(2000);
let fpr = inputvalues.encrypt.good.fingerprint; let fpr = inputvalues.encrypt.good.fingerprint;
context.encrypt(message, fpr).then(function (message_enc){ context.encrypt({ data: message, publicKeys: fpr })
context.sign(message_enc.data, fpr).then(function (message_encsign){ .then(function (message_enc){
context.verify(message_encsign.data).then(function (result){ context.sign({ data: message_enc.data, keys: fpr })
expect(result.data).to.equal(message_enc.data); .then(function (message_encsign){
expect(result.data).to.be.a('string'); context.verify({ data: message_encsign.data })
expect(result.signatures.all_valid).to.be.true; .then(function (result){
expect(result.signatures.count).to.equal(1); expect(result.data).to.equal(message_enc.data);
expect(result.signatures.signatures.good) expect(result.data).to.be.a('string');
.to.be.an('array'); expect(result.signatures.all_valid).to.be.true;
expect(result.signatures.signatures.good.length) expect(result.signatures.count).to.equal(1);
.to.equal(1); const arr = result.signatures.signatures.good;
expect(result.signatures.signatures.good[0].fingerprint) expect(arr).to.be.an('array');
.to.equal(fpr); expect(arr.length).to.equal(1);
expect(result.signatures.signatures.good[0].valid) expect(arr[0].fingerprint).to.equal(fpr);
.to.be.true; expect(arr[0].valid).to.be.true;
done(); done();
}); });
});
}); });
});
}); });
}); });

View File

@ -29,7 +29,7 @@ document.addEventListener('DOMContentLoaded', function () {
function (){ function (){
let data = document.getElementById('inputtext').value; let data = document.getElementById('inputtext').value;
let keyId = document.getElementById('pubkey').value; let keyId = document.getElementById('pubkey').value;
gpgmejs.encrypt(data, keyId).then( gpgmejs.encrypt({ data: data, privateKeys: keyId }).then(
function (answer){ function (answer){
if (answer.data){ if (answer.data){
document.getElementById( document.getElementById(
@ -43,7 +43,7 @@ document.addEventListener('DOMContentLoaded', function () {
document.getElementById('buttondecrypt').addEventListener('click', document.getElementById('buttondecrypt').addEventListener('click',
function (){ function (){
let data = document.getElementById('inputtext').value; let data = document.getElementById('inputtext').value;
gpgmejs.decrypt(data).then( gpgmejs.decrypt({ data: data }).then(
function (answer){ function (answer){
if (answer.data){ if (answer.data){
document.getElementById( document.getElementById(
@ -68,7 +68,7 @@ document.addEventListener('DOMContentLoaded', function () {
function (){ function (){
let data = document.getElementById('inputtext').value; let data = document.getElementById('inputtext').value;
let keyId = document.getElementById('pubkey').value; let keyId = document.getElementById('pubkey').value;
gpgmejs.sign(data, keyId).then( gpgmejs.sign({ data: data, keys: keyId }).then(
function (answer){ function (answer){
if (answer.data){ if (answer.data){
document.getElementById( document.getElementById(
@ -82,7 +82,7 @@ document.addEventListener('DOMContentLoaded', function () {
document.getElementById('verifytext').addEventListener('click', document.getElementById('verifytext').addEventListener('click',
function (){ function (){
let data = document.getElementById('inputtext').value; let data = document.getElementById('inputtext').value;
gpgmejs.verify(data).then( gpgmejs.verify({ data: data }).then(
function (answer){ function (answer){
let vals = ''; let vals = '';
if (answer.all_valid === true){ if (answer.all_valid === true){
@ -101,7 +101,11 @@ document.addEventListener('DOMContentLoaded', function () {
document.getElementById('searchkey').addEventListener('click', document.getElementById('searchkey').addEventListener('click',
function (){ function (){
let data = document.getElementById('inputtext').value; 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){ if (keys.length === 1){
document.getElementById( document.getElementById(
'pubkey').value = keys[0].fingerprint; 'pubkey').value = keys[0].fingerprint;

View File

@ -35,27 +35,38 @@ export class GPGME_Keyring {
/** /**
* Queries Keys (all Keys or a subset) from gnupg. * Queries Keys (all Keys or a subset) from gnupg.
* *
* @param {String | Array<String>} pattern (optional) A pattern to * @param {Object} options
* @param {String | Array<String>} options.pattern (optional) A pattern to
* search for in userIds or KeyIds. * search for in userIds or KeyIds.
* @param {Boolean} prepare_sync (optional) if set to true, most data * @param {Boolean} options.prepare_sync (optional) if set to true, most
* (with the exception of armored Key blocks) will be cached for the * data (with the exception of armored Key blocks) will be cached for the
* Keys. This enables direct, synchronous use of these properties for * Keys. This enables direct, synchronous use of these properties for
* all keys. It does not check for changes on the backend. The cached * all keys. It does not check for changes on the backend. The cached
* information can be updated with the {@link Key.refresh} method. * 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) * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
* @returns {Promise<Array<GPGME_Key>>} * @returns {Promise<Array<GPGME_Key>>}
* @static * @static
* @async * @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) { return new Promise(function (resolve, reject) {
let msg = createMessage('keylist'); let msg = createMessage('keylist');
if (pattern !== undefined && pattern !== null){ if (options && options.pattern) {
msg.setParameter('keys', 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); msg.setParameter('sigs', true);
if (search === true){ if (options && options.search === true){
msg.setParameter('locate', true); msg.setParameter('locate', true);
} }
msg.post().then(function (result){ msg.post().then(function (result){
@ -64,11 +75,11 @@ export class GPGME_Keyring {
resolve([]); resolve([]);
} else { } else {
let secondrequest; let secondrequest;
if (prepare_sync === true) { if (options && options.prepare_sync === true) {
secondrequest = function () { secondrequest = function () {
let msg2 = createMessage('keylist'); let msg2 = createMessage('keylist');
if (pattern){ if (options.pattern){
msg2.setParameter('keys', pattern); msg2.setParameter('keys', options.pattern);
} }
msg2.setParameter('secret', true); msg2.setParameter('secret', true);
return msg2.post(); return msg2.post();
@ -80,7 +91,7 @@ export class GPGME_Keyring {
} }
secondrequest().then(function (answer) { secondrequest().then(function (answer) {
for (let i=0; i < result.keys.length; i++){ for (let i=0; i < result.keys.length; i++){
if (prepare_sync === true){ if (options.prepare_sync === true){
if (answer && answer.keys) { if (answer && answer.keys) {
for (let j=0; for (let j=0;
j < answer.keys.length; j++ ){ j < answer.keys.length; j++ ){
@ -100,7 +111,7 @@ export class GPGME_Keyring {
} }
} }
let k = createKey(result.keys[i].fingerprint, let k = createKey(result.keys[i].fingerprint,
!prepare_sync, result.keys[i]); !options.prepare_sync, result.keys[i]);
resultset.push(k); resultset.push(k);
} }
resolve(resultset); resolve(resultset);
@ -126,31 +137,42 @@ export class GPGME_Keyring {
/** /**
* Fetches the armored public Key blocks for all Keys matching the * Fetches the armored public Key blocks for all Keys matching the
* pattern (if no pattern is given, fetches all keys known to gnupg). * pattern (if no pattern is given, fetches all keys known to gnupg).
* @param {String|Array<String>} pattern (optional) The Pattern to * @param {Object} options (optional)
* @param {String|Array<String>} options.pattern The Pattern to
* search for * 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 * fingerprints for the keys that have a secret key available
* @returns {Promise<exportResult|GPGME_Error>} Object containing the * @returns {Promise<exportResult|GPGME_Error>} Object containing the
* armored Key(s) and additional information. * armored Key(s) and additional information.
* @static * @static
* @async * @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) { return new Promise(function (resolve, reject) {
let msg = createMessage('export'); let msg = createMessage('export');
msg.setParameter('armor', true); msg.setParameter('armor', true);
if (with_secret_fpr === true) { if (options.with_secret_fpr === true) {
msg.setParameter('with-sec-fprs', true); msg.setParameter('with-sec-fprs', true);
} }
if (pattern !== undefined && pattern !== null){ if (options.pattern){
msg.setParameter('keys', pattern); if (
typeof options.pattern === 'string'
|| Array.isArray(options.pattern)
){
msg.setParameter('keys', options.pattern);
}
} }
msg.post().then(function (answer){ msg.post().then(function (answer){
const result = { armored: answer.data }; const result = { armored: answer.data };
if (with_secret_fpr === true if (options.with_secret_fpr === true){
&& answer.hasOwnProperty('sec-fprs') if (answer.hasOwnProperty('sec-fprs')){
) { result.secret_fprs = answer['sec-fprs'];
result.secret_fprs = answer['sec-fprs']; } else {
result.secret_fprs = [];
}
} }
resolve(result); resolve(result);
}, function (error){ }, function (error){
@ -300,7 +322,6 @@ export class GPGME_Keyring {
changes.signature = (result.status & 4) === 4; changes.signature = (result.status & 4) === 4;
changes.subkey = (result.status & 8) === 8; changes.subkey = (result.status & 8) === 8;
// 16 new secret key: not implemented // 16 new secret key: not implemented
fprs.push(result.fingerprint); fprs.push(result.fingerprint);
infos[result.fingerprint] = { infos[result.fingerprint] = {
changes: changes, changes: changes,
@ -309,19 +330,20 @@ export class GPGME_Keyring {
} }
let resultset = []; let resultset = [];
if (prepare_sync === true){ if (prepare_sync === true){
me.getKeys(fprs, true).then(function (result){ me.getKeys({ pattern: fprs, prepare_sync: true })
for (let i=0; i < result.length; i++) { .then(function (result){
resultset.push({ for (let i=0; i < result.length; i++) {
key: result[i], resultset.push({
changes: key: result[i],
infos[result[i].fingerprint].changes, changes:
status: infos[result[i].fingerprint].status infos[result[i].fingerprint].changes,
}); status: infos[result[i].fingerprint].status
} });
resolve({ Keys:resultset,summary: summary }); }
}, function (error){ resolve({ Keys:resultset,summary: summary });
reject(error); }, function (error){
}); reject(error);
});
} else { } else {
for (let i=0; i < fprs.length; i++) { for (let i=0; i < fprs.length; i++) {
resultset.push({ resultset.push({
@ -364,42 +386,49 @@ export class GPGME_Keyring {
* Generates a new Key pair directly in gpg, and returns a GPGME_Key * Generates a new Key pair directly in gpg, and returns a GPGME_Key
* representing that Key. Please note that due to security concerns, * representing that Key. Please note that due to security concerns,
* secret Keys can not be deleted or exported from inside gpgme.js. * secret Keys can not be deleted or exported from inside gpgme.js.
* * @param {Object} options
* @param {String} userId The user Id, e.g. 'Foo Bar <foo@bar.baz>' * @param {String} option.userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
* @param {String} algo (optional) algorithm (and optionally key size) * @param {String} option.algo (optional) algorithm (and optionally key
* to be used. See {@link supportedKeyAlgos} below for supported * size) to be used. See {@link supportedKeyAlgos} below for supported
* values. If ommitted, 'default' is used. * values. If ommitted, 'default' is used.
* @param {Number} expires (optional) Expiration time in seconds from now. * @param {Number} option.expires (optional) Expiration time in seconds
* If not set or set to 0, expiration will be 'never' * from now. If not set or set to 0, expiration will be 'never'
* @param {String} subkey_algo (optional) algorithm of the encryption * @param {String} options.subkey_algo (optional) algorithm of the
* subkey. If ommited the same as algo is used. * encryption subkey. If ommited the same as algo is used.
* *
* @return {Promise<Key|GPGME_Error>} * @return {Promise<Key|GPGME_Error>}
* @async * @async
*/ */
generateKey (userId, algo = 'default', expires, subkey_algo){ generateKey (options){
if ( if (!options
typeof (userId) !== 'string' || || typeof options !== 'object'
|| typeof options.userId !== 'string'
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
supportedKeyAlgos.indexOf(algo) < 0 || || ( options.algo && supportedKeyAlgos.indexOf(options.algo) < 0 )
(expires && !( Number.isInteger(expires) || expires < 0 )) || ( options.expires && !(
Number.isInteger(options.expires) || options.expires < 0 ) )
){ ){
return Promise.reject(gpgme_error('PARAM_WRONG')); return Promise.reject(gpgme_error('PARAM_WRONG'));
} }
// eslint-disable-next-line no-use-before-define // 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')); return Promise.reject(gpgme_error('PARAM_WRONG'));
} }
let me = this; let me = this;
return new Promise(function (resolve, reject){ return new Promise(function (resolve, reject){
let msg = createMessage('createkey'); let msg = createMessage('createkey');
msg.setParameter('userid', userId); msg.setParameter('userid', options.userId);
msg.setParameter('algo', algo ); if (!options.algo){
if (subkey_algo) { options.algo === 'default';
msg.setParameter('subkey-algo', subkey_algo );
} }
if (expires){ msg.setParameter('algo', options.algo);
msg.setParameter('expires', expires); if (options.subkey_algo) {
msg.setParameter('subkey-algo', options.subkey_algo );
}
if (options.expires){
msg.setParameter('expires', options.expires);
} else { } else {
msg.setParameter('expires', 0); msg.setParameter('expires', 0);
} }

View File

@ -110,52 +110,63 @@ export class GpgME {
/** /**
* Encrypt (and optionally sign) data * Encrypt (and optionally sign) data
* @param {String|Object} data text/data to be encrypted as String. Also * @param {Object} options
* accepts Objects with a getText method * @param {String|Object} options.data text/data to be encrypted as String.
* @param {inputKeys} publicKeys * Also accepts Objects with a getText method
* @param {inputKeys} options.publicKeys
* Keys used to encrypt the message * 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 * message. If Keys are present, the operation requested is assumed
* to be 'encrypt and sign' * to be 'encrypt and sign'
* @param {Boolean} base64 (optional) The data will be interpreted as * @param {Boolean} options.base64 (optional) The data will be interpreted
* base64 encoded data. * as base64 encoded data.
* @param {Boolean} armor (optional) Request the output as armored * @param {Boolean} options.armor (optional) Request the output as armored
* block. * block.
* @param {Boolean} wildcard (optional) If true, recipient information * @param {Boolean} options.wildcard (optional) If true, recipient
* will not be added to the message. * information will not be added to the message.
* @param {Object} additional use additional valid gpg options as * @param {Object} additional use additional valid gpg options as
* defined in {@link permittedOperations} * defined in {@link permittedOperations}
* @returns {Promise<encrypt_result>} Object containing the encrypted * @returns {Promise<encrypt_result>} Object containing the encrypted
* message and additional info. * message and additional info.
* @async * @async
*/ */
encrypt (data, publicKeys, secretKeys, base64=false, armor=true, encrypt (options){
wildcard=false, additional = {}){ 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'); let msg = createMessage('encrypt');
if (msg instanceof Error){ if (msg instanceof Error){
return Promise.reject(msg); return Promise.reject(msg);
} }
msg.setParameter('armor', armor); if (!options.hasOwnProperty('armor')){
msg.setParameter('always-trust', true); options.armor = true;
if (base64 === true) { }
msg.setParameter('armor', options.armor);
if (options.base64 === true) {
msg.setParameter('base64', true); msg.setParameter('base64', true);
} }
let pubkeys = toKeyIdArray(publicKeys); let pubkeys = toKeyIdArray(options.publicKeys);
msg.setParameter('keys', pubkeys); msg.setParameter('keys', pubkeys);
let sigkeys = toKeyIdArray(secretKeys); let sigkeys = toKeyIdArray(options.secretKeys);
if (sigkeys.length > 0) { if (sigkeys.length > 0) {
msg.setParameter('signing_keys', sigkeys); msg.setParameter('signing_keys', sigkeys);
} }
putData(msg, data); putData(msg, options.data);
if (wildcard === true){ if (options.wildcard === true){
msg.setParameter('throw-keyids', true); msg.setParameter('throw-keyids', true);
} }
if (additional){ if (options.additional){
let additional_Keys = Object.keys(additional); let additional_Keys = Object.keys(options.additional);
for (let k = 0; k < additional_Keys.length; k++) { for (let k = 0; k < additional_Keys.length; k++) {
try { try {
msg.setParameter(additional_Keys[k], msg.setParameter(additional_Keys[k],
additional[additional_Keys[k]]); options.additional[additional_Keys[k]]);
} }
catch (error){ catch (error){
return Promise.reject(error); return Promise.reject(error);
@ -171,17 +182,21 @@ export class GpgME {
/** /**
* Decrypts a Message * 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 * Strings and Objects with a getText method
* @param {Boolean} base64 (optional) false if the data is an armored * @param {Boolean} options.base64 (optional) false if the data is an
* block, true if it is base64 encoded binary data * armored block, true if it is base64 encoded binary data
* @param {Boolean} binary (optional) if true, treat the decoded data as * @param {Boolean} options.binary (optional) if true, treat the decoded
* binary, and return the data as Uint8Array * data as binary, and return the data as Uint8Array
* @returns {Promise<decrypt_result>} Decrypted Message and information * @returns {Promise<decrypt_result>} Decrypted Message and information
* @async * @async
*/ */
decrypt (data, base64=false, binary){ decrypt (options){
if (data === undefined){ if (!options || (typeof options !== 'object')){
return Promise.reject('PARAM_WRONG');
}
if (!options.data){
return Promise.reject(gpgme_error('MSG_EMPTY')); return Promise.reject(gpgme_error('MSG_EMPTY'));
} }
let msg = createMessage('decrypt'); let msg = createMessage('decrypt');
@ -189,13 +204,13 @@ export class GpgME {
if (msg instanceof Error){ if (msg instanceof Error){
return Promise.reject(msg); return Promise.reject(msg);
} }
if (base64 === true){ if (options.base64 === true){
msg.setParameter('base64', true); msg.setParameter('base64', true);
} }
if (binary === true){ if (options.binary === true){
msg.expected = 'binary'; msg.expected = 'binary';
} }
putData(msg, data); putData(msg, options.data);
return new Promise(function (resolve, reject){ return new Promise(function (resolve, reject){
msg.post().then(function (result){ msg.post().then(function (result){
let _result = { data: result.data }; let _result = { data: result.data };
@ -229,44 +244,49 @@ export class GpgME {
/** /**
* Sign a Message * Sign a Message
* @param {String|Object} data text/data to be signed. Accepts Strings * @param {Object} options Signing options
* and Objects with a getText method. * @param {String|Object} options.data text/data to be signed. Accepts
* @param {inputKeys} keys The key/keys to use for signing * Strings and Objects with a getText method.
* @param {String} mode The signing mode. Currently supported: * @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; * 'clearsign':The Message is embedded into the signature;
* 'detached': The signature is stored separately * 'detached': The signature is stored separately
* @param {Boolean} base64 input is considered base64 * @param {Boolean} options.base64 input is considered base64
* @returns {Promise<signResult>} * @returns {Promise<signResult>}
* @async * @async
*/ */
sign (data, keys, mode='clearsign', base64=false) { sign (options){
if (data === undefined){ if (
!options || (typeof options !== 'object')){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
if (!options.data){
return Promise.reject(gpgme_error('MSG_EMPTY')); 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){ if (key_arr.length === 0){
return Promise.reject(gpgme_error('MSG_NO_KEYS')); return Promise.reject(gpgme_error('MSG_NO_KEYS'));
} }
let msg = createMessage('sign'); let msg = createMessage('sign');
msg.setParameter('keys', key_arr); msg.setParameter('keys', key_arr);
if (base64 === true){ if (options.base64 === true){
msg.setParameter('base64', true); msg.setParameter('base64', true);
} }
msg.setParameter('mode', mode); msg.setParameter('mode', options.mode);
putData(msg, data); putData(msg, options.data);
return new Promise(function (resolve,reject) { return new Promise(function (resolve,reject) {
if (mode ==='detached'){
msg.expected ='binary';
}
msg.post().then( function (message) { msg.post().then( function (message) {
if (mode === 'clearsign'){ if (options.mode === 'clearsign'){
resolve({ resolve({
data: message.data } data: message.data }
); );
} else if (mode === 'detached') { } else if (options.mode === 'detached') {
resolve({ resolve({
data: data, data: options.data,
signature: message.data signature: message.data
}); });
} }
@ -278,28 +298,33 @@ export class GpgME {
/** /**
* Verifies data. * Verifies data.
* @param {String|Object} data text/data to be verified. Accepts Strings * @param {Object} options
* and Objects with a getText method * @param {String|Object} options.data text/data to be verified. Accepts
* @param {String} (optional) A detached signature. If not present, * Strings and Objects with a getText method
* @param {String} options.signature A detached signature. If not present,
* opaque mode is assumed * 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<verifyResult>} * @returns {Promise<verifyResult>}
*@async *@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 msg = createMessage('verify');
let dt = putData(msg, data); let dt = putData(msg, options.data);
if (dt instanceof Error){ if (dt instanceof Error){
return Promise.reject(dt); return Promise.reject(dt);
} }
if (signature){ if (options.signature){
if (typeof (signature)!== 'string'){ if (typeof signature !== 'string'){
return Promise.reject(gpgme_error('PARAM_WRONG')); return Promise.reject(gpgme_error('PARAM_WRONG'));
} else { } else {
msg.setParameter('signature', signature); msg.setParameter('signature', signature);
} }
} }
if (base64 === true){ if (options.base64 === true){
msg.setParameter('base64', true); msg.setParameter('base64', true);
} }
return new Promise(function (resolve, reject){ return new Promise(function (resolve, reject){
@ -342,14 +367,14 @@ function putData (message, data){
} }
if (!data){ if (!data){
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} else if (typeof (data) === 'string') { } else if (typeof data === 'string') {
message.setParameter('data', data); message.setParameter('data', data);
} else if ( } else if (
typeof (data) === 'object' && (typeof data === 'object') &&
typeof (data.getText) === 'function' (typeof data.getText === 'function')
){ ){
let txt = data.getText(); let txt = data.getText();
if (typeof (txt) === 'string'){ if (typeof txt === 'string'){
message.setParameter('data', txt); message.setParameter('data', txt);
} else { } else {
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');