Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36623087
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
51 KB
Subscribers
None
View Options
diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js
index d8fd8c81..59027088 100644
--- a/lang/js/src/Keyring.js
+++ b/lang/js/src/Keyring.js
@@ -1,469 +1,439 @@
/* 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+
*
* Author(s):
* Maximilian Krambach <mkrambach@intevation.de>
*/
import { createMessage } from './Message';
import { createKey } from './Key';
import { isFingerprint } from './Helpers';
import { gpgme_error } from './Errors';
/**
* This class offers access to the gnupg keyring
*/
export class GPGME_Keyring {
/**
* Queries Keys (all Keys or a subset) from gnupg.
*
- * @param {Object} options
+ * @param {Object} options:
* @param {String | Array<String>} options.pattern (optional) A pattern to
* search for in userIds or KeyIds.
* @param {Boolean} options.prepare_sync (optional) if set to true, most
* data (with the exception of armored Key blocks) will be cached for the
* Keys. This enables direct, synchronous use of these properties for
* all keys. It does not check for changes on the backend. The cached
* information can be updated with the {@link Key.refresh} method.
* @param {Boolean} options.search (optional) retrieve Keys from external
* servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
* @returns {Promise<Array<GPGME_Key>>}
* @static
* @async
*/
- getKeys (options){
- if (options && typeof options !== 'object'){
- return Promise.reject(gpgme_error('PARAM_WRONG'));
- }
+ getKeys ({ pattern, prepare_sync = false, search = false }){
return new Promise(function (resolve, reject) {
let msg = createMessage('keylist');
- if (options && options.pattern) {
- if (
- typeof options.pattern === 'string'
- || Array.isArray(options.pattern)
- ){
- msg.setParameter('keys', options.pattern);
- } else {
- reject(gpgme_error('PARAM_WRONG'));
- }
+ if (pattern) {
+ msg.setParameter('keys', pattern);
}
msg.setParameter('sigs', true);
- if (options && options.search === true){
+ if (search === true){
msg.setParameter('locate', true);
}
msg.post().then(function (result){
let resultset = [];
if (result.keys.length === 0){
resolve([]);
} else {
let secondrequest;
- if (options && options.prepare_sync === true) {
+ if (prepare_sync === true) {
secondrequest = function () {
let msg2 = createMessage('keylist');
- if (options.pattern){
- msg2.setParameter('keys', options.pattern);
+ if (pattern){
+ msg2.setParameter('keys', pattern);
}
msg2.setParameter('secret', true);
return msg2.post();
};
} else {
secondrequest = function () {
return Promise.resolve(true);
};
}
secondrequest().then(function (answer) {
for (let i=0; i < result.keys.length; i++){
- if (options.prepare_sync === true){
+ if (prepare_sync === true){
if (answer && answer.keys) {
for (let j=0;
j < answer.keys.length; j++ ){
const a = answer.keys[j];
const b = result.keys[i];
if (
a.fingerprint === b.fingerprint
) {
if (a.secret === true){
b.hasSecret = true;
} else {
b.hasSecret = false;
}
break;
}
}
}
}
let k = createKey(result.keys[i].fingerprint,
- !options.prepare_sync, result.keys[i]);
+ !prepare_sync, result.keys[i]);
resultset.push(k);
}
resolve(resultset);
}, function (error){
reject(error);
});
}
});
});
}
/**
* @typedef {Object} exportResult The result of a getKeysArmored
* operation.
* @property {String} armored The public Key(s) as armored block. Note
* that the result is one armored block, and not a block per key.
* @property {Array<String>} secret_fprs (optional) list of
* fingerprints for those Keys that also have a secret Key available in
* gnupg. The secret key will not be exported, but the fingerprint can
* be used in operations needing a secret key.
*/
/**
* Fetches the armored public Key blocks for all Keys matching the
* pattern (if no pattern is given, fetches all keys known to gnupg).
* @param {Object} options (optional)
* @param {String|Array<String>} options.pattern The Pattern to
* search for
* @param {Boolean} options.with_secret_fpr also return a list of
* fingerprints for the keys that have a secret key available
* @returns {Promise<exportResult|GPGME_Error>} Object containing the
* armored Key(s) and additional information.
* @static
* @async
*/
- getKeysArmored (options) {
- if (options && typeof options !== 'object'){
- return Promise.reject(gpgme_error('PARAM_WRONG'));
- }
+ getKeysArmored ({ pattern, with_secret_fpr }) {
return new Promise(function (resolve, reject) {
let msg = createMessage('export');
msg.setParameter('armor', true);
- if (options.with_secret_fpr === true) {
+ if (with_secret_fpr === true) {
msg.setParameter('with-sec-fprs', true);
}
- if (options.pattern){
- if (
- typeof options.pattern === 'string'
- || Array.isArray(options.pattern)
- ){
- msg.setParameter('keys', options.pattern);
- }
+ if (pattern){
+ msg.setParameter('keys', pattern);
}
msg.post().then(function (answer){
const result = { armored: answer.data };
- if (options.with_secret_fpr === true){
+ if (with_secret_fpr === true){
if (answer.hasOwnProperty('sec-fprs')){
result.secret_fprs = answer['sec-fprs'];
} else {
result.secret_fprs = [];
}
}
resolve(result);
}, function (error){
reject(error);
});
});
}
/**
* Returns the Key used by default in gnupg.
* (a.k.a. 'primary Key or 'main key').
* It looks up the gpg configuration if set, or the first key that
* contains a secret key.
*
* @returns {Promise<GPGME_Key|GPGME_Error>}
* @async
* @static
*/
getDefaultKey (prepare_sync = false) {
let me = this;
return new Promise(function (resolve, reject){
let msg = createMessage('config_opt');
msg.setParameter('component', 'gpg');
msg.setParameter('option', 'default-key');
msg.post().then(function (resp){
if (resp.option !== undefined
&& resp.option.hasOwnProperty('value')
&& resp.option.value.length === 1
&& resp.option.value[0].hasOwnProperty('string')
&& typeof (resp.option.value[0].string) === 'string'){
me.getKeys(resp.option.value[0].string, true).then(
function (keys){
if (keys.length === 1){
resolve(keys[0]);
} else {
reject(gpgme_error('KEY_NO_DEFAULT'));
}
}, function (error){
reject(error);
});
} else {
let msg = createMessage('keylist');
msg.setParameter('secret', true);
msg.post().then(function (result){
if (result.keys.length === 0){
reject(gpgme_error('KEY_NO_DEFAULT'));
} else {
for (let i=0; i< result.keys.length; i++ ) {
if (
result.keys[i].invalid === false &&
result.keys[i].expired === false &&
result.keys[i].revoked === false &&
result.keys[i].can_sign === true
) {
let k = createKey(
result.keys[i].fingerprint,
!prepare_sync,
result.keys[i]);
resolve(k);
break;
} else if (i === result.keys.length - 1){
reject(gpgme_error('KEY_NO_DEFAULT'));
}
}
}
}, function (error){
reject(error);
});
}
}, function (error){
reject(error);
});
});
}
/**
* @typedef {Object} importResult The result of a Key update
* @property {Object} summary Numerical summary of the result. See the
* feedbackValues variable for available Keys values and the gnupg
* documentation.
* https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html
* for details on their meaning.
* @property {Array<importedKeyResult>} Keys Array of Object containing
* GPGME_Keys with additional import information
*
*/
/**
* @typedef {Object} importedKeyResult
* @property {GPGME_Key} key The resulting key
* @property {String} status:
* 'nochange' if the Key was not changed,
* 'newkey' if the Key was imported in gpg, and did not exist
* previously,
* 'change' if the key existed, but details were updated. For details,
* Key.changes is available.
* @property {Boolean} changes.userId Changes in userIds
* @property {Boolean} changes.signature Changes in signatures
* @property {Boolean} changes.subkey Changes in subkeys
*/
/**
* Import an armored Key block into gnupg. Note that this currently
* will not succeed on private Key blocks.
* @param {String} armored Armored Key block of the Key(s) to be
* imported into gnupg
* @param {Boolean} prepare_sync prepare the keys for synched use
* (see {@link getKeys}).
* @returns {Promise<importResult>} A summary and Keys considered.
* @async
* @static
*/
importKey (armored, prepare_sync) {
let feedbackValues = ['considered', 'no_user_id', 'imported',
'imported_rsa', 'unchanged', 'new_user_ids', 'new_sub_keys',
'new_signatures', 'new_revocations', 'secret_read',
'secret_imported', 'secret_unchanged', 'skipped_new_keys',
'not_imported', 'skipped_v3_keys'];
if (!armored || typeof (armored) !== 'string'){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
let me = this;
return new Promise(function (resolve, reject){
let msg = createMessage('import');
msg.setParameter('data', armored);
msg.post().then(function (response){
let infos = {};
let fprs = [];
let summary = {};
for (let i=0; i < feedbackValues.length; i++ ){
summary[feedbackValues[i]] =
response.result[feedbackValues[i]];
}
if (!response.result.hasOwnProperty('imports') ||
response.result.imports.length === 0
){
resolve({ Keys:[],summary: summary });
return;
}
for (let res=0; res<response.result.imports.length; res++){
let result = response.result.imports[res];
let status = '';
if (result.status === 0){
status = 'nochange';
} else if ((result.status & 1) === 1){
status = 'newkey';
} else {
status = 'change';
}
let changes = {};
changes.userId = (result.status & 2) === 2;
changes.signature = (result.status & 4) === 4;
changes.subkey = (result.status & 8) === 8;
// 16 new secret key: not implemented
fprs.push(result.fingerprint);
infos[result.fingerprint] = {
changes: changes,
status: status
};
}
let resultset = [];
if (prepare_sync === true){
me.getKeys({ pattern: fprs, prepare_sync: true })
.then(function (result){
for (let i=0; i < result.length; i++) {
resultset.push({
key: result[i],
changes:
infos[result[i].fingerprint].changes,
status: infos[result[i].fingerprint].status
});
}
resolve({ Keys:resultset,summary: summary });
}, function (error){
reject(error);
});
} else {
for (let i=0; i < fprs.length; i++) {
resultset.push({
key: createKey(fprs[i]),
changes: infos[fprs[i]].changes,
status: infos[fprs[i]].status
});
}
resolve({ Keys:resultset,summary:summary });
}
}, function (error){
reject(error);
});
});
}
/**
* Convenience function for deleting a Key. See {@link Key.delete} for
* further information about the return values.
* @param {String} fingerprint
* @returns {Promise<Boolean|GPGME_Error>}
* @async
* @static
*/
deleteKey (fingerprint){
if (isFingerprint(fingerprint) === true) {
let key = createKey(fingerprint);
return key.delete();
} else {
return Promise.reject(gpgme_error('KEY_INVALID'));
}
}
/**
* Generates a new Key pair directly in gpg, and returns a GPGME_Key
* representing that Key. Please note that due to security concerns,
* secret Keys can not be deleted or exported from inside gpgme.js.
* @param {Object} options
* @param {String} option.userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
* @param {String} option.algo (optional) algorithm (and optionally key
* size) to be used. See {@link supportedKeyAlgos} below for supported
* values. If ommitted, 'default' is used.
* @param {Number} option.expires (optional) Expiration time in seconds
* from now. If not set or set to 0, expiration will be 'never'
* @param {String} options.subkey_algo (optional) algorithm of the
* encryption subkey. If ommited the same as algo is used.
*
* @return {Promise<Key|GPGME_Error>}
* @async
*/
- generateKey (options){
- if (!options
- || typeof options !== 'object'
- || typeof options.userId !== 'string'
+ generateKey ({ userId, algo = 'default', expires= 0, subkey_algo }){
+ if (typeof userId !== 'string'
// eslint-disable-next-line no-use-before-define
- || ( options.algo && supportedKeyAlgos.indexOf(options.algo) < 0 )
- || ( options.expires && !(
- Number.isInteger(options.expires) || options.expires < 0 ) )
+ || (algo && supportedKeyAlgos.indexOf(algo) < 0 )
+ || (!Number.isInteger(expires) || expires < 0 )
){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
// eslint-disable-next-line no-use-before-define
- if (options.subkey_algo && supportedKeyAlgos.indexOf(
- options.subkey_algo) < 0
- ){
+ if (subkey_algo && supportedKeyAlgos.indexOf(subkey_algo) < 0){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
let me = this;
return new Promise(function (resolve, reject){
let msg = createMessage('createkey');
- msg.setParameter('userid', options.userId);
- if (!options.algo){
- options.algo === 'default';
- }
- msg.setParameter('algo', options.algo);
- if (options.subkey_algo) {
- msg.setParameter('subkey-algo', options.subkey_algo );
- }
- if (options.expires){
- msg.setParameter('expires', options.expires);
- } else {
- msg.setParameter('expires', 0);
+ msg.setParameter('userid', userId);
+ msg.setParameter('algo', algo);
+ if (subkey_algo) {
+ msg.setParameter('subkey-algo',subkey_algo );
}
+ msg.setParameter('expires', expires);
msg.post().then(function (response){
me.getKeys(response.fingerprint, true).then(
// TODO prepare_sync?
function (result){
resolve(result);
}, function (error){
reject(error);
});
}, function (error) {
reject(error);
});
});
}
}
/**
* List of algorithms supported for key generation. Please refer to the gnupg
* documentation for details
*/
const supportedKeyAlgos = [
'default',
'rsa', 'rsa2048', 'rsa3072', 'rsa4096',
'dsa', 'dsa2048', 'dsa3072', 'dsa4096',
'elg', 'elg2048', 'elg3072', 'elg4096',
'ed25519',
'cv25519',
'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1',
'NIST P-256', 'NIST P-384', 'NIST P-521'
];
\ No newline at end of file
diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js
index ac640308..ffee719c 100644
--- a/lang/js/src/gpgmejs.js
+++ b/lang/js/src/gpgmejs.js
@@ -1,427 +1,414 @@
/* 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+
*
* Author(s):
* Maximilian Krambach <mkrambach@intevation.de>
*/
import { GPGME_Message, createMessage } from './Message';
import { toKeyIdArray } from './Helpers';
import { gpgme_error } from './Errors';
import { GPGME_Keyring } from './Keyring';
import { createSignature } from './Signature';
/**
* @typedef {Object} decrypt_result
* @property {String|Uint8Array} data The decrypted data
* @property {String} format Indicating how the data was converted after being
* received from gpgme.
* 'string': Data was decoded into an utf-8 string,
* 'base64': Data was not processed and is a base64 string
* 'uint8': data was turned into a Uint8Array
* @property {Boolean} is_mime (optional) the data claims to be a MIME
* object.
* @property {String} file_name (optional) the original file name
* @property {signatureDetails} signatures Verification details for
* signatures
*/
/**
* @typedef {Object} signatureDetails
* @property {Boolean} all_valid Summary if all signatures are fully valid
* @property {Number} count Number of signatures found
* @property {Number} failures Number of invalid signatures
* @property {Array<GPGME_Signature>} signatures.good All valid signatures
* @property {Array<GPGME_Signature>} signatures.bad All invalid signatures
*/
/**
* @typedef {Object} encrypt_result The result of an encrypt operation
* @property {String} data The encrypted message
* @property {Boolean} base64 Indicating whether returning payload data is
* base64 encoded
*/
/**
* @typedef { GPGME_Key | String | Object } inputKeys
* Accepts different identifiers of a gnupg Key that can be parsed by
* {@link toKeyIdArray}. Expected inputs are: One or an array of
* GPGME_Keys; one or an array of fingerprint strings; one or an array of
* openpgpjs Key objects.
*/
/**
* @typedef {Object} signResult The result of a signing operation
* @property {String} data The resulting data. Includes the signature in
* clearsign mode
* @property {String} signature The detached signature (if in detached mode)
*/
/** @typedef {Object} verifyResult The result of a verification
* @property {Boolean} data: The verified data
* @property {Boolean} is_mime (optional) the data claims to be a MIME
* object.
* @property {String} file_name (optional) the original file name
* @property {signatureDetails} signatures Verification details for
* signatures
*/
/**
* The main entry point for gpgme.js.
* @class
*/
export class GpgME {
constructor (){
this._Keyring = null;
}
/**
* setter for {@link setKeyring}.
* @param {GPGME_Keyring} keyring A Keyring to use
*/
set Keyring (keyring){
if (keyring && keyring instanceof GPGME_Keyring){
this._Keyring = keyring;
}
}
/**
* Accesses the {@link GPGME_Keyring}.
*/
get Keyring (){
if (!this._Keyring){
this._Keyring = new GPGME_Keyring;
}
return this._Keyring;
}
/**
* Encrypt (and optionally sign) data
* @param {Object} options
* @param {String|Object} options.data text/data to be encrypted as String.
* Also accepts Objects with a getText method
* @param {inputKeys} options.publicKeys
* Keys used to encrypt the message
* @param {inputKeys} opions.secretKeys (optional) Keys used to sign the
* message. If Keys are present, the operation requested is assumed
* to be 'encrypt and sign'
* @param {Boolean} options.base64 (optional) The data will be interpreted
* as base64 encoded data.
* @param {Boolean} options.armor (optional) Request the output as armored
* block.
* @param {Boolean} options.wildcard (optional) If true, recipient
* information will not be added to the message.
* @param {Object} additional use additional valid gpg options as
* defined in {@link permittedOperations}
* @returns {Promise<encrypt_result>} Object containing the encrypted
* message and additional info.
* @async
*/
- encrypt (options){
- if (!options || (typeof options !== 'object')){
- return Promise.reject(gpgme_error('PARAM_WRONG'));
- }
- if (!options.hasOwnProperty('data')
- || !options.hasOwnProperty('publicKeys')
- ){
+ encrypt ({ data, publicKeys, secretKeys, base64 = false, armor = true,
+ wildcard, additional = {} }){
+ if (!data || !publicKeys){
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
}
let msg = createMessage('encrypt');
if (msg instanceof Error){
return Promise.reject(msg);
}
- if (!options.hasOwnProperty('armor')){
- options.armor = true;
- }
- msg.setParameter('armor', options.armor);
+ msg.setParameter('armor', armor);
- if (options.base64 === true) {
+ if (base64 === true) {
msg.setParameter('base64', true);
}
- let pubkeys = toKeyIdArray(options.publicKeys);
+ let pubkeys = toKeyIdArray(publicKeys);
+ if (!pubkeys.length) {
+ return Promise.reject(gpgme_error('MSG_NO_KEYS'));
+ }
msg.setParameter('keys', pubkeys);
- let sigkeys = toKeyIdArray(options.secretKeys);
+ let sigkeys = toKeyIdArray(secretKeys);
if (sigkeys.length > 0) {
msg.setParameter('signing_keys', sigkeys);
}
- putData(msg, options.data);
- if (options.wildcard === true){
+ putData(msg, data);
+ if (wildcard === true){
msg.setParameter('throw-keyids', true);
}
- if (options.additional){
- let additional_Keys = Object.keys(options.additional);
+ if (additional){
+ let additional_Keys = Object.keys(additional);
for (let k = 0; k < additional_Keys.length; k++) {
try {
msg.setParameter(additional_Keys[k],
- options.additional[additional_Keys[k]]);
+ additional[additional_Keys[k]]);
}
catch (error){
return Promise.reject(error);
}
}
}
if (msg.isComplete() === true){
return msg.post();
} else {
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
}
}
/**
* Decrypts a Message
* @param {Object} options
* @param {String|Object} options.data text/data to be decrypted. Accepts
* Strings and Objects with a getText method
* @param {Boolean} options.base64 (optional) false if the data is an
* armored block, true if it is base64 encoded binary data
* @param {String} options.expect (optional) can be set to 'uint8' or
* 'base64'. Does no extra decoding on the data, and returns the decoded
* data as either Uint8Array or unprocessed(base64 encoded) string.
* @returns {Promise<decrypt_result>} Decrypted Message and information
* @async
*/
- decrypt (options){
- if (!options || (typeof options !== 'object')){
- return Promise.reject('PARAM_WRONG');
- }
- if (!options.data){
+ decrypt ({ data, base64, expect }){
+ if (!data){
return Promise.reject(gpgme_error('MSG_EMPTY'));
}
let msg = createMessage('decrypt');
if (msg instanceof Error){
return Promise.reject(msg);
}
- if (options.base64 === true){
+ if (base64 === true){
msg.setParameter('base64', true);
}
- if (options.expect === 'base64' || options.expect === 'uint8'){
- msg.expected = options.expect;
+ if (expect === 'base64' || expect === 'uint8'){
+ msg.expected = expect;
}
- putData(msg, options.data);
+ putData(msg, data);
return new Promise(function (resolve, reject){
msg.post().then(function (result){
let _result = { data: result.data };
_result.format = result.format ? result.format : null;
if (result.hasOwnProperty('dec_info')){
_result.is_mime = result.dec_info.is_mime ? true: false;
if (result.dec_info.file_name) {
_result.file_name = result.dec_info.file_name;
}
}
if (!result.file_name) {
_result.file_name = null;
}
if (result.hasOwnProperty('info')
&& result.info.hasOwnProperty('signatures')
&& Array.isArray(result.info.signatures)
) {
_result.signatures = collectSignatures(
result.info.signatures);
}
if (_result.signatures instanceof Error){
reject(_result.signatures);
} else {
resolve(_result);
}
}, function (error){
reject(error);
});
});
}
/**
* Sign a Message
* @param {Object} options Signing options
* @param {String|Object} options.data text/data to be signed. Accepts
* Strings and Objects with a getText method.
* @param {inputKeys} options.keys The key/keys to use for signing
* @param {String} options.mode The signing mode. Currently supported:
* 'clearsign':The Message is embedded into the signature;
* 'detached': The signature is stored separately
* @param {Boolean} options.base64 input is considered base64
* @returns {Promise<signResult>}
* @async
*/
- sign (options){
- if (
- !options || (typeof options !== 'object')){
- return Promise.reject(gpgme_error('PARAM_WRONG'));
- }
- if (!options.data){
+ sign ({ data, keys, mode = 'clearsign', base64 }){
+ if (!data){
return Promise.reject(gpgme_error('MSG_EMPTY'));
}
- if (!options.mode) {
- options.mode = 'clearsign';
- }
- let key_arr = toKeyIdArray(options.keys);
+ let key_arr = toKeyIdArray(keys);
if (key_arr.length === 0){
return Promise.reject(gpgme_error('MSG_NO_KEYS'));
}
- let msg = createMessage('sign');
+ let msg = createMessage('sign');
msg.setParameter('keys', key_arr);
- if (options.base64 === true){
+ if (base64 === true){
msg.setParameter('base64', true);
}
- msg.setParameter('mode', options.mode);
- putData(msg, options.data);
+ msg.setParameter('mode', mode);
+ putData(msg, data);
+
return new Promise(function (resolve,reject) {
msg.post().then( function (message) {
- if (options.mode === 'clearsign'){
+ if (mode === 'clearsign'){
resolve({
data: message.data }
);
- } else if (options.mode === 'detached') {
+ } else if (mode === 'detached') {
resolve({
- data: options.data,
+ data: data,
signature: message.data
});
}
}, function (error){
reject(error);
});
});
}
/**
* Verifies data.
* @param {Object} options
* @param {String|Object} options.data text/data to be verified. Accepts
* Strings and Objects with a getText method
* @param {String} options.signature A detached signature. If not present,
* opaque mode is assumed
* @param {Boolean} options.base64 Indicating that data and signature are
* base64 encoded
* @returns {Promise<verifyResult>}
*@async
*/
- verify (options){
- if (!options || (typeof options !== 'object') || !options.data){
+ verify ({ data, signature, base64 }){
+ if (!data){
return Promise.reject(gpgme_error('PARAM_WRONG'));
}
let msg = createMessage('verify');
- let dt = putData(msg, options.data);
+ let dt = putData(msg, data);
if (dt instanceof Error){
return Promise.reject(dt);
}
- if (options.signature){
+ if (signature){
if (typeof signature !== 'string'){
return Promise.reject(gpgme_error('PARAM_WRONG'));
} else {
msg.setParameter('signature', signature);
}
}
- if (options.base64 === true){
+ if (base64 === true){
msg.setParameter('base64', true);
}
return new Promise(function (resolve, reject){
msg.post().then(function (message){
if (!message.info || !message.info.signatures){
reject(gpgme_error('SIG_NO_SIGS'));
} else {
let _result = {
signatures: collectSignatures(message.info.signatures)
};
if (_result.signatures instanceof Error){
reject(_result.signatures);
} else {
_result.is_mime = message.info.is_mime? true: false;
if (message.info.filename){
_result.file_name = message.info.filename;
}
_result.data = message.data;
resolve(_result);
}
}
}, function (error){
reject(error);
});
});
}
}
/**
* Sets the data of the message, setting flags according on the data type
* @param {GPGME_Message} message The message where this data will be set
* @param { String| Object } data The data to enter. Expects either a string of
* data, or an object with a getText method
* @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise
* @private
*/
function putData (message, data){
if (!message || !(message instanceof GPGME_Message)) {
return gpgme_error('PARAM_WRONG');
}
if (!data){
return gpgme_error('PARAM_WRONG');
} else if (typeof data === 'string') {
message.setParameter('data', data);
} else if (
(typeof data === 'object') &&
(typeof data.getText === 'function')
){
let txt = data.getText();
if (typeof txt === 'string'){
message.setParameter('data', txt);
} else {
return gpgme_error('PARAM_WRONG');
}
} else {
return gpgme_error('PARAM_WRONG');
}
}
/**
* Parses, validates and converts incoming objects into signatures.
* @param {Array<Object>} sigs
* @returns {signatureDetails} Details about the signatures
*/
function collectSignatures (sigs){
if (!Array.isArray(sigs)){
return gpgme_error('SIG_NO_SIGS');
}
let summary = {
all_valid: false,
count: sigs.length,
failures: 0,
signatures: {
good: [],
bad: [],
}
};
for (let i=0; i< sigs.length; i++){
let sigObj = createSignature(sigs[i]);
if (sigObj instanceof Error) {
return gpgme_error('SIG_WRONG');
}
if (sigObj.valid !== true){
summary.failures += 1;
summary.signatures.bad.push(sigObj);
} else {
summary.signatures.good.push(sigObj);
}
}
if (summary.failures === 0){
summary.all_valid = true;
}
return summary;
}
\ No newline at end of file
diff --git a/lang/js/unittests.js b/lang/js/unittests.js
index 212effd3..8f1ffb66 100644
--- a/lang/js/unittests.js
+++ b/lang/js/unittests.js
@@ -1,379 +1,381 @@
/* 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 './node_modules/mocha/mocha'; /* global mocha, it, describe*/
import './node_modules/chai/chai';/* global chai*/
import { helper_params as hp } from './unittest_inputvalues';
import { message_params as mp } from './unittest_inputvalues';
import { whatever_params as wp } from './unittest_inputvalues';
import { key_params as kp } from './unittest_inputvalues';
import { Connection } from './src/Connection';
import { gpgme_error, err_list } from './src/Errors';
import { toKeyIdArray , isFingerprint } from './src/Helpers';
import { createKey } from './src/Key';
import { GPGME_Keyring } from './src/Keyring';
import { GPGME_Message, createMessage } from './src/Message';
mocha.setup('bdd');
const expect = chai.expect;
chai.config.includeStack = true;
function unittests (){
describe('Connection testing', function (){
it('Connecting', function (done) {
let conn0 = new Connection;
conn0.checkConnection().then(function (answer) {
expect(answer).to.not.be.empty;
expect(answer.gpgme).to.not.be.undefined;
expect(answer.gpgme).to.be.a('string');
expect(answer.info).to.be.an('Array');
expect(conn0.disconnect).to.be.a('function');
expect(conn0.post).to.be.a('function');
done();
});
});
it('Disconnecting', function (done) {
let conn0 = new Connection;
conn0.checkConnection(false).then(function (answer) {
expect(answer).to.be.true;
conn0.disconnect();
conn0.checkConnection(false).then(function (result) {
expect(result).to.be.false;
done();
});
});
});
});
describe('Error Object handling', function (){
// TODO: new GPGME_Error codes
it('check the Timeout error', function (){
let test0 = gpgme_error('CONN_TIMEOUT');
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('CONN_TIMEOUT');
});
it('Error Object returns generic code if code is not listed',
function (){
let test0 = gpgme_error(hp.invalidErrorCode);
expect(test0).to.be.an.instanceof(Error);
expect(test0.code).to.equal('GENERIC_ERROR');
}
);
it('Warnings like PARAM_IGNORED should not return errors', function (){
let test0 = gpgme_error('PARAM_IGNORED');
expect(test0).to.be.null;
});
});
describe('Fingerprint checking', function (){
it('isFingerprint(): valid Fingerprint', function (){
let test0 = isFingerprint(hp.validFingerprint);
expect(test0).to.be.true;
});
it('isFingerprint(): invalid Fingerprints', function (){
for (let i=0; i < hp.invalidFingerprints.length; i++){
let test0 = isFingerprint(hp.invalidFingerprints[i]);
expect(test0).to.be.false;
}
});
});
describe('toKeyIdArray() (converting input to fingerprint)', function (){
it('Correct fingerprint string', function (){
let test0 = toKeyIdArray(hp.validFingerprint);
expect(test0).to.be.an('array');
expect(test0).to.include(hp.validFingerprint);
});
it('openpgpjs-like object', function (){
let test0 = toKeyIdArray(hp.valid_openpgplike);
expect(test0).to.be.an('array').with.lengthOf(1);
expect(test0).to.include(
hp.valid_openpgplike.primaryKey.getFingerprint());
});
it('Array of valid inputs', function (){
let test0 = toKeyIdArray(hp.validKeys);
expect(test0).to.be.an('array');
expect(test0).to.have.lengthOf(hp.validKeys.length);
});
it('Incorrect inputs', function (){
it('valid Long ID', function (){
let test0 = toKeyIdArray(hp.validLongId);
expect(test0).to.be.empty;
});
it('invalidFingerprint', function (){
let test0 = toKeyIdArray(hp.invalidFingerprint);
expect(test0).to.be.empty;
});
it('invalidKeyArray', function (){
let test0 = toKeyIdArray(hp.invalidKeyArray);
expect(test0).to.be.empty;
});
it('Partially invalid array', function (){
let test0 = toKeyIdArray(hp.invalidKeyArray_OneBad);
expect(test0).to.be.an('array');
expect(test0).to.have.lengthOf(
hp.invalidKeyArray_OneBad.length - 1);
});
});
});
describe('GPGME_Key', function (){
it('Key has data after a first refresh', function (done) {
let key = createKey(kp.validKeyFingerprint);
key.refreshKey().then(function (key2){
expect(key2.get).to.be.a('function');
for (let i=0; i < kp.validKeyProperties.length; i++) {
let prop = key2.get(kp.validKeyProperties[i]);
expect(prop).to.not.be.undefined;
expect(prop).to.be.a('boolean');
}
expect(isFingerprint(key2.get('fingerprint'))).to.be.true;
expect(
key2.get('fingerprint')).to.equal(kp.validKeyFingerprint);
expect(
key2.get('fingerprint')).to.equal(key.fingerprint);
done();
});
});
it('Non-cached key async data retrieval', function (done){
let key = createKey(kp.validKeyFingerprint, true);
key.get('can_authenticate').then(function (result){
expect(result).to.be.a('boolean');
done();
});
});
it('Non-cached key async armored Key', function (done){
let key = createKey(kp.validKeyFingerprint, true);
key.get('armored').then(function (result){
expect(result).to.be.a('string');
expect(result).to.include('KEY BLOCK-----');
done();
});
});
it('Non-cached key async hasSecret', function (done){
let key = createKey(kp.validKeyFingerprint, true);
key.get('hasSecret').then(function (result){
expect(result).to.be.a('boolean');
done();
});
});
it('Non-cached key async hasSecret (no secret in Key)', function (done){
let key = createKey(kp.validFingerprintNoSecret, true);
key.get('hasSecret').then(function (result){
expect(result).to.be.a('boolean');
expect(result).to.equal(false);
done();
});
});
it('Querying non-existing Key returns an error', function (done) {
let key = createKey(kp.invalidKeyFingerprint);
key.refreshKey().then(function (){},
function (error){
expect(error).to.be.an.instanceof(Error);
expect(error.code).to.equal('KEY_NOKEY');
done();
});
});
it('createKey returns error if parameters are wrong', function (){
for (let i=0; i< 4; i++){
expect(function (){
createKey(wp.four_invalid_params[i]);
}).to.throw(
err_list.PARAM_WRONG.msg
);
}
});
// it('Overwriting getFingerprint does not work', function(){
// const evilFunction = function(){
// return 'bad Data';
// };
// let key = createKey(kp.validKeyFingerprint, true);
// expect(key.fingerprint).to.equal(kp.validKeyFingerprint);
// try {
// key.getFingerprint = evilFunction;
// }
// catch(e) {
// expect(e).to.be.an.instanceof(TypeError);
// }
// expect(key.fingerprint).to.equal(kp.validKeyFingerprint);
// expect(key.getFingerprint).to.not.equal(evilFunction);
// });
});
describe('GPGME_Keyring', function (){
it('correct Keyring initialization', function (){
let keyring = new GPGME_Keyring;
expect(keyring).to.be.an.instanceof(GPGME_Keyring);
expect(keyring.getKeys).to.be.a('function');
});
it('Loading Keys from Keyring, to be used synchronously',
function (done){
let keyring = new GPGME_Keyring;
- keyring.getKeys(null, true).then(function (result){
+ keyring.getKeys({ prepare_sync: true }).then(function (result){
expect(result).to.be.an('array');
expect(result[0].get('hasSecret')).to.be.a('boolean');
done();
});
}
);
it('Loading specific Key from Keyring, to be used synchronously',
function (done){
let keyring = new GPGME_Keyring;
- keyring.getKeys(kp.validKeyFingerprint, true).then(
+ keyring.getKeys({
+ pattern: kp.validKeyFingerprint,
+ prepare_sync: true }).then(
function (result){
expect(result).to.be.an('array');
expect(result[0].get('hasSecret')).to.be.a('boolean');
done();
}
);
}
);
it('Querying non-existing Key from Keyring', function (done){
let keyring = new GPGME_Keyring;
keyring.getKeys(kp.invalidKeyFingerprint, true).then(
function (result){
expect(result).to.be.an('array');
expect(result.length).to.equal(0);
done();
}
);
});
});
describe('GPGME_Message', function (){
it('creating encrypt Message', function (){
let test0 = createMessage('encrypt');
expect(test0).to.be.an.instanceof(GPGME_Message);
expect(test0.isComplete()).to.be.false;
});
it('Message is complete after setting mandatory data', function (){
let test0 = createMessage('encrypt');
test0.setParameter('data', mp.valid_encrypt_data);
test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete()).to.be.true;
});
it('Message is not complete after mandatory data is empty', function (){
let test0 = createMessage('encrypt');
test0.setParameter('keys', hp.validFingerprints);
expect(test0.isComplete()).to.be.false;
expect(function (){
test0.setParameter('data', '');
}).to.throw(
err_list.PARAM_WRONG.msg);
});
it('Complete Message contains the data that was set', function (){
let test0 = createMessage('encrypt');
test0.setParameter('data', mp.valid_encrypt_data);
test0.setParameter('keys', hp.validFingerprints);
expect(test0.message).to.not.be.null;
expect(test0.message).to.have.keys('op', 'data', 'keys',
'chunksize');
expect(test0.message.op).to.equal('encrypt');
expect(test0.message.data).to.equal(
mp.valid_encrypt_data);
});
it ('Not accepting non-allowed operation', function (){
expect(function () {
createMessage(mp.invalid_op_action);
}).to.throw(
err_list.MSG_WRONG_OP.msg);
});
it('Not accepting wrong parameter type', function (){
expect(function () {
createMessage(mp.invalid_op_type);
}).to.throw(
err_list.PARAM_WRONG.msg);
});
it('Not accepting wrong parameter name', function (){
let test0 = createMessage(mp.invalid_param_test.valid_op);
for (let i=0;
i < mp.invalid_param_test.invalid_param_names.length; i++){
expect(function (){
test0.setParameter(
mp.invalid_param_test.invalid_param_names[i],
'Somevalue');}
).to.throw(err_list.PARAM_WRONG.msg);
}
});
it('Not accepting wrong parameter value', function (){
let test0 = createMessage(mp.invalid_param_test.valid_op);
for (let j=0;
j < mp.invalid_param_test.invalid_values_0.length; j++){
expect(function (){
test0.setParameter(
mp.invalid_param_test.validparam_name_0,
mp.invalid_param_test.invalid_values_0[j]);
}).to.throw(err_list.PARAM_WRONG.msg);
}
});
});
}
export default { unittests };
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Feb 26, 6:40 PM (11 h, 54 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a5/87/6f54499082dec9104932f6f7a91b
Attached To
rM GPGME
Event Timeline
Log In to Comment