js: First testing and improvements
-- * Introduced Mocha/chai as testsuite. After development build 'npm test' should run the unit tests. Functionality exclusive to Browsers/WebExtensions cannot be run this way, so some other testing is still needed. - package.json: Added required development packages - .babelrc indirect configuration for mocha. ES6 transpiling needs some babel configuration, but mocha has no setting for it. - test/mocha.opts Vonfiguration for mocha runs * Fixed errors: - Helpers.js toKeyIdArray; isLongId is now exported - Key.js Key constructor failed - Message.js will not throw an Error during construction, a new message is now created with createMessage, which can return an Error or a GPGME_Message object * Tests: - test/Helpers: exports from Helpers.js, GPGME_Error handling - test/Message: first init test with bad parameters
This commit is contained in:
parent
1fb310cabe
commit
3685913bf5
1
lang/js/.babelrc
Normal file
1
lang/js/.babelrc
Normal file
@ -0,0 +1 @@
|
||||
{ "presets": ["es2015"] }
|
@ -5,13 +5,15 @@
|
||||
"main": "src/index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "mocha"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "",
|
||||
"devDependencies": {
|
||||
"webpack": "^4.5.0",
|
||||
"webpack-cli": "^2.0.14"
|
||||
"webpack-cli": "^2.0.14",
|
||||
"chai": "^4.1.2",
|
||||
"mocha": "^5.1.1"
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ export class Connection{
|
||||
*/
|
||||
post(message){
|
||||
if (!this.isConnected){
|
||||
return Promise.reject(gpgme_error('CONN_NO_CONNECT'));
|
||||
return Promise.reject(gpgme_error('CONN_DISCONNECTED'));
|
||||
}
|
||||
if (!message || !message instanceof GPGME_Message){
|
||||
return Promise.reject(gpgme_error('PARAM_WRONG'), message);
|
||||
|
@ -55,14 +55,9 @@ const err_list = {
|
||||
msg: 'The Message is empty.',
|
||||
type: 'error'
|
||||
},
|
||||
'MSG_OP_PENDING': {
|
||||
msg: 'There is no operation specified yet. The parameter cannot'
|
||||
+ ' be set',
|
||||
type: 'warning'
|
||||
},
|
||||
'MSG_WRONG_OP': {
|
||||
msg: 'The operation requested could not be found',
|
||||
type: 'warning'
|
||||
type: 'error'
|
||||
},
|
||||
'MSG_NO_KEYS' : {
|
||||
msg: 'There were no valid keys provided.',
|
||||
@ -78,7 +73,7 @@ const err_list = {
|
||||
},
|
||||
// generic
|
||||
'PARAM_WRONG':{
|
||||
msg: 'invalid parameter was found',
|
||||
msg: 'Invalid parameter was found',
|
||||
type: 'error'
|
||||
},
|
||||
'PARAM_IGNORED': {
|
||||
@ -111,7 +106,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
|
||||
return new GPGME_Error(code);
|
||||
}
|
||||
if (err_list[code].type === 'warning'){
|
||||
console.log(new GPGME_Error(code));
|
||||
console.warn(code + ': ' + err_list[code].msg);
|
||||
}
|
||||
return null;
|
||||
} else if (code === 'GNUPG_ERROR'){
|
||||
|
@ -18,6 +18,7 @@
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
import { gpgme_error } from "./Errors";
|
||||
import { GPGME_Key } from "./Key";
|
||||
|
||||
/**
|
||||
* Tries to return an array of fingerprints, either from input fingerprints or
|
||||
@ -26,7 +27,7 @@ import { gpgme_error } from "./Errors";
|
||||
* @returns {Array<String>} Array of fingerprints.
|
||||
*/
|
||||
|
||||
export function toKeyIdArray(input, nocheck){
|
||||
export function toKeyIdArray(input){
|
||||
if (!input){
|
||||
gpgme_error('MSG_NO_KEYS');
|
||||
return [];
|
||||
@ -46,7 +47,7 @@ export function toKeyIdArray(input, nocheck){
|
||||
let fpr = '';
|
||||
if (input[i] instanceof GPGME_Key){
|
||||
fpr = input[i].fingerprint;
|
||||
} else if (input[i].hasOwnProperty(primaryKey) &&
|
||||
} else if (input[i].hasOwnProperty('primaryKey') &&
|
||||
input[i].primaryKey.hasOwnProperty(getFingerprint)){
|
||||
fpr = input[i].primaryKey.getFingerprint();
|
||||
}
|
||||
@ -92,7 +93,7 @@ export function isFingerprint(string){
|
||||
/**
|
||||
* check if the input is a valid Hex string with a length of 16
|
||||
*/
|
||||
function isLongId(string){
|
||||
export function isLongId(string){
|
||||
return hextest(string, 16);
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import {isFingerprint} from './Helpers'
|
||||
import {gpgme_error} from './Errors'
|
||||
import { GPGME_Message } from './Message';
|
||||
import { isFingerprint } from './Helpers'
|
||||
import { gpgme_error } from './Errors'
|
||||
import { createMessage } from './Message';
|
||||
import { permittedOperations } from './permittedOperations';
|
||||
|
||||
export class GPGME_Key {
|
||||
@ -39,7 +39,7 @@ export class GPGME_Key {
|
||||
|
||||
set fingerprint(fpr){
|
||||
if (isFingerprint(fpr) === true && !this._fingerprint){
|
||||
this._fingerprint = fingerprint;
|
||||
this._fingerprint = fpr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,9 +181,12 @@ function checkKey(fingerprint, property){
|
||||
}
|
||||
return new Promise(function(resolve, reject){
|
||||
if (!isFingerprint(fingerprint)){
|
||||
reject('KEY_INVALID');
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
let msg = createMessage ('keyinfo');
|
||||
if (msg instanceof Error){
|
||||
reject(gpgme_error('PARAM_WRONG'));
|
||||
}
|
||||
let msg = new GPGME_Message('keyinfo');
|
||||
msg.setParameter('fingerprint', this.fingerprint);
|
||||
return (this.connection.post(msg)).then(function(result){
|
||||
if (result.hasOwnProperty(property)){
|
||||
|
@ -18,7 +18,7 @@
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
import {GPGME_Message} from './Message'
|
||||
import {createMessage} from './Message'
|
||||
import {GPGME_Key} from './Key'
|
||||
import { isFingerprint, isLongId } from './Helpers';
|
||||
import { gpgme_error } from './Errors';
|
||||
@ -50,7 +50,10 @@ export class GPGME_Keyring {
|
||||
*
|
||||
*/
|
||||
getKeys(pattern, include_secret){
|
||||
let msg = new GPGME_Message('listkeys');
|
||||
let msg = createMessage('listkeys');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
if (pattern && typeof(pattern) === 'string'){
|
||||
msg.setParameter('pattern', pattern);
|
||||
}
|
||||
|
@ -19,13 +19,34 @@
|
||||
*/
|
||||
import { permittedOperations } from './permittedOperations'
|
||||
import { gpgme_error } from './Errors'
|
||||
export class GPGME_Message {
|
||||
|
||||
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
|
||||
*/
|
||||
class GPGME_Message {
|
||||
//TODO getter
|
||||
|
||||
constructor(operation){
|
||||
setOperation(this, operation);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
set operation (op){
|
||||
|
||||
|
||||
}
|
||||
get operation(){
|
||||
return this._msg.op;
|
||||
}
|
||||
@ -41,9 +62,6 @@ export class GPGME_Message {
|
||||
if (!param || typeof(param) !== 'string'){
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (!this._msg || !this._msg.op){
|
||||
return gpgme_error('MSG_OP_PENDING');
|
||||
}
|
||||
let po = permittedOperations[this._msg.op];
|
||||
if (!po){
|
||||
return gpgme_error('MSG_WRONG_OP');
|
||||
@ -90,22 +108,3 @@ export class GPGME_Message {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the operation this message will have
|
||||
* @param {String} operation Must be defined in permittedOperations
|
||||
* TODO: move to constructor?
|
||||
*/
|
||||
function setOperation (scope, operation){
|
||||
if (!operation || typeof(operation) !== 'string'){
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (permittedOperations.hasOwnProperty(operation)){
|
||||
if (!scope._msg){
|
||||
scope._msg = {};
|
||||
}
|
||||
scope._msg.op = operation;
|
||||
} else {
|
||||
return gpgme_error('MSG_WRONG_OP');
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
import {Connection} from "./Connection"
|
||||
import {GPGME_Message} from './Message'
|
||||
import {GPGME_Message, createMessage} from './Message'
|
||||
import {toKeyIdArray} from "./Helpers"
|
||||
import { gpgme_error } from "./Errors"
|
||||
import { GPGME_Keyring } from "./Keyring";
|
||||
@ -71,8 +71,10 @@ export class GpgME {
|
||||
*/
|
||||
encrypt(data, publicKeys, wildcard=false){
|
||||
|
||||
let msg = new GPGME_Message('encrypt');
|
||||
|
||||
let msg = createMessage('encrypt');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg)
|
||||
}
|
||||
// TODO temporary
|
||||
msg.setParameter('armor', true);
|
||||
msg.setParameter('always-trust', true);
|
||||
@ -101,7 +103,10 @@ export class GpgME {
|
||||
if (data === undefined){
|
||||
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
||||
}
|
||||
let msg = new GPGME_Message('decrypt');
|
||||
let msg = createMessage('decrypt');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
putData(msg, data);
|
||||
return this.connection.post(msg);
|
||||
|
||||
@ -109,21 +114,27 @@ export class GpgME {
|
||||
|
||||
deleteKey(key, delete_secret = false, no_confirm = false){
|
||||
return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED'));
|
||||
let msg = new GPGME_Message('deletekey');
|
||||
let msg = createMessage('deletekey');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
let key_arr = toKeyIdArray(key);
|
||||
if (key_arr.length !== 1){
|
||||
throw('TODO');
|
||||
//should always be ONE key
|
||||
return Promise.reject(
|
||||
gpgme_error('GENERIC_ERROR'));
|
||||
// TBD should always be ONE key?
|
||||
}
|
||||
msg.setParameter('key', key_arr[0]);
|
||||
if (delete_secret === true){
|
||||
msg.setParameter('allow_secret', true); //TBD
|
||||
msg.setParameter('allow_secret', true);
|
||||
// TBD
|
||||
}
|
||||
if (no_confirm === true){ //TODO: Do we want this hidden deep in the code?
|
||||
msg.setParameter('delete_force', true); //TBD
|
||||
msg.setParameter('delete_force', true);
|
||||
// TBD
|
||||
}
|
||||
this.connection.post(msg).then(function(success){
|
||||
//TODO: it seems that there is always errors coming back:
|
||||
// TODO: it seems that there is always errors coming back:
|
||||
}, function(error){
|
||||
switch (error.msg){
|
||||
case 'ERR_NO_ERROR':
|
||||
|
110
lang/js/test/Helpers.js
Normal file
110
lang/js/test/Helpers.js
Normal file
@ -0,0 +1,110 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
import { expect } from "../node_modules/chai/chai";
|
||||
import { gpgme_error} from "../src/Errors";
|
||||
import { GPGME_Key } from "../src/Key";
|
||||
import { isLongId, isFingerprint, toKeyIdArray } from "../src/Helpers"
|
||||
|
||||
const helper_params = {
|
||||
validLongId: '0A0A0A0A0A0A0A0A',
|
||||
validGPGME_Key: new GPGME_Key('ADDBC303B6D31026F5EB4591A27EABDF283121BB'),
|
||||
validKeys: [new GPGME_Key('A1E3BC45BDC8E87B74F4392D53B151A1368E50F3'),
|
||||
'ADDBC303B6D31026F5EB4591A27EABDF283121BB',
|
||||
new GPGME_Key('EE17AEE730F88F1DE7713C54BBE0A4FF7851650A')],
|
||||
validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
|
||||
invalidLongId: '9A9A7A7A8A9A9A7A7A8A',
|
||||
invalidFingerprint: [{hello:'World'}],
|
||||
invalidKeyArray: {curiosity:'uncat'},
|
||||
invalidKeyArray_OneBad: [
|
||||
new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'),
|
||||
'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A',
|
||||
'3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'],
|
||||
invalidErrorCode: 'Please type in all your passwords.'
|
||||
}
|
||||
|
||||
describe('Error Object handling', function(){
|
||||
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(helper_params.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(helper_params.validFingerprint);
|
||||
expect(test0).to.be.true;
|
||||
});
|
||||
it('isFingerprint(): invalid Fingerprint', function(){
|
||||
let test0 = isFingerprint(helper_params.invalidFingerprint);
|
||||
expect(test0).to.be.false;
|
||||
});
|
||||
});
|
||||
describe('Converting to Fingerprint', function(){
|
||||
it('Correct Inputs', function(){
|
||||
it('Fingerprint string', function(){
|
||||
let test0 = toKeyIdArray(helper_params.validFingerprint);
|
||||
expect(test0).to.be.an('array');
|
||||
expect(test0).to.include(helper_params.validFingerprint);
|
||||
});
|
||||
it('GPGME_Key', function(){
|
||||
expect(helper_params.validGPGME_Key).to.be.an.instanceof(GPGME_Key);
|
||||
let test0 = toKeyIdArray(helper_params.validGPGME_Key);
|
||||
expect(test0).to.be.an('array');
|
||||
expect(test0).to.include(helper_params.validGPGME_Key.fingerprint);
|
||||
});
|
||||
it('Array of valid inputs', function(){
|
||||
let test0 = toKeyIdArray(helper_params.validKeys);
|
||||
expect(test0).to.be.an('array');
|
||||
expect(test0).to.have.lengthOf(helper_params.validKeys.length);
|
||||
});
|
||||
});
|
||||
describe('Incorrect inputs', function(){
|
||||
it('valid Long ID', function(){
|
||||
let test0 = toKeyIdArray(helper_params.validLongId);
|
||||
expect(test0).to.be.empty;
|
||||
});
|
||||
it('invalidFingerprint', function(){
|
||||
let test0 = toKeyIdArray(helper_params.invalidFingerprint);
|
||||
expect(test0).to.be.empty;
|
||||
});
|
||||
it('invalidKeyArray', function(){
|
||||
let test0 = toKeyIdArray(helper_params.invalidKeyArray);
|
||||
expect(test0).to.be.empty;
|
||||
});
|
||||
it('Partially invalid array', function(){
|
||||
let test0 = toKeyIdArray(helper_params.invalidKeyArray_OneBad);
|
||||
expect(test0).to.be.an('array');
|
||||
expect(test0).to.have.lengthOf(
|
||||
helper_params.invalidKeyArray_OneBad.length - 1);
|
||||
});
|
||||
});
|
||||
});
|
42
lang/js/test/Message.js
Normal file
42
lang/js/test/Message.js
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
import { expect } from "../node_modules/chai/chai";
|
||||
import { GPGME_Message, createMessage } from "../src/Message";
|
||||
|
||||
const message_params = {
|
||||
invalid_op_action : 'dance',
|
||||
invalid_op_type : [234, 34, '<>'],
|
||||
}
|
||||
|
||||
describe('Message Object', function(){
|
||||
describe('incorrect initialization', function(){
|
||||
it('non-allowed operation', function(){
|
||||
let test0 = createMessage(message_params.invalid_op_action);
|
||||
expect(test0).to.be.an.instanceof(Error);
|
||||
expect(test0.code).to.equal('MSG_WRONG_OP');
|
||||
});
|
||||
it('wrong parameter type in constructor', function(){
|
||||
let test0 = createMessage(message_params.invalid_op_type);
|
||||
expect(test0).to.be.an.instanceof(Error);
|
||||
expect(test0.code).to.equal('PARAM_WRONG');
|
||||
});
|
||||
});
|
||||
});
|
4
lang/js/test/mocha.opts
Normal file
4
lang/js/test/mocha.opts
Normal file
@ -0,0 +1,4 @@
|
||||
--require babel-register
|
||||
--reporter spec
|
||||
--ui bdd
|
||||
--colors
|
Loading…
Reference in New Issue
Block a user