js: encrypt improvement and decrypt method
* Compatibility class gpgme_openpgpjs offers an API that should accept openpgpjs syntax, throwing errors if a parameter is unexpected/not implemented * tried to be more generic in methods * waiting for multiple answers if 'more' is in the answer * more consistency checking on sending and receiving * updated the example extension --
This commit is contained in:
parent
94f21d9f6b
commit
6ab25e40d9
@ -3,16 +3,19 @@ NativeConnection:
|
|||||||
[X] nativeConnection: successfully sending an encrypt request,
|
[X] nativeConnection: successfully sending an encrypt request,
|
||||||
receiving an answer
|
receiving an answer
|
||||||
[X] nativeConnection successfull on Chromium, chrome and firefox
|
[X] nativeConnection successfull on Chromium, chrome and firefox
|
||||||
[ ] nativeConnection successfull on Windows, macOS, Linux
|
[*] nativeConnection successfull on Windows, macOS, Linux
|
||||||
[ ] nativeConnection with delayed, multipart (> 1MB) answer
|
[*] nativeConnection with delayed, multipart (> 1MB) answer
|
||||||
|
|
||||||
replicating Openpgpjs API:
|
replicating Openpgpjs API:
|
||||||
|
|
||||||
[*] Message handling (encrypt, verify, sign)
|
[*] Message handling (encrypt, verify, sign)
|
||||||
[ ] Key handling (import/export, modifying, status queries)
|
[x] encrypt
|
||||||
|
[ ] verify
|
||||||
|
[ ] sign
|
||||||
|
[*] Key handling (import/export, modifying, status queries)
|
||||||
[ ] Configuration handling
|
[ ] Configuration handling
|
||||||
[ ] check for completeness
|
[ ] check for completeness
|
||||||
[ ] handling of differences to openpgpjs
|
[*] handling of differences to openpgpjs
|
||||||
|
|
||||||
Communication with other implementations
|
Communication with other implementations
|
||||||
|
|
||||||
@ -21,10 +24,5 @@ Communication with other implementations
|
|||||||
Management:
|
Management:
|
||||||
[*] Define the gpgme interface
|
[*] Define the gpgme interface
|
||||||
[ ] check Permissions (e.g. csp) for the different envs
|
[ ] check Permissions (e.g. csp) for the different envs
|
||||||
[ ] agree on license
|
[X] agree on license
|
||||||
[ ] tests
|
[ ] tests
|
||||||
|
|
||||||
|
|
||||||
Problems:
|
|
||||||
[X] gpgme-json: interactive mode vs. bytelength; filename
|
|
||||||
[X] nativeApp chokes on arrays. We will get rid of that bnativeapp anyhow
|
|
||||||
|
@ -4,6 +4,6 @@ browsers' manifests (see README) need allowedextension added, and the path set
|
|||||||
|
|
||||||
manifest.json/ csp needs adaption
|
manifest.json/ csp needs adaption
|
||||||
|
|
||||||
/dist contains a current build which is used by example app.
|
/dist should be built which is used by the example app.
|
||||||
We may either want to update it on every commit, or never at all, but not
|
|
||||||
inconsistently.
|
csp in manifest.json MUST NOT contain "unsafe-eval" in production!
|
||||||
|
@ -1,20 +1,28 @@
|
|||||||
This is an example app for gpgme-json.
|
gpgmejs, as contained in this directory, is a javascript library for direct use
|
||||||
As of now, it only encrypts a given text.
|
of gnupg in browsers, with the help of nativeMessaging.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
-------------
|
-------------
|
||||||
|
gpgmejs uses webpack, and thus depends on nodejs for building. Webpack can be
|
||||||
|
installed by running
|
||||||
|
`npm install webpack webpack-cli --save-dev`.
|
||||||
|
|
||||||
gpgmejs uses webpack, the builds can be found in dist/
|
To create a current version of the package, the command is
|
||||||
(the testapplication uses that script at that location). To create a new
|
`npx webpack --config webpack.conf.js`.
|
||||||
package, the command is npx webpack --config webpack.conf.js.
|
|
||||||
If you want a more debuggable (i.e. not minified) build, just change the mode
|
If you want a more debuggable (i.e. not minified) build, just change the mode
|
||||||
in webpack.conf.js.
|
in webpack.conf.js.
|
||||||
|
|
||||||
|
TODO: gpgme_openpgpjs aims to offer an API similar to openpgpjs, throwing errors
|
||||||
|
if some part of the API is not implemented, 'translating' objects if possible.
|
||||||
|
This will be incorporated into the build process later, for now it is a line to
|
||||||
|
uncomment in src/index.js
|
||||||
|
|
||||||
Demo WebExtension:
|
Demo WebExtension:
|
||||||
As soon as a bundled webpack is in dist/ (TODO: .gitignore or not?),
|
As soon as a bundled webpack is in dist/
|
||||||
the gpgmejs folder can just be included in the extensions tab of the browser in
|
the gpgmejs folder can just be included in the extensions tab of the browser in
|
||||||
questions (extension debug mode needs to be active). For chrome, selecting the
|
questions (extension debug mode needs to be active). For chrome, selecting the
|
||||||
folder is sufficient, for firefox, the manifest.json needs to be selected.
|
folder is sufficient, for firefox, the manifest.json needs to be selected.
|
||||||
|
Please note that it is just for demonstration/debug purposes!
|
||||||
|
|
||||||
In the browsers' nativeMessaging configuration folder a file 'gpgmejs.json'
|
In the browsers' nativeMessaging configuration folder a file 'gpgmejs.json'
|
||||||
is needed, with the following content:
|
is needed, with the following content:
|
||||||
@ -47,6 +55,3 @@ Firefox:
|
|||||||
The ExtensionIdentifier can be seen as Extension ID on the about:addons page if
|
The ExtensionIdentifier can be seen as Extension ID on the about:addons page if
|
||||||
addon-debugging is active. In firefox, the temporary addon is removed once
|
addon-debugging is active. In firefox, the temporary addon is removed once
|
||||||
firefox exits, and the identifier will need to be changed more often.
|
firefox exits, and the identifier will need to be changed more often.
|
||||||
|
|
||||||
For testing purposes, it could be a good idea to change the keyID in the
|
|
||||||
ui.html, to not having to type it every time.
|
|
||||||
|
@ -4,15 +4,11 @@
|
|||||||
"name": "gpgme-json with native Messaging",
|
"name": "gpgme-json with native Messaging",
|
||||||
"description": "This should be able to encrypt a text using gpgme-json",
|
"description": "This should be able to encrypt a text using gpgme-json",
|
||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
"content_security_policy": "default-src 'self' 'unsafe-eval' filesystem",
|
"content_security_policy": "default-src 'self' 'unsafe-eval' filesystem:",
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_icon": "testicon.png",
|
"default_icon": "testicon.png",
|
||||||
"default_title": "gpgme.js",
|
"default_title": "gpgme.js",
|
||||||
"default_popup": "ui.html"
|
"default_popup": "testapplication_index.html"
|
||||||
},
|
},
|
||||||
"permissions": ["nativeMessaging", "activeTab"],
|
"permissions": ["nativeMessaging", "activeTab"]
|
||||||
|
|
||||||
"background": {
|
|
||||||
"scripts": [ "dist/gpgmejs.bundle.js"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "gpgmejs",
|
"name": "gpgmejs",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "javascript part of a nativeMessaging gnupg integration",
|
"description": "javascript part of a nativeMessaging gnupg integration",
|
||||||
"main": "src/gpgmejs.js",
|
"main": "src/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "",
|
"license": "",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^4.3.0",
|
"webpack": "^4.5.0",
|
||||||
"webpack-cli": "^2.0.13"
|
"webpack-cli": "^2.0.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
* 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
|
* gnupg. It should be alive as long as there are additional messages to be
|
||||||
* expected.
|
* expected.
|
||||||
*/
|
*/
|
||||||
|
import { permittedOperations } from './permittedOperations'
|
||||||
|
|
||||||
export function Connection(){
|
export class 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
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
this.disconnect = function () {
|
/**
|
||||||
if (this.connection){
|
* Opens and closes a port. Thus, it is made sure that the connection can
|
||||||
this.connection.disconnect();
|
* 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately closes the open port
|
||||||
|
*/
|
||||||
|
disconnect() {
|
||||||
|
if (this._connection){
|
||||||
|
this._connection.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message and resolves with the answer.
|
* Sends a message and resolves with the answer.
|
||||||
* @param {*} operation The interaction requested from gpgme
|
* @param {GPGME_Message} message
|
||||||
* @param {*} message A json-capable object to pass the operation details.
|
* @returns {Promise<Object>} the gnupg answer, or rejection with error
|
||||||
* TODO: _msg should contain configurable parameters
|
* information
|
||||||
|
* TODO: better/more consistent error information
|
||||||
*/
|
*/
|
||||||
this.post = function(operation, message){
|
post(message){
|
||||||
let timeout = 5000;
|
if (!message || !message instanceof GPGME_Message){
|
||||||
|
return Promise.reject('ERR_NO_MSG');
|
||||||
|
}
|
||||||
|
// let timeout = 5000; //TODO config
|
||||||
let me = this;
|
let me = this;
|
||||||
if (!message || !operation){
|
|
||||||
return Promise.reject('no message'); // TBD
|
|
||||||
}
|
|
||||||
|
|
||||||
let keys = Object.keys(message);
|
|
||||||
for (let i=0; i < keys.length; i++){
|
|
||||||
let property = keys[i];
|
|
||||||
me._msg[property] = message[property];
|
|
||||||
}
|
|
||||||
me._msg['op'] = operation;
|
|
||||||
// TODO fancier checks if what we want is consistent with submitted content
|
|
||||||
return new Promise(function(resolve, reject){
|
return new Promise(function(resolve, reject){
|
||||||
me.connection.onMessage.addListener(function(msg) {
|
let answer = new Answer(message.op);
|
||||||
|
let listener = function(msg) {
|
||||||
if (!msg){
|
if (!msg){
|
||||||
reject('empty answer.');
|
me._connection.onMessage.removeListener(listener)
|
||||||
}
|
reject('EMPTY_ANSWER');
|
||||||
if (msg.type === "error"){
|
} else if (msg.type === "error"){
|
||||||
|
me._connection.onMessage.removeListener(listener)
|
||||||
reject(msg.msg);
|
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);
|
||||||
function connect(){
|
me._connection.postMessage(message);
|
||||||
let connection = chrome.runtime.connectNative('gpgmejson');
|
//TBD: needs to be aware if there is a pinentry pending
|
||||||
if (!connection){
|
// setTimeout(
|
||||||
let msg = chrome.runtime.lastError || 'no message'; //TBD
|
// function(){
|
||||||
throw(msg);
|
// me.disconnect();
|
||||||
|
// reject('TIMEOUT');
|
||||||
|
// }, timeout);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return connection;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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{
|
||||||
|
|
||||||
|
constructor(operation){
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
84
lang/js/src/Helpers.js
Normal file
84
lang/js/src/Helpers.js
Normal file
@ -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);
|
||||||
|
};
|
109
lang/js/src/Message.js
Normal file
109
lang/js/src/Message.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,187 +1,131 @@
|
|||||||
import {Connection} from "./Connection"
|
/* 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 encrypt(data, publicKeys, privateKeys, passwords=null,
|
import {Connection} from "./Connection"
|
||||||
sessionKey, filename, compression, armor=true, detached=false,
|
import {GPGME_Message} from './Message'
|
||||||
signature=null, returnSessionKey=false, wildcard=false, date=new Date()){
|
import {toKeyIdArray} from "./Helpers"
|
||||||
// gpgme_op_encrypt ( <-gpgme doc on this operation
|
|
||||||
// gpgme_ctx_t ctx,
|
export class GpgME {
|
||||||
// gpgme_key_t recp[],
|
/**
|
||||||
// gpgme_encrypt_flags_t flags,
|
* initial check if connection si successfull. Will throw ERR_NO_CONNECT or
|
||||||
// gpgme_data_t plain,
|
* ERR_NO_CONNECT_RLE (if chrome.runtime.lastError is available) if the
|
||||||
// gpgme_data_t cipher)
|
* connection fails.
|
||||||
// flags:
|
* TODO The connection to the nativeMessaging host will, for now, be closed
|
||||||
// GPGME_ENCRYPT_ALWAYS_TRUST
|
* after each interaction. Session management with gpg_agent is TBD.
|
||||||
// GPGME_ENCRYPT_NO_ENCRYPT_TO
|
* TODO: add configuration
|
||||||
// GPGME_ENCRYPT_NO_COMPRESS
|
*/
|
||||||
// GPGME_ENCRYPT_PREPARE
|
constructor(){
|
||||||
// GPGME_ENCRYPT_EXPECT_SIGN
|
let conn = new Connection();
|
||||||
// GPGME_ENCRYPT_SYMMETRIC
|
// this.keyring = new Keyring(); TBD
|
||||||
// GPGME_ENCRYPT_THROW_KEYIDS
|
// TODO config, e.g.
|
||||||
// GPGME_ENCRYPT_WRAP
|
this.configuration = {
|
||||||
if (passwords !== null){
|
null_expire_is_never: true
|
||||||
throw('Password!'); // TBD
|
};
|
||||||
|
conn.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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){
|
||||||
|
|
||||||
|
let msg = new GPGME_Message;
|
||||||
|
msg.operation = 'encrypt';
|
||||||
|
|
||||||
|
// TODO temporary
|
||||||
|
msg.setParameter('armor', true);
|
||||||
|
msg.setParameter('always-trust', true);
|
||||||
|
|
||||||
let pubkeys = toKeyIdArray(publicKeys);
|
let pubkeys = toKeyIdArray(publicKeys);
|
||||||
let privkeys = toKeyIdArray(privateKeys);
|
msg.setParameter('keys', pubkeys);
|
||||||
|
|
||||||
// TODO filename: data is supposed to be empty, file is provided
|
putData(msg, data);
|
||||||
// TODO config compression detached signature
|
if (wildcard === true){msg.setParameter('throw-keyids', true);
|
||||||
// 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?
|
|
||||||
|
|
||||||
|
if (msg.isComplete === true) {
|
||||||
let conn = new Connection();
|
let conn = new Connection();
|
||||||
if (wildcard){
|
return (conn.post(msg.message));
|
||||||
// Connection.set('throw-keyids', true); TODO Connection.set not yet existant
|
|
||||||
}
|
}
|
||||||
return conn.post('encrypt', {
|
else {
|
||||||
'data': data,
|
return Promise.reject('NO_CONNECT');
|
||||||
'keys': publicKeys,
|
//TODO
|
||||||
'armor': armor});
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
//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()}){
|
* @param {String} data TODO Format: base64? String? Message with the encrypted data
|
||||||
throw('not implemented here');
|
* @returns {Promise<Object>} decrypted message:
|
||||||
// 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);
|
data: The decrypted data. This may be base64 encoded.
|
||||||
return false;
|
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.
|
||||||
export function sign({ data, privateKeys, armor=true, detached=false, date=new Date() }) {
|
* @async
|
||||||
//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 conn = new Connection();
|
|
||||||
let privkeys = toKeyIdArray(privateKeys);
|
|
||||||
return conn.post('sign', {
|
|
||||||
'data': data,
|
|
||||||
'keys': privkeys,
|
|
||||||
'armor': armor});
|
|
||||||
};
|
|
||||||
|
|
||||||
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});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function encryptKey({ privateKey, passphrase }) {
|
|
||||||
throw('not implemented here');
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
decrypt(data){
|
||||||
* Checks if the submitted value is a keyID.
|
|
||||||
* TODO: should accept all strings that are accepted as keyID by gnupg
|
if (data === undefined){
|
||||||
* TODO: See if Key becomes an object later on
|
throw('ERR_EMPTY_MSG');
|
||||||
* @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){
|
let msg = new GPGME_Message;
|
||||||
return false;
|
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);
|
||||||
}
|
}
|
||||||
let regexp= /^[0-9a-fA-F]*$/i;
|
else {
|
||||||
return regexp.test(key);
|
return Promise.reject('NO_CONNECT');
|
||||||
};
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to return an array of keyID values, either from a string or an array.
|
* Sets the data of the message, converting Uint8Array to base64 and setting
|
||||||
* Filters out those that do not meet the criteria. (TODO: silently for now)
|
* the base64 flag
|
||||||
* @param {*} array Input value.
|
* @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){
|
function putData(message, data){
|
||||||
let result = [];
|
if (!message || !message instanceof GPGME_Message ) {
|
||||||
if (!array){
|
throw('NO_MESSAGE_OBJECT');
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
if (!Array.isArray(array)){
|
if (!data){
|
||||||
if (isKeyId(array) === true){
|
//TODO Debug only! No data is legitimate
|
||||||
return [keyId];
|
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;
|
}
|
||||||
}
|
|
||||||
for (let i=0; i < array.length; i++){
|
|
||||||
if (isKeyId(array[i]) === true){
|
|
||||||
result.push(array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
156
lang/js/src/gpgmejs_openpgpjs.js
Normal file
156
lang/js/src/gpgmejs_openpgpjs.js
Normal file
@ -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;
|
||||||
|
}
|
@ -1,14 +1,23 @@
|
|||||||
import * as gpgmejs from'./gpgmejs'
|
/* gpgme.js - Javascript integration for gpgme
|
||||||
export default gpgmejs;
|
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
|
||||||
|
|
||||||
/**
|
|
||||||
* Export each high level api function separately.
|
|
||||||
* Usage:
|
|
||||||
*
|
*
|
||||||
* import { encryptMessage } from 'gpgme.js'
|
* This file is part of GPGME.
|
||||||
* encryptMessage(keys, text)
|
*
|
||||||
|
* 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 {
|
|
||||||
encrypt, decrypt, sign, verify,
|
import { GpgME as gpgmejs } from "./gpgmejs";
|
||||||
generateKey, reformatKey
|
// import { GpgME_openPGPCompatibility as gpgmejs } from "./gpgmejs_openpgpjs";
|
||||||
} from './gpgmejs';
|
export default gpgmejs;
|
||||||
|
75
lang/js/src/permittedOperations.js
Normal file
75
lang/js/src/permittedOperations.js
Normal file
@ -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']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
lang/js/test_index.js
Normal file
25
lang/js/test_index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/* 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+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
chrome.tabs.create({
|
||||||
|
url: './ui2.html'
|
||||||
|
});
|
||||||
|
});
|
@ -1,21 +1,57 @@
|
|||||||
/**
|
/* gpgme.js - Javascript integration for gpgme
|
||||||
* Testing nativeMessaging. This is a temporary plugin using the gpgmejs
|
* Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
|
||||||
implemetation as contained in src/
|
*
|
||||||
*/
|
* This file is part of GPGME.
|
||||||
function buttonclicked(event){
|
*
|
||||||
let data = document.getElementById("text0").value;
|
* GPGME is free software; you can redistribute it and/or modify it
|
||||||
let keyId = document.getElementById("key").value;
|
* under the terms of the GNU Lesser General Public License as
|
||||||
let enc = Gpgmejs.encrypt(data, [keyId]).then(function(answer){
|
* 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+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function encryptbuttonclicked(event){
|
||||||
|
let data = document.getElementById('cleartext').value;
|
||||||
|
let keyId = document.getElementById('pubkey').value;
|
||||||
|
let communication = new Gpgmejs;
|
||||||
|
let enc = communication.encrypt(data, keyId).then(
|
||||||
|
function(answer){
|
||||||
console.log(answer);
|
console.log(answer);
|
||||||
console.log(answer.type);
|
if (answer.data){
|
||||||
console.log(answer.data);
|
console.log(answer.data);
|
||||||
alert(answer.data);
|
document.getElementById('answer').value = answer.data;
|
||||||
|
}
|
||||||
|
}, function(errormsg){
|
||||||
|
alert('Error: '+ errormsg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function decryptbuttonclicked(event){
|
||||||
|
let data = document.getElementById("ciphertext").value;
|
||||||
|
let communication = new Gpgmejs;
|
||||||
|
let enc = communication.decrypt(data).then(
|
||||||
|
function(answer){
|
||||||
|
console.log(answer);
|
||||||
|
if (answer.data){
|
||||||
|
document.getElementById('answer').value = answer.data;
|
||||||
|
}
|
||||||
}, function(errormsg){
|
}, function(errormsg){
|
||||||
alert('Error: '+ errormsg);
|
alert('Error: '+ errormsg);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
document.getElementById("button0").addEventListener("click",
|
document.getElementById("buttonencrypt").addEventListener("click",
|
||||||
buttonclicked);
|
encryptbuttonclicked);
|
||||||
});
|
document.getElementById("buttondecrypt").addEventListener("click",
|
||||||
|
decryptbuttonclicked);
|
||||||
|
});
|
||||||
|
9
lang/js/testapplication_index.html
Normal file
9
lang/js/testapplication_index.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script src="test_index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,24 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<link rel="stylesheet" href="ui.css"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<!--TODO: replace this mess with require -->
|
|
||||||
<script src="dist/gpgmejs.bundle.js"></script>
|
|
||||||
<script src="testapplication.js"></script>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span class="label">Text: </span>
|
|
||||||
<input type="text" id='text0' />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="label">Public key ID: </span>
|
|
||||||
<input type="text" id="key" value="Your Public Key ID here" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button id="button0">Encrypt</button><br>
|
|
||||||
<div id="answer"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
33
lang/js/ui2.html
Normal file
33
lang/js/ui2.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="stylesheet" href="ui.css"/>
|
||||||
|
<script src="dist/gpgmejs.bundle.js"></script>
|
||||||
|
<script src="testapplication.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="label">Text: </span>
|
||||||
|
<input type="text" id='cleartext' />
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="label">Public key ID: </span>
|
||||||
|
<input type="text" id="pubkey" value="" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button id="buttonencrypt">Encrypt</button><br>
|
||||||
|
<hr>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="label">Encrypted armored Text: </span>
|
||||||
|
<textarea rows="5" cols="65" id="ciphertext" wrap="hard"></textarea>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button id="buttondecrypt">Decrypt</button><br>
|
||||||
|
<hr>
|
||||||
|
<h3>Result data:</h3>
|
||||||
|
<textarea id="answer" rows="5" cols="65" wrap="hard"></textarea>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,3 +1,24 @@
|
|||||||
|
/* 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 the configuration file for building the gpgmejs-Library with webpack
|
||||||
|
*/
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -8,6 +29,7 @@ module.exports = {
|
|||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'gpgmejs.bundle.js',
|
filename: 'gpgmejs.bundle.js',
|
||||||
libraryTarget: 'var',
|
libraryTarget: 'var',
|
||||||
|
libraryExport: 'default',
|
||||||
library: 'Gpgmejs'
|
library: 'Gpgmejs'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user