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 rrenkert@intevation.de 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.
This commit is contained in:
parent
94a0ed361e
commit
129fa919b9
@ -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]);
|
||||
}
|
||||
|
@ -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'
|
||||
|
@ -134,4 +134,73 @@ export function decode (property){
|
||||
return property;
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <iz@onicos.co.jp>
|
||||
* 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;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ export class GPGME_Message {
|
||||
}
|
||||
|
||||
set expected (value){
|
||||
if (value === 'base64'){
|
||||
if (value === 'binary'){
|
||||
this._expected = value;
|
||||
}
|
||||
}
|
||||
|
@ -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'){
|
||||
|
Loading…
Reference in New Issue
Block a user