aboutsummaryrefslogtreecommitdiffstats
path: root/lang/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'lang/js/src')
-rw-r--r--lang/js/src/Connection.js208
-rw-r--r--lang/js/src/Helpers.js84
-rw-r--r--lang/js/src/Message.js109
-rw-r--r--lang/js/src/gpgmejs.js282
-rw-r--r--lang/js/src/gpgmejs_openpgpjs.js156
-rw-r--r--lang/js/src/index.js33
-rw-r--r--lang/js/src/permittedOperations.js75
7 files changed, 714 insertions, 233 deletions
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
index e8fea542..784929e9 100644
--- a/lang/js/src/Connection.js
+++ b/lang/js/src/Connection.js
@@ -1,76 +1,180 @@
+import { GPGME_Message } from "./Message";
+
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
/**
* A connection port will be opened for each communication between gpgmejs and
* gnupg. It should be alive as long as there are additional messages to be
* expected.
*/
+import { permittedOperations } from './permittedOperations'
-export function Connection(){
- if (!this.connection){
- this.connection = connect();
- this._msg = {
- 'always-trust': true,
- // 'no-encrypt-to': false,
- // 'no-compress': true,
- // 'throw-keyids': false,
- // 'wrap': false,
- 'armor': true,
- 'base64': false
- };
- };
+export class Connection{
- this.disconnect = function () {
- if (this.connection){
- this.connection.disconnect();
+ /**
+ * Opens and closes a port. Thus, it is made sure that the connection can
+ * be used.
+ * THIS BEHAVIOUR MAY CHANGE!
+ * discussion is to keep a port alive as long as the context stays the same
+ *
+ * TODO returns nothing, but triggers exceptions if not successfull
+ */
+ constructor(){
+ this._connection = chrome.runtime.connectNative('gpgmejson');
+ if (!this._connection){
+ if (chrome.runtime.lastError){
+ throw('NO_CONNECT_RLE');
+ } else {
+ throw('NO_CONNECT');
+ }
}
- };
+ this._flags = {}; // TODO general config
+ }
/**
- * Sends a message and resolves with the answer.
- * @param {*} operation The interaction requested from gpgme
- * @param {*} message A json-capable object to pass the operation details.
- * TODO: _msg should contain configurable parameters
+ * Immediately closes the open port
*/
- this.post = function(operation, message){
- let timeout = 5000;
- let me = this;
- if (!message || !operation){
- return Promise.reject('no message'); // TBD
+ disconnect() {
+ if (this._connection){
+ this._connection.disconnect();
}
+ }
- let keys = Object.keys(message);
- for (let i=0; i < keys.length; i++){
- let property = keys[i];
- me._msg[property] = message[property];
+ /**
+ * Sends a message and resolves with the answer.
+ * @param {GPGME_Message} message
+ * @returns {Promise<Object>} the gnupg answer, or rejection with error
+ * information
+ * TODO: better/more consistent error information
+ */
+ post(message){
+ if (!message || !message instanceof GPGME_Message){
+ return Promise.reject('ERR_NO_MSG');
}
- me._msg['op'] = operation;
- // TODO fancier checks if what we want is consistent with submitted content
+ // let timeout = 5000; //TODO config
+ let me = this;
return new Promise(function(resolve, reject){
- me.connection.onMessage.addListener(function(msg) {
+ let answer = new Answer(message.op);
+ let listener = function(msg) {
if (!msg){
- reject('empty answer.');
- }
- if (msg.type === "error"){
+ me._connection.onMessage.removeListener(listener)
+ reject('EMPTY_ANSWER');
+ } else if (msg.type === "error"){
+ me._connection.onMessage.removeListener(listener)
reject(msg.msg);
+ } else {
+ answer.add(msg);
+ if (msg.more === true){
+ me._connection.postMessage({'op': 'getmore'});
+ } else {
+ me._connection.onMessage.removeListener(listener)
+ resolve(answer.message);
+ }
}
- resolve(msg);
- });
+ };
- me.connection.postMessage(me._msg);
- setTimeout(
- function(){
- me.disconnect();
- reject('Timeout');
- }, timeout);
+ me._connection.onMessage.addListener(listener);
+ me._connection.postMessage(message);
+ //TBD: needs to be aware if there is a pinentry pending
+ // setTimeout(
+ // function(){
+ // me.disconnect();
+ // reject('TIMEOUT');
+ // }, timeout);
});
- };
+ }
};
+/**
+ * A class for answer objects, checking and processing the return messages of
+ * the nativeMessaging communication
+ * @param {String} operation The operation, to look up validity of return keys
+ */
+class Answer{
-function connect(){
- let connection = chrome.runtime.connectNative('gpgmejson');
- if (!connection){
- let msg = chrome.runtime.lastError || 'no message'; //TBD
- throw(msg);
+ constructor(operation){
+ this.operation = operation;
}
- return connection;
-};
+
+ /**
+ *
+ * @param {Object} msg The message as received with nativeMessaging
+ * TODO: "error" and "more" handling are not in here, but in post()
+ */
+ add(msg){
+ if (this._response === undefined){
+ this._response = {};
+ }
+ let messageKeys = Object.keys(msg);
+ let poa = permittedOperations[this.operation].answer;
+ for (let i= 0; i < messageKeys.length; i++){
+ let key = messageKeys[i];
+ switch (key) {
+ case 'type':
+ if ( msg.type !== 'error' && poa.type.indexOf(msg.type) < 0){
+ console.log( 'unexpected answer type: ' + msg.type);
+ throw('UNEXPECTED_TYPE');
+
+ }
+ break;
+ case 'more':
+ break;
+ default:
+ //data should be concatenated
+ if (poa.data.indexOf(key) >= 0){
+ if (!this._response.hasOwnProperty(key)){
+ this._response[key] = '';
+ }
+ this._response[key] = this._response[key].concat(msg[key]);
+ }
+ //params should not change through the message
+ else if (poa.params.indexOf(key) >= 0){
+ if (!this._response.hasOwnProperty(key)){
+ this._response[key] = msg[key];
+ }
+ else if (this._response[key] !== msg[key]){
+ throw('UNEXPECTED_TYPE');
+ }
+ }
+ //infos may be json objects etc. Not yet defined.
+ // Pushing them into arrays for now
+ else if (poa.infos.indexOf(key) >= 0){
+ if (!this._response.hasOwnProperty(key)){
+ this._response[key] = [];
+ }
+ this._response.push(msg[key]);
+ }
+ else {
+ console.log('unexpected answer parameter: ' + key);
+ throw('UNEXPECTED_PARAM');
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Returns the assembled message. TODO: does not care yet if completed.
+ */
+ get message(){
+ return this._response;
+ }
+}
diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js
new file mode 100644
index 00000000..eeb7a3c4
--- /dev/null
+++ b/lang/js/src/Helpers.js
@@ -0,0 +1,84 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+/**
+ * Tries to return an array of fingerprints, either from input fingerprints or
+ * from Key objects
+ * @param {String|Array<String>} input Input value.
+ * @returns {Array<String>} Array of fingerprints.
+ */
+export function toKeyIdArray(input){
+ if (!input){
+ return [];
+ // TODO: Warning or error here? Did we expect something or is "nothing" okay?
+ }
+ if (input instanceof Array){
+ let result = [];
+ for (let i=0; i < input.length; i++){
+ if (isFingerprint(input[i]) === true){
+ result.push(input[i]);
+ } else {
+ //TODO error?
+ console.log('gpgmejs/Helpers.js Warning: '+
+ input[i] +
+ ' is not a valid key fingerprint and will not be used');
+ }
+ }
+ return result;
+ } else if (isFingerprint(input) === true) {
+ return [input];
+ }
+ console.log('gpgmejs/Helpers.js Warning: ' + input +
+ ' is not a valid key fingerprint and will not be used');
+ return [];
+};
+
+/**
+ * check if values are valid hexadecimal values of a specified length
+ * @param {*} key input value.
+ * @param {int} len the expected length of the value
+ */
+function hextest(key, len){
+ if (!key || typeof(key) !== "string"){
+ return false;
+ }
+ if (key.length !== len){
+ return false;
+ }
+ let regexp= /^[0-9a-fA-F]*$/i;
+ return regexp.test(key);
+};
+
+/**
+ * check if the input is a valid Hex string with a length of 40
+ */
+export function isFingerprint(string){
+ return hextest(string, 40);
+};
+
+//TODO needed anywhere?
+function isLongId(string){
+ return hextest(string, 16);
+};
+
+//TODO needed anywhere?
+function isShortId(string){
+ return hextest(string, 8);
+};
diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js
new file mode 100644
index 00000000..90b554a1
--- /dev/null
+++ b/lang/js/src/Message.js
@@ -0,0 +1,109 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+import { permittedOperations } from './permittedOperations'
+
+export class GPGME_Message {
+ //TODO getter
+
+ constructor(){
+ }
+
+ /**
+ * Defines the operation this message will have
+ * @param {String} operation Mus be defined in permittedOperations
+ * TODO: move to constructor?
+ */
+ set operation (operation){
+ if (!operation || typeof(operation) !== 'string'){
+ throw('ERR_WRONG_PARAM');
+ }
+ if (operation in permittedOperations){
+ if (!this._msg){
+ this._msg = {};
+ }
+ this._msg.op = operation;
+ } else {
+ throw('ERR_NOT_IMPLEMENTED');
+ }
+ }
+
+ /**
+ * Sets a parameter for the message. Note that the operation has to be set
+ * first, to be able to check if the parameter is permittted
+ * @param {String} param Parameter to set
+ * @param {any} value Value to set //TODO: Some type checking
+ * @returns {Boolean} If the parameter was set successfully
+ */
+ setParameter(param,value){
+ if (!param || typeof(param) !== 'string'){
+ throw('ERR_WRONG_PARAM');
+ }
+ if (!this._msg || !this._msg.op){
+ console.log('There is no operation specified yet. '+
+ 'The parameter cannot be set');
+ return false;
+ }
+ let po = permittedOperations[this._msg.op];
+ if (!po){
+ throw('LAZY_PROGRAMMER');
+ //TODO
+ return false;
+ }
+ if (po.required.indexOf(param) >= 0 || po.optional.indexOf(param) >= 0){
+ this._msg[param] = value;
+ return true;
+ }
+ console.log('' + param + ' is invalid and could not be set');
+ return false;
+ }
+
+ /**
+ * Check if the message has the minimum requirements to be sent, according
+ * to the definitions in permittedOperations
+ * @returns {Boolean}
+ */
+ get isComplete(){
+ if (!this._msg.op){
+ return false;
+ }
+ let reqParams = permittedOperations[this._msg.op].required;
+ for (let i=0; i < reqParams.length; i++){
+ if (!reqParams[i] in this._msg){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the prepared message with parameters and completeness checked
+ * @returns {Object|null} Object to be posted to gnupg, or null if
+ * incomplete
+ */
+ get message(){
+ if (this.isComplete === true){
+ return this._msg;
+ }
+ else {
+ return null;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index dedbf809..8323ac3b 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -1,187 +1,131 @@
-import {Connection} from "./Connection"
-
-export function encrypt(data, publicKeys, privateKeys, passwords=null,
- sessionKey, filename, compression, armor=true, detached=false,
- signature=null, returnSessionKey=false, wildcard=false, date=new Date()){
- // gpgme_op_encrypt ( <-gpgme doc on this operation
- // gpgme_ctx_t ctx,
- // gpgme_key_t recp[],
- // gpgme_encrypt_flags_t flags,
- // gpgme_data_t plain,
- // gpgme_data_t cipher)
- // flags:
- // GPGME_ENCRYPT_ALWAYS_TRUST
- // GPGME_ENCRYPT_NO_ENCRYPT_TO
- // GPGME_ENCRYPT_NO_COMPRESS
- // GPGME_ENCRYPT_PREPARE
- // GPGME_ENCRYPT_EXPECT_SIGN
- // GPGME_ENCRYPT_SYMMETRIC
- // GPGME_ENCRYPT_THROW_KEYIDS
- // GPGME_ENCRYPT_WRAP
- if (passwords !== null){
- throw('Password!'); // TBD
- }
-
- let pubkeys = toKeyIdArray(publicKeys);
- let privkeys = toKeyIdArray(privateKeys);
-
- // TODO filename: data is supposed to be empty, file is provided
- // TODO config compression detached signature
- // TODO signature to add to the encrypted message (?) || privateKeys: signature is desired
- // gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher)
-
- // TODO sign date overwriting implemented in gnupg?
-
- let conn = new Connection();
- if (wildcard){
- // Connection.set('throw-keyids', true); TODO Connection.set not yet existant
- }
- return conn.post('encrypt', {
- 'data': data,
- 'keys': publicKeys,
- 'armor': armor});
-};
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
-export function decrypt(message, privateKeys, passwords, sessionKeys, publicKeys,
- format='utf8', signature=null, date=new Date()) {
- if (passwords !== null){
- throw('Password!'); // TBD
- }
- if (format === 'binary'){
- // Connection.set('base64', true);
- }
- if (publicKeys || signature){
- // Connection.set('signature', signature);
- // request verification, too
+import {Connection} from "./Connection"
+import {GPGME_Message} from './Message'
+import {toKeyIdArray} from "./Helpers"
+
+export class GpgME {
+ /**
+ * initial check if connection si successfull. Will throw ERR_NO_CONNECT or
+ * ERR_NO_CONNECT_RLE (if chrome.runtime.lastError is available) if the
+ * connection fails.
+ * TODO The connection to the nativeMessaging host will, for now, be closed
+ * after each interaction. Session management with gpg_agent is TBD.
+ * TODO: add configuration
+ */
+ constructor(){
+ let conn = new Connection();
+ // this.keyring = new Keyring(); TBD
+ // TODO config, e.g.
+ this.configuration = {
+ null_expire_is_never: true
+ };
+ conn.disconnect();
}
- //privateKeys optionally if keyId was thrown?
- // gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
- // response is gpgme_op_decrypt_result (gpgme_ctx_t ctx) (next available?)
- return conn.post('decrypt', {
- 'data': message
- });
-}
-// BIG TODO.
-export function generateKey({userIds=[], passphrase, numBits=2048, unlocked=false, keyExpirationTime=0, curve="", date=new Date()}){
- throw('not implemented here');
- // gpgme_op_createkey (gpgme_ctx_t ctx, const char *userid, const char *algo, unsigned long reserved, unsigned long expires, gpgme_key_t extrakey, unsigned int flags);
- return false;
-}
+ /**
+ * @param {String|Uint8Array} data text/data to be encrypted as String/Uint8Array
+ * @param {GPGME_Key|String|Array<String>|Array<GPGME_Key>} publicKeys Keys used to encrypt the message
+ * @param {Boolean} wildcard (optional) If true, recipient information will not be added to the message
+ */
+ encrypt (data, publicKeys, wildcard=false){
-export function sign({ data, privateKeys, armor=true, detached=false, date=new Date() }) {
- //TODO detached GPGME_SIG_MODE_DETACH | GPGME_SIG_MODE_NORMAL
- // gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig, gpgme_sig_mode_t mode)
- // TODO date not supported
+ let msg = new GPGME_Message;
+ msg.operation = 'encrypt';
- let conn = new Connection();
- let privkeys = toKeyIdArray(privateKeys);
- return conn.post('sign', {
- 'data': data,
- 'keys': privkeys,
- 'armor': armor});
-};
+ // TODO temporary
+ msg.setParameter('armor', true);
+ msg.setParameter('always-trust', true);
-export function verify({ message, publicKeys, signature=null, date=new Date() }) {
- //TODO extra signature: sig, signed_text, plain: null
- // inline sig: signed_text:null, plain as writable (?)
- // date not supported
- //gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plain)
- let conn = new Connection();
- let privkeys = toKeyIdArray(privateKeys);
- return conn.post('sign', {
- 'data': data,
- 'keys': privkeys,
- 'armor': armor});
-}
+ let pubkeys = toKeyIdArray(publicKeys);
+ msg.setParameter('keys', pubkeys);
+ putData(msg, data);
+ if (wildcard === true){msg.setParameter('throw-keyids', true);
+ };
-export function reformatKey(privateKey, userIds=[], passphrase="", unlocked=false, keyExpirationTime=0){
- let privKey = toKeyIdArray(privateKey);
- if (privKey.length !== 1){
- return false; //TODO some error handling. There is not exactly ONE key we are editing
+ if (msg.isComplete === true) {
+ let conn = new Connection();
+ return (conn.post(msg.message));
+ }
+ else {
+ return Promise.reject('NO_CONNECT');
+ //TODO
+ }
}
- let conn = new Connection();
- // TODO key management needs to be changed somewhat
- return conn.post('TODO', {
- 'key': privKey[0],
- 'keyExpirationTime': keyExpirationTime, //TODO check if this is 0 or a positive and plausible number
- 'userIds': userIds //TODO check if empty or plausible strings
- });
- // unlocked will be ignored
-}
-export function decryptKey({ privateKey, passphrase }) {
- throw('not implemented here');
- return false;
-};
+ /**
+ * @param {String} data TODO Format: base64? String? Message with the encrypted data
+ * @returns {Promise<Object>} decrypted message:
+ data: The decrypted data. This may be base64 encoded.
+ base64: Boolean indicating whether data is base64 encoded.
+ mime: A Boolean indicating whether the data is a MIME object.
+ info: An optional object with extra information.
+ * @async
+ */
-export function encryptKey({ privateKey, passphrase }) {
- throw('not implemented here');
- return false;
-};
+ decrypt(data){
-export function encryptSessionKey({data, algorithm, publicKeys, passwords, wildcard=false }) {
- //openpgpjs:
- // Encrypt a symmetric session key with public keys, passwords, or both at
- // once. At least either public keys or passwords must be specified.
- throw('not implemented here');
- return false;
-};
-
-export function decryptSessionKeys({ message, privateKeys, passwords }) {
- throw('not implemented here');
- return false;
-};
-
-// //TODO worker handling
-
-// //TODO key representation
-// //TODO: keyring handling
-
-
-/**
- * Helper functions and checks
- */
-
-/**
- * Checks if the submitted value is a keyID.
- * TODO: should accept all strings that are accepted as keyID by gnupg
- * TODO: See if Key becomes an object later on
- * @param {*} key input value. Is expected to be a string of 8,16 or 40 chars
- * representing hex values. Will return false if that expectation is not met
- */
-function isKeyId(key){
- if (!key || typeof(key) !== "string"){
- return false;
- }
- if ([8,16,40].indexOf(key.length) < 0){
- return false;
+ if (data === undefined){
+ throw('ERR_EMPTY_MSG');
+ }
+ let msg = new GPGME_Message;
+ msg.operation = 'decrypt';
+ putData(msg, data);
+ // TODO: needs proper EOL to be decrypted.
+
+ if (msg.isComplete === true){
+ let conn = new Connection();
+ return conn.post(msg.message);
+ }
+ else {
+ return Promise.reject('NO_CONNECT');
+ //TODO
+ }
}
- let regexp= /^[0-9a-fA-F]*$/i;
- return regexp.test(key);
-};
+}
/**
- * Tries to return an array of keyID values, either from a string or an array.
- * Filters out those that do not meet the criteria. (TODO: silently for now)
- * @param {*} array Input value.
+ * Sets the data of the message, converting Uint8Array to base64 and setting
+ * the base64 flag
+ * @param {GPGME_Message} message The message where this data will be set
+ * @param {*} data The data to enter
+ * @param {String} propertyname // TODO unchecked still
*/
-function toKeyIdArray(array){
- let result = [];
- if (!array){
- return result;
- }
- if (!Array.isArray(array)){
- if (isKeyId(array) === true){
- return [keyId];
- }
- return result;
+function putData(message, data){
+ if (!message || !message instanceof GPGME_Message ) {
+ throw('NO_MESSAGE_OBJECT');
}
- for (let i=0; i < array.length; i++){
- if (isKeyId(array[i]) === true){
- result.push(array[i]);
- }
+ if (!data){
+ //TODO Debug only! No data is legitimate
+ console.log('Warning. no data in message');
+ message.setParameter('data', '');
+ } else if (data instanceof Uint8Array){
+ let decoder = new TextDecoder('utf8');
+ message.setParameter('base64', true);
+ message.setParameter ('data', decoder.decode(data));
+ } else if (typeof(data) === 'string') {
+ message.setParameter('base64', false);
+ message.setParameter('data', data);
+ } else {
+ throw('ERR_WRONG_TYPE');
}
- return result;
-};
+} \ No newline at end of file
diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js
new file mode 100644
index 00000000..1eec4da4
--- /dev/null
+++ b/lang/js/src/gpgmejs_openpgpjs.js
@@ -0,0 +1,156 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+/**
+ * This is a compatibility API to be used as openpgpjs syntax.
+ * Non-implemented options will throw an error if set (not null or undefined)
+ * TODO Some info about differences
+ */
+
+ import { GpgME } from "./gpgmejs";
+// import {Keyring} from "./Keyring" TODO
+
+
+export class GpgME_openPGPCompatibility {
+
+ constructor(){
+ this._gpgme = new GpgME;
+ }
+
+ /**
+ * Encrypt Message
+ * Supported:
+ * @param {String|Uint8Array} data
+ * @param {Key|Array<Key>} publicKeys
+ * @param {Boolean} wildcard
+ * TODO:
+ * @param {Key|Array<Key>} privateKeys
+ * @param {String} filename
+ * @param {module:enums.compression} compression
+ * @param {Boolean} armor
+ * @param {Boolean} detached
+ * unsupported:
+ * @param {String|Array<String>} passwords
+ * @param {Object} sessionKey
+ * @param {Signature} signature
+ * @param {Boolean} returnSessionKey
+ *
+ * @returns {Promise<Object>}
+ * {data: ASCII armored message,
+ * signature: detached signature if 'detached' is true
+ * }
+ * @async
+ * @static
+ */
+ encrypt({data = '', publicKeys = '', privateKeys, passwords, sessionKey,
+ filename, compression, armor=true, detached=false, signature=null,
+ returnSessionKey=null, wildcard=false, date=null}) {
+ if (passwords !== undefined
+ || sessionKey !== undefined
+ || signature !== null
+ || returnSessionKey !== null
+ || date !== null){
+ throw('NOT_IMPLEMENTED');
+ }
+ if ( privateKeys
+ || filename
+ || compression
+ || armor === false
+ || detached == true){
+ console.log('may be implemented later');
+ throw('NOT_YET_IMPLEMENTED');
+ }
+ return this.GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard);
+ }
+
+ /** Decrypt Message
+ * supported
+ * TODO: @param {Message} message TODO: for now it accepts an armored string only
+ * Unsupported:
+ * @param {String|Array<String>} passwords
+ * @param {Object|Array<Object>} sessionKeys
+ * @param {Date} date
+
+ * TODO
+ * @param {Key|Array<Key>} privateKey
+ * @param {Key|Array<Key>} publicKeys
+ * @param {String} format (optional) return data format either as 'utf8' or 'binary'
+ * @param {Signature} signature (optional) detached signature for verification
+
+ * @returns {Promise<Object>} decrypted and verified message in the form:
+ * { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] }
+ * @async
+ * @static
+ */
+ decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format='utf8', signature=null, date}) {
+ if (passwords !== undefined
+ || sessionKeys
+ || date){
+
+ throw('NOT_IMPLEMENTED');
+ }
+ if ( privateKeys
+ || publicKeys
+ || format !== 'utf8'
+ || signature
+ ){
+ console.log('may be implemented later');
+ throw('NOT_YET_IMPLEMENTED');
+ }
+ return this.GpgME.decrypt(message);
+ // TODO: translate between:
+ // openpgp:
+ // { data:Uint8Array|String,
+ // filename:String,
+ // signatures:[{ keyid:String, valid:Boolean }] }
+ // and gnupg:
+ // data: The decrypted data. This may be base64 encoded.
+ // base64: Boolean indicating whether data is base64 encoded.
+ // mime: A Boolean indicating whether the data is a MIME object.
+ // info: An optional object with extra information.
+ }
+}
+
+/**
+ *
+ * @param {Object | String} Key Either a (presumably openpgp Key) Object with a
+ * primaryKeyproperty and a method getFingerprint, or a string.
+ * @returns {String} Unchecked string value claiming to be a fingerprint
+ * TODO: gpgmejs checks again, so it's okay here.
+ */
+function translateKeyInput(Key){
+ if (!Key){
+ return [];
+ }
+ if (!Array.isArray(Key)){
+ Key = [Key];
+ }
+ let resultslist = [];
+ for (let i=0; i < Key.length; i++){
+ if (typeof(Key[i]) === 'string'){
+ resultslist.push(Key);
+ } else if (
+ Key[i].hasOwnProperty(primaryKey) &&
+ Key[i].primaryKey.hasOwnProperty(getFingerprint)){
+ resultslist.push(Key[i].primaryKey.getFingerprint());
+ }
+ }
+ return resultslist;
+} \ No newline at end of file
diff --git a/lang/js/src/index.js b/lang/js/src/index.js
index 02dc919d..f70bd2d8 100644
--- a/lang/js/src/index.js
+++ b/lang/js/src/index.js
@@ -1,14 +1,23 @@
-import * as gpgmejs from'./gpgmejs'
-export default gpgmejs;
-
-/**
- * Export each high level api function separately.
- * Usage:
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
*
- * import { encryptMessage } from 'gpgme.js'
- * encryptMessage(keys, text)
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
*/
-export {
- encrypt, decrypt, sign, verify,
- generateKey, reformatKey
- } from './gpgmejs';
+
+import { GpgME as gpgmejs } from "./gpgmejs";
+// import { GpgME_openPGPCompatibility as gpgmejs } from "./gpgmejs_openpgpjs";
+export default gpgmejs;
diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js
new file mode 100644
index 00000000..3c11b8e0
--- /dev/null
+++ b/lang/js/src/permittedOperations.js
@@ -0,0 +1,75 @@
+/* gpgme.js - Javascript integration for gpgme
+ * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+ /**
+ * Definition of the possible interactions with gpgme-json.
+ * operation: <Object>
+ required: Array<String>
+ optional: Array<String>
+ answer: <Object>
+ type: <String< The content type of answer expected
+ data: Array<String> The payload property of the answer. May be
+ partial and in need of concatenation
+ params: Array<String> Information that do not change throughout
+ the message
+ infos: Array<String> arbitrary information that may change
+ }
+ }
+ */
+
+export const permittedOperations = {
+ encrypt: {
+ required: ['keys', 'data'],
+ optional: [
+ 'protocol',
+ 'chunksize',
+ 'base64',
+ 'mime',
+ 'armor',
+ 'always-trust',
+ 'no-encrypt-to',
+ 'no-compress',
+ 'throw-keyids',
+ 'want-address',
+ 'wrap'
+ ],
+ answer: {
+ type: ['ciphertext'],
+ data: ['data'],
+ params: ['base64'],
+ infos: []
+ }
+ },
+
+ decrypt: {
+ required: ['data'],
+ optional: [
+ 'protocol',
+ 'chunksize',
+ 'base64'
+ ],
+ answer: {
+ type: ['plaintext'],
+ data: ['data'],
+ params: ['base64', 'mime'],
+ infos: ['info']
+ }
+ }
+}