/* gpgme.js - Javascript integration for gpgme
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
* SPDX-License-Identifier: LGPL-2.1+
*/
/**
* The key class allows to query the information defined in gpgme Key Objects
* (see https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html)
*
* This is a stub, as the gpgme-json side is not yet implemented
*
*/
import { isFingerprint } from './Helpers'
import { gpgme_error } from './Errors'
import { createMessage } from './Message';
import { permittedOperations } from './permittedOperations';
import { Connection } from './Connection';
export function createKey(fingerprint, parent){
if (!isFingerprint(fingerprint)){
return gpgme_error('PARAM_WRONG');
}
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);
} else {
return gpgme_error('PARAM_WRONG');
}
}
export class GPGME_Key {
constructor(fingerprint, connection){
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._fingerprint){
return gpgme_error('KEY_INVALID');
}
if (!this._connection instanceof Connection){
return gpgme_error('CONN_NO_CONNECT');
} else {
return this._connection;
}
}
set fingerprint(fpr){
if (isFingerprint(fpr) === true && !this._fingerprint){
this._fingerprint = fpr;
}
}
get fingerprint(){
if (!this._fingerprint){
return gpgme_error('KEY_INVALID');
}
return this._fingerprint;
}
/**
* hasSecret returns true if a secret subkey is included in this Key
*/
get hasSecret(){
return this.checkKey('secret');
}
get isRevoked(){
return this.checkKey('revoked');
}
get isExpired(){
return this.checkKey('expired');
}
get isDisabled(){
return this.checkKey('disabled');
}
get isInvalid(){
return this.checkKey('invalid');
}
get canEncrypt(){
return this.checkKey('can_encrypt');
}
get canSign(){
return this.checkKey('can_sign');
}
get canCertify(){
return this.checkKey('can_certify');
}
get canAuthenticate(){
return this.checkKey('can_authenticate');
}
get isQualified(){
return this.checkKey('is_qualified');
}
get armored(){
let msg = createMessage ('export_key');
msg.setParameter('armor', true);
if (msg instanceof Error){
return gpgme_error('KEY_INVALID');
}
this.connection.post(msg).then(function(result){
return result.data;
});
// TODO return value not yet checked. Should result in an armored block
// in correct encoding
}
/**
* TODO returns true if this is the default key used to sign
*/
get isDefault(){
throw('NOT_YET_IMPLEMENTED');
}
/**
* get the Key's subkeys as GPGME_Key objects
* @returns {Array}
*/
get subkeys(){
return this.checkKey('subkeys').then(function(result){
// TBD expecting a list of fingerprints
if (!Array.isArray(result)){
result = [result];
}
let resultset = [];
for (let i=0; i < result.length; i++){
let subkey = new GPGME_Key(result[i], this.connection);
if (subkey instanceof GPGME_Key){
resultset.push(subkey);
}
}
return Promise.resolve(resultset);
}, function(error){
//TODO this.checkKey fails
});
}
/**
* creation time stamp of the key
* @returns {Date|null} TBD
*/
get timestamp(){
return this.checkKey('timestamp');
//TODO GPGME: -1 if the timestamp is invalid, and 0 if it is not available.
}
/**
* The expiration timestamp of this key TBD
* @returns {Date|null} TBD
*/
get expires(){
return this.checkKey('expires');
// TODO convert to Date; check for 0
}
/**
* getter name TBD
* @returns {String|Array} The user ids associated with this key
*/
get userIds(){
return this.checkKey('uids');
}
/**
* @returns {String} The public key algorithm supported by this subkey
*/
get pubkey_algo(){
return this.checkKey('pubkey_algo');
}
/**
* generic function to query gnupg information on a key.
* @param {*} property The gpgme-json property to check.
* TODO: check if Promise.then(return)
*/
checkKey(property){
if (!this._fingerprint){
return gpgme_error('KEY_INVALID');
}
return gpgme_error('NOT_YET_IMPLEMENTED');
// TODO: async is not what is to be ecpected from Key information :(
if (!property || typeof(property) !== 'string' ||
!permittedOperations['keyinfo'].hasOwnProperty(property)){
return gpgme_error('PARAM_WRONG');
}
let msg = createMessage ('keyinfo');
if (msg instanceof Error){
return gpgme_error('PARAM_WRONG');
}
msg.setParameter('fingerprint', this.fingerprint);
this.connection.post(msg).then(function(result, error){
if (error){
return gpgme_error('GNUPG_ERROR',error.msg);
} else if (result.hasOwnProperty(property)){
return result[property];
}
else if (property == 'secret'){
// TBD property undefined means "not true" in case of secret?
return false;
} else {
return gpgme_error('CONN_UNEXPECTED_ANSWER');
}
}, function(error){
return gpgme_error('GENERIC_ERROR');
});
}
};