js: more Keyring/Key handling
-- * src/Keys.js - made setKeyData more consistent with other methods - added convenience methods (Key.armored, Key.hasSecret) - Added a Key delete function * src/Keyring.js: - added a getkeysArmored which allows for bulk export of public Keys gpgmejs: - removed deleteKey. It is now a method of the Key itself - Encrypt: Added some common options as parameter, and the possibility to set all allowed flags via an additional Object
This commit is contained in:
parent
53ce2b94bc
commit
332b4adbcc
@ -71,6 +71,10 @@ const err_list = {
|
||||
msg:'This key does not exist in GPG',
|
||||
type: 'error'
|
||||
},
|
||||
'KEY_NO_INIT': {
|
||||
msg:'This property has not been retrieved yet from GPG',
|
||||
type: 'error'
|
||||
}
|
||||
// generic
|
||||
'PARAM_WRONG':{
|
||||
msg: 'Invalid parameter was found',
|
||||
|
@ -93,56 +93,31 @@ export class GPGME_Key {
|
||||
} else if (this._data.fingerprint !== data.fingerprint){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
|
||||
let booleans = ['expired', 'disabled','invalid','can_encrypt',
|
||||
'can_sign','can_certify','can_authenticate','secret',
|
||||
'is_qualified'];
|
||||
for (let b =0; b < booleans.length; b++) {
|
||||
if (
|
||||
!data.hasOwnProperty(booleans[b]) ||
|
||||
typeof(data[booleans[b]]) !== 'boolean'
|
||||
){
|
||||
let dataKeys = Object.keys(data);
|
||||
for (let i=0; i< dataKeys.length; i++){
|
||||
if (!validKeyProperties.hasOwnProperty(dataKeys[i])){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
this._data[booleans[b]] = data[booleans[b]];
|
||||
}
|
||||
if (typeof(data.protocol) !== 'string'){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
// TODO check valid protocols?
|
||||
this._data.protocol = data.protocol;
|
||||
|
||||
if (typeof(data.owner_trust) !== 'string'){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
// TODO check valid values?
|
||||
this._data.owner_trust = data.owner_trust;
|
||||
|
||||
// TODO: what about origin ?
|
||||
if (!Number.isInteger(data.last_update)){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
this._data.last_update = data.last_update;
|
||||
|
||||
this._data.subkeys = [];
|
||||
if (data.hasOwnProperty('subkeys')){
|
||||
if (!Array.isArray(data.subkeys)){
|
||||
if (validKeyProperties[dataKeys[i]](data[dataKeys[i]]) !== true ){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
for (let i=0; i< data.subkeys.length; i++) {
|
||||
this._data.subkeys.push(
|
||||
new GPGME_Subkey(data.subkeys[i]));
|
||||
}
|
||||
}
|
||||
|
||||
this._data.userids = [];
|
||||
if (data.hasOwnProperty('userids')){
|
||||
if (!Array.isArray(data.userids)){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
for (let i=0; i< data.userids.length; i++) {
|
||||
this._data.userids.push(
|
||||
new GPGME_UserId(data.userids[i]));
|
||||
switch (dataKeys[i]){
|
||||
case 'subkeys':
|
||||
this._data.subkeys = [];
|
||||
for (let i=0; i< data.subkeys.length; i++) {
|
||||
this._data.subkeys.push(
|
||||
new GPGME_Subkey(data.subkeys[i]));
|
||||
}
|
||||
break;
|
||||
case 'userids':
|
||||
this._data.userids = [];
|
||||
for (let i=0; i< data.userids.length; i++) {
|
||||
this._data.userids.push(
|
||||
new GPGME_UserId(data.userids[i]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this._data[dataKeys[i]] = data[dataKeys[i]];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@ -161,7 +136,9 @@ export class GPGME_Key {
|
||||
if (cached === false) {
|
||||
let me = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (property === 'armor'){
|
||||
if (!validKeyProperties.hasOwnProperty(property)){
|
||||
reject('PARAM_WRONG');
|
||||
} else if (property === 'armored'){
|
||||
resolve(me.getArmor());
|
||||
} else if (property === 'hasSecret'){
|
||||
resolve(me.getHasSecret());
|
||||
@ -173,15 +150,23 @@ export class GPGME_Key {
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!this._data.hasOwnProperty(property)){
|
||||
} else {
|
||||
if (!validKeyProperties.hasOwnProperty(property)){
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (!this._data.hasOwnProperty(property)){
|
||||
return gpgme_error('KEY_NO_INIT');
|
||||
} else {
|
||||
return (this._data[property]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get armored () {
|
||||
return this.get('armored');
|
||||
//TODO exception if empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the Key from gnupg
|
||||
*/
|
||||
@ -207,15 +192,6 @@ export class GPGME_Key {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the armored block of the non- secret parts of the Key.
|
||||
* @returns {String} the armored Key block.
|
||||
* Notice that this may be outdated cached info. Use the async getArmor if
|
||||
* you need the most current info
|
||||
*/
|
||||
|
||||
// get armor(){ TODO }
|
||||
|
||||
/**
|
||||
* Query the armored block of the non- secret parts of the Key directly
|
||||
* from gpg.
|
||||
@ -279,6 +255,49 @@ export class GPGME_Key {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to be directly used as properties of the 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @returns {String} The armored public Key block
|
||||
*/
|
||||
get armored(){
|
||||
return this.get('armored', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Boolean} If the key is considered a "private Key",
|
||||
* i.e. owns 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 {Boolean} 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);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,3 +472,78 @@ const validSubKeyProperties = {
|
||||
return (Number.isInteger(value) && value > 0);
|
||||
}
|
||||
}
|
||||
const validKeyProperties = {
|
||||
//TODO better validation?
|
||||
'fingerprint': function(value){
|
||||
return isFingerprint(value);
|
||||
},
|
||||
'armored': function(value){
|
||||
return typeof(value === 'string');
|
||||
},
|
||||
'revoked': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'expired': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'disabled': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'invalid': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'can_encrypt': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'can_sign': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'can_certify': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'can_authenticate': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'secret': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'is_qualified': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
},
|
||||
'protocol': function(value){
|
||||
return typeof(value) === 'string';
|
||||
//TODO check for implemented ones
|
||||
},
|
||||
'issuer_serial': function(value){
|
||||
return typeof(value) === 'string';
|
||||
},
|
||||
'issuer_name': function(value){
|
||||
return typeof(value) === 'string';
|
||||
},
|
||||
'chain_id': function(value){
|
||||
return typeof(value) === 'string';
|
||||
},
|
||||
'owner_trust': function(value){
|
||||
return typeof(value) === 'string';
|
||||
},
|
||||
'last_update': function(value){
|
||||
return (Number.isInteger(value));
|
||||
//TODO undefined/null possible?
|
||||
},
|
||||
'origin': function(value){
|
||||
return (Number.isInteger(value));
|
||||
},
|
||||
'subkeys': function(value){
|
||||
return (Array.isArray(value));
|
||||
},
|
||||
'userids': function(value){
|
||||
return (Array.isArray(value));
|
||||
},
|
||||
'tofu': function(value){
|
||||
return (Array.isArray(value));
|
||||
},
|
||||
'hasSecret': function(value){
|
||||
return typeof(value) === 'boolean';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
import {createMessage} from './Message'
|
||||
import {GPGME_Key, createKey} from './Key'
|
||||
import { isFingerprint } from './Helpers';
|
||||
import { isFingerprint, toKeyIdArray } from './Helpers';
|
||||
import { gpgme_error } from './Errors';
|
||||
|
||||
export class GPGME_Keyring {
|
||||
@ -43,10 +43,10 @@ export class GPGME_Keyring {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let msg;
|
||||
msg = createMessage('keylist');
|
||||
if (pattern && typeof(pattern) === 'string'){
|
||||
if (pattern !== undefined){
|
||||
msg.setParameter('keys', pattern);
|
||||
}
|
||||
msg.setParameter('sigs', true); //TODO do we need this?
|
||||
msg.setParameter('sigs', true);
|
||||
msg.post().then(function(result){
|
||||
let resultset = [];
|
||||
let promises = [];
|
||||
@ -72,10 +72,30 @@ export class GPGME_Keyring {
|
||||
});
|
||||
});
|
||||
}
|
||||
// TODO:
|
||||
// deleteKey(key, include_secret=false)
|
||||
// getKeysArmored(pattern) //just dump all armored keys
|
||||
|
||||
/**
|
||||
* Fetches the armored public Key blocks for all Keys matchin the pattern
|
||||
* (if no pattern is given, fetches all known to gnupg)
|
||||
* @param {String|Array<String>} pattern (optional)
|
||||
* @returns {Promise<String>} Armored Key blocks
|
||||
*/
|
||||
getKeysArmored(pattern) {
|
||||
if (pattern)
|
||||
return new Promise(function(resolve, reject) {
|
||||
let msg = createMessage('export');
|
||||
msg.setParameter('armor', true);
|
||||
if (pattern !== undefined){
|
||||
msg.setParameter('keys', pattern);
|
||||
}
|
||||
msg.post().then(function(result){
|
||||
resolve(result.data);
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
// getDefaultKey() Big TODO
|
||||
// importKeys(armoredKeys)
|
||||
// generateKey --> TODO (Andre noch anfragen!)
|
||||
|
||||
};
|
||||
|
@ -46,28 +46,48 @@ export class GpgME {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} data text/data to be encrypted as String
|
||||
* 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<String>|Array<GPGME_Key>} publicKeys Keys used to encrypt the message
|
||||
* @param {GPGME_Key|String|Array<String>|Array<GPGME_Key>} secretKeys (optional) Keys used to sign the message
|
||||
* @param {Boolean} base64 (optional) The data is already considered to be in base64 encoding
|
||||
* @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<Object>} Encrypted message:
|
||||
* data: The encrypted message
|
||||
* base64: Boolean indicating whether data is base64 encoded.
|
||||
* @async
|
||||
*/
|
||||
encrypt(data, publicKeys, base64=false, wildcard=false){
|
||||
|
||||
encrypt(data, publicKeys, secretKeys, base64=false, armor=true,
|
||||
wildcard=false, additional = {}
|
||||
){
|
||||
let msg = createMessage('encrypt');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg)
|
||||
}
|
||||
// TODO temporary
|
||||
msg.setParameter('armor', true);
|
||||
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 {
|
||||
@ -76,16 +96,17 @@ export class GpgME {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} data TODO base64? Message with the encrypted data
|
||||
* @param {Boolean} base64 (optional) Response should stay base64
|
||||
* 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<Object>} decrypted message:
|
||||
data: The decrypted data. This may be base64 encoded.
|
||||
base64: Boolean indicating whether data is base64 encoded.
|
||||
mime: A Boolean indicating whether the data is a MIME object.
|
||||
info: An optional object with extra information.
|
||||
signatures: Array of signature Objects TODO not yet implemented.
|
||||
// should be an object that can tell if all signatures are valid etc.
|
||||
* @async
|
||||
*/
|
||||
|
||||
decrypt(data, base64=false){
|
||||
if (data === undefined){
|
||||
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
||||
@ -99,10 +120,22 @@ export class GpgME {
|
||||
}
|
||||
putData(msg, data);
|
||||
return msg.post();
|
||||
|
||||
}
|
||||
|
||||
sign(data, keys, mode='clearsign', base64=false) { //sender
|
||||
/**
|
||||
* 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<String>|Array<GPGME_Key>} 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<Object>}
|
||||
* data: The resulting data. In clearsign mode this includes the signature
|
||||
* 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'));
|
||||
}
|
||||
@ -139,38 +172,10 @@ export class GpgME {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
deleteKey(key, delete_secret = false, no_confirm = false){
|
||||
return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED'));
|
||||
let msg = createMessage('deletekey');
|
||||
if (msg instanceof Error){
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
let key_arr = toKeyIdArray(key);
|
||||
if (key_arr.length !== 1){
|
||||
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
|
||||
}
|
||||
if (no_confirm === true){ //TODO: Do we want this hidden deep in the code?
|
||||
msg.setParameter('delete_force', true);
|
||||
// TBD
|
||||
}
|
||||
if (msg.isComplete === true){
|
||||
return msg.post();
|
||||
} else {
|
||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data of the message
|
||||
* 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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user