diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
index 5c534039..2fe955e6 100644
--- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
+++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
@@ -1,116 +1,225 @@
+
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*/
describe('Encryption and Decryption', function () {
it('Successful encrypt and decrypt simple string', function (done) {
let prm = Gpgmejs.init();
prm.then(function (context) {
context.encrypt(
inputvalues.encrypt.good.data,
inputvalues.encrypt.good.fingerprint).then(function (answer) {
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
context.decrypt(answer.data).then(function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(inputvalues.encrypt.good.data);
context.connection.disconnect();
done();
});
});
});
});
+
+ it('Decrypt simple non-ascii', function (done) {
+ let prm = Gpgmejs.init();
+ prm.then(function (context) {
+ let data = encryptedData;
+ context.decrypt(data).then(
+ function (result) {
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(result.data).to.equal(
+ '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n');
+ done();
+ });
+ });
+ }).timeout(3000);
+
it('Roundtrip does not destroy trailing whitespace',
function (done) {
let prm = Gpgmejs.init();
prm.then(function (context) {
let data = 'Keks. \rKeks \n Keks \r\n';
context.encrypt(data,
inputvalues.encrypt.good.fingerprint).then(
function (answer) {
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include(
'BEGIN PGP MESSAGE');
expect(answer.data).to.include(
'END PGP MESSAGE');
context.decrypt(answer.data).then(
function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(data);
context.connection.disconnect();
done();
});
});
});
- }).timeout(5000);
+ }).timeout(5000);
for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){
it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + (j + 1) + '/' + inputvalues.encrypt.good.data_nonascii_32.length + ')',
function (done) {
let input = inputvalues.encrypt.good.data_nonascii_32[j];
expect(input).to.have.length(32);
let prm = Gpgmejs.init();
prm.then(function (context) {
let data = '';
for (let i=0; i < 34 * 1024; i++){
data += input;
}
context.encrypt(data,
inputvalues.encrypt.good.fingerprint).then(
function (answer) {
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include(
'BEGIN PGP MESSAGE');
expect(answer.data).to.include(
'END PGP MESSAGE');
context.decrypt(answer.data).then(
function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(data);
context.connection.disconnect();
done();
});
});
});
- }).timeout(5000);
+ }).timeout(3000);
};
- it('Decrypt simple non-ascii', function (done) {
+ it('Random data, as string', function (done) {
+ let data = bigString(1000);
let prm = Gpgmejs.init();
prm.then(function (context) {
- data = encryptedData;
- context.decrypt(data).then(
- function (result) {
- expect(result).to.not.be.empty;
- expect(result.data).to.be.a('string');
- expect(result.data).to.equal(
- '¡Äußerste µ€ før ñoquis@hóme! Добрый день\n');
- done();
- });
+ context.encrypt(data,
+ inputvalues.encrypt.good.fingerprint).then(
+ function (answer) {
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a("string");
+ expect(answer.data).to.include(
+ 'BEGIN PGP MESSAGE');
+ expect(answer.data).to.include(
+ 'END PGP MESSAGE');
+ context.decrypt(answer.data).then(
+ function (result) {
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(result.data).to.equal(data);
+ context.connection.disconnect();
+ done();
+ });
+ });
});
}).timeout(3000);
+
+ it('Data, input as base64', function (done) {
+ let data = inputvalues.encrypt.good.data;
+ let b64data = btoa(data);
+ let prm = Gpgmejs.init();
+ prm.then(function (context) {
+ context.encrypt(b64data,
+ inputvalues.encrypt.good.fingerprint,).then(
+ function (answer) {
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a("string");
+ expect(answer.data).to.include(
+ 'BEGIN PGP MESSAGE');
+ expect(answer.data).to.include(
+ 'END PGP MESSAGE');
+ context.decrypt(answer.data).then(
+ function (result) {
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(data).to.equal(data);
+ context.connection.disconnect();
+ done();
+ });
+ });
+ });
+ }).timeout(3000);
+
+ it('Random data, input as base64', function (done) {
+ //TODO fails. The result is
+ let data = bigBoringString(0.001);
+ let b64data = btoa(data);
+ let prm = Gpgmejs.init();
+ prm.then(function (context) {
+ context.encrypt(b64data,
+ inputvalues.encrypt.good.fingerprint, true).then(
+ function (answer) {
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a("string");
+ expect(answer.data).to.include(
+ 'BEGIN PGP MESSAGE');
+ expect(answer.data).to.include(
+ 'END PGP MESSAGE');
+ context.decrypt(answer.data).then(
+ function (result) {
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(result.data).to.equal(data);
+ context.connection.disconnect();
+ done();
+ });
+ });
+ });
+ }).timeout(3000);
+
+ it('Random data, input and output as base64', function (done) {
+ let data = bigBoringString(0.0001);
+ let b64data = btoa(data);
+ let prm = Gpgmejs.init();
+ prm.then(function (context) {
+ context.encrypt(b64data,
+ inputvalues.encrypt.good.fingerprint).then(
+ function (answer) {
+ expect(answer).to.not.be.empty;
+ expect(answer.data).to.be.a("string");
+
+ expect(answer.data).to.include(
+ 'BEGIN PGP MESSAGE');
+ expect(answer.data).to.include(
+ 'END PGP MESSAGE');
+ context.decrypt(answer.data, true).then(
+ function (result) {
+ expect(result).to.not.be.empty;
+ expect(result.data).to.be.a('string');
+ expect(result.data).to.equal(b64data);
+ context.connection.disconnect();
+ done();
+ });
+ });
+ });
+ }).timeout(3000);
+
+
});
diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js
index c95bebda..4e55fd26 100644
--- a/lang/js/BrowserTestExtension/tests/longRunningTests.js
+++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js
@@ -1,65 +1,40 @@
describe('Long running Encryption/Decryption', function () {
for (let i=0; i < 100; i++) {
it('Successful encrypt/decrypt completely random data ' + (i+1) + '/100', function (done) {
let prm = Gpgmejs.init();
let data = bigString(2*1024*1024);
prm.then(function (context) {
context.encrypt(data,
inputvalues.encrypt.good.fingerprint).then(
function (answer){
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include(
'BEGIN PGP MESSAGE');
expect(answer.data).to.include(
'END PGP MESSAGE');
context.decrypt(answer.data).then(
function(result){
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
if (result.data.length !== data.length) {
console.log('diff: ' + (result.data.length - data.length));
for (let i=0; i < result.data.length; i++){
if (result.data[i] !== data[i]){
console.log('position: ' + i);
console.log('result : '+ result.data.charCodeAt(i) + result.data[i-2] + result.data[i-1] + result.data[i] + result.data[i+1] + result.data[i+2]);
console.log('original: ' + data.charCodeAt(i) + data[i-2] + data[i-1] + data[i] + data[i+1] + data[i+2]);
break;
}
}
}
expect(result.data).to.equal(data);
context.connection.disconnect();
done();
});
});
});
}).timeout(8000);
};
- it('Successful encrypt 1 MB Uint8Array', function (done) {
- //TODO: this succeeds, but result may be bogus (String with byte values as numbers)
- let prm = Gpgmejs.init();
- let data = bigUint8(1);
- prm.then(function (context) {
- context.encrypt(data,
- inputvalues.encrypt.good.fingerprint).then(
- function (answer){
- expect(answer).to.not.be.empty;
- expect(answer.data).to.be.a("string");
- expect(answer.data).to.include(
- 'BEGIN PGP MESSAGE');
- expect(answer.data).to.include(
- 'END PGP MESSAGE');
- context.decrypt(answer.data).then(
- function(result){
- expect(result).to.not.be.empty;
- expect(result.data).to.be.a('string');
- expect(result.data).to.equal(data);
- done();
- });
- });
- });
- }).timeout(5000);
-
});
diff --git a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js
index 98b6e1d8..cccaf604 100644
--- a/lang/js/BrowserTestExtension/tests/openpgpModeTest.js
+++ b/lang/js/BrowserTestExtension/tests/openpgpModeTest.js
@@ -1,196 +1,169 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*/
describe('Encrypting-Decrypting in openpgp mode, using a Message object', function () {
it('Simple Encrypt-Decrypt', function (done) {
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
prm.then(function (context) {
context.encrypt({
data: openpgp.message.fromText(inputvalues.encrypt.good.data),
publicKeys: inputvalues.encrypt.good.fingerprint}
).then(function (answer) {
expect(answer).to.not.be.empty;
expect(answer).to.be.an("object");
expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
let msg = openpgp.message.fromText(answer.data);
context.decrypt({message:msg}).then(function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(inputvalues.encrypt.good.data);
context._GpgME.connection.disconnect();
done();
});
});
});
});
- it('Encrypt-Decrypt, sending Uint8Array as data', function (done) {
- //TODO! fails. Reason is that atob<->btoa destroys the uint8Array,
- // resulting in a string of constituyent numbers
- // (error already occurs in encryption)
-
- let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
- prm.then(function (context) {
- let input = bigUint8(0.3);
- expect(input).to.be.an.instanceof(Uint8Array);
- context.encrypt({
- data: input,
- publicKeys: inputvalues.encrypt.good.fingerprint}
- ).then(function (answer) {
- expect(answer).to.not.be.empty;
- expect(answer.data).to.be.a("string");
- expect(answer.data).to.include('BEGIN PGP MESSAGE');
- expect(answer.data).to.include('END PGP MESSAGE');
- context.decrypt({message:answer.data}).then(function (result) {
- expect(result).to.not.be.empty;
- expect(result.data).to.be.an.instanceof(Uint8Array);
- expect(result.data).to.equal(input);
- context._GpgME.connection.disconnect();
- done();
- });
- });
- });
- });
it('Keys as Fingerprints', function(done){
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
let input = inputvalues.encrypt.good.data_nonascii;
prm.then(function (context) {
context.encrypt({
data: input,
publicKeys: inputvalues.encrypt.good.fingerprint}
).then(function (answer) {
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
context.decrypt({message:answer.data}).then(function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(input);
context._GpgME.connection.disconnect();
done();
});
});
});
});
it('Keys as openpgp Keys', function(){
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
let data = inputvalues.encrypt.good.data_nonascii;
let key = openpgp.key.readArmored(openpgpInputs.pubKeyArmored);
expect(key).to.be.an('object');
prm.then(function (context) {
context.encrypt({
data: data,
publicKeys: [key]}
).then( function (answer) {
expect(answer).to.not.be.empty;
expect(answer.data).to.be.a("string");
expect(answer.data).to.include('BEGIN PGP MESSAGE');
expect(answer.data).to.include('END PGP MESSAGE');
context.decrypt({message:answer.data}).then( function (result){
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(data);
context._GpgME.connection.disconnect();
done();
});
});
});
});
it('Trying to send non-implemented parameters: passwords', function(done){
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
let data = 'Hello World';
let key = inputvalues.encrypt.good.fingerprint;
prm.then(function (context) {
context.encrypt({
data: data,
publicKeys: [key],
passwords: 'My secret password'}
).then( function(){},
function(error){
expect(error).to.be.an.instanceof(Error);
expect(error.code).equal('NOT_IMPLEMENTED');
done();
});
});
});
it('Trying to send non-implemented parameters: signature', function(done){
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
let data = 'Hello World';
let key = inputvalues.encrypt.good.fingerprint;
prm.then(function (context) {
context.encrypt({
data: data,
publicKeys: [key],
signature: {any: 'value'}
}).then(
function(){},
function(error){
expect(error).to.be.an.instanceof(Error);
expect(error.code).equal('NOT_IMPLEMENTED');
done();
});
});
});
});
describe('Keyring in openpgp mode', function(){
it('Check Existence and structure of Keyring after init', function(done){
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
prm.then(function (context) {
expect(context.Keyring).to.be.an('object');
expect(context.Keyring.getPublicKeys).to.be.a('function');
expect(context.Keyring.deleteKey).to.be.a('function');
expect(context.Keyring.getDefaultKey).to.be.a('function');
done();
});
});
// TODO: gpgme key interface not yet there
});
describe('Decrypting and verification in openpgp mode', function(){
it('Decrypt', function(){
let msg = openpgp.message.fromText(inputvalues.encryptedData);
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
prm.then(function (context) {
context.decrypt({message: msg})
.then(function(answer){
expect(answer.data).to.be.a('string');
expect(result.data).to.equal('¡Äußerste µ€ før ñoquis@hóme! Добрый день\n');
done();
});
});
});
it('Decryption attempt with bad data returns gnupg error', function(done){
let msg = openpgp.message.fromText(bigString(0.1));
let prm = Gpgmejs.init({api_style: 'gpgme_openpgpjs'});
prm.then(function (context) {
context.decrypt({message: msg})
.then( function(){},
function(error){
expect(error).to.be.an.instanceof(Error);
expect(error.code).to.equal('GNUPG_ERROR');
expect(error.message).to.be.a('string');
// TBD: Type of error
done();
});
});
}).timeout(4000);
});
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
index 1931a55b..9c2a6428 100644
--- a/lang/js/src/Connection.js
+++ b/lang/js/src/Connection.js
@@ -1,235 +1,241 @@
/* 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+
*/
/**
* A connection port will be opened for each communication between gpgmejs and
* gnupg. It should be alive as long as there are additional messages to be
* expected.
*/
import { permittedOperations } from './permittedOperations'
import { gpgme_error } from "./Errors"
import { GPGME_Message } from "./Message";
/**
* A Connection handles the nativeMessaging interaction.
*/
export class Connection{
constructor(){
this.connect();
let me = this;
}
/**
* (Simple) Connection check.
* @returns {Boolean} true if the onDisconnect event has not been fired.
* Please note that the event listener of the port takes some time
* (5 ms seems enough) to react after the port is created. Then this will
* return undefined
*/
get isConnected(){
return this._isConnected;
}
/**
* Immediately closes the open port.
*/
disconnect() {
if (this._connection){
this._connection.disconnect();
}
}
/**
* Opens a nativeMessaging port.
*/
connect(){
if (this._isConnected === true){
gpgme_error('CONN_ALREADY_CONNECTED');
} else {
this._isConnected = true;
this._connection = chrome.runtime.connectNative('gpgmejson');
let me = this;
this._connection.onDisconnect.addListener(
function(){
me._isConnected = false;
}
);
}
}
/**
* Sends a message and resolves with the answer.
* @param {GPGME_Message} message
* @returns {Promise