js: code cleanup (eslint)
[gpgme.git] / lang / js / src / Message.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 import { permittedOperations } from './permittedOperations';
25 import { gpgme_error } from './Errors';
26 import { Connection } from './Connection';
27
28 export function createMessage(operation){
29     if (typeof(operation) !== 'string'){
30         return gpgme_error('PARAM_WRONG');
31     }
32     if (permittedOperations.hasOwnProperty(operation)){
33         return new GPGME_Message(operation);
34     } else {
35         return gpgme_error('MSG_WRONG_OP');
36     }
37 }
38
39 /**
40  * Prepares a communication request. It checks operations and parameters in
41  * ./permittedOperations.
42  * @param {String} operation
43  */
44 export class GPGME_Message {
45     //TODO getter
46
47     constructor(operation){
48         this.operation = operation;
49         this._expected = 'string';
50     }
51
52     set operation (op){
53         if (typeof(op) === 'string'){
54             if (!this._msg){
55                 this._msg = {};
56             }
57             if (!this._msg.op & permittedOperations.hasOwnProperty(op)){
58                 this._msg.op = op;
59             }
60         }
61     }
62
63     get operation(){
64         return this._msg.op;
65     }
66
67     set expected(string){
68         if (string === 'base64'){
69             this._expected = 'base64';
70         }
71     }
72
73     get expected() {
74         if (this._expected === 'base64'){
75             return this._expected;
76         }
77         return 'string';
78     }
79
80     /**
81      * Sets a parameter for the message. Note that the operation has to be set
82      * first, to be able to check if the parameter is permittted
83      * @param {String} param Parameter to set
84      * @param {any} value Value to set //TODO: Some type checking
85      * @returns {Boolean} If the parameter was set successfully
86      */
87     setParameter(param,value){
88         if (!param || typeof(param) !== 'string'){
89             return gpgme_error('PARAM_WRONG');
90         }
91         let po = permittedOperations[this._msg.op];
92         if (!po){
93             return gpgme_error('MSG_WRONG_OP');
94         }
95         let poparam = null;
96         if (po.required.hasOwnProperty(param)){
97             poparam = po.required[param];
98         } else if (po.optional.hasOwnProperty(param)){
99             poparam = po.optional[param];
100         } else {
101             return gpgme_error('PARAM_WRONG');
102         }
103         let checktype = function(val){
104             switch(typeof(val)){
105             case 'string':
106                 if (poparam.allowed.indexOf(typeof(val)) >= 0
107                         && val.length > 0) {
108                     return true;
109                 }
110                 return gpgme_error('PARAM_WRONG');
111             case 'number':
112                 if (
113                     poparam.allowed.indexOf('number') >= 0
114                         && isNaN(value) === false){
115                     return true;
116                 }
117                 return gpgme_error('PARAM_WRONG');
118
119             case 'boolean':
120                 if (poparam.allowed.indexOf('boolean') >= 0){
121                     return true;
122                 }
123                 return gpgme_error('PARAM_WRONG');
124             case 'object':
125                 if (Array.isArray(val)){
126                     if (poparam.array_allowed !== true){
127                         return gpgme_error('PARAM_WRONG');
128                     }
129                     for (let i=0; i < val.length; i++){
130                         let res = checktype(val[i]);
131                         if (res !== true){
132                             return res;
133                         }
134                     }
135                     if (val.length > 0) {
136                         return true;
137                     }
138                 } else if (val instanceof Uint8Array){
139                     if (poparam.allowed.indexOf('Uint8Array') >= 0){
140                         return true;
141                     }
142                     return gpgme_error('PARAM_WRONG');
143                 } else {
144                     return gpgme_error('PARAM_WRONG');
145                 }
146                 break;
147             default:
148                 return gpgme_error('PARAM_WRONG');
149             }
150         };
151         let typechecked = checktype(value);
152         if (typechecked !== true){
153             return typechecked;
154         }
155         if (poparam.hasOwnProperty('allowed_data')){
156             if (poparam.allowed_data.indexOf(value) < 0){
157                 return gpgme_error('PARAM_WRONG');
158             }
159         }
160         this._msg[param] = value;
161         return true;
162     }
163
164     /**
165      * Check if the message has the minimum requirements to be sent, according
166      * to the definitions in permittedOperations
167      * @returns {Boolean}
168      */
169     get isComplete(){
170         if (!this._msg.op){
171             return false;
172         }
173         let reqParams = Object.keys(
174             permittedOperations[this._msg.op].required);
175         let msg_params = Object.keys(this._msg);
176         for (let i=0; i < reqParams.length; i++){
177             if (msg_params.indexOf(reqParams[i]) < 0){
178                 return false;
179             }
180         }
181         return true;
182     }
183
184     /**
185      * Returns the prepared message with parameters and completeness checked
186      * @returns {Object|null} Object to be posted to gnupg, or null if
187      * incomplete
188      */
189     get message(){
190         if (this.isComplete === true){
191             return this._msg;
192         }
193         else {
194             return null;
195         }
196
197     }
198
199     post(){
200         let me = this;
201         return new Promise(function(resolve, reject) {
202             if (me.isComplete === true) {
203                 let conn  = new Connection;
204                 conn.post(me).then(function(response) {
205                     resolve(response);
206                 }, function(reason) {
207                     reject(gpgme_error('GNUPG_ERROR', reason));
208                 });
209             }
210             else {
211                 reject(gpgme_error('MSG_INCOMPLETE'));
212             }
213         });
214     }
215 }