js: changed Key class stub

--

* src/Key.js:
  A Key object cannot offer more than basic functionality outside a
  connection, so it now requires a connection to be present.
This commit is contained in:
Maximilian Krambach 2018-05-03 14:12:10 +02:00
parent fda7b13f1b
commit 6f67814eb4
5 changed files with 110 additions and 68 deletions

View File

@ -30,11 +30,42 @@ import { isFingerprint } from './Helpers'
import { gpgme_error } from './Errors' import { gpgme_error } from './Errors'
import { createMessage } from './Message'; import { createMessage } from './Message';
import { permittedOperations } from './permittedOperations'; import { permittedOperations } from './permittedOperations';
import { Connection } from './Connection';
export function createKey(fingerprint, parent){
if (!isFingerprint(fingerprint)){
return gpgme_error('KEY_INVALID');
}
if ( parent instanceof Connection){
return new GPGME_Key(fingerprint, parent);
} else if ( parent.hasOwnProperty('connection') &&
parent.connection instanceof Connection){
return new GPGME_Key(fingerprint, parent.connection);
}
}
export class GPGME_Key { export class GPGME_Key {
constructor(fingerprint){ constructor(fingerprint, connection){
this.fingerprint = fingerprint; this.fingerprint = fingerprint;
this.connection = connection;
}
set connection(conn){
if (this._connection instanceof Connection) {
gpgme_error('CONN_ALREADY_CONNECTED');
} else if (conn instanceof Connection ) {
this._connection = conn;
}
}
get connection(){
if (!this._connection instanceof Connection){
return gpgme_error('CONN_NO_CONNECT');
} else {
return this._connection;
}
} }
set fingerprint(fpr){ set fingerprint(fpr){
@ -51,55 +82,56 @@ export class GPGME_Key {
* hasSecret returns true if a secret subkey is included in this Key * hasSecret returns true if a secret subkey is included in this Key
*/ */
get hasSecret(){ get hasSecret(){
return checkKey(this._fingerprint, 'secret'); return this.checkKey('secret');
} }
get isRevoked(){ get isRevoked(){
return checkKey(this._fingerprint, 'revoked'); return this.checkKey('revoked');
} }
get isExpired(){ get isExpired(){
return checkKey(this._fingerprint, 'expired'); return this.checkKey('expired');
} }
get isDisabled(){ get isDisabled(){
return checkKey(this._fingerprint, 'disabled'); return this.checkKey('disabled');
} }
get isInvalid(){ get isInvalid(){
return checkKey(this._fingerprint, 'invalid'); return this.checkKey('invalid');
} }
get canEncrypt(){ get canEncrypt(){
return checkKey(this._fingerprint, 'can_encrypt'); return this.checkKey('can_encrypt');
} }
get canSign(){ get canSign(){
return checkKey(this._fingerprint, 'can_sign'); return this.checkKey('can_sign');
} }
get canCertify(){ get canCertify(){
return checkKey(this._fingerprint, 'can_certify'); return this.checkKey('can_certify');
} }
get canAuthenticate(){ get canAuthenticate(){
return checkKey(this._fingerprint, 'can_authenticate'); return this.checkKey('can_authenticate');
} }
get isQualified(){ get isQualified(){
return checkKey(this._fingerprint, 'is_qualified'); return this.checkKey('is_qualified');
} }
get armored(){ get armored(){
let me = this; let msg = createMessage ('export_key');
return new Promise(function(resolve, reject){ msg.setParameter('armor', true);
let conn = new Connection(); if (msg instanceof Error){
conn.setFlag('armor', true); return gpgme_error('INVALID_KEY');
conn.post('export',{'fpr': me._fingerprint}); }
this.connection.post(msg).then(function(result){
return result.data;
}); });
// TODO return value not yet checked. Should result in an armored block // TODO return value not yet checked. Should result in an armored block
// in correct encoding // in correct encoding
// TODO openpgpjs also returns secKey if private = true?
} }
/** /**
@ -114,21 +146,21 @@ export class GPGME_Key {
* @returns {Array<GPGME_Key>} * @returns {Array<GPGME_Key>}
*/ */
get subkeys(){ get subkeys(){
return checkKey(this._fingerprint, 'subkeys').then(function(result){ return this.checkKey('subkeys').then(function(result){
// TBD expecting a list of fingerprints // TBD expecting a list of fingerprints
if (!Array.isArray(result)){ if (!Array.isArray(result)){
result = [result]; result = [result];
} }
let resultset = []; let resultset = [];
for (let i=0; i < result.length; i++){ for (let i=0; i < result.length; i++){
let subkey = new GPGME_Key(result[i]); let subkey = new GPGME_Key(result[i], this.connection);
if (subkey instanceof GPGME_Key){ if (subkey instanceof GPGME_Key){
resultset.push(subkey); resultset.push(subkey);
} }
} }
return Promise.resolve(resultset); return Promise.resolve(resultset);
}, function(error){ }, function(error){
//TODO checkKey fails //TODO this.checkKey fails
}); });
} }
@ -137,7 +169,7 @@ export class GPGME_Key {
* @returns {Date|null} TBD * @returns {Date|null} TBD
*/ */
get timestamp(){ get timestamp(){
return checkKey(this._fingerprint, 'timestamp'); return this.checkKey('timestamp');
//TODO GPGME: -1 if the timestamp is invalid, and 0 if it is not available. //TODO GPGME: -1 if the timestamp is invalid, and 0 if it is not available.
} }
@ -146,7 +178,7 @@ export class GPGME_Key {
* @returns {Date|null} TBD * @returns {Date|null} TBD
*/ */
get expires(){ get expires(){
return checkKey(this._fingerprint, 'expires'); return this.checkKey('expires');
// TODO convert to Date; check for 0 // TODO convert to Date; check for 0
} }
@ -155,51 +187,47 @@ export class GPGME_Key {
* @returns {String|Array<String>} The user ids associated with this key * @returns {String|Array<String>} The user ids associated with this key
*/ */
get userIds(){ get userIds(){
return checkKey(this._fingerprint, 'uids'); return this.checkKey('uids');
} }
/** /**
* @returns {String} The public key algorithm supported by this subkey * @returns {String} The public key algorithm supported by this subkey
*/ */
get pubkey_algo(){ get pubkey_algo(){
return checkKey(this._fingerprint, 'pubkey_algo'); return this.checkKey('pubkey_algo');
} }
};
/** /**
* generic function to query gnupg information on a key. * generic function to query gnupg information on a key.
* @param {*} fingerprint The identifier of the Keyring * @param {*} property The gpgme-json property to check.
* @param {*} property The gpgme-json property to check * TODO: check if Promise.then(return)
*
*/ */
function checkKey(fingerprint, property){ checkKey(property){
return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); return gpgme_error('NOT_YET_IMPLEMENTED');
if (!property || !permittedOperations[keyinfo].hasOwnProperty(property)){ // TODO: async is not what is to be ecpected from Key information :(
return Promise.reject(gpgme_error('PARAM_WRONG')); if (!property || typeof(property) !== 'string' ||
} !permittedOperations['keyinfo'].hasOwnProperty(property)){
return new Promise(function(resolve, reject){ return gpgme_error('PARAM_WRONG');
if (!isFingerprint(fingerprint)){
reject(gpgme_error('KEY_INVALID'));
} }
let msg = createMessage ('keyinfo'); let msg = createMessage ('keyinfo');
if (msg instanceof Error){ if (msg instanceof Error){
reject(gpgme_error('PARAM_WRONG')); return gpgme_error('PARAM_WRONG');
} }
msg.setParameter('fingerprint', this.fingerprint); msg.setParameter('fingerprint', this.fingerprint);
return (this.connection.post(msg)).then(function(result, error){ this.connection.post(msg).then(function(result, error){
if (error){ if (error){
reject(gpgme_error('GNUPG_ERROR',error.msg)); return gpgme_error('GNUPG_ERROR',error.msg);
} else if (result.hasOwnProperty(property)){ } else if (result.hasOwnProperty(property)){
resolve(result[property]); return result[property];
} }
else if (property == 'secret'){ else if (property == 'secret'){
// TBD property undefined means "not true" in case of secret? // TBD property undefined means "not true" in case of secret?
resolve(false); return false;
} else { } else {
reject(gpgme_error('CONN_UNEXPECTED_ANSWER')); return gpgme_error('CONN_UNEXPECTED_ANSWER');
} }
}, function(error){ }, function(error){
//TODO error handling return gpgme_error('GENERIC_ERROR');
});
}); });
}
}; };

View File

@ -61,6 +61,7 @@ export class GPGME_Keyring {
if (include_secret){ if (include_secret){
msg.setParameter('with-secret', true); msg.setParameter('with-secret', true);
} }
let me = this;
this.connection.post(msg).then(function(result){ this.connection.post(msg).then(function(result){
let fpr_list = []; let fpr_list = [];
@ -72,7 +73,7 @@ export class GPGME_Keyring {
fpr_list = result.keys; fpr_list = result.keys;
} }
for (let i=0; i < fpr_list.length; i++){ for (let i=0; i < fpr_list.length; i++){
let newKey = new GPGME_Key(fpr_list[i]); let newKey = new GPGME_Key(fpr_list[i], me._connection);
if (newKey instanceof GPGME_Key){ if (newKey instanceof GPGME_Key){
resultset.push(newKey); resultset.push(newKey);
} }

View File

@ -26,9 +26,10 @@
import { GpgME } from "./gpgmejs"; import { GpgME } from "./gpgmejs";
import {GPGME_Keyring} from "./Keyring" import {GPGME_Keyring} from "./Keyring"
import { GPGME_Key } from "./Key"; import { GPGME_Key, createKey } from "./Key";
import { isFingerprint } from "./Helpers" import { isFingerprint } from "./Helpers"
import { gpgme_error } from "./Errors" import { gpgme_error } from "./Errors"
import { Connection } from "./Connection";
export class GpgME_openpgpmode { export class GpgME_openpgpmode {
@ -47,7 +48,7 @@
initGpgME(connection, config = {}){ initGpgME(connection, config = {}){
if (connection && typeof(config) ==='object'){ if (connection && typeof(config) ==='object'){
this._config = config; this._config = config;
if (!this._GPGME){ if (!this._GpgME){
this._GpgME = new GpgME(connection, config); this._GpgME = new GpgME(connection, config);
} }
if (!this._keyring){ if (!this._keyring){
@ -223,7 +224,7 @@ class GPGME_Keyring_openpgpmode {
if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){ if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){
return Promise.reject(gpgme_error('PARAM_WRONG')); return Promise.reject(gpgme_error('PARAM_WRONG'));
} }
let key_to_delete = new GPGME_Key(key.fingerprint); let key_to_delete = createKey(key.fingerprint, this._gpgme_keyring_GpgME);
return key_to_delete.deleteKey(key.secret); return key_to_delete.deleteKey(key.secret);
} }
} }
@ -233,15 +234,22 @@ class GPGME_Keyring_openpgpmode {
* Offers the Key information as the openpgpmode wants * Offers the Key information as the openpgpmode wants
*/ */
class GPGME_Key_openpgpmode { class GPGME_Key_openpgpmode {
constructor(value){ constructor(value, connection){
this.init = value; this.init(value, connection);
} }
set init (value){ /**
* Can be either constructed using an existing GPGME_Key, or a fingerprint
* and a connection
* @param {String|GPGME_Key} value
* @param {Connection} connection
*/
init (value, connection){
if (!this._GPGME_Key && value instanceof GPGME_Key){ if (!this._GPGME_Key && value instanceof GPGME_Key){
this._GPGME_Key = value; this._GPGME_Key = value;
} else if (!this._GPGME_Key && isFingerprint(value)){ } else if (!this._GPGME_Key && isFingerprint(value) &&
this._GPGME_Key = new GPGME_Key(value); connection instanceof Connection){
this._GPGME_Key = createKey(value, connection);
} }
} }
@ -264,6 +272,8 @@ class GPGME_Key_openpgpmode {
/** /**
* creates GPGME_Key_openpgpmode from GPGME_Keys * creates GPGME_Key_openpgpmode from GPGME_Keys
* @param {GPGME_Key|Array<GPGME_Key>} input keys
* @returns {Array<GPGME_Key_openpgpmode>}
*/ */
function translateKeys(input){ function translateKeys(input){
if (!input){ if (!input){

View File

@ -36,9 +36,12 @@ function init(config){
return new Promise(function(resolve, reject){ return new Promise(function(resolve, reject){
let connection = new Connection; let connection = new Connection;
// TODO: Delayed reaction is ugly. We need to listen to the port's // TODO: Delayed reaction is ugly. We need to listen to the port's
// event listener in isConnected, but this takes some time (<5ms) to // event listener in isConnected, but in some cases this takes some
// disconnect if there is no successfull connection. // time (<5ms) to disconnect if there is no successfull connection.
let delayedreaction = function(){ let delayedreaction = function(){
if (connection === undefined) {
reject(gpgme_error('CONN_NO_CONNECT'));
}
if (connection.isConnected === true){ if (connection.isConnected === true){
if (_conf.api_style && _conf.api_style === 'gpgme_openpgpjs'){ if (_conf.api_style && _conf.api_style === 'gpgme_openpgpjs'){
resolve(new GpgME_openpgpmode(connection, _conf)); resolve(new GpgME_openpgpmode(connection, _conf));

View File

@ -1,12 +1,10 @@
import { gpgme_error } from "../src/Errors";
import {GPGME_Key} from "../src/Key"
export const helper_params = { export const helper_params = {
validLongId: '0A0A0A0A0A0A0A0A', validLongId: '0A0A0A0A0A0A0A0A',
validGPGME_Key: new GPGME_Key('ADDBC303B6D31026F5EB4591A27EABDF283121BB'), validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3',
validKeys: [new GPGME_Key('A1E3BC45BDC8E87B74F4392D53B151A1368E50F3'),
'ADDBC303B6D31026F5EB4591A27EABDF283121BB', 'ADDBC303B6D31026F5EB4591A27EABDF283121BB',
new GPGME_Key('EE17AEE730F88F1DE7713C54BBE0A4FF7851650A')], 'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'],
validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
'9AAE7A338A9A9A7A7A8A9A9A7A7A8A9A9A7A7DDA'], '9AAE7A338A9A9A7A7A8A9A9A7A7A8A9A9A7A7DDA'],
@ -14,10 +12,10 @@ export const helper_params = {
invalidFingerprint: [{hello:'World'}], invalidFingerprint: [{hello:'World'}],
invalidKeyArray: {curiosity:'uncat'}, invalidKeyArray: {curiosity:'uncat'},
invalidKeyArray_OneBad: [ invalidKeyArray_OneBad: [
new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), '12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08',
'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A',
'3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'],
invalidErrorCode: 'Please type in all your passwords.' invalidErrorCode: 'Please type in all your passwords.',
} }
export const message_params = { export const message_params = {
@ -28,10 +26,12 @@ export const message_params = {
valid_op: 'encrypt', valid_op: 'encrypt',
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', new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null] invalid_values_0: [2134, 'All your passwords', gpgme_error('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null]
} }
} }
export const whatever_params = {
four_invalid_params: ['<(((-<', '>°;==;~~', '^^', '{{{{o}}}}']
}
export default { export default {
helper_params: helper_params, helper_params: helper_params,