js: fixing errors found by testing
[gpgme.git] / lang / js / src / Key.js
1 /* gpgme.js - Javascript integration for gpgme
2  * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1+
19  */
20
21 /**
22  * The key class allows to query the information defined in gpgme Key Objects
23  * (see https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html)
24  *
25  * This is a stub, as the gpgme-json side is not yet implemented
26  *
27  */
28
29 import { isFingerprint } from './Helpers'
30 import { gpgme_error } from './Errors'
31 import { createMessage } from './Message';
32 import { permittedOperations } from './permittedOperations';
33 import { Connection } from './Connection';
34
35
36 export function createKey(fingerprint, parent){
37     if (!isFingerprint(fingerprint)){
38         return gpgme_error('PARAM_WRONG');
39     }
40     if ( parent instanceof Connection){
41         return new GPGME_Key(fingerprint, parent);
42     } else if ( parent.hasOwnProperty('connection') &&
43         parent.connection instanceof Connection){
44             return new GPGME_Key(fingerprint, parent.connection);
45     } else {
46         return gpgme_error('PARAM_WRONG');
47     }
48 }
49
50 export class GPGME_Key {
51
52     constructor(fingerprint, connection){
53         this.fingerprint = fingerprint;
54         this.connection = connection;
55     }
56
57     set connection(conn){
58         if (this._connection instanceof Connection) {
59             gpgme_error('CONN_ALREADY_CONNECTED');
60         } else if (conn instanceof Connection ) {
61             this._connection = conn;
62         }
63     }
64
65     get connection(){
66         if (!this._fingerprint){
67             return gpgme_error('KEY_INVALID');
68         }
69         if (!this._connection instanceof Connection){
70             return gpgme_error('CONN_NO_CONNECT');
71         } else {
72             return this._connection;
73         }
74     }
75
76     set fingerprint(fpr){
77         if (isFingerprint(fpr) === true && !this._fingerprint){
78             this._fingerprint = fpr;
79         }
80     }
81
82     get fingerprint(){
83         if (!this._fingerprint){
84             return gpgme_error('KEY_INVALID');
85         }
86         return this._fingerprint;
87     }
88
89     /**
90      * hasSecret returns true if a secret subkey is included in this Key
91      */
92     get hasSecret(){
93         return this.checkKey('secret');
94     }
95
96     get isRevoked(){
97         return this.checkKey('revoked');
98     }
99
100     get isExpired(){
101         return this.checkKey('expired');
102     }
103
104     get isDisabled(){
105         return this.checkKey('disabled');
106     }
107
108     get isInvalid(){
109         return this.checkKey('invalid');
110     }
111
112     get canEncrypt(){
113         return this.checkKey('can_encrypt');
114     }
115
116     get canSign(){
117         return this.checkKey('can_sign');
118     }
119
120     get canCertify(){
121         return this.checkKey('can_certify');
122     }
123
124     get canAuthenticate(){
125         return this.checkKey('can_authenticate');
126     }
127
128     get isQualified(){
129         return this.checkKey('is_qualified');
130     }
131
132     get armored(){
133         let msg = createMessage ('export_key');
134         msg.setParameter('armor', true);
135         if (msg instanceof Error){
136             return gpgme_error('KEY_INVALID');
137         }
138         this.connection.post(msg).then(function(result){
139             return result.data;
140         });
141         // TODO return value not yet checked. Should result in an armored block
142         // in correct encoding
143     }
144
145     /**
146      * TODO returns true if this is the default key used to sign
147      */
148     get isDefault(){
149         throw('NOT_YET_IMPLEMENTED');
150     }
151
152     /**
153      * get the Key's subkeys as GPGME_Key objects
154      * @returns {Array<GPGME_Key>}
155      */
156     get subkeys(){
157         return this.checkKey('subkeys').then(function(result){
158             // TBD expecting a list of fingerprints
159             if (!Array.isArray(result)){
160                 result = [result];
161             }
162             let resultset = [];
163             for (let i=0; i < result.length; i++){
164                 let subkey = new GPGME_Key(result[i], this.connection);
165                 if (subkey instanceof GPGME_Key){
166                     resultset.push(subkey);
167                 }
168             }
169             return Promise.resolve(resultset);
170         }, function(error){
171             //TODO this.checkKey fails
172         });
173     }
174
175     /**
176      * creation time stamp of the key
177      * @returns {Date|null} TBD
178      */
179     get timestamp(){
180         return this.checkKey('timestamp');
181         //TODO GPGME: -1 if the timestamp is invalid, and 0 if it is not available.
182     }
183
184     /**
185      * The expiration timestamp of this key TBD
186      *  @returns {Date|null} TBD
187      */
188     get expires(){
189         return this.checkKey('expires');
190         // TODO convert to Date; check for 0
191     }
192
193     /**
194      * getter name TBD
195      * @returns {String|Array<String>} The user ids associated with this key
196      */
197     get userIds(){
198         return this.checkKey('uids');
199     }
200
201     /**
202      * @returns {String} The public key algorithm supported by this subkey
203      */
204     get pubkey_algo(){
205         return this.checkKey('pubkey_algo');
206     }
207
208     /**
209     * generic function to query gnupg information on a key.
210     * @param {*} property The gpgme-json property to check.
211     * TODO: check if Promise.then(return)
212     */
213     checkKey(property){
214         if (!this._fingerprint){
215             return gpgme_error('KEY_INVALID');
216         }
217         return gpgme_error('NOT_YET_IMPLEMENTED');
218         // TODO: async is not what is to be ecpected from Key information :(
219         if (!property || typeof(property) !== 'string' ||
220             !permittedOperations['keyinfo'].hasOwnProperty(property)){
221             return gpgme_error('PARAM_WRONG');
222         }
223         let msg = createMessage ('keyinfo');
224         if (msg instanceof Error){
225             return gpgme_error('PARAM_WRONG');
226         }
227         msg.setParameter('fingerprint', this.fingerprint);
228         this.connection.post(msg).then(function(result, error){
229             if (error){
230                 return gpgme_error('GNUPG_ERROR',error.msg);
231             } else if (result.hasOwnProperty(property)){
232                 return result[property];
233             }
234             else if (property == 'secret'){
235                 // TBD property undefined means "not true" in case of secret?
236                 return false;
237             } else {
238                 return gpgme_error('CONN_UNEXPECTED_ANSWER');
239             }
240         }, function(error){
241             return gpgme_error('GENERIC_ERROR');
242         });
243     }
244 };