diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
index a84be27c..bd72c1d2 100644
--- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
+++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js
@@ -1,226 +1,199 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
/* global describe, it, expect, Gpgmejs */
/* global inputvalues, encryptedData, bigString, bigBoringString */
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);
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);
done();
});
});
});
}).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);
done();
});
});
});
}).timeout(3000);
}
it('Random data, as string', function (done) {
let data = bigString(1000);
let prm = Gpgmejs.init();
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(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(
+ 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(data).to.equal(data);
done();
});
});
});
}).timeout(3000);
it('Random data, input as base64', function (done) {
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, true).then(
- function (result) {
- expect(result).to.not.be.empty;
- expect(result.data).to.be.a('string');
- expect(result.data).to.equal(b64data);
- done();
- });
- });
- });
- }).timeout(3000);
-
- 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(
+ context.decrypt(answer.data).then(
function (result) {
expect(result).to.not.be.empty;
expect(result.data).to.be.a('string');
expect(result.data).to.equal(b64data);
done();
});
});
});
}).timeout(3000);
-
});
diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js
index eefe126d..e148d1cf 100644
--- a/lang/js/BrowserTestExtension/tests/longRunningTests.js
+++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js
@@ -1,78 +1,80 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
/* global describe, it, expect, Gpgmejs */
/* global bigString, inputvalues */
describe('Long running Encryption/Decryption', function () {
- for (let i=0; i < 100; i++) {
+ for (let i=0; i < 101; 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));
+ 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]);
+ 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);
done();
});
});
});
}).timeout(8000);
}
});
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
index e9c0b213..f399b22b 100644
--- a/lang/js/src/Connection.js
+++ b/lang/js/src/Connection.js
@@ -1,270 +1,251 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
/* global chrome */
import { permittedOperations } from './permittedOperations';
import { gpgme_error } from './Errors';
import { GPGME_Message, createMessage } from './Message';
/**
* A Connection handles the nativeMessaging interaction.
*/
export class Connection{
constructor(){
this.connect();
}
/**
* Retrieves the information about the backend.
* @param {Boolean} details (optional) If set to false, the promise will
* just return a connection status
* @returns {Promise}
* {String} The property 'gpgme': Version number of gpgme
* {Array} 'info' Further information about the backends.
* Example:
* "protocol": "OpenPGP",
* "fname": "/usr/bin/gpg",
* "version": "2.2.6",
* "req_version": "1.4.0",
* "homedir": "default"
*/
checkConnection(details = true){
if (details === true) {
return this.post(createMessage('version'));
} else {
let me = this;
return new Promise(function(resolve) {
Promise.race([
me.post(createMessage('version')),
new Promise(function(resolve, reject){
setTimeout(function(){
reject(gpgme_error('CONN_TIMEOUT'));
}, 500);
})
]).then(function(){ // success
resolve(true);
}, function(){ // failure
resolve(false);
});
});
}
}
/**
* Immediately closes the open port.
*/
disconnect() {
if (this._connection){
this._connection.disconnect();
this._connection = null;
}
}
/**
* Opens a nativeMessaging port.
*/
connect(){
if (!this._connection){
this._connection = chrome.runtime.connectNative('gpgmejson');
}
}
/**
* Sends a message and resolves with the answer.
* @param {GPGME_Message} message
* @returns {Promise} the gnupg answer, or rejection with error
* information.
*/
post(message){
if (!message || !(message instanceof GPGME_Message)){
this.disconnect();
return Promise.reject(gpgme_error(
'PARAM_WRONG', 'Connection.post'));
}
if (message.isComplete !== true){
this.disconnect();
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
}
let me = this;
+ let chunksize = message.chunksize;
return new Promise(function(resolve, reject){
let answer = new Answer(message);
let listener = function(msg) {
if (!msg){
me._connection.onMessage.removeListener(listener);
me._connection.disconnect();
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
- } else if (msg.type === 'error'){
- me._connection.onMessage.removeListener(listener);
- me._connection.disconnect();
- reject(gpgme_error('GNUPG_ERROR', msg.msg));
} else {
- let answer_result = answer.add(msg);
+ let answer_result = answer.collect(msg);
if (answer_result !== true){
me._connection.onMessage.removeListener(listener);
me._connection.disconnect();
reject(answer_result);
- } else if (msg.more === true){
- me._connection.postMessage({'op': 'getmore'});
} else {
- me._connection.onMessage.removeListener(listener);
- me._connection.disconnect();
- resolve(answer.message);
+ if (msg.more === true){
+ me._connection.postMessage({
+ 'op': 'getmore',
+ 'chunksize': chunksize
+ });
+ } else {
+ me._connection.onMessage.removeListener(listener);
+ me._connection.disconnect();
+ if (answer.message instanceof Error){
+ reject(answer.message);
+ } else {
+ resolve(answer.message);
+ }
+ }
}
}
};
me._connection.onMessage.addListener(listener);
if (permittedOperations[message.operation].pinentry){
return me._connection.postMessage(message.message);
} else {
return Promise.race([
me._connection.postMessage(message.message),
function(resolve, reject){
setTimeout(function(){
me._connection.disconnect();
reject(gpgme_error('CONN_TIMEOUT'));
}, 5000);
}]).then(function(result){
return result;
}, function(reject){
if(!(reject instanceof Error)) {
me._connection.disconnect();
return gpgme_error('GNUPG_ERROR', reject);
} else {
return reject;
}
});
}
});
}
}
/**
* A class for answer objects, checking and processing the return messages of
* the nativeMessaging communication.
* @param {String} operation The operation, to look up validity of returning
* messages
*/
class Answer{
constructor(message){
this.operation = message.operation;
- this.expected = message.expected;
+ this.expect = message.expect;
}
- /**
- * Add the information to the answer
- * @param {Object} msg The message as received with nativeMessaging
- * returns true if successfull, gpgme_error otherwise
- */
- add(msg){
- if (this._response === undefined){
- this._response = {};
+ collect(msg){
+ if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
+ return gpgme_error('CONN_UNEXPECTED_ANSWER');
+ }
+ if (this._responseb64 === undefined){
+ //this._responseb64 = [msg.response];
+ this._responseb64 = msg.response;
+ return true;
+ } else {
+ //this._responseb64.push(msg.response);
+ this._responseb64 += msg.response;
+ return true;
}
- let messageKeys = Object.keys(msg);
+ }
+
+ get message(){
+ if (this._responseb64 === undefined){
+ return gpgme_error('CONN_UNEXPECTED_ANSWER');
+ }
+ // let _decodedResponse = JSON.parse(atob(this._responseb64.join('')));
+ let _decodedResponse = JSON.parse(atob(this._responseb64));
+ let _response = {};
+ let messageKeys = Object.keys(_decodedResponse);
let poa = permittedOperations[this.operation].answer;
if (messageKeys.length === 0){
return gpgme_error('CONN_UNEXPECTED_ANSWER');
}
for (let i= 0; i < messageKeys.length; i++){
let key = messageKeys[i];
switch (key) {
case 'type':
- if ( msg.type !== 'error' && poa.type.indexOf(msg.type) < 0){
+ if (_decodedResponse.type === 'error'){
+ return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg));
+ } else if (poa.type.indexOf(_decodedResponse.type) < 0){
return gpgme_error('CONN_UNEXPECTED_ANSWER');
}
break;
- case 'more':
+ case 'base64':
break;
- default:
- //data should be concatenated
- if (poa.data.indexOf(key) >= 0){
- if (!this._response.hasOwnProperty(key)){
- this._response[key] = '';
- }
- this._response[key] += msg[key];
- }
- //params should not change through the message
- else if (poa.params.indexOf(key) >= 0){
- if (!this._response.hasOwnProperty(key)){
- this._response[key] = msg[key];
- }
- else if (this._response[key] !== msg[key]){
- return gpgme_error('CONN_UNEXPECTED_ANSWER',msg[key]);
- }
+ case 'msg':
+ if (_decodedResponse.type === 'error'){
+ return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg));
}
- //infos may be json objects etc. Not yet defined.
- // Pushing them into arrays for now
- else if (poa.infos.indexOf(key) >= 0){
- if (!this._response.hasOwnProperty(key)){
- this._response[key] = [];
- }
-
- if (Array.isArray(msg[key])) {
- for (let i=0; i< msg[key].length; i++) {
- this._response[key].push(msg[key][i]);
- }
- } else {
- this._response[key].push(msg[key]);
- }
+ break;
+ default:
+ if (!poa.data.hasOwnProperty(key)){
+ return gpgme_error('CONN_UNEXPECTED_ANSWER');
}
- else {
+ if( typeof(_decodedResponse[key]) !== poa.data[key] ){
return gpgme_error('CONN_UNEXPECTED_ANSWER');
}
- break;
- }
- }
- return true;
- }
-
- /**
- * @returns {Object} the assembled message, original data assumed to be
- * (javascript-) strings
- */
- get message(){
- let keys = Object.keys(this._response);
- let msg = {};
- let poa = permittedOperations[this.operation].answer;
- for (let i=0; i < keys.length; i++) {
- if (poa.data.indexOf(keys[i]) >= 0
- && this._response.base64 === true
- ) {
- msg[keys[i]] = atob(this._response[keys[i]]);
- if (this.expected === 'base64'){
- msg[keys[i]] = this._response[keys[i]];
- } else {
- msg[keys[i]] = decodeURIComponent(
- atob(this._response[keys[i]]).split('').map(
+ if (_decodedResponse.base64 === true
+ && poa.data[key] === 'string'
+ && this.expect === undefined
+ ){
+ _response[key] = decodeURIComponent(
+ atob(_decodedResponse[key]).split('').map(
function(c) {
return '%' +
- ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+ ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
+ } else {
+ _response[key] = _decodedResponse[key];
}
- } else {
- msg[keys[i]] = this._response[keys[i]];
+ break;
}
}
- return msg;
+ return _response;
}
}
diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js
index 0ddda6c4..7ccf7efc 100644
--- a/lang/js/src/Message.js
+++ b/lang/js/src/Message.js
@@ -1,215 +1,244 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
import { permittedOperations } from './permittedOperations';
import { gpgme_error } from './Errors';
import { Connection } from './Connection';
export function createMessage(operation){
if (typeof(operation) !== 'string'){
return gpgme_error('PARAM_WRONG');
}
if (permittedOperations.hasOwnProperty(operation)){
return new GPGME_Message(operation);
} else {
return gpgme_error('MSG_WRONG_OP');
}
}
/**
* Prepares a communication request. It checks operations and parameters in
* ./permittedOperations.
* @param {String} operation
*/
export class GPGME_Message {
//TODO getter
constructor(operation){
this.operation = operation;
- this._expected = 'string';
}
set operation (op){
if (typeof(op) === 'string'){
if (!this._msg){
this._msg = {};
}
if (!this._msg.op & permittedOperations.hasOwnProperty(op)){
this._msg.op = op;
}
}
}
-
get operation(){
return this._msg.op;
}
- set expected(string){
- if (string === 'base64'){
- this._expected = 'base64';
+ /**
+ * Set the maximum size of responses from gpgme in bytes. Values allowed
+ * range from 10kB to 1MB. The lower limit is arbitrary, the upper limit
+ * fixed by browsers' nativeMessaging specifications
+ */
+ set chunksize(value){
+ if (
+ Number.isInteger(value) &&
+ value > 10 * 1024 &&
+ value <= 1024 * 1024
+ ){
+ this._chunksize = value;
+ }
+ }
+ get chunksize(){
+ if (this._chunksize === undefined){
+ return 1024 * 1023;
+ } else {
+ return this._chunksize;
}
}
- get expected() {
- if (this._expected === 'base64'){
- return this._expected;
+ /**
+ * If expect is set to 'base64', the response is expected to be base64
+ * encoded binary
+ */
+ set expect(value){
+ if (value ==='base64'){
+ this._expect = value;
+ }
+ }
+
+ get expect(){
+ if ( this._expect === 'base64'){
+ return this._expect;
}
- return 'string';
+ return undefined;
}
+
/**
* Sets a parameter for the message. Note that the operation has to be set
* first, to be able to check if the parameter is permittted
* @param {String} param Parameter to set
* @param {any} value Value to set //TODO: Some type checking
* @returns {Boolean} If the parameter was set successfully
*/
setParameter(param,value){
if (!param || typeof(param) !== 'string'){
return gpgme_error('PARAM_WRONG');
}
let po = permittedOperations[this._msg.op];
if (!po){
return gpgme_error('MSG_WRONG_OP');
}
let poparam = null;
if (po.required.hasOwnProperty(param)){
poparam = po.required[param];
} else if (po.optional.hasOwnProperty(param)){
poparam = po.optional[param];
} else {
return gpgme_error('PARAM_WRONG');
}
let checktype = function(val){
switch(typeof(val)){
case 'string':
if (poparam.allowed.indexOf(typeof(val)) >= 0
&& val.length > 0) {
return true;
}
return gpgme_error('PARAM_WRONG');
case 'number':
if (
poparam.allowed.indexOf('number') >= 0
&& isNaN(value) === false){
return true;
}
return gpgme_error('PARAM_WRONG');
case 'boolean':
if (poparam.allowed.indexOf('boolean') >= 0){
return true;
}
return gpgme_error('PARAM_WRONG');
case 'object':
if (Array.isArray(val)){
if (poparam.array_allowed !== true){
return gpgme_error('PARAM_WRONG');
}
for (let i=0; i < val.length; i++){
let res = checktype(val[i]);
if (res !== true){
return res;
}
}
if (val.length > 0) {
return true;
}
} else if (val instanceof Uint8Array){
if (poparam.allowed.indexOf('Uint8Array') >= 0){
return true;
}
return gpgme_error('PARAM_WRONG');
} else {
return gpgme_error('PARAM_WRONG');
}
break;
default:
return gpgme_error('PARAM_WRONG');
}
};
let typechecked = checktype(value);
if (typechecked !== true){
return typechecked;
}
if (poparam.hasOwnProperty('allowed_data')){
if (poparam.allowed_data.indexOf(value) < 0){
return gpgme_error('PARAM_WRONG');
}
}
this._msg[param] = value;
return true;
}
/**
* Check if the message has the minimum requirements to be sent, according
* to the definitions in permittedOperations
* @returns {Boolean}
*/
get isComplete(){
if (!this._msg.op){
return false;
}
let reqParams = Object.keys(
permittedOperations[this._msg.op].required);
let msg_params = Object.keys(this._msg);
for (let i=0; i < reqParams.length; i++){
if (msg_params.indexOf(reqParams[i]) < 0){
return false;
}
}
return true;
}
/**
* Returns the prepared message with parameters and completeness checked
* @returns {Object|null} Object to be posted to gnupg, or null if
* incomplete
*/
get message(){
if (this.isComplete === true){
+ this._msg.chunksize = this.chunksize;
return this._msg;
}
else {
return null;
}
}
post(){
let me = this;
return new Promise(function(resolve, reject) {
if (me.isComplete === true) {
let conn = new Connection;
+ if (me._msg.chunksize === undefined){
+ me._msg.chunksize = 1023*1024;
+ }
conn.post(me).then(function(response) {
resolve(response);
}, function(reason) {
- reject(gpgme_error('GNUPG_ERROR', reason));
+ reject(reason);
});
}
else {
reject(gpgme_error('MSG_INCOMPLETE'));
}
});
}
}
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index cbad9021..09bca7f9 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -1,217 +1,213 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
import {GPGME_Message, createMessage} from './Message';
import {toKeyIdArray} from './Helpers';
import { gpgme_error } from './Errors';
import { GPGME_Keyring } from './Keyring';
export class GpgME {
/**
* initializes GpgME by opening a nativeMessaging port
* TODO: add configuration
*/
constructor(config){ //TODO config not parsed
this._config = config;
}
set Keyring(keyring){
if (keyring && keyring instanceof GPGME_Keyring){
this._Keyring = keyring;
}
}
get Keyring(){
if (!this._Keyring){
this._Keyring = new GPGME_Keyring;
}
return this._Keyring;
}
/**
* Encrypt (and optionally sign) a Message
* @param {String|Object} data text/data to be encrypted as String. Also
* accepts Objects with a getText method
* @param {GPGME_Key|String|Array|Array} publicKeys
* Keys used to encrypt the message
* @param {GPGME_Key|String|Array|Array} secretKeys
* (optional) Keys used to sign the message
- * @param {Boolean} base64 (optional) The data is already considered to be
- * in base64 encoding
+ * @param {Boolean} base64 (optional) The data will be interpreted as
+ * base64 encoded data
* @param {Boolean} armor (optional) Request the output as armored block
* @param {Boolean} wildcard (optional) If true, recipient information will
* not be added to the message
* @param {Object} additional use additional gpg options
* (refer to src/permittedOperations)
* @returns {Promise} Encrypted message:
* data: The encrypted message
* base64: Boolean indicating whether data is base64 encoded.
* @async
*/
encrypt(data, publicKeys, secretKeys, base64=false, armor=true,
wildcard=false, additional = {}
){
let msg = createMessage('encrypt');
if (msg instanceof Error){
return Promise.reject(msg);
}
msg.setParameter('armor', armor);
msg.setParameter('always-trust', true);
if (base64 === true) {
msg.setParameter('base64', true);
}
let pubkeys = toKeyIdArray(publicKeys);
msg.setParameter('keys', pubkeys);
let sigkeys = toKeyIdArray(secretKeys);
if (sigkeys.length > 0) {
msg.setParameter('signing_keys', sigkeys);
}
putData(msg, data);
if (wildcard === true){
msg.setParameter('throw-keyids', true);
}
if (additional){
let additional_Keys = Object.keys(additional);
for (let k = 0; k < additional_Keys.length; k++) {
msg.setParameter(additional_Keys[k],
additional[additional_Keys[k]]);
}
}
if (msg.isComplete === true){
return msg.post();
} else {
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
}
}
/**
* Decrypt a Message
* @param {String|Object} data text/data to be decrypted. Accepts Strings
* and Objects with a getText method
- * @param {Boolean} base64 (optional) Response is expected to be base64
- * encoded
* @returns {Promise} decrypted message:
- data: The decrypted data. This may be base64 encoded.
+ data: The decrypted data.
base64: Boolean indicating whether data is base64 encoded.
mime: A Boolean indicating whether the data is a MIME object.
signatures: Array of signature Objects TODO not yet implemented.
- // should be an object that can tell if all signatures are valid .
+ // should be an object that can tell if all signatures are valid.
* @async
*/
- decrypt(data, base64=false){
+ decrypt(data){
if (data === undefined){
return Promise.reject(gpgme_error('MSG_EMPTY'));
}
let msg = createMessage('decrypt');
- if (base64 === true){
- msg.expected = 'base64';
- }
+
if (msg instanceof Error){
return Promise.reject(msg);
}
putData(msg, data);
return msg.post();
}
/**
* Sign a Message
* @param {String|Object} data text/data to be decrypted. Accepts Strings
* and Objects with a gettext methos
* @param {GPGME_Key|String|Array|Array} keys The
* key/keys to use for signing
* @param {*} mode The signing mode. Currently supported:
* 'clearsign': (default) The Message is embedded into the signature
* 'detached': The signature is stored separately
* @param {*} base64 input is considered base64
* @returns {Promise}
* data: The resulting data. Includes the signature in clearsign mode
* signature: The detached signature (if in detached mode)
* @async
*/
sign(data, keys, mode='clearsign', base64=false) {
if (data === undefined){
return Promise.reject(gpgme_error('MSG_EMPTY'));
}
let key_arr = toKeyIdArray(keys);
if (key_arr.length === 0){
return Promise.reject(gpgme_error('MSG_NO_KEYS'));
}
let msg = createMessage('sign');
msg.setParameter('keys', key_arr);
if (base64 === true){
msg.setParameter('base64', true);
}
msg.setParameter('mode', mode);
putData(msg, data);
- if (mode === 'detached') {
- msg.expected = 'base64';
- }
return new Promise(function(resolve,reject) {
+ if (mode ==='detached'){
+ msg.expect= 'base64';
+ }
msg.post().then( function(message) {
if (mode === 'clearsign'){
resolve({
data: message.data}
);
} else if (mode === 'detached') {
resolve({
data: data,
signature: message.data
});
}
}, function(error){
reject(error);
});
});
}
}
/**
* Sets the data of the message, setting flags according on the data type
* @param {GPGME_Message} message The message where this data will be set
* @param {*} data The data to enter
*/
function putData(message, data){
if (!message || !(message instanceof GPGME_Message) ) {
return gpgme_error('PARAM_WRONG');
}
if (!data){
return gpgme_error('PARAM_WRONG');
} else if (typeof(data) === 'string') {
message.setParameter('data', data);
} else if (
typeof(data) === 'object' &&
typeof(data.getText) === 'function'
){
let txt = data.getText();
if (typeof(txt) === 'string'){
message.setParameter('data', txt);
} else {
return gpgme_error('PARAM_WRONG');
}
} else {
return gpgme_error('PARAM_WRONG');
}
}
diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js
index 445a40cc..6ac33af9 100644
--- a/lang/js/src/permittedOperations.js
+++ b/lang/js/src/permittedOperations.js
@@ -1,331 +1,322 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*
* Author(s):
* Maximilian Krambach
*/
/**
* Definition of the possible interactions with gpgme-json.
* operation:
required: Array
name The name of the property
allowed: Array of allowed types. Currently accepted values:
['number', 'string', 'boolean', 'Uint8Array']
array_allowed: Boolean. If the value can be an array of the above
allowed_data: If present, restricts to the given value
optional: Array
see 'required', with these parameters not being mandatory for a
complete message
pinentry: boolean If a pinentry dialog is expected, and a timeout of
5000 ms would be too short
answer:
type: The payload property of the answer. May be
- partial and in need of concatenation
- params: Array Information that do not change throughout
- the message
- infos: Array<*> arbitrary information that may result in a list
+ data:
+ the properties expected and their type, eg: {'data':'string'}
}
}
*/
export const permittedOperations = {
encrypt: {
pinentry: true, //TODO only with signing_keys
required: {
'keys': {
allowed: ['string'],
array_allowed: true
},
'data': {
allowed: ['string']
}
},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
'signing_keys': {
allowed: ['string'],
array_allowed: true
},
- 'chunksize': {
- allowed: ['number']
- },
'base64': {
allowed: ['boolean']
},
'mime': {
allowed: ['boolean']
},
'armor': {
allowed: ['boolean']
},
'always-trust': {
allowed: ['boolean']
},
'no-encrypt-to': {
allowed: ['string'],
array_allowed: true
},
'no-compress': {
allowed: ['boolean']
},
'throw-keyids': {
allowed: ['boolean']
},
'want-address': {
allowed: ['boolean']
},
'wrap': {
allowed: ['boolean']
}
},
answer: {
type: ['ciphertext'],
- data: ['data'],
- params: ['base64'],
- infos: []
+ data: {
+ 'data': 'string',
+ 'base64':'boolean'
+ }
}
},
decrypt: {
pinentry: true,
required: {
'data': {
allowed: ['string']
}
},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
- 'chunksize': {
- allowed: ['number'],
- },
'base64': {
allowed: ['boolean']
}
},
answer: {
type: ['plaintext'],
- data: ['data'],
- params: ['base64', 'mime'],
- infos: ['signatures']
+ data: {
+ 'data': 'string',
+ 'base64': 'boolean',
+ 'mime': 'boolean',
+ 'signatures': 'object'
+ }
}
},
sign: {
pinentry: true,
required: {
'data': {
allowed: ['string']},
'keys': {
allowed: ['string'],
array_allowed: true
}
},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
- 'chunksize': {
- allowed: ['number'],
- },
'sender': {
allowed: ['string'],
},
'mode': {
allowed: ['string'],
allowed_data: ['detached', 'clearsign']
// TODO 'opaque' is not used, but available on native app
},
'base64': {
allowed: ['boolean']
},
'armor': {
allowed: ['boolean']
},
},
answer: {
type: ['signature', 'ciphertext'],
- data: ['data'], // Unless armor mode is used a Base64 encoded binary
- // signature. In armor mode a string with an armored
- // OpenPGP or a PEM message.
- params: ['base64']
+ data: {
+ 'data': 'string',
+ 'base64':'boolean'
+ }
+
}
},
// note: For the meaning of the optional keylist flags, refer to
// https://www.gnupg.org/documentation/manuals/gpgme/Key-Listing-Mode.html
keylist:{
required: {},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
- 'chunksize': {
- allowed: ['number'],
- },
'secret': {
allowed: ['boolean']
},
'extern': {
allowed: ['boolean']
},
'local':{
allowed: ['boolean']
},
'sigs':{
allowed: ['boolean']
},
'notations':{
allowed: ['boolean']
},
'tofu': {
allowed: ['boolean']
},
'ephemeral': {
allowed: ['boolean']
},
'validate': {
allowed: ['boolean']
},
'keys': {
allowed: ['string'],
array_allowed: true
}
},
answer: {
type: ['keys'],
- data: [],
- params: ['base64'],
- infos: ['keys']
+ data: {
+ 'base64': 'boolean',
+ 'keys': 'object'
+ }
}
},
export: {
required: {},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
- 'chunksize': {
- allowed: ['number'],
- },
'keys': {
allowed: ['string'],
array_allowed: true
},
'armor': {
allowed: ['boolean']
},
'extern': {
allowed: ['boolean']
},
'minimal': {
allowed: ['boolean']
},
'raw': {
allowed: ['boolean']
},
'pkcs12':{
allowed: ['boolean']
}
// secret: not yet implemented
},
answer: {
type: ['keys'],
- data: ['data'],
- params: ['base64']
+ data: {
+ 'data': 'string',
+ 'base64': 'boolean'
+ }
}
},
import: {
required: {
'data': {
allowed: ['string']
}
},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
'base64': {
allowed: ['boolean']
},
},
answer: {
- infos: ['result'],
type: [],
- data: [],
- params: []
+ data: {
+ 'result': 'Object'
+ }
}
},
delete: {
pinentry: true,
required:{
'key': {
allowed: ['string']
}
},
optional: {
'protocol': {
allowed: ['string'],
allowed_data: ['cms', 'openpgp']
},
- // 'secret': { not yet implemented
+ // 'secret': { not implemented
// allowed: ['boolean']
// }
},
answer: {
- data: [],
- params:['success'],
- infos: []
+ data: {
+ 'success': 'boolean'
+ }
}
},
version: {
required: {},
optional: {},
answer: {
type: [''],
- data: ['gpgme'],
- infos: ['info'],
- params:[]
+ data: {
+ 'gpgme': 'string',
+ 'info': 'object'
+ }
}
}
/**
* TBD handling of secrets
* TBD key modification?
* TBD: key generation
*/
};
diff --git a/lang/js/unittests.js b/lang/js/unittests.js
index ce1dd0c3..169e8ebc 100644
--- a/lang/js/unittests.js
+++ b/lang/js/unittests.js
@@ -1,390 +1,391 @@
/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*/
import './node_modules/mocha/mocha'; /*global mocha, it, describe*/
import './node_modules/chai/chai';/*global chai*/
import { helper_params as hp } from './unittest_inputvalues';
import { message_params as mp } from './unittest_inputvalues';
import { whatever_params as wp } from './unittest_inputvalues';
import { key_params as kp } from './unittest_inputvalues';
import { Connection } from './src/Connection';
import { gpgme_error } from './src/Errors';
import { toKeyIdArray , isFingerprint } from './src/Helpers';
import { GPGME_Key , createKey } from './src/Key';
import { GPGME_Keyring } from './src/Keyring';
import {GPGME_Message, createMessage} from './src/Message';
mocha.setup('bdd');
const expect = chai.expect;
chai.config.includeStack = true;
function unittests (){
describe('Connection testing', function(){
it('Connecting', function(done) {
let conn0 = new Connection;
conn0.checkConnection().then(function(answer) {
expect(answer).to.not.be.empty;
expect(answer.gpgme).to.not.be.undefined;
expect(answer.gpgme).to.be.a('string');
expect(answer.info).to.be.an('Array');
expect(conn0.disconnect).to.be.a('function');
expect(conn0.post).to.be.a('function');
done();
});
});
it('Disconnecting', function(done) {
let conn0 = new Connection;
conn0.checkConnection(false).then(function(answer) {
expect(answer).to.be.true;
conn0.disconnect();
conn0.checkConnection(false).then(function(result) {
expect(result).to.be.false;
done();
});
});
});
});
describe('Error Object handling', function(){
// TODO: new GPGME_Error codes
it('check the Timeout error', function(){
let test0 = gpgme_error('CONN_TIMEOUT');
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('CONN_TIMEOUT');
});
it('Error Object returns generic code if code is not listed',
function(){
let test0 = gpgme_error(hp.invalidErrorCode);
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('GENERIC_ERROR');
}
);
it('Warnings like PARAM_IGNORED should not return errors', function(){
let test0 = gpgme_error('PARAM_IGNORED');
expect(test0).to.be.null;
});
});
describe('Fingerprint checking', function(){
it('isFingerprint(): valid Fingerprint', function(){
let test0 = isFingerprint(hp.validFingerprint);
expect(test0).to.be.true;
});
it('isFingerprint(): invalid Fingerprints', function(){
for (let i=0; i < hp.invalidFingerprints.length; i++){
let test0 = isFingerprint(hp.invalidFingerprints[i]);
expect(test0).to.be.false;
}
});
});
describe('toKeyIdArray() (converting input to fingerprint)', function(){
it('Correct fingerprint string', function(){
let test0 = toKeyIdArray(hp.validFingerprint);
expect(test0).to.be.an('array');
expect(test0).to.include(hp.validFingerprint);
});
it('correct GPGME_Key', function(){
expect(hp.validGPGME_Key).to.be.an.instanceof(GPGME_Key);
let test0 = toKeyIdArray(hp.validGPGME_Key);
expect(test0).to.be.an('array');
expect(test0).to.include(hp.validGPGME_Key.fingerprint);
});
it('openpgpjs-like object', function(){
let test0 = toKeyIdArray(hp.valid_openpgplike);
expect(test0).to.be.an('array').with.lengthOf(1);
expect(test0).to.include(
hp.valid_openpgplike.primaryKey.getFingerprint());
});
it('Array of valid inputs', function(){
let test0 = toKeyIdArray(hp.validKeys);
expect(test0).to.be.an('array');
expect(test0).to.have.lengthOf(hp.validKeys.length);
});
it('Incorrect inputs', function(){
it('valid Long ID', function(){
let test0 = toKeyIdArray(hp.validLongId);
expect(test0).to.be.empty;
});
it('invalidFingerprint', function(){
let test0 = toKeyIdArray(hp.invalidFingerprint);
expect(test0).to.be.empty;
});
it('invalidKeyArray', function(){
let test0 = toKeyIdArray(hp.invalidKeyArray);
expect(test0).to.be.empty;
});
it('Partially invalid array', function(){
let test0 = toKeyIdArray(hp.invalidKeyArray_OneBad);
expect(test0).to.be.an('array');
expect(test0).to.have.lengthOf(
hp.invalidKeyArray_OneBad.length - 1);
});
});
});
describe('GPGME_Key', function(){
it('correct Key initialization', function(){
let key = createKey(kp.validKeyFingerprint);
expect(key).to.be.an.instanceof(GPGME_Key);
});
it('Key has data after a first refresh', function(done) {
let key = createKey(kp.validKeyFingerprint);
key.refreshKey().then(function(key2){
expect(key2).to.be.an.instanceof(GPGME_Key);
expect(key2.get).to.be.a('function');
for (let i=0; i < kp.validKeyProperties.length; i++) {
let prop = key2.get(kp.validKeyProperties[i]);
expect(prop).to.not.be.undefined;
expect(prop).to.be.a('boolean');
}
expect(isFingerprint(key2.get('fingerprint'))).to.be.true;
expect(
key2.get('fingerprint')).to.equal(kp.validKeyFingerprint);
expect(
key2.get('fingerprint')).to.equal(key.fingerprint);
done();
});
});
it('Non-cached key async data retrieval', function (done){
let key = createKey(kp.validKeyFingerprint);
key.get('can_authenticate',false).then(function(result){
expect(result).to.be.a('boolean');
done();
});
});
it('Non-cached key async armored Key', function (done){
let key = createKey(kp.validKeyFingerprint);
key.get('armored', false).then(function(result){
expect(result).to.be.a('string');
expect(result).to.include('KEY BLOCK-----');
done();
});
});
it('Non-cached key async hasSecret', function (done){
let key = createKey(kp.validKeyFingerprint);
key.get('hasSecret', false).then(function(result){
expect(result).to.be.a('boolean');
done();
});
});
it('Non-cached key async hasSecret (no secret in Key)', function (done){
let key = createKey(kp.validFingerprintNoSecret);
expect(key).to.be.an.instanceof(GPGME_Key);
key.get('hasSecret', false).then(function(result){
expect(result).to.be.a('boolean');
expect(result).to.equal(false);
done();
});
});
it('Querying non-existing Key returns an error', function(done) {
let key = createKey(kp.invalidKeyFingerprint);
key.refreshKey().then(function(){},
function(error){
expect(error).to.be.an.instanceof(Error);
expect(error.code).to.equal('KEY_NOKEY');
done();
});
});
it('createKey returns error if parameters are wrong', function(){
for (let i=0; i< 4; i++){
let key0 = createKey(wp.four_invalid_params[i]);
expect(key0).to.be.an.instanceof(Error);
expect(key0.code).to.equal('PARAM_WRONG');
}
});
it('malformed GPGME_Key cannot be used', function(){
for (let i=0; i < 4; i++){
let key = new GPGME_Key(wp.four_invalid_params[i]);
expect(key.fingerprint).to.be.an.instanceof(Error);
expect(key.fingerprint.code).to.equal('KEY_INVALID');
}
});
// TODO: tests for subkeys
// TODO: tests for userids
// TODO: some invalid tests for key/keyring
});
describe('GPGME_Keyring', function(){
it('correct Keyring initialization', function(){
let keyring = new GPGME_Keyring;
expect(keyring).to.be.an.instanceof(GPGME_Keyring);
expect(keyring.getKeys).to.be.a('function');
});
it('Loading Keys from Keyring, to be used synchronously',
function(done){
let keyring = new GPGME_Keyring;
keyring.getKeys(null, true).then(function(result){
expect(result).to.be.an('array');
expect(result[0]).to.be.an.instanceof(GPGME_Key);
expect(result[0].get('armored')).to.be.a('string');
expect(result[0].get('armored')).to.include(
'-----END PGP PUBLIC KEY BLOCK-----');
done();
});
}
);
it('Loading specific Key from Keyring, to be used synchronously',
function(done){
let keyring = new GPGME_Keyring;
keyring.getKeys(kp.validKeyFingerprint, true).then(
function(result){
expect(result).to.be.an('array');
expect(result[0]).to.be.an.instanceof(GPGME_Key);
expect(result[0].get('armored')).to.be.a('string');
expect(result[0].get('armored')).to.include(
'-----END PGP PUBLIC KEY BLOCK-----');
done();
}
);
}
);
it('Querying non-existing Key from Keyring', function(done){
let keyring = new GPGME_Keyring;
keyring.getKeys(kp.invalidKeyFingerprint, true).then(
function(result){
expect(result).to.be.an('array');
expect(result.length).to.equal(0);
done();
}
);
});
});
describe('GPGME_Message', function(){
it('creating encrypt Message', function(){
let test0 = createMessage('encrypt');
expect(test0).to.be.an.instanceof(GPGME_Message);
expect(test0.isComplete).to.be.false;
});
it('Message is complete after setting mandatory data', function(){
let test0 = createMessage('encrypt');
test0.setParameter('data', mp.valid_encrypt_data);
test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete).to.be.true;
});
it('Message is not complete after mandatory data is empty', function(){
let test0 = createMessage('encrypt');
test0.setParameter('data', '');
test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete).to.be.false;
});
it('Complete Message contains the data that was set', function(){
let test0 = createMessage('encrypt');
test0.setParameter('data', mp.valid_encrypt_data);
test0.setParameter('keys', hp.validFingerprints);
expect(test0.message).to.not.be.null;
- expect(test0.message).to.have.keys('op', 'data', 'keys');
+ expect(test0.message).to.have.keys('op', 'data', 'keys',
+ 'chunksize');
expect(test0.message.op).to.equal('encrypt');
expect(test0.message.data).to.equal(
mp.valid_encrypt_data);
});
it ('Not accepting non-allowed operation', function(){
let test0 = createMessage(mp.invalid_op_action);
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('MSG_WRONG_OP');
});
it('Not accepting wrong parameter type', function(){
let test0 = createMessage(mp.invalid_op_type);
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('PARAM_WRONG');
});
it('Not accepting wrong parameter name', function(){
let test0 = createMessage(mp.invalid_param_test.valid_op);
for (let i=0;
i < mp.invalid_param_test.invalid_param_names.length; i++){
let ret = test0.setParameter(
mp.invalid_param_test.invalid_param_names[i],
'Somevalue');
expect(ret).to.be.an.instanceof(Error);
expect(ret.code).to.equal('PARAM_WRONG');
}
});
it('Not accepting wrong parameter value', function(){
let test0 = createMessage(mp.invalid_param_test.valid_op);
for (let j=0;
j < mp.invalid_param_test.invalid_values_0.length; j++){
let ret = test0.setParameter(
mp.invalid_param_test.validparam_name_0,
mp.invalid_param_test.invalid_values_0[j]);
expect(ret).to.be.an.instanceof(Error);
expect(ret.code).to.equal('PARAM_WRONG');
}
});
});
}
export default {unittests};
\ No newline at end of file