aboutsummaryrefslogtreecommitdiffstats
path: root/lang/js
diff options
context:
space:
mode:
authorMaximilian Krambach <[email protected]>2018-08-22 14:32:31 +0000
committerMaximilian Krambach <[email protected]>2018-08-22 14:32:31 +0000
commit129fa919b935d97d995bc6b457c7f6984c06e825 (patch)
treed25245b9ae7634acd99d713e12832fd97c988af0 /lang/js
parentjs: Return error if signature has no fingerprint (diff)
downloadgpgme-129fa919b935d97d995bc6b457c7f6984c06e825.tar.gz
gpgme-129fa919b935d97d995bc6b457c7f6984c06e825.zip
js: improve decryption performance
-- * src/Connection.js, src/Helpers.js: performance of decoding incoming base64 data was improved to about 4 times the speed by introducing two more efficient functions (thanks to [email protected] for finding and testing them) * src/gpgmejs.js: Decrypted data will now return as Uint8Array, if the caller does not wish for a decoding. Decoding binary data will return invalid data, and a Uint8Array may be desired. This can be indicated by using the (new) 'binary' option in decrypt. * src/Errors.js A new error in case this decoding fails * src/Message.js, src/Connection.js: expected is change from base64 to binary, to avoid confusion later on.
Diffstat (limited to 'lang/js')
-rw-r--r--lang/js/src/Connection.js24
-rw-r--r--lang/js/src/Errors.js4
-rw-r--r--lang/js/src/Helpers.js71
-rw-r--r--lang/js/src/Message.js2
-rw-r--r--lang/js/src/gpgmejs.js18
5 files changed, 100 insertions, 19 deletions
diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js
index 928ac681..8756cce1 100644
--- a/lang/js/src/Connection.js
+++ b/lang/js/src/Connection.js
@@ -26,7 +26,7 @@
import { permittedOperations } from './permittedOperations';
import { gpgme_error } from './Errors';
import { GPGME_Message, createMessage } from './Message';
-import { decode } from './Helpers';
+import { decode, atobArray, Utf8ArrayToStr } from './Helpers';
/**
* A Connection handles the nativeMessaging interaction via a port. As the
@@ -223,8 +223,9 @@ class Answer{
}
}
/**
- * Returns the base64 encoded answer data with the content verified
- * against {@link permittedOperations}.
+ * Decodes and verifies the base64 encoded answer data. Verified against
+ * {@link permittedOperations}.
+ * @returns {Object} The readable gpnupg answer
*/
getMessage (){
if (this._response_b64 === null){
@@ -264,14 +265,15 @@ class Answer{
}
if (_decodedResponse.base64 === true
&& poa.data[key] === 'string'
- && this.expected !== 'base64'
- ){
- _response[key] = decodeURIComponent(
- atob(_decodedResponse[key]).split('').map(
- function (c) {
- return '%' +
- ('00' + c.charCodeAt(0).toString(16)).slice(-2);
- }).join(''));
+ ) {
+ if (this.expected === 'binary'){
+ _response[key] = atobArray(_decodedResponse[key]);
+ _response.binary = true;
+ } else {
+ _response[key] = Utf8ArrayToStr(
+ atobArray(_decodedResponse[key]));
+ _response.binary = false;
+ }
} else {
_response[key] = decode(_decodedResponse[key]);
}
diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js
index 73418028..145c3a59 100644
--- a/lang/js/src/Errors.js
+++ b/lang/js/src/Errors.js
@@ -103,6 +103,10 @@ export const err_list = {
msg: 'Invalid parameter was found',
type: 'error'
},
+ 'DECODE_FAIL': {
+ msg: 'Decoding failed due to unexpected data',
+ type: 'error'
+ },
'PARAM_IGNORED': {
msg: 'An parameter was set that has no effect in gpgmejs',
type: 'warning'
diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js
index ba4277ab..9fa5775b 100644
--- a/lang/js/src/Helpers.js
+++ b/lang/js/src/Helpers.js
@@ -134,4 +134,73 @@ export function decode (property){
return property;
}
return property;
-} \ No newline at end of file
+}
+
+/**
+ * Turns a base64 encoded string into an uint8 array
+ * @param {String} base64 encoded String
+ * @returns {Uint8Array}
+ * adapted from https://gist.github.com/borismus/1032746
+ */
+export function atobArray (base64) {
+ if (typeof (base64) !== 'string'){
+ throw gpgme_error('DECODE_FAIL');
+ }
+ const raw = window.atob(base64);
+ const rawLength = raw.length;
+ let array = new Uint8Array(new ArrayBuffer(rawLength));
+ for (let i = 0; i < rawLength; i++) {
+ array[i] = raw.charCodeAt(i);
+ }
+ return array;
+}
+
+/**
+ * Turns a Uint8Array into an utf8-String
+ * @param {*} array Uint8Array
+ * @returns {String}
+ * Taken and slightly adapted from
+ * http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt
+ * (original header:
+ * utf.js - UTF-8 <=> UTF-16 convertion
+ *
+ * Copyright (C) 1999 Masanao Izumo <[email protected]>
+ * Version: 1.0
+ * LastModified: Dec 25 1999
+ * This library is free. You can redistribute it and/or modify it.
+ * )
+ */
+export function Utf8ArrayToStr (array) {
+ let out, i, len, c, char2, char3;
+ out = '';
+ len = array.length;
+ i = 0;
+ if (array instanceof Uint8Array === false){
+ throw gpgme_error('DECODE_FAIL');
+ }
+ while (i < len) {
+ c = array[i++];
+ switch (c >> 4) {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ // 0xxxxxxx
+ out += String.fromCharCode(c);
+ break;
+ case 12: case 13:
+ // 110x xxxx 10xx xxxx
+ char2 = array[i++];
+ out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14:
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ char2 = array[i++];
+ char3 = array[i++];
+ out += String.fromCharCode(((c & 0x0F) << 12) |
+ ((char2 & 0x3F) << 6) |
+ ((char3 & 0x3F) << 0));
+ break;
+ default:
+ break;
+ }
+ }
+ return out;
+}
diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js
index b83caf6d..48813df7 100644
--- a/lang/js/src/Message.js
+++ b/lang/js/src/Message.js
@@ -64,7 +64,7 @@ export class GPGME_Message {
}
set expected (value){
- if (value === 'base64'){
+ if (value === 'binary'){
this._expected = value;
}
}
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index 7692298f..513e4a56 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -30,8 +30,8 @@ import { createSignature } from './Signature';
/**
* @typedef {Object} decrypt_result
- * @property {String} data The decrypted data
- * @property {Boolean} base64 indicating whether data is base64 encoded.
+ * @property {String|Uint8Array} data The decrypted data
+ * @property {Boolean} binary indicating whether data is an Uint8Array.
* @property {Boolean} is_mime (optional) the data claims to be a MIME
* object.
* @property {String} file_name (optional) the original file name
@@ -51,7 +51,8 @@ import { createSignature } from './Signature';
/**
* @typedef {Object} encrypt_result The result of an encrypt operation
* @property {String} data The encrypted message
- * @property {Boolean} base64 Indicating whether data is base64 encoded.
+ * @property {Boolean} binary Indicating whether returning payload data is an
+ * Uint8Array.
*/
/**
@@ -174,10 +175,12 @@ export class GpgME {
* Strings and Objects with a getText method
* @param {Boolean} base64 (optional) false if the data is an armored
* block, true if it is base64 encoded binary data
+ * @param {Boolean} binary (optional) if true, treat the decoded data as
+ * binary, and return the data as Uint8Array
* @returns {Promise<decrypt_result>} Decrypted Message and information
* @async
*/
- decrypt (data, base64=false){
+ decrypt (data, base64=false, binary){
if (data === undefined){
return Promise.reject(gpgme_error('MSG_EMPTY'));
}
@@ -189,11 +192,14 @@ export class GpgME {
if (base64 === true){
msg.setParameter('base64', true);
}
+ if (binary === true){
+ msg.expected = 'binary';
+ }
putData(msg, data);
return new Promise(function (resolve, reject){
msg.post().then(function (result){
let _result = { data: result.data };
- _result.base64 = result.base64 ? true: false;
+ _result.binary = result.binary ? true: false;
if (result.hasOwnProperty('dec_info')){
_result.is_mime = result.dec_info.is_mime ? true: false;
if (result.dec_info.file_name) {
@@ -251,7 +257,7 @@ export class GpgME {
putData(msg, data);
return new Promise(function (resolve,reject) {
if (mode ==='detached'){
- msg.expected ='base64';
+ msg.expected ='binary';
}
msg.post().then( function (message) {
if (mode === 'clearsign'){