js: change the write access for js class methods

--
* src/ [Connection, Error, Key, Keyring, MEssage, Signature, gpgmejs]:
    Functions and values that are not meant to be overwritten are now
    moved into their constructors, thus eliminating the possibility of
    overwrites after initialization.

* Key: The mode of use (synchronous cached, or async promises) ivs now
  determined at initialization of that Key. The property Key.isAsync
  reflects this state.

* unittests: fixed old Key syntax for testing.

* Message.js isComplete is now a method and not a getter anymore.

* Added some startup tests.
This commit is contained in:
Maximilian Krambach 2018-07-27 20:36:21 +02:00
parent b18b96fb36
commit 94ee0988d4
11 changed files with 409 additions and 400 deletions

View File

@ -86,7 +86,9 @@ const inputvalues = {// eslint-disable-line no-unused-vars
'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' +
'=ioB6\n' + '=ioB6\n' +
'-----END PGP SIGNATURE-----\n', '-----END PGP SIGNATURE-----\n',
} },
someInputParameter: 'bad string'
}; };
// (Pseudo-)Random String covering all of utf8. // (Pseudo-)Random String covering all of utf8.
@ -158,27 +160,6 @@ function slightlyLessBoringString(megabytes, set){
return string.join(''); return string.join('');
} }
// Take a gpg looking string and destroy it a bit by changing random values
// eslint-disable-next-line no-unused-vars
function destroylegitimateGpg(string, mutations=5){
const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/\n';
for (let i=0; i < mutations.length; i++){
// leave the first and last 35 chars (header/footer) intact
let position = Math.floor(Math.random() *(string.length - 70)) + 35;
let str0 = string.substring(0,position - 1);
let str1 = string.substring(position, position + 1);
let str2 = string.substring(position +1);
let success = false;
while (!success){
let newchar = Math.floor(Math.random() * allowed.length);
if (newchar !== str1){
string = str0 + newchar + str2;
success = true;
}
}
}
}
// Data encrypted with testKey // Data encrypted with testKey
const encryptedData =// eslint-disable-line no-unused-vars const encryptedData =// eslint-disable-line no-unused-vars
'-----BEGIN PGP MESSAGE-----\n' + '-----BEGIN PGP MESSAGE-----\n' +

View File

@ -21,16 +21,27 @@
* Maximilian Krambach <mkrambach@intevation.de> * Maximilian Krambach <mkrambach@intevation.de>
*/ */
/* global describe, it, expect, Gpgmejs */ /* global describe, it, expect, Gpgmejs, inputvalues */
describe('GPGME context', function(){ describe('GPGME context', function(){
it('Starting a GpgME instance', function(done){ it('Starting a GpgME instance', function(done){
let prm = Gpgmejs.init(); let prm = Gpgmejs.init();
const input = inputvalues.someInputParameter;
prm.then( prm.then(
function(context){ function(context){
expect(context).to.be.an('object'); expect(context).to.be.an('object');
expect(context.encrypt).to.be.a('function'); expect(context.encrypt).to.be.a('function');
expect(context.decrypt).to.be.a('function'); expect(context.decrypt).to.be.a('function');
expect(context.sign).to.be.a('function');
expect(context.verify).to.be.a('function');
context.Keyring = input;
expect(context.Keyring).to.be.an('object');
expect(context.Keyring).to.not.equal(input);
expect(context._Keyring).to.equal(context.Keyring);
expect(context.Keyring.getKeys).to.be.a('function');
expect(context.Keyring.getDefaultKey).to.be.a('function');
expect(context.Keyring.importKey).to.be.a('function');
expect(context.Keyring.generateKey).to.be.a('function');
done(); done();
}); });
}); });

View File

@ -38,8 +38,19 @@ import { GPGME_Message, createMessage } from './Message';
export class Connection{ export class Connection{
constructor(){ constructor(){
this.connect(); let _connection = chrome.runtime.connectNative('gpgmejson');
/**
* Immediately closes an open port.
*/
this.disconnect = function () {
if (_connection){
_connection.disconnect();
_connection = null;
} }
};
/** /**
* @typedef {Object} backEndDetails * @typedef {Object} backEndDetails
@ -63,14 +74,15 @@ export class Connection{
* backend * backend
* @async * @async
*/ */
checkConnection(details = true){ this.checkConnection = function(details = true){
const msg = createMessage('version');
if (details === true) { if (details === true) {
return this.post(createMessage('version')); return this.post(msg);
} else { } else {
let me = this; let me = this;
return new Promise(function(resolve) { return new Promise(function(resolve) {
Promise.race([ Promise.race([
me.post(createMessage('version')), me.post(msg),
new Promise(function(resolve, reject){ new Promise(function(resolve, reject){
setTimeout(function(){ setTimeout(function(){
reject(gpgme_error('CONN_TIMEOUT')); reject(gpgme_error('CONN_TIMEOUT'));
@ -83,26 +95,7 @@ export class Connection{
}); });
}); });
} }
} };
/**
* Immediately closes an 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 {@link GPGME_Message} via tghe nativeMessaging port. It resolves * Sends a {@link GPGME_Message} via tghe nativeMessaging port. It resolves
@ -113,65 +106,65 @@ export class Connection{
* @returns {Promise<Object>} The collected answer * @returns {Promise<Object>} The collected answer
* @async * @async
*/ */
post(message){ this.post = function (message){
if (!message || !(message instanceof GPGME_Message)){ if (!message || !(message instanceof GPGME_Message)){
this.disconnect(); this.disconnect();
return Promise.reject(gpgme_error( return Promise.reject(gpgme_error(
'PARAM_WRONG', 'Connection.post')); 'PARAM_WRONG', 'Connection.post'));
} }
if (message.isComplete !== true){ if (message.isComplete() !== true){
this.disconnect(); this.disconnect();
return Promise.reject(gpgme_error('MSG_INCOMPLETE')); return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
} }
let me = this;
let chunksize = message.chunksize; let chunksize = message.chunksize;
return new Promise(function(resolve, reject){ return new Promise(function(resolve, reject){
let answer = new Answer(message); let answer = new Answer(message);
let listener = function(msg) { let listener = function(msg) {
if (!msg){ if (!msg){
me._connection.onMessage.removeListener(listener); _connection.onMessage.removeListener(listener);
me._connection.disconnect(); _connection.disconnect();
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER')); reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
} else { } else {
let answer_result = answer.collect(msg); let answer_result = answer.collect(msg);
if (answer_result !== true){ if (answer_result !== true){
me._connection.onMessage.removeListener(listener); _connection.onMessage.removeListener(listener);
me._connection.disconnect(); _connection.disconnect();
reject(answer_result); reject(answer_result);
} else { } else {
if (msg.more === true){ if (msg.more === true){
me._connection.postMessage({ _connection.postMessage({
'op': 'getmore', 'op': 'getmore',
'chunksize': chunksize 'chunksize': chunksize
}); });
} else { } else {
me._connection.onMessage.removeListener(listener); _connection.onMessage.removeListener(listener);
me._connection.disconnect(); _connection.disconnect();
if (answer.message instanceof Error){ const message = answer.getMessage();
reject(answer.message); if (message instanceof Error){
reject(message);
} else { } else {
resolve(answer.message); resolve(message);
} }
} }
} }
} }
}; };
me._connection.onMessage.addListener(listener); _connection.onMessage.addListener(listener);
if (permittedOperations[message.operation].pinentry){ if (permittedOperations[message.operation].pinentry){
return me._connection.postMessage(message.message); return _connection.postMessage(message.message);
} else { } else {
return Promise.race([ return Promise.race([
me._connection.postMessage(message.message), _connection.postMessage(message.message),
function(resolve, reject){ function(resolve, reject){
setTimeout(function(){ setTimeout(function(){
me._connection.disconnect(); _connection.disconnect();
reject(gpgme_error('CONN_TIMEOUT')); reject(gpgme_error('CONN_TIMEOUT'));
}, 5000); }, 5000);
}]).then(function(result){ }]).then(function(result){
return result; return result;
}, function(reject){ }, function(reject){
if(!(reject instanceof Error)) { if(!(reject instanceof Error)) {
me._connection.disconnect(); _connection.disconnect();
return gpgme_error('GNUPG_ERROR', reject); return gpgme_error('GNUPG_ERROR', reject);
} else { } else {
return reject; return reject;
@ -179,7 +172,8 @@ export class Connection{
}); });
} }
}); });
} };
}
} }
/** /**
@ -193,10 +187,16 @@ class Answer{
* @param {GPGME_Message} message * @param {GPGME_Message} message
*/ */
constructor(message){ constructor(message){
this.operation = message.operation; const operation = message.operation;
this.expect = message.expect; const expect = message.expect;
} let response_b64 = null;
this.getOperation = function(){
return operation;
};
this.getExpect = function(){
return expect;
};
/** /**
* Adds incoming base64 encoded data to the existing response * Adds incoming base64 encoded data to the existing response
* @param {*} msg base64 encoded data. * @param {*} msg base64 encoded data.
@ -204,34 +204,30 @@ class Answer{
* *
* @private * @private
*/ */
collect(msg){ this.collect = function (msg){
if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) { if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
return gpgme_error('CONN_UNEXPECTED_ANSWER'); return gpgme_error('CONN_UNEXPECTED_ANSWER');
} }
if (this._responseb64 === undefined){ if (response_b64 === null){
//this._responseb64 = [msg.response]; response_b64 = msg.response;
this._responseb64 = msg.response;
return true; return true;
} else { } else {
//this._responseb64.push(msg.response); response_b64 += msg.response;
this._responseb64 += msg.response;
return true; return true;
} }
} };
/** /**
* Returns the base64 encoded answer data with the content verified against * Returns the base64 encoded answer data with the content verified against
* {@link permittedOperations}. * {@link permittedOperations}.
*/ */
get message(){ this.getMessage = function (){
if (this._responseb64 === undefined){ if (response_b64 === undefined){
return gpgme_error('CONN_UNEXPECTED_ANSWER'); return gpgme_error('CONN_UNEXPECTED_ANSWER');
} }
// let _decodedResponse = JSON.parse(atob(this._responseb64.join(''))); let _decodedResponse = JSON.parse(atob(response_b64));
let _decodedResponse = JSON.parse(atob(this._responseb64));
let _response = {}; let _response = {};
let messageKeys = Object.keys(_decodedResponse); let messageKeys = Object.keys(_decodedResponse);
let poa = permittedOperations[this.operation].answer; let poa = permittedOperations[this.getOperation()].answer;
if (messageKeys.length === 0){ if (messageKeys.length === 0){
return gpgme_error('CONN_UNEXPECTED_ANSWER'); return gpgme_error('CONN_UNEXPECTED_ANSWER');
} }
@ -262,7 +258,7 @@ class Answer{
} }
if (_decodedResponse.base64 === true if (_decodedResponse.base64 === true
&& poa.data[key] === 'string' && poa.data[key] === 'string'
&& this.expect === undefined && this.getExpect() === undefined
){ ){
_response[key] = decodeURIComponent( _response[key] = decodeURIComponent(
atob(_decodedResponse[key]).split('').map( atob(_decodedResponse[key]).split('').map(
@ -277,5 +273,6 @@ class Answer{
} }
} }
return _response; return _response;
} };
}
} }

View File

@ -143,7 +143,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
* @extends Error * @extends Error
*/ */
class GPGME_Error extends Error{ class GPGME_Error extends Error{
constructor(code, msg=''){ constructor(code = 'GENERIC_ERROR', msg=''){
if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){ if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){
super(msg); super(msg);
} else if (err_list.hasOwnProperty(code)){ } else if (err_list.hasOwnProperty(code)){
@ -155,12 +155,12 @@ class GPGME_Error extends Error{
} else { } else {
super(err_list['GENERIC_ERROR'].msg); super(err_list['GENERIC_ERROR'].msg);
} }
this.code = code || 'GENERIC_ERROR'; this.getCode = function(){
} return code;
set code(value){ };
this._code = value;
} }
get code(){ get code(){
return this._code; return this.getCode();
} }
} }

View File

@ -28,13 +28,16 @@ import { createMessage } from './Message';
/** /**
* Validates the given fingerprint and creates a new {@link GPGME_Key} * Validates the given fingerprint and creates a new {@link GPGME_Key}
* @param {String} fingerprint * @param {String} fingerprint
* @param {Boolean} async If True, Key properties (except fingerprint) will be
* queried from gnupg on each call, making the operation up-to-date, the
* answers will be Promises, and the performance will likely suffer
* @returns {GPGME_Key|GPGME_Error} * @returns {GPGME_Key|GPGME_Error}
*/ */
export function createKey(fingerprint){ export function createKey(fingerprint, async = false){
if (!isFingerprint(fingerprint)){ if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} }
else return new GPGME_Key(fingerprint); else return new GPGME_Key(fingerprint, async);
} }
/** /**
@ -48,31 +51,30 @@ export function createKey(fingerprint){
*/ */
export class GPGME_Key { export class GPGME_Key {
constructor(fingerprint){ constructor(fingerprint, async){
this.fingerprint = fingerprint;
}
set fingerprint(fpr){
if (isFingerprint(fpr) === true) {
if (this._data === undefined) {
this._data = {fingerprint: fpr};
} else {
if (this._data.fingerprint === undefined){
this._data.fingerprint = fpr;
}
}
}
}
/** /**
* @returns {String} The fingerprint defining this Key * @property {Boolean} If true, most answers will be asynchronous
*/ */
get fingerprint(){ this.isAsync = async;
if (!this._data || !this._data.fingerprint){
let _data = {fingerprint: fingerprint};
this.getFingerprint = function(){
if (!_data.fingerprint || !isFingerprint(_data.fingerprint)){
return gpgme_error('KEY_INVALID'); return gpgme_error('KEY_INVALID');
} }
return this._data.fingerprint; return _data.fingerprint;
} };
/**
* Property indicating if the Key possesses a private/secret part. If this
* information is not yet cached, it returns an {@link GPGME_Error} with
* code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case.
* @returns {Boolean} If the Key has a secret subkey.
*/
this.hasSecret= function (){
return this.get('hasSecret', true);
};
/** /**
* @param {Object} data Bulk set the data for this key, with an Object sent * @param {Object} data Bulk set the data for this key, with an Object sent
@ -81,97 +83,89 @@ export class GPGME_Key {
* error if something went wrong * error if something went wrong
* @private * @private
*/ */
setKeyData(data){ this.setKeyData = function (data){
if (this._data === undefined) { if (typeof(data) !== 'object') {
this._data = {};
}
if (
typeof(data) !== 'object') {
return gpgme_error('KEY_INVALID'); return gpgme_error('KEY_INVALID');
} }
if (!this._data.fingerprint && isFingerprint(data.fingerprint)){ if (!data.fingerprint || data.fingerprint !== _data.fingerprint){
if (data.fingerprint !== this.fingerprint){
return gpgme_error('KEY_INVALID'); return gpgme_error('KEY_INVALID');
} }
this._data.fingerprint = data.fingerprint; let keys = Object.keys(data);
} else if (this._data.fingerprint !== data.fingerprint){ for (let i=0; i< keys.length; i++){
if (!validKeyProperties.hasOwnProperty(keys[i])){
return gpgme_error('KEY_INVALID'); return gpgme_error('KEY_INVALID');
} }
let dataKeys = Object.keys(data); //running the defined validation function
for (let i=0; i< dataKeys.length; i++){ if (validKeyProperties[keys[i]](data[keys[i]]) !== true ){
if (!validKeyProperties.hasOwnProperty(dataKeys[i])){
return gpgme_error('KEY_INVALID'); return gpgme_error('KEY_INVALID');
} }
if (validKeyProperties[dataKeys[i]](data[dataKeys[i]]) !== true ){ switch (keys[i]){
return gpgme_error('KEY_INVALID');
}
switch (dataKeys[i]){
case 'subkeys': case 'subkeys':
this._data.subkeys = []; _data.subkeys = [];
for (let i=0; i< data.subkeys.length; i++) { for (let i=0; i< data.subkeys.length; i++) {
this._data.subkeys.push( _data.subkeys.push(
new GPGME_Subkey(data.subkeys[i])); new GPGME_Subkey(data.subkeys[i]));
} }
break; break;
case 'userids': case 'userids':
this._data.userids = []; _data.userids = [];
for (let i=0; i< data.userids.length; i++) { for (let i=0; i< data.userids.length; i++) {
this._data.userids.push( _data.userids.push(
new GPGME_UserId(data.userids[i])); new GPGME_UserId(data.userids[i]));
} }
break; break;
case 'last_update': case 'last_update':
this._data[dataKeys[i]] = new Date( data[dataKeys[i]] * 1000 ); _data[keys[i]] = new Date( data[keys[i]] * 1000 );
break; break;
default: default:
this._data[dataKeys[i]] = data[dataKeys[i]]; _data[keys[i]] = data[keys[i]];
} }
} }
return this; return this;
} };
/** /**
* Query any property of the Key listed in {@link validKeyProperties} * Query any property of the Key listed in {@link validKeyProperties}
* @param {String} property property to be retreived * @param {String} property property to be retreived
* @param {Boolean} cached (optional) if false, the data will be directly
* queried from gnupg, and the operation will be asynchronous. Else, the
* data will be fetched from the state of the initialization of the Key.
* The cached mode may contain outdated information, but can be used as
* synchronous operation, where the backend is not expected to change Keys
* during a session. The key still can be reloaded by invoking
* {@link refreshKey}.
* @returns {*|Promise<*>} the value (Boolean, String, Array, Object). * @returns {*|Promise<*>} the value (Boolean, String, Array, Object).
* If 'cached' is false, the value will be resolved as a Promise. * If 'cached' is false, the value will be resolved as a Promise.
*/ */
get(property, cached=true) { this.get = function(property) {
if (cached === false) { if (this.isAsync === true) {
let me = this; let me = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!validKeyProperties.hasOwnProperty(property)){ if (property === 'armored'){
reject('PARAM_WRONG');
} else if (property === 'armored'){
resolve(me.getArmor()); resolve(me.getArmor());
} else if (property === 'hasSecret'){ } else if (property === 'hasSecret'){
resolve(me.getHasSecret()); resolve(me.getHasSecret());
} else if (validKeyProperties.hasOwnProperty(property)){
let msg = createMessage('keylist');
msg.setParameter('keys', _data.fingerprint);
msg.post().then(function(result){
if (result.keys && result.keys.length === 1 &&
result.keys[0].hasOwnProperty(property)){
resolve(result.keys[0][property]);
} else { } else {
me.refreshKey().then(function(key){ reject(gpgme_error('CONN_UNEXPECTED_ANSWER'));
resolve(key.get(property, true)); }
}, function(error){ }, function(error){
reject(error); reject(gpgme_error(error));
}); });
} else {
reject(gpgme_error('PARAM_WRONG'));
} }
}); });
} else { } else {
if (!validKeyProperties.hasOwnProperty(property)){ if (!validKeyProperties.hasOwnProperty(property)){
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} }
if (!this._data.hasOwnProperty(property)){ if (!_data.hasOwnProperty(property)){
return gpgme_error('KEY_NO_INIT'); return gpgme_error('KEY_NO_INIT');
} else { } else {
return (this._data[property]); return (_data[property]);
}
} }
} }
};
/** /**
* Reloads the Key information from gnupg. This is only useful if you use * Reloads the Key information from gnupg. This is only useful if you use
@ -181,15 +175,15 @@ export class GPGME_Key {
* @returns {Promise<GPGME_Key|GPGME_Error>} * @returns {Promise<GPGME_Key|GPGME_Error>}
* @async * @async
*/ */
refreshKey() { this.refreshKey = function() {
let me = this; let me = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!me._data.fingerprint){ if (!_data.fingerprint){
reject(gpgme_error('KEY_INVALID')); reject(gpgme_error('KEY_INVALID'));
} }
let msg = createMessage('keylist'); let msg = createMessage('keylist');
msg.setParameter('sigs', true); msg.setParameter('sigs', true);
msg.setParameter('keys', me._data.fingerprint); msg.setParameter('keys', _data.fingerprint);
msg.post().then(function(result){ msg.post().then(function(result){
if (result.keys.length === 1){ if (result.keys.length === 1){
me.setKeyData(result.keys[0]); me.setKeyData(result.keys[0]);
@ -209,7 +203,7 @@ export class GPGME_Key {
reject(gpgme_error('GNUPG_ERROR'), error); reject(gpgme_error('GNUPG_ERROR'), error);
}); });
}); });
} };
/** /**
* Query the armored block of the Key directly from gnupg. Please note that * Query the armored block of the Key directly from gnupg. Please note that
@ -217,23 +211,22 @@ export class GPGME_Key {
* @returns {Promise<String|GPGME_Error>} * @returns {Promise<String|GPGME_Error>}
* @async * @async
*/ */
getArmor(){ this.getArmor = function(){
let me = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!me._data.fingerprint){ if (!_data.fingerprint){
reject(gpgme_error('KEY_INVALID')); reject(gpgme_error('KEY_INVALID'));
} }
let msg = createMessage('export'); let msg = createMessage('export');
msg.setParameter('armor', true); msg.setParameter('armor', true);
msg.setParameter('keys', me._data.fingerprint); msg.setParameter('keys', _data.fingerprint);
msg.post().then(function(result){ msg.post().then(function(result){
me._data.armored = result.data; _data.armored = result.data;
resolve(result.data); resolve(result.data);
}, function(error){ }, function(error){
reject(error); reject(error);
}); });
}); });
} };
/** /**
* Find out if the Key includes a secret part. Note that this is a rather * Find out if the Key includes a secret part. Note that this is a rather
@ -244,39 +237,61 @@ export class GPGME_Key {
* available in the gnupg Keyring * available in the gnupg Keyring
* @async * @async
*/ */
getHasSecret(){ this.getHasSecret = function (){
let me = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!me._data.fingerprint){ if (!_data.fingerprint){
reject(gpgme_error('KEY_INVALID')); reject(gpgme_error('KEY_INVALID'));
} }
let msg = createMessage('keylist'); let msg = createMessage('keylist');
msg.setParameter('keys', me._data.fingerprint); msg.setParameter('keys', _data.fingerprint);
msg.setParameter('secret', true); msg.setParameter('secret', true);
msg.post().then(function(result){ msg.post().then(function(result){
me._data.hasSecret = null; _data.hasSecret = null;
if ( if (
result.keys && result.keys &&
result.keys.length === 1 && result.keys.length === 1 &&
result.keys[0].secret === true result.keys[0].secret === true
) { ) {
me._data.hasSecret = true; _data.hasSecret = true;
resolve(true); resolve(true);
} else { } else {
me._data.hasSecret = false; _data.hasSecret = false;
resolve(false); resolve(false);
} }
}, function(error){ }, function(error){
reject(error); reject(error);
}); });
}); });
};
/**
* Deletes the (public) Key from the GPG Keyring. Note that a deletion of a
* secret key is not supported by the native backend.
* @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
* rejects with a GPG error otherwise.
*/
this.delete= function (){
return new Promise(function(resolve, reject){
if (!_data.fingerprint){
reject(gpgme_error('KEY_INVALID'));
}
let msg = createMessage('delete');
msg.setParameter('key', _data.fingerprint);
msg.post().then(function(result){
resolve(result.success);
}, function(error){
reject(error);
});
});
};
} }
/** /**
* Convenience functions to be directly used as properties of the Key * @returns {String} The fingerprint defining this Key
* Notice that these rely on cached info and may be outdated. Use the async
* get(property, false) if you need the most current info
*/ */
get fingerprint(){
return this.getFingerprint();
}
/** /**
* Property for the export of armored Key. If the armored Key is not * Property for the export of armored Key. If the armored Key is not
@ -287,38 +302,6 @@ export class GPGME_Key {
get armored(){ get armored(){
return this.get('armored', true); return this.get('armored', true);
} }
/**
* Property indicating if the Key possesses a private/secret part. If this
* information is not yet cached, it returns an {@link GPGME_Error} with
* code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case.
* @returns {Boolean} If the Key has a secret subkey.
*/
get hasSecret(){
return this.get('hasSecret', true);
}
/**
* Deletes the (public) Key from the GPG Keyring. Note that a deletion of a
* secret key is not supported by the native backend.
* @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
* rejects with a GPG error otherwise.
*/
delete(){
let me = this;
return new Promise(function(resolve, reject){
if (!me._data.fingerprint){
reject(gpgme_error('KEY_INVALID'));
}
let msg = createMessage('delete');
msg.setParameter('key', me._data.fingerprint);
msg.post().then(function(result){
resolve(result.success);
}, function(error){
reject(error);
});
});
}
} }
/** /**
@ -334,11 +317,8 @@ class GPGME_Subkey {
* @private * @private
*/ */
constructor(data){ constructor(data){
let _data = {};
let keys = Object.keys(data); let keys = Object.keys(data);
for (let i=0; i< keys.length; i++) {
this.setProperty(keys[i], data[keys[i]]);
}
}
/** /**
* Validates a subkey property against {@link validSubKeyProperties} and * Validates a subkey property against {@link validSubKeyProperties} and
@ -347,31 +327,35 @@ class GPGME_Subkey {
* @param {*} value * @param {*} value
* @param private * @param private
*/ */
setProperty(property, value){ const setProperty = function (property, value){
if (!this._data){
this._data = {};
}
if (validSubKeyProperties.hasOwnProperty(property)){ if (validSubKeyProperties.hasOwnProperty(property)){
if (validSubKeyProperties[property](value) === true) { if (validSubKeyProperties[property](value) === true) {
if (property === 'timestamp' || property === 'expires'){ if (property === 'timestamp' || property === 'expires'){
this._data[property] = new Date(value * 1000); _data[property] = new Date(value * 1000);
} else { } else {
this._data[property] = value; _data[property] = value;
} }
} }
} }
};
for (let i=0; i< keys.length; i++) {
setProperty(keys[i], data[keys[i]]);
} }
/** /**
* Fetches any information about this subkey * Fetches any information about this subkey
* @param {String} property Information to request * @param {String} property Information to request
* @returns {String | Number | Date} * @returns {String | Number | Date}
*/ */
get(property) { this.get = function(property) {
if (this._data.hasOwnProperty(property)){ if (_data.hasOwnProperty(property)){
return (this._data[property]); return (_data[property]);
}
} }
};
}
} }
/** /**
@ -387,11 +371,23 @@ class GPGME_UserId {
* @private * @private
*/ */
constructor(data){ constructor(data){
let _data = {};
let keys = Object.keys(data); let keys = Object.keys(data);
const setProperty = function(property, value){
if (validUserIdProperties.hasOwnProperty(property)){
if (validUserIdProperties[property](value) === true) {
if (property === 'last_update'){
_data[property] = new Date(value*1000);
} else {
_data[property] = value;
}
}
}
};
for (let i=0; i< keys.length; i++) { for (let i=0; i< keys.length; i++) {
this.setProperty(keys[i], data[keys[i]]); setProperty(keys[i], data[keys[i]]);
}
} }
/** /**
* Validates a subkey property against {@link validUserIdProperties} and * Validates a subkey property against {@link validUserIdProperties} and
* sets it if validation is successful * sets it if validation is successful
@ -399,34 +395,21 @@ class GPGME_UserId {
* @param {*} value * @param {*} value
* @param private * @param private
*/ */
setProperty(property, value){
if (!this._data){
this._data = {};
}
if (validUserIdProperties.hasOwnProperty(property)){
if (validUserIdProperties[property](value) === true) {
if (property === 'last_update'){
this._data[property] = new Date(value*1000);
} else {
this._data[property] = value;
}
}
}
}
/** /**
* Fetches information about the user * Fetches information about the user
* @param {String} property Information to request * @param {String} property Information to request
* @returns {String | Number} * @returns {String | Number}
*/ */
get(property) { this.get = function (property) {
if (this._data.hasOwnProperty(property)){ if (_data.hasOwnProperty(property)){
return (this._data[property]); return (_data[property]);
}
} }
};
} }
}
/** /**
* Validation definition for userIds. Each valid userId property is represented * Validation definition for userIds. Each valid userId property is represented
* as a key- Value pair, with their value being a validation function to check * as a key- Value pair, with their value being a validation function to check

View File

@ -32,7 +32,6 @@ import { gpgme_error } from './Errors';
*/ */
export class GPGME_Keyring { export class GPGME_Keyring {
constructor(){ constructor(){
}
/** /**
* Queries Keys (all Keys or a subset) from gnupg. * Queries Keys (all Keys or a subset) from gnupg.
@ -50,7 +49,7 @@ export class GPGME_Keyring {
* @static * @static
* @async * @async
*/ */
getKeys(pattern, prepare_sync=false, search=false){ this.getKeys = function(pattern, prepare_sync=false, search=false){
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 (pattern !== undefined && pattern !== null){
@ -107,7 +106,7 @@ export class GPGME_Keyring {
} }
}); });
}); });
} };
/** /**
* @typedef {Object} exportResult The result of a getKeysArmored operation. * @typedef {Object} exportResult The result of a getKeysArmored operation.
@ -131,7 +130,7 @@ export class GPGME_Keyring {
* @static * @static
* @async * @async
*/ */
getKeysArmored(pattern, with_secret_fpr) { this.getKeysArmored = function(pattern, with_secret_fpr) {
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);
@ -153,7 +152,7 @@ export class GPGME_Keyring {
reject(error); reject(error);
}); });
}); });
} };
/** /**
* Returns the Key used by default in gnupg. * Returns the Key used by default in gnupg.
@ -165,7 +164,7 @@ export class GPGME_Keyring {
* @async * @async
* @static * @static
*/ */
getDefaultKey() { this.getDefaultKey = function() {
let me = this; let me = this;
return new Promise(function(resolve, reject){ return new Promise(function(resolve, reject){
let msg = createMessage('config_opt'); let msg = createMessage('config_opt');
@ -206,7 +205,7 @@ export class GPGME_Keyring {
reject(error); reject(error);
}); });
}); });
} };
/** /**
* @typedef {Object} importResult The result of a Key update * @typedef {Object} importResult The result of a Key update
@ -244,7 +243,7 @@ export class GPGME_Keyring {
* @async * @async
* @static * @static
*/ */
importKey(armored, prepare_sync) { this.importKey = function (armored, prepare_sync) {
let feedbackValues = ['considered', 'no_user_id', 'imported', let feedbackValues = ['considered', 'no_user_id', 'imported',
'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys', 'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys',
'new_signatures', 'new_revocations', 'secret_read', 'new_signatures', 'new_revocations', 'secret_read',
@ -323,7 +322,7 @@ export class GPGME_Keyring {
}); });
} };
/** /**
* Convenience function for deleting a Key. See {@link Key.delete} for * Convenience function for deleting a Key. See {@link Key.delete} for
@ -333,14 +332,14 @@ export class GPGME_Keyring {
* @async * @async
* @static * @static
*/ */
deleteKey(fingerprint){ this.deleteKey = function(fingerprint){
if (isFingerprint(fingerprint) === true) { if (isFingerprint(fingerprint) === true) {
let key = createKey(fingerprint); let key = createKey(fingerprint);
return key.delete(); return key.delete();
} else { } else {
return Promise.reject(gpgme_error('KEY_INVALID')); return Promise.reject(gpgme_error('KEY_INVALID'));
} }
} };
/** /**
* 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
@ -356,7 +355,7 @@ export class GPGME_Keyring {
* @return {Promise<Key|GPGME_Error>} * @return {Promise<Key|GPGME_Error>}
* @async * @async
*/ */
generateKey(userId, algo = 'default', expires){ this.generateKey = function (userId, algo = 'default', expires){
if ( if (
typeof(userId) !== 'string' || typeof(userId) !== 'string' ||
supportedKeyAlgos.indexOf(algo) < 0 || supportedKeyAlgos.indexOf(algo) < 0 ||
@ -385,7 +384,8 @@ export class GPGME_Keyring {
reject(error); reject(error);
}); });
}); });
} };
}
} }
/** /**

View File

@ -52,22 +52,14 @@ export function createMessage(operation){
export class GPGME_Message { export class GPGME_Message {
constructor(operation){ constructor(operation){
this.operation = operation; let _msg = {
} op: operation,
chunksize: 1023* 1024
};
set operation (op){ this.getOperation = function(){
if (typeof(op) === 'string'){ return _msg.op;
if (!this._msg){ };
this._msg = {};
}
if (!this._msg.op & permittedOperations.hasOwnProperty(op)){
this._msg.op = op;
}
}
}
get operation(){
return this._msg.op;
}
/** /**
* The maximum size of responses from gpgme in bytes. As of July 2018, * The maximum size of responses from gpgme in bytes. As of July 2018,
@ -78,41 +70,23 @@ export class GPGME_Message {
* messages will be received in chunks. * messages will be received in chunks.
* If the value is not explicitly specified, 1023 KB is used. * If the value is not explicitly specified, 1023 KB is used.
*/ */
set chunksize(value){ this.setChunksize = function (value){
if ( if (
Number.isInteger(value) && Number.isInteger(value) &&
value > 10 * 1024 && value > 10 * 1024 &&
value <= 1024 * 1024 value <= 1024 * 1024
){ ){
this._chunksize = value; _msg.chunksize = value;
}
}
get chunksize(){
if (this._chunksize === undefined){
return 1024 * 1023;
} else {
return this._chunksize;
}
} }
};
/** this.getMsg = function(){
* Expect indicates which format data is expected to be in. It currently return _msg;
* only supports 'base64', indicating that the response data from gnupg are };
* 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 undefined;
}
this.getChunksize= function() {
return _msg.chunksize;
};
/** /**
* Sets a parameter for the message. It validates with * Sets a parameter for the message. It validates with
@ -121,11 +95,11 @@ export class GPGME_Message {
* @param {any} value Value to set * @param {any} value Value to set
* @returns {Boolean} If the parameter was set successfully * @returns {Boolean} If the parameter was set successfully
*/ */
setParameter( param,value ){ this.setParameter = function ( param,value ){
if (!param || typeof(param) !== 'string'){ if (!param || typeof(param) !== 'string'){
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} }
let po = permittedOperations[this._msg.op]; let po = permittedOperations[_msg.op];
if (!po){ if (!po){
return gpgme_error('MSG_WRONG_OP'); return gpgme_error('MSG_WRONG_OP');
} }
@ -195,59 +169,42 @@ export class GPGME_Message {
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} }
} }
this._msg[param] = value; _msg[param] = value;
return true; return true;
} };
/** /**
* Check if the message has the minimum requirements to be sent, that is * Check if the message has the minimum requirements to be sent, that is
* all 'required' parameters according to {@link permittedOperations}. * all 'required' parameters according to {@link permittedOperations}.
* @returns {Boolean} true if message is complete. * @returns {Boolean} true if message is complete.
*/ */
get isComplete(){ this.isComplete = function(){
if (!this._msg.op){ if (!_msg.op){
return false; return false;
} }
let reqParams = Object.keys( let reqParams = Object.keys(
permittedOperations[this._msg.op].required); permittedOperations[_msg.op].required);
let msg_params = Object.keys(this._msg); let msg_params = Object.keys(_msg);
for (let i=0; i < reqParams.length; i++){ for (let i=0; i < reqParams.length; i++){
if (msg_params.indexOf(reqParams[i]) < 0){ if (msg_params.indexOf(reqParams[i]) < 0){
return false; return false;
} }
} }
return true; 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;
}
}
/** /**
* Sends the Message via nativeMessaging and resolves with the answer. * Sends the Message via nativeMessaging and resolves with the answer.
* @returns {Promise<Object|GPGME_Error>} * @returns {Promise<Object|GPGME_Error>}
* @async * @async
*/ */
post(){ this.post = function(){
let me = this; let me = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (me.isComplete === true) { if (me.isComplete() === true) {
let conn = new Connection; let conn = new Connection;
if (me._msg.chunksize === undefined){
me._msg.chunksize = me.chunksize;
}
conn.post(me).then(function(response) { conn.post(me).then(function(response) {
resolve(response); resolve(response);
}, function(reason) { }, function(reason) {
@ -258,5 +215,27 @@ export class GPGME_Message {
reject(gpgme_error('MSG_INCOMPLETE')); reject(gpgme_error('MSG_INCOMPLETE'));
} }
}); });
} };
}
/**
* 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){
return this.getMsg();
}
else {
return null;
}
}
get operation(){
return this.getOperation();
}
get chunksize(){
return this.getChunksize();
}
} }

View File

@ -82,44 +82,47 @@ export function createSignature(sigObject){
class GPGME_Signature { class GPGME_Signature {
constructor(sigObject){ constructor(sigObject){
this._rawSigObject = sigObject; let _rawSigObject = sigObject;
}
get fingerprint(){ this.getFingerprint = function(){
return this._rawSigObject.fingerprint; if (!_rawSigObject.fingerprint){
return gpgme_error('SIG_WRONG');
} else {
return _rawSigObject.fingerprint;
} }
};
/** /**
* The expiration of this Signature as Javascript date, or null if * The expiration of this Signature as Javascript date, or null if
* signature does not expire * signature does not expire
* @returns {Date | null} * @returns {Date | null}
*/ */
get expiration(){ this.getExpiration = function(){
if (!this._rawSigObject.exp_timestamp){ if (!_rawSigObject.exp_timestamp){
return null; return null;
} }
return new Date(this._rawSigObject.exp_timestamp* 1000); return new Date(_rawSigObject.exp_timestamp* 1000);
} };
/** /**
* The creation date of this Signature in Javascript Date * The creation date of this Signature in Javascript Date
* @returns {Date} * @returns {Date}
*/ */
get timestamp(){ this.getTimestamp= function (){
return new Date(this._rawSigObject.timestamp * 1000); return new Date(_rawSigObject.timestamp * 1000);
} };
/** /**
* The overall validity of the key. If false, errorDetails may contain * The overall validity of the key. If false, errorDetails may contain
* additional information * additional information
*/ */
get valid() { this.getValid= function() {
if (this._rawSigObject.summary.valid === true){ if (_rawSigObject.summary.valid === true){
return true; return true;
} else { } else {
return false; return false;
} }
} };
/** /**
* gives more information on non-valid signatures. Refer to the gpgme docs * gives more information on non-valid signatures. Refer to the gpgme docs
@ -127,19 +130,54 @@ class GPGME_Signature {
* details on the values * details on the values
* @returns {Object} Object with boolean properties * @returns {Object} Object with boolean properties
*/ */
get errorDetails(){ this.getErrorDetails = function (){
let properties = ['revoked', 'key-expired', 'sig-expired', let properties = ['revoked', 'key-expired', 'sig-expired',
'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy', 'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy',
'sys-error']; 'sys-error'];
let result = {}; let result = {};
for (let i=0; i< properties.length; i++){ for (let i=0; i< properties.length; i++){
if ( this._rawSigObject.hasOwnProperty(properties[i]) ){ if ( _rawSigObject.hasOwnProperty(properties[i]) ){
result[properties[i]] = this._rawSigObject[properties[i]]; result[properties[i]] = _rawSigObject[properties[i]];
} }
} }
return result; return result;
};
}
/**
* Convenience getter for {@link getFingerprint}
*/
get fingerprint(){
return this.getFingerprint();
} }
/**
* Convenience getter for {@link getExpiration}
*/
get expiration(){
return this.getExpiration();
}
/**
* Convenience getter for {@link getTimeStamp}
*/
get timestamp(){
return this.getTimestamp();
}
/**
* Convenience getter for {@link getValid}
*/
get valid(){
return this.getValid();
}
/**
* Convenience getter for {@link getErrorDetails}
*/
get errorDetails(){
return this.getErrorDetails();
}
} }
/** /**

View File

@ -22,8 +22,8 @@
*/ */
import {GPGME_Message, createMessage} from './Message'; import { GPGME_Message, createMessage } from './Message';
import {toKeyIdArray} from './Helpers'; import { toKeyIdArray } from './Helpers';
import { gpgme_error } from './Errors'; import { gpgme_error } from './Errors';
import { GPGME_Keyring } from './Keyring'; import { GPGME_Keyring } from './Keyring';
import { createSignature } from './Signature'; import { createSignature } from './Signature';
@ -85,23 +85,27 @@ import { createSignature } from './Signature';
export class GpgME { export class GpgME {
constructor(){ constructor(){
} let _Keyring = null;
set Keyring(keyring){ /**
* Sets a new Keyring to be used
* @param {GPGME_Keyring} keyring
*/
this.setKeyring = function(keyring){
if (keyring && keyring instanceof GPGME_Keyring){ if (keyring && keyring instanceof GPGME_Keyring){
this._Keyring = keyring; _Keyring = keyring;
}
} }
};
/** /**
* Accesses the {@link GPGME_Keyring}. * Accesses the {@link GPGME_Keyring}.
*/ */
get Keyring(){ this.getKeyring = function(){
if (!this._Keyring){ if (!_Keyring){
this._Keyring = new GPGME_Keyring; _Keyring = new GPGME_Keyring;
}
return this._Keyring;
} }
return _Keyring;
};
/** /**
* Encrypt (and optionally sign) data * Encrypt (and optionally sign) data
@ -123,8 +127,8 @@ export class GpgME {
* message and additional info. * message and additional info.
* @async * @async
*/ */
encrypt(data, publicKeys, secretKeys, base64=false, armor=true, this.encrypt = function (data, publicKeys, secretKeys, base64=false,
wildcard=false, additional = {} armor=true, wildcard=false, additional = {}
){ ){
let msg = createMessage('encrypt'); let msg = createMessage('encrypt');
if (msg instanceof Error){ if (msg instanceof Error){
@ -152,12 +156,12 @@ export class GpgME {
additional[additional_Keys[k]]); additional[additional_Keys[k]]);
} }
} }
if (msg.isComplete === true){ if (msg.isComplete() === true){
return msg.post(); return msg.post();
} else { } else {
return Promise.reject(gpgme_error('MSG_INCOMPLETE')); return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
} }
} };
/** /**
* Decrypts a Message * Decrypts a Message
@ -168,7 +172,7 @@ export class GpgME {
* @returns {Promise<decrypt_result>} Decrypted Message and information * @returns {Promise<decrypt_result>} Decrypted Message and information
* @async * @async
*/ */
decrypt(data, base64=false){ this.decrypt = function (data, base64=false){
if (data === undefined){ if (data === undefined){
return Promise.reject(gpgme_error('MSG_EMPTY')); return Promise.reject(gpgme_error('MSG_EMPTY'));
} }
@ -203,7 +207,7 @@ export class GpgME {
reject(error); reject(error);
}); });
}); });
} };
/** /**
* Sign a Message * Sign a Message
@ -217,7 +221,7 @@ export class GpgME {
* @returns {Promise<signResult>} * @returns {Promise<signResult>}
* @async * @async
*/ */
sign(data, keys, mode='clearsign', base64=false) { this.sign = function (data, keys, mode='clearsign', base64=false) {
if (data === undefined){ if (data === undefined){
return Promise.reject(gpgme_error('MSG_EMPTY')); return Promise.reject(gpgme_error('MSG_EMPTY'));
} }
@ -252,7 +256,7 @@ export class GpgME {
reject(error); reject(error);
}); });
}); });
} };
/** /**
* Verifies data. * Verifies data.
@ -264,7 +268,7 @@ export class GpgME {
* @returns {Promise<verifyResult>} * @returns {Promise<verifyResult>}
*@async *@async
*/ */
verify(data, signature, base64 = false){ this.verify= function (data, signature, base64 = false){
let msg = createMessage('verify'); let msg = createMessage('verify');
let dt = putData(msg, data); let dt = putData(msg, data);
if (dt instanceof Error){ if (dt instanceof Error){
@ -297,6 +301,25 @@ export class GpgME {
reject(error); reject(error);
}); });
}); });
};
}
/**
* setter for {@link setKeyring}.
* @param {GPGME_Keyring} keyring A Keyring to use
*/
set Keyring(keyring){
this.setKeyring(keyring);
}
/**
* Accesses the {@link GPGME_Keyring}.
*/
get Keyring(){
if (!this._Keyring){
this._Keyring = new GPGME_Keyring;
}
return this._Keyring;
} }
} }
@ -309,7 +332,7 @@ export class GpgME {
* @private * @private
*/ */
function putData(message, data){ function putData(message, data){
if (!message || !(message instanceof GPGME_Message) ) { if (!message || !message instanceof GPGME_Message) {
return gpgme_error('PARAM_WRONG'); return gpgme_error('PARAM_WRONG');
} }
if (!data){ if (!data){

View File

@ -1,12 +1,9 @@
import {Connection} from './src/Connection';
import {createKey} from './src/Key'; import {createKey} from './src/Key';
let conn = new Connection;
export const helper_params = { export const helper_params = {
validLongId: '0A0A0A0A0A0A0A0A', validLongId: '0A0A0A0A0A0A0A0A',
validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3', validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3',
createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'),
'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'], 'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'],
validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
@ -15,11 +12,11 @@ export const helper_params = {
invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)], invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)],
invalidKeyArray: {curiosity:'uncat'}, invalidKeyArray: {curiosity:'uncat'},
invalidKeyArray_OneBad: [ invalidKeyArray_OneBad: [
createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'),
'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A',
'3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'],
invalidErrorCode: 'Please type in all your passwords.', invalidErrorCode: 'Please type in all your passwords.',
validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn), validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', true),
valid_openpgplike: { primaryKey: { valid_openpgplike: { primaryKey: {
getFingerprint: function(){ getFingerprint: function(){
return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';} return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';}
@ -36,7 +33,7 @@ export const message_params = {
invalid_param_names: [22,'dance', {}], invalid_param_names: [22,'dance', {}],
validparam_name_0: 'mime', validparam_name_0: 'mime',
invalid_values_0: [2134, 'All your passwords', invalid_values_0: [2134, 'All your passwords',
createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), null] createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null]
} }
}; };

View File

@ -194,16 +194,16 @@ function unittests (){
}); });
it('Non-cached key async data retrieval', function (done){ it('Non-cached key async data retrieval', function (done){
let key = createKey(kp.validKeyFingerprint); let key = createKey(kp.validKeyFingerprint, true);
key.get('can_authenticate',false).then(function(result){ key.get('can_authenticate').then(function(result){
expect(result).to.be.a('boolean'); expect(result).to.be.a('boolean');
done(); done();
}); });
}); });
it('Non-cached key async armored Key', function (done){ it('Non-cached key async armored Key', function (done){
let key = createKey(kp.validKeyFingerprint); let key = createKey(kp.validKeyFingerprint, true);
key.get('armored', false).then(function(result){ key.get('armored').then(function(result){
expect(result).to.be.a('string'); expect(result).to.be.a('string');
expect(result).to.include('KEY BLOCK-----'); expect(result).to.include('KEY BLOCK-----');
done(); done();
@ -211,17 +211,17 @@ function unittests (){
}); });
it('Non-cached key async hasSecret', function (done){ it('Non-cached key async hasSecret', function (done){
let key = createKey(kp.validKeyFingerprint); let key = createKey(kp.validKeyFingerprint, true);
key.get('hasSecret', false).then(function(result){ key.get('hasSecret').then(function(result){
expect(result).to.be.a('boolean'); expect(result).to.be.a('boolean');
done(); done();
}); });
}); });
it('Non-cached key async hasSecret (no secret in Key)', function (done){ it('Non-cached key async hasSecret (no secret in Key)', function (done){
let key = createKey(kp.validFingerprintNoSecret); let key = createKey(kp.validFingerprintNoSecret, true);
expect(key).to.be.an.instanceof(GPGME_Key); expect(key).to.be.an.instanceof(GPGME_Key);
key.get('hasSecret', false).then(function(result){ key.get('hasSecret').then(function(result){
expect(result).to.be.a('boolean'); expect(result).to.be.a('boolean');
expect(result).to.equal(false); expect(result).to.equal(false);
done(); done();
@ -317,7 +317,7 @@ function unittests (){
let test0 = createMessage('encrypt'); let test0 = createMessage('encrypt');
expect(test0).to.be.an.instanceof(GPGME_Message); expect(test0).to.be.an.instanceof(GPGME_Message);
expect(test0.isComplete).to.be.false; expect(test0.isComplete()).to.be.false;
}); });
it('Message is complete after setting mandatory data', function(){ it('Message is complete after setting mandatory data', function(){
@ -325,14 +325,14 @@ function unittests (){
test0.setParameter('data', mp.valid_encrypt_data); test0.setParameter('data', mp.valid_encrypt_data);
test0.setParameter('keys', hp.validFingerprints); test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete).to.be.true; expect(test0.isComplete()).to.be.true;
}); });
it('Message is not complete after mandatory data is empty', function(){ it('Message is not complete after mandatory data is empty', function(){
let test0 = createMessage('encrypt'); let test0 = createMessage('encrypt');
test0.setParameter('data', ''); test0.setParameter('data', '');
test0.setParameter('keys', hp.validFingerprints); test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete).to.be.false; expect(test0.isComplete()).to.be.false;
}); });
it('Complete Message contains the data that was set', function(){ it('Complete Message contains the data that was set', function(){