js: Added browser testing for unit tests
[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('KEY_INVALID');
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     }
46 }
47
48 export class GPGME_Key {
49
50     constructor(fingerprint, connection){
51         this.fingerprint = fingerprint;
52         this.connection = connection;
53     }
54
55     set connection(conn){
56         if (this._connection instanceof Connection) {
57             gpgme_error('CONN_ALREADY_CONNECTED');
58         } else if (conn instanceof Connection ) {
59             this._connection = conn;
60         }
61     }
62
63     get connection(){
64         if (!this._fingerprint){
65             return gpgme_error('KEY_INVALID');
66         }
67         if (!this._connection instanceof Connection){
68             return gpgme_error('CONN_NO_CONNECT');
69         } else {
70             return this._connection;
71         }
72     }
73
74     set fingerprint(fpr){
75         if (isFingerprint(fpr) === true && !this._fingerprint){
76             this._fingerprint = fpr;
77         }
78     }
79
80     get fingerprint(){
81         if (!this._fingerprint){
82             return gpgme_error('KEY_INVALID');
83         }
84         return this._fingerprint;
85     }
86
87     /**
88      * hasSecret returns true if a secret subkey is included in this Key
89      */
90     get hasSecret(){
91         return this.checkKey('secret');
92     }
93
94     get isRevoked(){
95         return this.checkKey('revoked');
96     }
97
98     get isExpired(){
99         return this.checkKey('expired');
100     }
101
102     get isDisabled(){
103         return this.checkKey('disabled');
104     }
105
106     get isInvalid(){
107         return this.checkKey('invalid');
108     }
109
110     get canEncrypt(){
111         return this.checkKey('can_encrypt');
112     }
113
114     get canSign(){
115         return this.checkKey('can_sign');
116     }
117
118     get canCertify(){
119         return this.checkKey('can_certify');
120     }
121
122     get canAuthenticate(){
123         return this.checkKey('can_authenticate');
124     }
125
126     get isQualified(){
127         return this.checkKey('is_qualified');
128     }
129
130     get armored(){
131         let msg = createMessage ('export_key');
132         msg.setParameter('armor', true);
133         if (msg instanceof Error){
134             return gpgme_error('KEY_INVALID');
135         }
136         this.connection.post(msg).then(function(result){
137             return result.data;
138         });
139         // TODO return value not yet checked. Should result in an armored block
140         // in correct encoding
141     }
142
143     /**
144      * TODO returns true if this is the default key used to sign
145      */
146     get isDefault(){
147         throw('NOT_YET_IMPLEMENTED');
148     }
149
150     /**
151      * get the Key's subkeys as GPGME_Key objects
152      * @returns {Array<GPGME_Key>}
153      */
154     get subkeys(){
155         return this.checkKey('subkeys').then(function(result){
156             // TBD expecting a list of fingerprints
157             if (!Array.isArray(result)){
158                 result = [result];
159             }
160             let resultset = [];
161             for (let i=0; i < result.length; i++){
162                 let subkey = new GPGME_Key(result[i], this.connection);
163                 if (subkey instanceof GPGME_Key){
164                     resultset.push(subkey);
165                 }
166             }
167             return Promise.resolve(resultset);
168         }, function(error){
169             //TODO this.checkKey fails
170         });
171     }
172
173     /**
174      * creation time stamp of the key
175      * @returns {Date|null} TBD
176      */
177     get timestamp(){
178         return this.checkKey('timestamp');
179         //TODO GPGME: -1 if the timestamp is invalid, and 0 if it is not available.
180     }
181
182     /**
183      * The expiration timestamp of this key TBD
184      *  @returns {Date|null} TBD
185      */
186     get expires(){
187         return this.checkKey('expires');
188         // TODO convert to Date; check for 0
189     }
190
191     /**
192      * getter name TBD
193      * @returns {String|Array<String>} The user ids associated with this key
194      */
195     get userIds(){
196         return this.checkKey('uids');
197     }
198
199     /**
200      * @returns {String} The public key algorithm supported by this subkey
201      */
202     get pubkey_algo(){
203         return this.checkKey('pubkey_algo');
204     }
205
206     /**
207     * generic function to query gnupg information on a key.
208     * @param {*} property The gpgme-json property to check.
209     * TODO: check if Promise.then(return)
210     */
211     checkKey(property){
212         if (!this._fingerprint){
213             return gpgme_error('KEY_INVALID');
214         }
215         return gpgme_error('NOT_YET_IMPLEMENTED');
216         // TODO: async is not what is to be ecpected from Key information :(
217         if (!property || typeof(property) !== 'string' ||
218             !permittedOperations['keyinfo'].hasOwnProperty(property)){
219             return gpgme_error('PARAM_WRONG');
220         }
221         let msg = createMessage ('keyinfo');
222         if (msg instanceof Error){
223             return gpgme_error('PARAM_WRONG');
224         }
225         msg.setParameter('fingerprint', this.fingerprint);
226         this.connection.post(msg).then(function(result, error){
227             if (error){
228                 return gpgme_error('GNUPG_ERROR',error.msg);
229             } else if (result.hasOwnProperty(property)){
230                 return result[property];
231             }
232             else if (property == 'secret'){
233                 // TBD property undefined means "not true" in case of secret?
234                 return false;
235             } else {
236                 return gpgme_error('CONN_UNEXPECTED_ANSWER');
237             }
238         }, function(error){
239             return gpgme_error('GENERIC_ERROR');
240         });
241     }
242 };