js: implement import/delete Key, some fixes
[gpgme.git] / lang / js / src / Keyring.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 import {createMessage} from './Message';
22 import {createKey} from './Key';
23 import { isFingerprint } from './Helpers';
24 import { gpgme_error } from './Errors';
25
26 export class GPGME_Keyring {
27     constructor(){
28     }
29
30     /**
31      * @param {String} pattern (optional) pattern A pattern to search for,
32      * in userIds or KeyIds
33      * @param {Boolean} prepare_sync (optional, default true) if set to true,
34      * Key.armor and Key.hasSecret will be called, so they can be used
35      * inmediately. This allows for full synchronous use. If set to false,
36      * these will initially only be available as Promises in getArmor() and
37      * getHasSecret()
38      * @returns {Promise.<Array<GPGME_Key>>}
39      *
40      */
41     getKeys(pattern, prepare_sync){
42         return new Promise(function(resolve, reject) {
43             let msg = createMessage('keylist');
44             if (pattern !== undefined){
45                 msg.setParameter('keys', pattern);
46             }
47             msg.setParameter('sigs', true);
48             msg.post().then(function(result){
49                 let resultset = [];
50                 let promises = [];
51                 if (result.keys.length === 0){
52                     resolve([]);
53                 } else {
54                     for (let i=0; i< result.keys.length; i++){
55                         let k = createKey(result.keys[i].fingerprint);
56                         k.setKeyData(result.keys[i]);
57                         if (prepare_sync === true){
58                             promises.push(k.getArmor());
59                             promises.push(k.getHasSecret());
60                         }
61                         resultset.push(k);
62                     }
63                     if (promises.length > 0) {
64                         Promise.all(promises).then(function() {
65                             resolve(resultset);
66                         }, function(error){
67                             reject(error);
68                         });
69                     } else {
70                         resolve(resultset);
71                     }
72                 }
73             });
74         });
75     }
76
77     /**
78      * Fetches the armored public Key blocks for all Keys matchin the pattern
79      * (if no pattern is given, fetches all known to gnupg)
80      * @param {String|Array<String>} pattern (optional)
81      * @returns {Promise<String>} Armored Key blocks
82      */
83     getKeysArmored(pattern) {
84         return new Promise(function(resolve, reject) {
85             let msg = createMessage('export');
86             msg.setParameter('armor', true);
87             if (pattern !== undefined){
88                 msg.setParameter('keys', pattern);
89             }
90             msg.post().then(function(result){
91                 resolve(result.data);
92             }, function(error){
93                 reject(error);
94             });
95         });
96     }
97
98     // getDefaultKey() Big TODO
99
100     /**
101      *
102      * @param {String} armored Armored Key block of the Kex(s) to be imported into gnupg
103      * @param {Boolean} prepare_sync prepare the keys for synched use (see getKeys()).
104      * @returns {Promise<Array<Object>>} An array of objects for the Keys considered.
105     *       Key.key The key itself as a GPGME_Key
106      *      Key.status String:
107      *          'nochange' if the Key was not changed,
108      *          'newkey' if the Key was imported in gpg, and did not exist previously,
109      *          'change' if the key existed, but details were updated. For details,
110      *              Key.changes is available.
111      *      Key.changes.userId: Boolean userIds changed
112      *      Key.changes.signature: Boolean signatures changed
113      *      Key.changes.subkey: Boolean subkeys changed
114      * // TODO: not yet implemented: Information about Keys that failed
115      *          (e.g. malformed Keys, secretKeys are not accepted)
116      */
117     importKey(armored, prepare_sync) {
118         if (!armored || typeof(armored) !== 'string'){
119             return Promise.reject(gpgme_error('PARAM_WRONG'));
120         }
121         let me = this;
122         return new Promise(function(resolve, reject){
123             let msg = createMessage('import');
124             msg.setParameter('data', armored);
125             msg.post().then(function(response){
126                 let infos = {};
127                 let fprs = [];
128                 for (var res=0; res < response.result[0].imports.length; res++) {
129                     let result = response.result[0].imports[res];
130                     let status = '';
131                     if (result.status === 0){
132                         status = 'nochange';
133                     } else if ((result.status & 1) === 1){
134                         status = 'newkey';
135                     } else {
136                         status = 'change';
137                     }
138                     let changes = {};
139                     changes.userId = (result.status & 2) === 2;
140                     changes.signature = (result.status & 4) === 4;
141                     changes.subkey = (result.status & 8) === 8;
142                     //16 new secret key: not implemented
143
144                     fprs.push(result.fingerprint);
145                     infos[result.fingerprint] = {
146                         changes: changes,
147                         status: status
148                     };
149                 }
150                 let resultset = [];
151                 if (prepare_sync === true){
152                     me.getKeys(fprs, true).then(function(result){
153                         for (let i=0; i < result.length; i++) {
154                             resultset.push({
155                                 key: result[i],
156                                 changes: infos[result[i].fingerprint].changes,
157                                 status: infos[result[i].fingerprint].status
158                             });
159                         }
160                         resolve(resultset);
161                     }, function(error){
162                         reject(error);
163                     });
164                 } else {
165                     for (let i=0; i < fprs.length; i++) {
166                         resultset.push({
167                             key: createKey(fprs[i]),
168                             changes: infos[fprs[i]].changes,
169                             status: infos[fprs[i]].status
170                         });
171                     }
172                     resolve(resultset);
173                 }
174
175             }, function(error){
176                 reject(error);
177             });
178
179
180         });
181
182
183     }
184
185     deleteKey(fingerprint){
186         if (isFingerprint(fingerprint) === true) {
187             let key = createKey(fingerprint);
188             key.delete();
189         }
190     }
191
192     // generateKey
193 }