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