js: code cleanup (eslint)
[gpgme.git] / lang / js / src / gpgmejs.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  * Author(s):
21  *     Maximilian Krambach <mkrambach@intevation.de>
22  */
23
24
25 import {GPGME_Message, createMessage} from './Message';
26 import {toKeyIdArray} from './Helpers';
27 import { gpgme_error } from './Errors';
28 import { GPGME_Keyring } from './Keyring';
29
30 export class GpgME {
31     /**
32      * initializes GpgME by opening a nativeMessaging port
33      * TODO: add configuration
34      */
35     constructor(config){ //TODO config not parsed
36         this._config = config;
37     }
38
39     set Keyring(keyring){
40         if (keyring && keyring instanceof GPGME_Keyring){
41             this._Keyring = keyring;
42         }
43     }
44
45     get Keyring(){
46         if (!this._Keyring){
47             this._Keyring = new GPGME_Keyring;
48         }
49         return this._Keyring;
50     }
51
52     /**
53      * Encrypt (and optionally sign) a Message
54      * @param {String|Object} data text/data to be encrypted as String. Also
55      * accepts Objects with a getText method
56      * @param  {GPGME_Key|String|Array<String>|Array<GPGME_Key>} publicKeys
57      * Keys used to encrypt the message
58      * @param  {GPGME_Key|String|Array<String>|Array<GPGME_Key>} secretKeys
59      * (optional) Keys used to sign the message
60      * @param {Boolean} base64 (optional) The data is already considered to be
61      * in base64 encoding
62      * @param {Boolean} armor (optional) Request the output as armored block
63      * @param {Boolean} wildcard (optional) If true, recipient information will
64      *  not be added to the message
65      * @param {Object} additional use additional gpg options
66      * (refer to src/permittedOperations)
67      * @returns {Promise<Object>} Encrypted message:
68      *   data: The encrypted message
69      *   base64: Boolean indicating whether data is base64 encoded.
70      * @async
71      */
72     encrypt(data, publicKeys, secretKeys, base64=false, armor=true,
73         wildcard=false, additional = {}
74     ){
75         let msg = createMessage('encrypt');
76         if (msg instanceof Error){
77             return Promise.reject(msg);
78         }
79         msg.setParameter('armor', armor);
80         msg.setParameter('always-trust', true);
81         if (base64 === true) {
82             msg.setParameter('base64', true);
83         }
84         let pubkeys = toKeyIdArray(publicKeys);
85         msg.setParameter('keys', pubkeys);
86         let sigkeys = toKeyIdArray(secretKeys);
87         if (sigkeys.length > 0) {
88             msg.setParameter('signing_keys', sigkeys);
89         }
90         putData(msg, data);
91         if (wildcard === true){
92             msg.setParameter('throw-keyids', true);
93         }
94         if (additional){
95             let additional_Keys = Object.keys(additional);
96             for (let k = 0; k < additional_Keys.length; k++) {
97                 msg.setParameter(additional_Keys[k],
98                     additional[additional_Keys[k]]);
99             }
100         }
101         if (msg.isComplete === true){
102             return msg.post();
103         } else {
104             return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
105         }
106     }
107
108     /**
109     * Decrypt a Message
110     * @param {String|Object} data text/data to be decrypted. Accepts Strings
111     *  and Objects with a getText method
112     * @param {Boolean} base64 (optional) Response is expected to be base64
113     * encoded
114     * @returns {Promise<Object>} decrypted message:
115         data:   The decrypted data.  This may be base64 encoded.
116         base64: Boolean indicating whether data is base64 encoded.
117         mime:   A Boolean indicating whether the data is a MIME object.
118         signatures: Array of signature Objects TODO not yet implemented.
119             // should be an object that can tell if all signatures are valid .
120     * @async
121     */
122     decrypt(data, base64=false){
123         if (data === undefined){
124             return Promise.reject(gpgme_error('MSG_EMPTY'));
125         }
126         let msg = createMessage('decrypt');
127         if (base64 === true){
128             msg.expected = 'base64';
129         }
130         if (msg instanceof Error){
131             return Promise.reject(msg);
132         }
133         putData(msg, data);
134         return msg.post();
135     }
136
137     /**
138      * Sign a Message
139      * @param {String|Object} data text/data to be decrypted. Accepts Strings
140      * and Objects with a gettext methos
141      * @param {GPGME_Key|String|Array<String>|Array<GPGME_Key>} keys The
142      * key/keys to use for signing
143      * @param {*} mode The signing mode. Currently supported:
144      *      'clearsign': (default) The Message is embedded into the signature
145      *      'detached': The signature is stored separately
146      * @param {*} base64 input is considered base64
147      * @returns {Promise<Object>}
148      *    data: The resulting data. Includes the signature in clearsign mode
149      *    signature: The detached signature (if in detached mode)
150      * @async
151      */
152     sign(data, keys, mode='clearsign', base64=false) {
153         if (data === undefined){
154             return Promise.reject(gpgme_error('MSG_EMPTY'));
155         }
156         let key_arr = toKeyIdArray(keys);
157         if (key_arr.length === 0){
158             return Promise.reject(gpgme_error('MSG_NO_KEYS'));
159         }
160         let msg = createMessage('sign');
161
162         msg.setParameter('keys', key_arr);
163         if (base64 === true){
164             msg.setParameter('base64', true);
165         }
166         msg.setParameter('mode', mode);
167         putData(msg, data);
168         if (mode === 'detached') {
169             msg.expected = 'base64';
170         }
171         return new Promise(function(resolve,reject) {
172             msg.post().then( function(message) {
173                 if (mode === 'clearsign'){
174                     resolve({
175                         data: message.data}
176                     );
177                 } else if (mode === 'detached') {
178                     resolve({
179                         data: data,
180                         signature: message.data
181                     });
182                 }
183             }, function(error){
184                 reject(error);
185             });
186         });
187     }
188 }
189
190 /**
191  * Sets the data of the message, setting flags according on the data type
192  * @param {GPGME_Message} message The message where this data will be set
193  * @param {*} data The data to enter
194  */
195 function putData(message, data){
196     if (!message || !(message instanceof GPGME_Message) ) {
197         return gpgme_error('PARAM_WRONG');
198     }
199     if (!data){
200         return gpgme_error('PARAM_WRONG');
201     } else if (typeof(data) === 'string') {
202         message.setParameter('data', data);
203     } else if (
204         typeof(data) === 'object' &&
205         typeof(data.getText) === 'function'
206     ){
207         let txt = data.getText();
208         if (typeof(txt) === 'string'){
209             message.setParameter('data', txt);
210         } else {
211             return gpgme_error('PARAM_WRONG');
212         }
213
214     } else {
215         return gpgme_error('PARAM_WRONG');
216     }
217 }