js: revert changes to class read/write restriction
-- * undoes94ee0988d4
ande16a87e839
. I do not fully understand why my approach was bad, but I am not in a position to argue. This revert was requested to me after a review, and I'm doing it in the assumption that more experienced people know better than me. * unittests: Also changed some outdated tests that stopped working since754e799d35
(as GPGME_Key is not exported, one cannot check for instanceof in the tests anymore)
This commit is contained in:
parent
74684f24c6
commit
1954d27be8
@ -39,144 +39,146 @@ import { decode } from './Helpers';
|
|||||||
export class Connection{
|
export class Connection{
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
let _connection = chrome.runtime.connectNative('gpgmejson');
|
this._connection = chrome.runtime.connectNative('gpgmejson');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately closes an open port.
|
||||||
|
*/
|
||||||
|
disconnect() {
|
||||||
|
if (this._connection){
|
||||||
|
this._connection.disconnect();
|
||||||
|
this._connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediately closes an open port.
|
* @typedef {Object} backEndDetails
|
||||||
*/
|
* @property {String} gpgme Version number of gpgme
|
||||||
this.disconnect = function () {
|
* @property {Array<Object>} info Further information about the backend
|
||||||
if (_connection){
|
* and the used applications (Example:
|
||||||
_connection.disconnect();
|
* {
|
||||||
_connection = null;
|
* "protocol": "OpenPGP",
|
||||||
}
|
* "fname": "/usr/bin/gpg",
|
||||||
};
|
* "version": "2.2.6",
|
||||||
|
* "req_version": "1.4.0",
|
||||||
|
* "homedir": "default"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
* Retrieves the information about the backend.
|
||||||
* @typedef {Object} backEndDetails
|
* @param {Boolean} details (optional) If set to false, the promise will
|
||||||
* @property {String} gpgme Version number of gpgme
|
* just return if a connection was successful.
|
||||||
* @property {Array<Object>} info Further information about the backend
|
* @returns {Promise<backEndDetails>|Promise<Boolean>} Details from the
|
||||||
* and the used applications (Example:
|
* backend
|
||||||
* {
|
* @async
|
||||||
* "protocol": "OpenPGP",
|
*/
|
||||||
* "fname": "/usr/bin/gpg",
|
checkConnection (details = true){
|
||||||
* "version": "2.2.6",
|
const msg = createMessage('version');
|
||||||
* "req_version": "1.4.0",
|
if (details === true) {
|
||||||
* "homedir": "default"
|
return this.post(msg);
|
||||||
* }
|
} else {
|
||||||
*/
|
let me = this;
|
||||||
|
return new Promise(function(resolve) {
|
||||||
/**
|
Promise.race([
|
||||||
* Retrieves the information about the backend.
|
me.post(msg),
|
||||||
* @param {Boolean} details (optional) If set to false, the promise will
|
new Promise(function(resolve, reject){
|
||||||
* just return if a connection was successful.
|
setTimeout(function(){
|
||||||
* @returns {Promise<backEndDetails>|Promise<Boolean>} Details from the
|
reject(gpgme_error('CONN_TIMEOUT'));
|
||||||
* backend
|
}, 500);
|
||||||
* @async
|
})
|
||||||
*/
|
]).then(function(){ // success
|
||||||
this.checkConnection = function(details = true){
|
resolve(true);
|
||||||
const msg = createMessage('version');
|
}, function(){ // failure
|
||||||
if (details === true) {
|
resolve(false);
|
||||||
return this.post(msg);
|
|
||||||
} else {
|
|
||||||
let me = this;
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
Promise.race([
|
|
||||||
me.post(msg),
|
|
||||||
new Promise(function(resolve, reject){
|
|
||||||
setTimeout(function(){
|
|
||||||
reject(gpgme_error('CONN_TIMEOUT'));
|
|
||||||
}, 500);
|
|
||||||
})
|
|
||||||
]).then(function(){ // success
|
|
||||||
resolve(true);
|
|
||||||
}, function(){ // failure
|
|
||||||
resolve(false);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a {@link GPGME_Message} via tghe nativeMessaging port. It
|
* Sends a {@link GPGME_Message} via tghe nativeMessaging port. It
|
||||||
* resolves with the completed answer after all parts have been
|
* resolves with the completed answer after all parts have been
|
||||||
* received and reassembled, or rejects with an {@link GPGME_Error}.
|
* received and reassembled, or rejects with an {@link GPGME_Error}.
|
||||||
*
|
*
|
||||||
* @param {GPGME_Message} message
|
* @param {GPGME_Message} message
|
||||||
* @returns {Promise<Object>} The collected answer
|
* @returns {Promise<Object>} The collected answer
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
this.post = function (message){
|
post(message){
|
||||||
if (!message || !(message instanceof GPGME_Message)){
|
if (!message || !(message instanceof GPGME_Message)){
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
return Promise.reject(gpgme_error(
|
return Promise.reject(gpgme_error(
|
||||||
'PARAM_WRONG', 'Connection.post'));
|
'PARAM_WRONG', 'Connection.post'));
|
||||||
}
|
}
|
||||||
if (message.isComplete() !== true){
|
if (message.isComplete() !== true){
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||||
}
|
}
|
||||||
let chunksize = message.chunksize;
|
let chunksize = message.chunksize;
|
||||||
return new Promise(function(resolve, reject){
|
const me = this;
|
||||||
let answer = Object.freeze(new Answer(message));
|
return new Promise(function(resolve, reject){
|
||||||
let listener = function(msg) {
|
let answer = new Answer(message);
|
||||||
if (!msg){
|
let listener = function(msg) {
|
||||||
_connection.onMessage.removeListener(listener);
|
if (!msg){
|
||||||
_connection.disconnect();
|
me._connection.onMessage.removeListener(listener);
|
||||||
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
|
me._connection.disconnect();
|
||||||
|
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
|
||||||
|
} else {
|
||||||
|
let answer_result = answer.collect(msg);
|
||||||
|
if (answer_result !== true){
|
||||||
|
me._connection.onMessage.removeListener(listener);
|
||||||
|
me._connection.disconnect();
|
||||||
|
reject(answer_result);
|
||||||
} else {
|
} else {
|
||||||
let answer_result = answer.collect(msg);
|
if (msg.more === true){
|
||||||
if (answer_result !== true){
|
me._connection.postMessage({
|
||||||
_connection.onMessage.removeListener(listener);
|
'op': 'getmore',
|
||||||
_connection.disconnect();
|
'chunksize': chunksize
|
||||||
reject(answer_result);
|
});
|
||||||
} else {
|
} else {
|
||||||
if (msg.more === true){
|
me._connection.onMessage.removeListener(listener);
|
||||||
_connection.postMessage({
|
me._connection.disconnect();
|
||||||
'op': 'getmore',
|
const message = answer.getMessage();
|
||||||
'chunksize': chunksize
|
if (message instanceof Error){
|
||||||
});
|
reject(message);
|
||||||
} else {
|
} else {
|
||||||
_connection.onMessage.removeListener(listener);
|
resolve(message);
|
||||||
_connection.disconnect();
|
|
||||||
const message = answer.getMessage();
|
|
||||||
if (message instanceof Error){
|
|
||||||
reject(message);
|
|
||||||
} else {
|
|
||||||
resolve(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
_connection.onMessage.addListener(listener);
|
|
||||||
if (permittedOperations[message.operation].pinentry){
|
|
||||||
return _connection.postMessage(message.message);
|
|
||||||
} else {
|
|
||||||
return Promise.race([
|
|
||||||
_connection.postMessage(message.message),
|
|
||||||
function(resolve, reject){
|
|
||||||
setTimeout(function(){
|
|
||||||
_connection.disconnect();
|
|
||||||
reject(gpgme_error('CONN_TIMEOUT'));
|
|
||||||
}, 5000);
|
|
||||||
}]).then(function(result){
|
|
||||||
return result;
|
|
||||||
}, function(reject){
|
|
||||||
if(!(reject instanceof Error)) {
|
|
||||||
_connection.disconnect();
|
|
||||||
return gpgme_error('GNUPG_ERROR', reject);
|
|
||||||
} else {
|
|
||||||
return reject;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
};
|
me._connection.onMessage.addListener(listener);
|
||||||
|
if (permittedOperations[message.operation].pinentry){
|
||||||
|
return me._connection.postMessage(message.message);
|
||||||
|
} else {
|
||||||
|
return Promise.race([
|
||||||
|
me._connection.postMessage(message.message),
|
||||||
|
function(resolve, reject){
|
||||||
|
setTimeout(function(){
|
||||||
|
me._connection.disconnect();
|
||||||
|
reject(gpgme_error('CONN_TIMEOUT'));
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
]).then(function(result){
|
||||||
|
return result;
|
||||||
|
}, function(reject){
|
||||||
|
if(!(reject instanceof Error)) {
|
||||||
|
me._connection.disconnect();
|
||||||
|
return gpgme_error('GNUPG_ERROR', reject);
|
||||||
|
} else {
|
||||||
|
return reject;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for answer objects, checking and processing the return messages of
|
* A class for answer objects, checking and processing the return messages of
|
||||||
* the nativeMessaging communication.
|
* the nativeMessaging communication.
|
||||||
@ -188,95 +190,94 @@ class Answer{
|
|||||||
* @param {GPGME_Message} message
|
* @param {GPGME_Message} message
|
||||||
*/
|
*/
|
||||||
constructor(message){
|
constructor(message){
|
||||||
const operation = message.operation;
|
this._operation = message.operation;
|
||||||
const expected = message.getExpect();
|
this._expected = message.expected;
|
||||||
let response_b64 = null;
|
this._response_b64 = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.getOperation = function(){
|
get operation (){
|
||||||
return operation;
|
return this._operation;
|
||||||
};
|
}
|
||||||
|
|
||||||
this.getExpect = function(){
|
get expected (){
|
||||||
return expected;
|
return this._expected;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds incoming base64 encoded data to the existing response
|
* Adds incoming base64 encoded data to the existing response
|
||||||
* @param {*} msg base64 encoded data.
|
* @param {*} msg base64 encoded data.
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.collect = function (msg){
|
collect (msg){
|
||||||
if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
|
if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||||
}
|
}
|
||||||
if (response_b64 === null){
|
if (!this._response_b64){
|
||||||
response_b64 = msg.response;
|
this._response_b64 = msg.response;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
response_b64 += msg.response;
|
this._response_b64 += msg.response;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the base64 encoded answer data with the content verified
|
* Returns the base64 encoded answer data with the content verified
|
||||||
* against {@link permittedOperations}.
|
* against {@link permittedOperations}.
|
||||||
*/
|
*/
|
||||||
this.getMessage = function (){
|
getMessage(){
|
||||||
if (response_b64 === undefined){
|
if (this._response_b64 === null){
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||||
}
|
}
|
||||||
let _decodedResponse = JSON.parse(atob(response_b64));
|
let _decodedResponse = JSON.parse(atob(this._response_b64));
|
||||||
let _response = {};
|
let _response = {};
|
||||||
let messageKeys = Object.keys(_decodedResponse);
|
let messageKeys = Object.keys(_decodedResponse);
|
||||||
let poa = permittedOperations[this.getOperation()].answer;
|
let poa = permittedOperations[this.operation].answer;
|
||||||
if (messageKeys.length === 0){
|
if (messageKeys.length === 0){
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||||
}
|
}
|
||||||
for (let i= 0; i < messageKeys.length; i++){
|
for (let i= 0; i < messageKeys.length; i++){
|
||||||
let key = messageKeys[i];
|
let key = messageKeys[i];
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'type':
|
case 'type':
|
||||||
if (_decodedResponse.type === 'error'){
|
if (_decodedResponse.type === 'error'){
|
||||||
return (gpgme_error('GNUPG_ERROR',
|
return (gpgme_error('GNUPG_ERROR',
|
||||||
decode(_decodedResponse.msg)));
|
decode(_decodedResponse.msg)));
|
||||||
} else if (poa.type.indexOf(_decodedResponse.type) < 0){
|
} else if (poa.type.indexOf(_decodedResponse.type) < 0){
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'base64':
|
|
||||||
break;
|
|
||||||
case 'msg':
|
|
||||||
if (_decodedResponse.type === 'error'){
|
|
||||||
return (gpgme_error('GNUPG_ERROR',
|
|
||||||
_decodedResponse.msg));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!poa.data.hasOwnProperty(key)){
|
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
|
||||||
}
|
|
||||||
if( typeof(_decodedResponse[key]) !== poa.data[key] ){
|
|
||||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
|
||||||
}
|
|
||||||
if (_decodedResponse.base64 === true
|
|
||||||
&& poa.data[key] === 'string'
|
|
||||||
&& this.getExpect() !== 'base64'
|
|
||||||
){
|
|
||||||
_response[key] = decodeURIComponent(
|
|
||||||
atob(_decodedResponse[key]).split('').map(
|
|
||||||
function(c) {
|
|
||||||
return '%' +
|
|
||||||
('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
||||||
}).join(''));
|
|
||||||
} else {
|
|
||||||
_response[key] = decode(_decodedResponse[key]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'base64':
|
||||||
|
break;
|
||||||
|
case 'msg':
|
||||||
|
if (_decodedResponse.type === 'error'){
|
||||||
|
return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!poa.data.hasOwnProperty(key)){
|
||||||
|
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||||
|
}
|
||||||
|
if( typeof(_decodedResponse[key]) !== poa.data[key] ){
|
||||||
|
return gpgme_error('CONN_UNEXPECTED_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(''));
|
||||||
|
} else {
|
||||||
|
_response[key] = decode(_decodedResponse[key]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return _response;
|
}
|
||||||
};
|
return _response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ const err_list = {
|
|||||||
export function gpgme_error(code = 'GENERIC_ERROR', info){
|
export function gpgme_error(code = 'GENERIC_ERROR', info){
|
||||||
if (err_list.hasOwnProperty(code)){
|
if (err_list.hasOwnProperty(code)){
|
||||||
if (err_list[code].type === 'error'){
|
if (err_list[code].type === 'error'){
|
||||||
return Object.freeze(new GPGME_Error(code));
|
return new GPGME_Error(code);
|
||||||
}
|
}
|
||||||
if (err_list[code].type === 'warning'){
|
if (err_list[code].type === 'warning'){
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@ -131,10 +131,10 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else if (code === 'GNUPG_ERROR'){
|
} else if (code === 'GNUPG_ERROR'){
|
||||||
return Object.freeze(new GPGME_Error(code, info));
|
return new GPGME_Error(code, info);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Object.freeze(new GPGME_Error('GENERIC_ERROR'));
|
return new GPGME_Error('GENERIC_ERROR');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +148,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
|
|||||||
*/
|
*/
|
||||||
class GPGME_Error extends Error{
|
class GPGME_Error extends Error{
|
||||||
constructor(code = 'GENERIC_ERROR', msg=''){
|
constructor(code = 'GENERIC_ERROR', msg=''){
|
||||||
|
|
||||||
if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){
|
if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){
|
||||||
super(msg);
|
super(msg);
|
||||||
} else if (err_list.hasOwnProperty(code)){
|
} else if (err_list.hasOwnProperty(code)){
|
||||||
@ -159,12 +160,10 @@ class GPGME_Error extends Error{
|
|||||||
} else {
|
} else {
|
||||||
super(err_list['GENERIC_ERROR'].msg);
|
super(err_list['GENERIC_ERROR'].msg);
|
||||||
}
|
}
|
||||||
this.getCode = function(){
|
this._code = code;
|
||||||
return code;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get code(){
|
get code(){
|
||||||
return this.getCode();
|
return this._code;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,12 +40,12 @@ export function createKey(fingerprint, async = false, data){
|
|||||||
return gpgme_error('PARAM_WRONG');
|
return gpgme_error('PARAM_WRONG');
|
||||||
}
|
}
|
||||||
if (data !== undefined){
|
if (data !== undefined){
|
||||||
data = validateKeyData(data);
|
data = validateKeyData(fingerprint, data);
|
||||||
}
|
}
|
||||||
if (data instanceof Error){
|
if (data instanceof Error){
|
||||||
return gpgme_error('KEY_INVALID');
|
return gpgme_error('KEY_INVALID');
|
||||||
} else {
|
} else {
|
||||||
return Object.freeze(new GPGME_Key(fingerprint, async, data));
|
return new GPGME_Key(fingerprint, async, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,184 +65,181 @@ class GPGME_Key {
|
|||||||
/**
|
/**
|
||||||
* @property {Boolean} If true, most answers will be asynchronous
|
* @property {Boolean} If true, most answers will be asynchronous
|
||||||
*/
|
*/
|
||||||
this.isAsync = async;
|
this._async = async;
|
||||||
|
|
||||||
let _data = {fingerprint: fingerprint.toUpperCase()};
|
this._data = {fingerprint: fingerprint.toUpperCase()};
|
||||||
if (data !== undefined
|
if (data !== undefined
|
||||||
&& data.fingerprint.toUpperCase() === _data.fingerprint
|
&& data.fingerprint.toUpperCase() === this._data.fingerprint
|
||||||
) {
|
) {
|
||||||
_data = data;
|
this._data = data;
|
||||||
}
|
}
|
||||||
this.getFingerprint = function(){
|
}
|
||||||
if (!_data.fingerprint || !isFingerprint(_data.fingerprint)){
|
|
||||||
return gpgme_error('KEY_INVALID');
|
|
||||||
}
|
|
||||||
return _data.fingerprint;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query any property of the Key listed in {@link validKeyProperties}
|
* Query any property of the Key listed in {@link validKeyProperties}
|
||||||
* @param {String} property property to be retreived
|
* @param {String} property property to be retreived
|
||||||
* @returns {Boolean| String | Date | Array | Object |GPGME_Error}
|
* @returns {Boolean| String | Date | Array | Object |GPGME_Error}
|
||||||
* the value of the property. If the Key is set to Async, the value
|
* the value of the property. If the Key is set to Async, the value
|
||||||
* will be fetched from gnupg and resolved as a Promise. If Key is not
|
* will be fetched from gnupg and resolved as a Promise. If Key is not
|
||||||
* async, the armored property is not available (it can still be
|
* async, the armored property is not available (it can still be
|
||||||
* retrieved asynchronously by {@link Key.getArmor})
|
* retrieved asynchronously by {@link Key.getArmor})
|
||||||
*/
|
*/
|
||||||
this.get = function(property) {
|
get(property) {
|
||||||
if (this.isAsync === true) {
|
if (this._async === true) {
|
||||||
switch (property){
|
switch (property){
|
||||||
case 'armored':
|
case 'armored':
|
||||||
return this.getArmor();
|
return this.getArmor();
|
||||||
case 'hasSecret':
|
case 'hasSecret':
|
||||||
return this.getGnupgSecretState();
|
return this.getGnupgSecretState();
|
||||||
default:
|
default:
|
||||||
return getGnupgState(property);
|
return getGnupgState(this.fingerprint, property);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (property === 'armored') {
|
||||||
|
return gpgme_error('KEY_ASYNC_ONLY');
|
||||||
|
}
|
||||||
|
if (!validKeyProperties.hasOwnProperty(property)){
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
} else {
|
} else {
|
||||||
if (property === 'armored') {
|
return (this._data[property]);
|
||||||
return gpgme_error('KEY_ASYNC_ONLY');
|
|
||||||
}
|
|
||||||
if (!validKeyProperties.hasOwnProperty(property)){
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
} else {
|
|
||||||
return (_data[property]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the Key information from gnupg. This is only useful if you
|
* Reloads the Key information from gnupg. This is only useful if you
|
||||||
* use the GPGME_Keys cached. Note that this is a performance hungry
|
* use the GPGME_Keys cached. Note that this is a performance hungry
|
||||||
* operation. If you desire more than a few refreshs, it may be
|
* operation. If you desire more than a few refreshs, it may be
|
||||||
* advisable to run {@link Keyring.getKeys} instead.
|
* advisable to run {@link Keyring.getKeys} instead.
|
||||||
* @returns {Promise<GPGME_Key|GPGME_Error>}
|
* @returns {Promise<GPGME_Key|GPGME_Error>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
this.refreshKey = function() {
|
refreshKey() {
|
||||||
let me = this;
|
let me = this;
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
if (!_data.fingerprint){
|
if (!me._data.fingerprint){
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
}
|
}
|
||||||
let msg = createMessage('keylist');
|
let msg = createMessage('keylist');
|
||||||
msg.setParameter('sigs', true);
|
msg.setParameter('sigs', true);
|
||||||
msg.setParameter('keys', _data.fingerprint);
|
msg.setParameter('keys', me._data.fingerprint);
|
||||||
msg.post().then(function(result){
|
msg.post().then(function(result){
|
||||||
if (result.keys.length === 1){
|
if (result.keys.length === 1){
|
||||||
const newdata = validateKeyData(
|
const newdata = validateKeyData(
|
||||||
_data.fingerprint, result.keys[0]);
|
me._data.fingerprint, result.keys[0]);
|
||||||
if (newdata instanceof Error){
|
if (newdata instanceof Error){
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
} else {
|
} else {
|
||||||
_data = newdata;
|
me._data = newdata;
|
||||||
me.getGnupgSecretState().then(function(){
|
me.getGnupgSecretState().then(function(){
|
||||||
me.getArmor().then(function(){
|
me.getArmor().then(function(){
|
||||||
resolve(me);
|
resolve(me);
|
||||||
}, function(error){
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
}, function(error){
|
}, function(error){
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
}
|
}, function(error){
|
||||||
} else {
|
reject(error);
|
||||||
reject(gpgme_error('KEY_NOKEY'));
|
});
|
||||||
}
|
}
|
||||||
}, function (error) {
|
|
||||||
reject(gpgme_error('GNUPG_ERROR'), error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query the armored block of the Key directly from gnupg. Please note
|
|
||||||
* that this will not get you any export of the secret/private parts of
|
|
||||||
* a Key
|
|
||||||
* @returns {Promise<String|GPGME_Error>}
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.getArmor = function(){
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
if (!_data.fingerprint){
|
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
|
||||||
}
|
|
||||||
let msg = createMessage('export');
|
|
||||||
msg.setParameter('armor', true);
|
|
||||||
msg.setParameter('keys', _data.fingerprint);
|
|
||||||
msg.post().then(function(result){
|
|
||||||
resolve(result.data);
|
|
||||||
}, function(error){
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find out if the Key is part of a Key pair including public and
|
|
||||||
* private key(s). If you want this information about more than a few
|
|
||||||
* Keys in synchronous mode, it may be advisable to run
|
|
||||||
* {@link Keyring.getKeys} instead, as it performs faster in bulk
|
|
||||||
* querying this state.
|
|
||||||
* @returns {Promise<Boolean|GPGME_Error>} True if a private Key is
|
|
||||||
* available in the gnupg Keyring.
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.getGnupgSecretState = function (){
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
if (!_data.fingerprint){
|
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
|
||||||
} else {
|
} else {
|
||||||
let msg = createMessage('keylist');
|
reject(gpgme_error('KEY_NOKEY'));
|
||||||
msg.setParameter('keys', _data.fingerprint);
|
|
||||||
msg.setParameter('secret', true);
|
|
||||||
msg.post().then(function(result){
|
|
||||||
_data.hasSecret = null;
|
|
||||||
if (
|
|
||||||
result.keys &&
|
|
||||||
result.keys.length === 1 &&
|
|
||||||
result.keys[0].secret === true
|
|
||||||
) {
|
|
||||||
_data.hasSecret = true;
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
_data.hasSecret = false;
|
|
||||||
resolve(false);
|
|
||||||
}
|
|
||||||
}, function(error){
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}, function (error) {
|
||||||
|
reject(gpgme_error('GNUPG_ERROR'), error);
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the (public) Key from the GPG Keyring. Note that a deletion
|
* Query the armored block of the Key directly from gnupg. Please note
|
||||||
* of a secret key is not supported by the native backend.
|
* that this will not get you any export of the secret/private parts of
|
||||||
* @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
|
* a Key
|
||||||
* rejects with a GPG error otherwise.
|
* @returns {Promise<String|GPGME_Error>}
|
||||||
*/
|
* @async
|
||||||
this.delete= function (){
|
*/
|
||||||
return new Promise(function(resolve, reject){
|
getArmor() {
|
||||||
if (!_data.fingerprint){
|
const me = this;
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
return new Promise(function(resolve, reject) {
|
||||||
}
|
if (!me._data.fingerprint){
|
||||||
let msg = createMessage('delete');
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
msg.setParameter('key', _data.fingerprint);
|
}
|
||||||
|
let msg = createMessage('export');
|
||||||
|
msg.setParameter('armor', true);
|
||||||
|
msg.setParameter('keys', me._data.fingerprint);
|
||||||
|
msg.post().then(function(result){
|
||||||
|
resolve(result.data);
|
||||||
|
}, function(error){
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out if the Key is part of a Key pair including public and
|
||||||
|
* private key(s). If you want this information about more than a few
|
||||||
|
* Keys in synchronous mode, it may be advisable to run
|
||||||
|
* {@link Keyring.getKeys} instead, as it performs faster in bulk
|
||||||
|
* querying this state.
|
||||||
|
* @returns {Promise<Boolean|GPGME_Error>} True if a private Key is
|
||||||
|
* available in the gnupg Keyring.
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
getGnupgSecretState (){
|
||||||
|
const me = this;
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
if (!me._data.fingerprint){
|
||||||
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
|
} else {
|
||||||
|
let msg = createMessage('keylist');
|
||||||
|
msg.setParameter('keys', me._data.fingerprint);
|
||||||
|
msg.setParameter('secret', true);
|
||||||
msg.post().then(function(result){
|
msg.post().then(function(result){
|
||||||
resolve(result.success);
|
me._data.hasSecret = null;
|
||||||
|
if (
|
||||||
|
result.keys &&
|
||||||
|
result.keys.length === 1 &&
|
||||||
|
result.keys[0].secret === true
|
||||||
|
) {
|
||||||
|
me._data.hasSecret = true;
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
me._data.hasSecret = false;
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
}, function(error){
|
}, function(error){
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the (public) Key from the GPG Keyring. Note that a deletion
|
||||||
|
* of a secret key is not supported by the native backend.
|
||||||
|
* @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
|
||||||
|
* rejects with a GPG error otherwise.
|
||||||
|
*/
|
||||||
|
delete(){
|
||||||
|
const me = this;
|
||||||
|
return new Promise(function(resolve, reject){
|
||||||
|
if (!me._data.fingerprint){
|
||||||
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
|
}
|
||||||
|
let msg = createMessage('delete');
|
||||||
|
msg.setParameter('key', me._data.fingerprint);
|
||||||
|
msg.post().then(function(result){
|
||||||
|
resolve(result.success);
|
||||||
|
}, function(error){
|
||||||
|
reject(error);
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {String} The fingerprint defining this Key. Convenience getter
|
* @returns {String} The fingerprint defining this Key. Convenience getter
|
||||||
*/
|
*/
|
||||||
get fingerprint(){
|
get fingerprint(){
|
||||||
return this.getFingerprint();
|
return this._data.fingerprint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,8 +256,9 @@ class GPGME_Subkey {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(data){
|
constructor(data){
|
||||||
let _data = {};
|
this._data = {};
|
||||||
let keys = Object.keys(data);
|
let keys = Object.keys(data);
|
||||||
|
const me = this;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a subkey property against {@link validSubKeyProperties} and
|
* Validates a subkey property against {@link validSubKeyProperties} and
|
||||||
@ -273,9 +271,9 @@ class GPGME_Subkey {
|
|||||||
if (validSubKeyProperties.hasOwnProperty(property)){
|
if (validSubKeyProperties.hasOwnProperty(property)){
|
||||||
if (validSubKeyProperties[property](value) === true) {
|
if (validSubKeyProperties[property](value) === true) {
|
||||||
if (property === 'timestamp' || property === 'expires'){
|
if (property === 'timestamp' || property === 'expires'){
|
||||||
_data[property] = new Date(value * 1000);
|
me._data[property] = new Date(value * 1000);
|
||||||
} else {
|
} else {
|
||||||
_data[property] = value;
|
me._data[property] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,18 +281,19 @@ class GPGME_Subkey {
|
|||||||
for (let i=0; i< keys.length; i++) {
|
for (let i=0; i< keys.length; i++) {
|
||||||
setProperty(keys[i], data[keys[i]]);
|
setProperty(keys[i], data[keys[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches any information about this subkey
|
|
||||||
* @param {String} property Information to request
|
|
||||||
* @returns {String | Number | Date}
|
|
||||||
*/
|
|
||||||
this.get = function(property) {
|
|
||||||
if (_data.hasOwnProperty(property)){
|
|
||||||
return (_data[property]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches any information about this subkey
|
||||||
|
* @param {String} property Information to request
|
||||||
|
* @returns {String | Number | Date}
|
||||||
|
*/
|
||||||
|
get(property) {
|
||||||
|
if (this._data.hasOwnProperty(property)){
|
||||||
|
return (this._data[property]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,15 +309,16 @@ class GPGME_UserId {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(data){
|
constructor(data){
|
||||||
let _data = {};
|
this._data = {};
|
||||||
|
const me = this;
|
||||||
let keys = Object.keys(data);
|
let keys = Object.keys(data);
|
||||||
const setProperty = function(property, value){
|
const setProperty = function(property, value){
|
||||||
if (validUserIdProperties.hasOwnProperty(property)){
|
if (validUserIdProperties.hasOwnProperty(property)){
|
||||||
if (validUserIdProperties[property](value) === true) {
|
if (validUserIdProperties[property](value) === true) {
|
||||||
if (property === 'last_update'){
|
if (property === 'last_update'){
|
||||||
_data[property] = new Date(value*1000);
|
me._data[property] = new Date(value*1000);
|
||||||
} else {
|
} else {
|
||||||
_data[property] = value;
|
me._data[property] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,18 +326,19 @@ class GPGME_UserId {
|
|||||||
for (let i=0; i< keys.length; i++) {
|
for (let i=0; i< keys.length; i++) {
|
||||||
setProperty(keys[i], data[keys[i]]);
|
setProperty(keys[i], data[keys[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches information about the user
|
|
||||||
* @param {String} property Information to request
|
|
||||||
* @returns {String | Number}
|
|
||||||
*/
|
|
||||||
this.get = function (property) {
|
|
||||||
if (_data.hasOwnProperty(property)){
|
|
||||||
return (_data[property]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches information about the user
|
||||||
|
* @param {String} property Information to request
|
||||||
|
* @returns {String | Number}
|
||||||
|
*/
|
||||||
|
get(property) {
|
||||||
|
if (this._data.hasOwnProperty(property)){
|
||||||
|
return (this._data[property]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -569,10 +570,11 @@ const validKeyProperties = {
|
|||||||
* an error if something went wrong.
|
* an error if something went wrong.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function validateKeyData(data){
|
function validateKeyData(fingerprint, data){
|
||||||
const key = {};
|
const key = {};
|
||||||
if ( typeof(data) !== 'object'
|
if (!fingerprint || typeof(data) !== 'object' || !data.fingerprint
|
||||||
|| !data.fingerprint){
|
|| fingerprint !== data.fingerprint.toUpperCase()
|
||||||
|
){
|
||||||
return gpgme_error('KEY_INVALID');
|
return gpgme_error('KEY_INVALID');
|
||||||
}
|
}
|
||||||
let props = Object.keys(data);
|
let props = Object.keys(data);
|
||||||
@ -588,15 +590,15 @@ function validateKeyData(data){
|
|||||||
case 'subkeys':
|
case 'subkeys':
|
||||||
key.subkeys = [];
|
key.subkeys = [];
|
||||||
for (let i=0; i< data.subkeys.length; i++) {
|
for (let i=0; i< data.subkeys.length; i++) {
|
||||||
key.subkeys.push(Object.freeze(
|
key.subkeys.push(
|
||||||
new GPGME_Subkey(data.subkeys[i])));
|
new GPGME_Subkey(data.subkeys[i]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'userids':
|
case 'userids':
|
||||||
key.userids = [];
|
key.userids = [];
|
||||||
for (let i=0; i< data.userids.length; i++) {
|
for (let i=0; i< data.userids.length; i++) {
|
||||||
key.userids.push(Object.freeze(
|
key.userids.push(
|
||||||
new GPGME_UserId(data.userids[i])));
|
new GPGME_UserId(data.userids[i]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'last_update':
|
case 'last_update':
|
||||||
@ -623,19 +625,19 @@ function getGnupgState (fingerprint, property){
|
|||||||
} else {
|
} else {
|
||||||
let msg = createMessage('keylist');
|
let msg = createMessage('keylist');
|
||||||
msg.setParameter('keys', fingerprint);
|
msg.setParameter('keys', fingerprint);
|
||||||
msg.post().then(function(result){
|
msg.post().then(function(res){
|
||||||
if (!result.keys || result.keys.length !== 1){
|
if (!res.keys || res.keys.length !== 1){
|
||||||
reject(gpgme_error('KEY_INVALID'));
|
reject(gpgme_error('KEY_INVALID'));
|
||||||
} else {
|
} else {
|
||||||
const key = result.keys[0];
|
const key = res.keys[0];
|
||||||
let result;
|
let result;
|
||||||
switch (property){
|
switch (property){
|
||||||
case 'subkeys':
|
case 'subkeys':
|
||||||
result = [];
|
result = [];
|
||||||
if (key.subkeys.length){
|
if (key.subkeys.length){
|
||||||
for (let i=0; i < key.subkeys.length; i++) {
|
for (let i=0; i < key.subkeys.length; i++) {
|
||||||
result.push(Object.freeze(
|
result.push(
|
||||||
new GPGME_Subkey(key.subkeys[i])));
|
new GPGME_Subkey(key.subkeys[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
@ -644,8 +646,8 @@ function getGnupgState (fingerprint, property){
|
|||||||
result = [];
|
result = [];
|
||||||
if (key.userids.length){
|
if (key.userids.length){
|
||||||
for (let i=0; i< key.userids.length; i++) {
|
for (let i=0; i< key.userids.length; i++) {
|
||||||
result.push(Object.freeze(
|
result.push(
|
||||||
new GPGME_UserId(key.userids[i])));
|
new GPGME_UserId(key.userids[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
|
@ -32,383 +32,384 @@ import { gpgme_error } from './Errors';
|
|||||||
*/
|
*/
|
||||||
export class GPGME_Keyring {
|
export class GPGME_Keyring {
|
||||||
constructor(){
|
constructor(){
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries Keys (all Keys or a subset) from gnupg.
|
* Queries Keys (all Keys or a subset) from gnupg.
|
||||||
*
|
*
|
||||||
* @param {String | Array<String>} pattern (optional) A pattern to
|
* @param {String | Array<String>} pattern (optional) A pattern to
|
||||||
* search for in userIds or KeyIds.
|
* search for in userIds or KeyIds.
|
||||||
* @param {Boolean} prepare_sync (optional) if set to true, most data
|
* @param {Boolean} prepare_sync (optional) if set to true, most data
|
||||||
* (with the exception of armored Key blocks) will be cached for the
|
* (with the exception of armored Key blocks) will be cached for the
|
||||||
* Keys. This enables direct, synchronous use of these properties for
|
* Keys. This enables direct, synchronous use of these properties for
|
||||||
* all keys. It does not check for changes on the backend. The cached
|
* all keys. It does not check for changes on the backend. The cached
|
||||||
* information can be updated with the {@link Key.refresh} method.
|
* information can be updated with the {@link Key.refresh} method.
|
||||||
* @param {Boolean} search (optional) retrieve Keys from external
|
* @param {Boolean} search (optional) retrieve Keys from external
|
||||||
* servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
|
* servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
|
||||||
* @returns {Promise<Array<GPGME_Key>>}
|
* @returns {Promise<Array<GPGME_Key>>}
|
||||||
* @static
|
* @static
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
this.getKeys = function(pattern, prepare_sync=false, search=false){
|
getKeys (pattern, prepare_sync=false, search=false){
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
let msg = createMessage('keylist');
|
let msg = createMessage('keylist');
|
||||||
if (pattern !== undefined && pattern !== null){
|
if (pattern !== undefined && pattern !== null){
|
||||||
msg.setParameter('keys', pattern);
|
msg.setParameter('keys', pattern);
|
||||||
}
|
}
|
||||||
msg.setParameter('sigs', true);
|
msg.setParameter('sigs', true);
|
||||||
if (search === true){
|
if (search === true){
|
||||||
msg.setParameter('locate', true);
|
msg.setParameter('locate', true);
|
||||||
}
|
}
|
||||||
msg.post().then(function(result){
|
msg.post().then(function(result){
|
||||||
let resultset = [];
|
let resultset = [];
|
||||||
if (result.keys.length === 0){
|
if (result.keys.length === 0){
|
||||||
resolve([]);
|
resolve([]);
|
||||||
|
} else {
|
||||||
|
let secondrequest;
|
||||||
|
if (prepare_sync === true) {
|
||||||
|
secondrequest = function() {
|
||||||
|
let msg2 = createMessage('keylist');
|
||||||
|
msg2.setParameter('keys', pattern);
|
||||||
|
msg2.setParameter('secret', true);
|
||||||
|
return msg2.post();
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
let secondrequest;
|
secondrequest = function() {
|
||||||
if (prepare_sync === true) {
|
return Promise.resolve(true);
|
||||||
secondrequest = function() {
|
};
|
||||||
let msg2 = createMessage('keylist');
|
}
|
||||||
msg2.setParameter('keys', pattern);
|
secondrequest().then(function(answer) {
|
||||||
msg2.setParameter('secret', true);
|
for (let i=0; i < result.keys.length; i++){
|
||||||
return msg2.post();
|
if (prepare_sync === true){
|
||||||
};
|
if (answer && answer.keys) {
|
||||||
} else {
|
for (let j=0;
|
||||||
secondrequest = function() {
|
j < answer.keys.length; j++ ){
|
||||||
return Promise.resolve(true);
|
const a = answer.keys[j];
|
||||||
};
|
const b = result.keys[i];
|
||||||
}
|
if (
|
||||||
secondrequest().then(function(answer) {
|
a.fingerprint === b.fingerprint
|
||||||
for (let i=0; i < result.keys.length; i++){
|
) {
|
||||||
if (prepare_sync === true){
|
if (a.secret === true){
|
||||||
if (answer && answer.keys) {
|
b.hasSecret = true;
|
||||||
for (let j=0;
|
} else {
|
||||||
j < answer.keys.length; j++ ){
|
b.hasSecret = false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let k = createKey(result.keys[i].fingerprint,
|
|
||||||
!prepare_sync, result.keys[i]);
|
|
||||||
resultset.push(k);
|
|
||||||
}
|
}
|
||||||
resolve(resultset);
|
let k = createKey(result.keys[i].fingerprint,
|
||||||
|
!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 {String|Array<String>} pattern (optional) The Pattern to
|
||||||
|
* search for
|
||||||
|
* @param {Boolean} with_secret_fpr (optional) 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 (pattern, with_secret_fpr) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
let msg = createMessage('export');
|
||||||
|
msg.setParameter('armor', true);
|
||||||
|
if (with_secret_fpr === true) {
|
||||||
|
msg.setParameter('with-sec-fprs', true);
|
||||||
|
}
|
||||||
|
if (pattern !== undefined && pattern !== null){
|
||||||
|
msg.setParameter('keys', pattern);
|
||||||
|
}
|
||||||
|
msg.post().then(function(answer){
|
||||||
|
const result = {armored: answer.data};
|
||||||
|
if (with_secret_fpr === true
|
||||||
|
&& answer.hasOwnProperty('sec-fprs')
|
||||||
|
) {
|
||||||
|
result.secret_fprs = answer['sec-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){
|
}, function(error){
|
||||||
reject(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'));
|
||||||
* @typedef {Object} exportResult The result of a getKeysArmored
|
} else {
|
||||||
* operation.
|
for (let i=0; i< result.keys.length; i++ ) {
|
||||||
* @property {String} armored The public Key(s) as armored block. Note
|
if (result.keys[i].invalid === false) {
|
||||||
* that the result is one armored block, and not a block per key.
|
let k = createKey(
|
||||||
* @property {Array<String>} secret_fprs (optional) list of
|
result.keys[i].fingerprint,
|
||||||
* fingerprints for those Keys that also have a secret Key available in
|
!prepare_sync,
|
||||||
* gnupg. The secret key will not be exported, but the fingerprint can
|
result.keys[i]);
|
||||||
* be used in operations needing a secret key.
|
resolve(k);
|
||||||
*/
|
break;
|
||||||
|
} else if (i === result.keys.length - 1){
|
||||||
/**
|
|
||||||
* Fetches the armored public Key blocks for all Keys matching the
|
|
||||||
* pattern (if no pattern is given, fetches all keys known to gnupg).
|
|
||||||
* @param {String|Array<String>} pattern (optional) The Pattern to
|
|
||||||
* search for
|
|
||||||
* @param {Boolean} with_secret_fpr (optional) 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
|
|
||||||
*/
|
|
||||||
this.getKeysArmored = function(pattern, with_secret_fpr) {
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
let msg = createMessage('export');
|
|
||||||
msg.setParameter('armor', true);
|
|
||||||
if (with_secret_fpr === true) {
|
|
||||||
msg.setParameter('with-sec-fprs', true);
|
|
||||||
}
|
|
||||||
if (pattern !== undefined && pattern !== null){
|
|
||||||
msg.setParameter('keys', pattern);
|
|
||||||
}
|
|
||||||
msg.post().then(function(answer){
|
|
||||||
const result = {armored: answer.data};
|
|
||||||
if (with_secret_fpr === true
|
|
||||||
&& answer.hasOwnProperty('sec-fprs')
|
|
||||||
) {
|
|
||||||
result.secret_fprs = answer['sec-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
|
|
||||||
*/
|
|
||||||
this.getDefaultKey = function(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'));
|
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) {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
this.importKey = function (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 = {};
|
}, function(error){
|
||||||
changes.userId = (result.status & 2) === 2;
|
reject(error);
|
||||||
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(fprs, 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
|
|
||||||
*/
|
|
||||||
this.deleteKey = function(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 {String} userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
|
|
||||||
* @param {String} algo (optional) algorithm (and optionally key size)
|
|
||||||
* to be used. See {@link supportedKeyAlgos} below for supported
|
|
||||||
* values.
|
|
||||||
* @param {Date} expires (optional) Expiration date. If not set,
|
|
||||||
* expiration will be set to 'never'
|
|
||||||
*
|
|
||||||
* @return {Promise<Key|GPGME_Error>}
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.generateKey = function (userId, algo = 'default', expires){
|
|
||||||
if (
|
|
||||||
typeof(userId) !== 'string' ||
|
|
||||||
supportedKeyAlgos.indexOf(algo) < 0 ||
|
|
||||||
(expires && !(expires instanceof Date))
|
|
||||||
){
|
|
||||||
return Promise.reject(gpgme_error('PARAM_WRONG'));
|
|
||||||
}
|
|
||||||
let me = this;
|
|
||||||
return new Promise(function(resolve, reject){
|
|
||||||
let msg = createMessage('createkey');
|
|
||||||
msg.setParameter('userid', userId);
|
|
||||||
msg.setParameter('algo', algo );
|
|
||||||
if (expires){
|
|
||||||
msg.setParameter('expires',
|
|
||||||
Math.floor(expires.valueOf()/1000));
|
|
||||||
} else {
|
|
||||||
msg.setParameter('expires', 0);
|
|
||||||
}
|
}
|
||||||
msg.post().then(function(response){
|
}, function(error){
|
||||||
me.getKeys(response.fingerprint, true).then(
|
reject(error);
|
||||||
// TODO prepare_sync?
|
|
||||||
function(result){
|
|
||||||
resolve(result);
|
|
||||||
}, 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(fprs, 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 {String} userId The user Id, e.g. 'Foo Bar <foo@bar.baz>'
|
||||||
|
* @param {String} algo (optional) algorithm (and optionally key size)
|
||||||
|
* to be used. See {@link supportedKeyAlgos} below for supported
|
||||||
|
* values.
|
||||||
|
* @param {Date} expires (optional) Expiration date. If not set,
|
||||||
|
* expiration will be set to 'never'
|
||||||
|
*
|
||||||
|
* @return {Promise<Key|GPGME_Error>}
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
generateKey(userId, algo = 'default', expires){
|
||||||
|
if (
|
||||||
|
typeof(userId) !== 'string' ||
|
||||||
|
supportedKeyAlgos.indexOf(algo) < 0 ||
|
||||||
|
(expires && !(expires instanceof Date))
|
||||||
|
){
|
||||||
|
return Promise.reject(gpgme_error('PARAM_WRONG'));
|
||||||
|
}
|
||||||
|
let me = this;
|
||||||
|
return new Promise(function(resolve, reject){
|
||||||
|
let msg = createMessage('createkey');
|
||||||
|
msg.setParameter('userid', userId);
|
||||||
|
msg.setParameter('algo', algo );
|
||||||
|
if (expires){
|
||||||
|
msg.setParameter('expires',
|
||||||
|
Math.floor(expires.valueOf()/1000));
|
||||||
|
} else {
|
||||||
|
msg.setParameter('expires', 0);
|
||||||
|
}
|
||||||
|
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
|
* List of algorithms supported for key generation. Please refer to the gnupg
|
||||||
* documentation for details
|
* documentation for details
|
||||||
|
@ -36,7 +36,7 @@ export function createMessage(operation){
|
|||||||
return gpgme_error('PARAM_WRONG');
|
return gpgme_error('PARAM_WRONG');
|
||||||
}
|
}
|
||||||
if (permittedOperations.hasOwnProperty(operation)){
|
if (permittedOperations.hasOwnProperty(operation)){
|
||||||
return Object.freeze(new GPGME_Message(operation));
|
return new GPGME_Message(operation);
|
||||||
} else {
|
} else {
|
||||||
return gpgme_error('MSG_WRONG_OP');
|
return gpgme_error('MSG_WRONG_OP');
|
||||||
}
|
}
|
||||||
@ -52,180 +52,47 @@ export function createMessage(operation){
|
|||||||
export class GPGME_Message {
|
export class GPGME_Message {
|
||||||
|
|
||||||
constructor(operation){
|
constructor(operation){
|
||||||
let _msg = {
|
this._msg = {
|
||||||
op: operation,
|
op: operation,
|
||||||
chunksize: 1023* 1024
|
chunksize: 1023* 1024
|
||||||
};
|
};
|
||||||
let expected = null;
|
this._expected = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.getOperation = function(){
|
get operation(){
|
||||||
return _msg.op;
|
return this._msg.op;
|
||||||
};
|
}
|
||||||
|
|
||||||
this.setExpect = function(value){
|
set expected (value){
|
||||||
if (value === 'base64'){
|
if (value === 'base64'){
|
||||||
expected = value;
|
this._expected = value;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
this.getExpect = function(){
|
|
||||||
return expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
get expected() {
|
||||||
* The maximum size of responses from gpgme in bytes. As of July 2018,
|
return this._expected;
|
||||||
* most browsers will only accept answers up to 1 MB of size.
|
}
|
||||||
* Everything above that threshold will not pass through
|
/**
|
||||||
* nativeMessaging; answers that are larger need to be sent in parts.
|
* The maximum size of responses from gpgme in bytes. As of July 2018,
|
||||||
* The lower limit is set to 10 KB. Messages smaller than the threshold
|
* most browsers will only accept answers up to 1 MB of size.
|
||||||
* will not encounter problems, larger messages will be received in
|
* Everything above that threshold will not pass through
|
||||||
* chunks. If the value is not explicitly specified, 1023 KB is used.
|
* nativeMessaging; answers that are larger need to be sent in parts.
|
||||||
*/
|
* The lower limit is set to 10 KB. Messages smaller than the threshold
|
||||||
this.setChunksize = function (value){
|
* will not encounter problems, larger messages will be received in
|
||||||
if (
|
* chunks. If the value is not explicitly specified, 1023 KB is used.
|
||||||
Number.isInteger(value) &&
|
*/
|
||||||
value > 10 * 1024 &&
|
set chunksize(value){
|
||||||
value <= 1024 * 1024
|
if (
|
||||||
){
|
Number.isInteger(value) &&
|
||||||
_msg.chunksize = value;
|
value > 10 * 1024 &&
|
||||||
}
|
value <= 1024 * 1024
|
||||||
};
|
){
|
||||||
|
this._msg.chunksize = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.getMsg = function(){
|
get chunksize(){
|
||||||
return _msg;
|
return this._msg.chunksize;
|
||||||
};
|
|
||||||
|
|
||||||
this.getChunksize= function() {
|
|
||||||
return _msg.chunksize;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a parameter for the message. It validates with
|
|
||||||
* {@link permittedOperations}
|
|
||||||
* @param {String} param Parameter to set
|
|
||||||
* @param {any} value Value to set
|
|
||||||
* @returns {Boolean} If the parameter was set successfully
|
|
||||||
*/
|
|
||||||
this.setParameter = function ( param,value ){
|
|
||||||
if (!param || typeof(param) !== 'string'){
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
let po = permittedOperations[_msg.op];
|
|
||||||
if (!po){
|
|
||||||
return gpgme_error('MSG_WRONG_OP');
|
|
||||||
}
|
|
||||||
let poparam = null;
|
|
||||||
if (po.required.hasOwnProperty(param)){
|
|
||||||
poparam = po.required[param];
|
|
||||||
} else if (po.optional.hasOwnProperty(param)){
|
|
||||||
poparam = po.optional[param];
|
|
||||||
} else {
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
// check incoming value for correctness
|
|
||||||
let checktype = function(val){
|
|
||||||
switch(typeof(val)){
|
|
||||||
case 'string':
|
|
||||||
if (poparam.allowed.indexOf(typeof(val)) >= 0
|
|
||||||
&& val.length > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
case 'number':
|
|
||||||
if (
|
|
||||||
poparam.allowed.indexOf('number') >= 0
|
|
||||||
&& isNaN(value) === false){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
|
|
||||||
case 'boolean':
|
|
||||||
if (poparam.allowed.indexOf('boolean') >= 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
case 'object':
|
|
||||||
if (Array.isArray(val)){
|
|
||||||
if (poparam.array_allowed !== true){
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
for (let i=0; i < val.length; i++){
|
|
||||||
let res = checktype(val[i]);
|
|
||||||
if (res !== true){
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (val.length > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (val instanceof Uint8Array){
|
|
||||||
if (poparam.allowed.indexOf('Uint8Array') >= 0){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
} else {
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let typechecked = checktype(value);
|
|
||||||
if (typechecked !== true){
|
|
||||||
return typechecked;
|
|
||||||
}
|
|
||||||
if (poparam.hasOwnProperty('allowed_data')){
|
|
||||||
if (poparam.allowed_data.indexOf(value) < 0){
|
|
||||||
return gpgme_error('PARAM_WRONG');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_msg[param] = value;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the message has the minimum requirements to be sent, that is
|
|
||||||
* all 'required' parameters according to {@link permittedOperations}.
|
|
||||||
* @returns {Boolean} true if message is complete.
|
|
||||||
*/
|
|
||||||
this.isComplete = function(){
|
|
||||||
if (!_msg.op){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let reqParams = Object.keys(
|
|
||||||
permittedOperations[_msg.op].required);
|
|
||||||
let msg_params = Object.keys(_msg);
|
|
||||||
for (let i=0; i < reqParams.length; i++){
|
|
||||||
if (msg_params.indexOf(reqParams[i]) < 0){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Sends the Message via nativeMessaging and resolves with the answer.
|
|
||||||
* @returns {Promise<Object|GPGME_Error>}
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.post = function(){
|
|
||||||
let me = this;
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
if (me.isComplete() === true) {
|
|
||||||
|
|
||||||
let conn = Object.freeze(new Connection);
|
|
||||||
conn.post(me).then(function(response) {
|
|
||||||
resolve(response);
|
|
||||||
}, function(reason) {
|
|
||||||
reject(reason);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reject(gpgme_error('MSG_INCOMPLETE'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,18 +100,140 @@ export class GPGME_Message {
|
|||||||
* @returns {Object|null} Object to be posted to gnupg, or null if
|
* @returns {Object|null} Object to be posted to gnupg, or null if
|
||||||
* incomplete
|
* incomplete
|
||||||
*/
|
*/
|
||||||
get message(){
|
get message() {
|
||||||
if (this.isComplete() === true){
|
if (this.isComplete() === true){
|
||||||
return this.getMsg();
|
return this._msg;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get operation(){
|
|
||||||
return this.getOperation();
|
/**
|
||||||
|
* Sets a parameter for the message. It validates with
|
||||||
|
* {@link permittedOperations}
|
||||||
|
* @param {String} param Parameter to set
|
||||||
|
* @param {any} value Value to set
|
||||||
|
* @returns {Boolean} If the parameter was set successfully
|
||||||
|
*/
|
||||||
|
setParameter ( param,value ){
|
||||||
|
if (!param || typeof(param) !== 'string'){
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
let po = permittedOperations[this._msg.op];
|
||||||
|
if (!po){
|
||||||
|
return gpgme_error('MSG_WRONG_OP');
|
||||||
|
}
|
||||||
|
let poparam = null;
|
||||||
|
if (po.required.hasOwnProperty(param)){
|
||||||
|
poparam = po.required[param];
|
||||||
|
} else if (po.optional.hasOwnProperty(param)){
|
||||||
|
poparam = po.optional[param];
|
||||||
|
} else {
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
// check incoming value for correctness
|
||||||
|
let checktype = function(val){
|
||||||
|
switch(typeof(val)){
|
||||||
|
case 'string':
|
||||||
|
if (poparam.allowed.indexOf(typeof(val)) >= 0
|
||||||
|
&& val.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
case 'number':
|
||||||
|
if (
|
||||||
|
poparam.allowed.indexOf('number') >= 0
|
||||||
|
&& isNaN(value) === false){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
if (poparam.allowed.indexOf('boolean') >= 0){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
case 'object':
|
||||||
|
if (Array.isArray(val)){
|
||||||
|
if (poparam.array_allowed !== true){
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
for (let i=0; i < val.length; i++){
|
||||||
|
let res = checktype(val[i]);
|
||||||
|
if (res !== true){
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (val instanceof Uint8Array){
|
||||||
|
if (poparam.allowed.indexOf('Uint8Array') >= 0){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
} else {
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let typechecked = checktype(value);
|
||||||
|
if (typechecked !== true){
|
||||||
|
return typechecked;
|
||||||
|
}
|
||||||
|
if (poparam.hasOwnProperty('allowed_data')){
|
||||||
|
if (poparam.allowed_data.indexOf(value) < 0){
|
||||||
|
return gpgme_error('PARAM_WRONG');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._msg[param] = value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
get chunksize(){
|
|
||||||
return this.getChunksize();
|
|
||||||
|
/**
|
||||||
|
* Check if the message has the minimum requirements to be sent, that is
|
||||||
|
* all 'required' parameters according to {@link permittedOperations}.
|
||||||
|
* @returns {Boolean} true if message is complete.
|
||||||
|
*/
|
||||||
|
isComplete(){
|
||||||
|
if (!this._msg.op){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let reqParams = Object.keys(
|
||||||
|
permittedOperations[this._msg.op].required);
|
||||||
|
let msg_params = Object.keys(this._msg);
|
||||||
|
for (let i=0; i < reqParams.length; i++){
|
||||||
|
if (msg_params.indexOf(reqParams[i]) < 0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Sends the Message via nativeMessaging and resolves with the answer.
|
||||||
|
* @returns {Promise<Object|GPGME_Error>}
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
post (){
|
||||||
|
let me = this;
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
if (me.isComplete() === true) {
|
||||||
|
|
||||||
|
let conn = new Connection;
|
||||||
|
conn.post(me).then(function(response) {
|
||||||
|
resolve(response);
|
||||||
|
}, function(reason) {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reject(gpgme_error('MSG_INCOMPLETE'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ export function createSignature(sigObject){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Object.freeze(new GPGME_Signature(sigObject));
|
return new GPGME_Signature(sigObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,101 +82,65 @@ export function createSignature(sigObject){
|
|||||||
class GPGME_Signature {
|
class GPGME_Signature {
|
||||||
|
|
||||||
constructor(sigObject){
|
constructor(sigObject){
|
||||||
let _rawSigObject = sigObject;
|
this._rawSigObject = sigObject;
|
||||||
|
|
||||||
this.getFingerprint = function(){
|
|
||||||
if (!_rawSigObject.fingerprint){
|
|
||||||
return gpgme_error('SIG_WRONG');
|
|
||||||
} else {
|
|
||||||
return _rawSigObject.fingerprint;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The expiration of this Signature as Javascript date, or null if
|
|
||||||
* signature does not expire
|
|
||||||
* @returns {Date | null}
|
|
||||||
*/
|
|
||||||
this.getExpiration = function(){
|
|
||||||
if (!_rawSigObject.exp_timestamp){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Date(_rawSigObject.exp_timestamp* 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The creation date of this Signature in Javascript Date
|
|
||||||
* @returns {Date}
|
|
||||||
*/
|
|
||||||
this.getTimestamp= function (){
|
|
||||||
return new Date(_rawSigObject.timestamp * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The overall validity of the key. If false, errorDetails may contain
|
|
||||||
* additional information.
|
|
||||||
*/
|
|
||||||
this.getValid= function() {
|
|
||||||
if (_rawSigObject.summary.valid === true){
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gives more information on non-valid signatures. Refer to the gpgme
|
|
||||||
* docs https://www.gnupg.org/documentation/manuals/gpgme/Verify.html
|
|
||||||
* for details on the values.
|
|
||||||
* @returns {Object} Object with boolean properties
|
|
||||||
*/
|
|
||||||
this.getErrorDetails = function (){
|
|
||||||
let properties = ['revoked', 'key-expired', 'sig-expired',
|
|
||||||
'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy',
|
|
||||||
'sys-error'];
|
|
||||||
let result = {};
|
|
||||||
for (let i=0; i< properties.length; i++){
|
|
||||||
if ( _rawSigObject.hasOwnProperty(properties[i]) ){
|
|
||||||
result[properties[i]] = _rawSigObject[properties[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience getter for {@link getFingerprint}
|
|
||||||
*/
|
|
||||||
get fingerprint(){
|
get fingerprint(){
|
||||||
return this.getFingerprint();
|
if (!this._rawSigObject.fingerprint){
|
||||||
|
return gpgme_error('SIG_WRONG');
|
||||||
|
} else {
|
||||||
|
return this._rawSigObject.fingerprint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience getter for {@link getExpiration}
|
* The expiration of this Signature as Javascript date, or null if
|
||||||
|
* signature does not expire
|
||||||
|
* @returns {Date | null}
|
||||||
*/
|
*/
|
||||||
get expiration(){
|
get expiration(){
|
||||||
return this.getExpiration();
|
if (!this._rawSigObject.exp_timestamp){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Date(this._rawSigObject.exp_timestamp* 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience getter for {@link getTimeStamp}
|
* The creation date of this Signature in Javascript Date
|
||||||
|
* @returns {Date}
|
||||||
*/
|
*/
|
||||||
get timestamp(){
|
get timestamp (){
|
||||||
return this.getTimestamp();
|
return new Date(this._rawSigObject.timestamp * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience getter for {@link getValid}
|
* The overall validity of the key. If false, errorDetails may contain
|
||||||
|
* additional information.
|
||||||
*/
|
*/
|
||||||
get valid(){
|
get valid () {
|
||||||
return this.getValid();
|
if (this._rawSigObject.summary.valid === true){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience getter for {@link getErrorDetails}
|
* gives more information on non-valid signatures. Refer to the gpgme
|
||||||
|
* docs https://www.gnupg.org/documentation/manuals/gpgme/Verify.html
|
||||||
|
* for details on the values.
|
||||||
|
* @returns {Object} Object with boolean properties
|
||||||
*/
|
*/
|
||||||
get errorDetails(){
|
get errorDetails(){
|
||||||
return this.getErrorDetails();
|
let properties = ['revoked', 'key-expired', 'sig-expired',
|
||||||
|
'key-missing', 'crl-missing', 'crl-too-old', 'bad-policy',
|
||||||
|
'sys-error'];
|
||||||
|
let result = {};
|
||||||
|
for (let i=0; i< properties.length; i++){
|
||||||
|
if ( this._rawSigObject.hasOwnProperty(properties[i]) ){
|
||||||
|
result[properties[i]] = this._rawSigObject[properties[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,228 +85,7 @@ import { createSignature } from './Signature';
|
|||||||
export class GpgME {
|
export class GpgME {
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
let _Keyring = null;
|
this._Keyring = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a new Keyring to be used
|
|
||||||
* @param {GPGME_Keyring} keyring
|
|
||||||
*/
|
|
||||||
this.setKeyring = function(keyring){
|
|
||||||
if (keyring && keyring instanceof GPGME_Keyring){
|
|
||||||
_Keyring = keyring;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accesses the {@link GPGME_Keyring}.
|
|
||||||
*/
|
|
||||||
this.getKeyring = function(){
|
|
||||||
if (!_Keyring){
|
|
||||||
_Keyring = Object.freeze(new GPGME_Keyring);
|
|
||||||
}
|
|
||||||
return _Keyring;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt (and optionally sign) data
|
|
||||||
* @param {String|Object} data text/data to be encrypted as String. Also
|
|
||||||
* accepts Objects with a getText method
|
|
||||||
* @param {inputKeys} publicKeys
|
|
||||||
* Keys used to encrypt the message
|
|
||||||
* @param {inputKeys} secretKeys (optional) Keys used to sign the
|
|
||||||
* message. If Keys are present, the operation requested is assumed
|
|
||||||
* to be 'encrypt and sign'
|
|
||||||
* @param {Boolean} base64 (optional) The data will be interpreted as
|
|
||||||
* base64 encoded data.
|
|
||||||
* @param {Boolean} armor (optional) Request the output as armored
|
|
||||||
* block.
|
|
||||||
* @param {Boolean} 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
|
|
||||||
*/
|
|
||||||
this.encrypt = function (data, publicKeys, secretKeys, base64=false,
|
|
||||||
armor=true, wildcard=false, additional = {}
|
|
||||||
){
|
|
||||||
let msg = createMessage('encrypt');
|
|
||||||
if (msg instanceof Error){
|
|
||||||
return Promise.reject(msg);
|
|
||||||
}
|
|
||||||
msg.setParameter('armor', armor);
|
|
||||||
msg.setParameter('always-trust', true);
|
|
||||||
if (base64 === true) {
|
|
||||||
msg.setParameter('base64', true);
|
|
||||||
}
|
|
||||||
let pubkeys = toKeyIdArray(publicKeys);
|
|
||||||
msg.setParameter('keys', pubkeys);
|
|
||||||
let sigkeys = toKeyIdArray(secretKeys);
|
|
||||||
if (sigkeys.length > 0) {
|
|
||||||
msg.setParameter('signing_keys', sigkeys);
|
|
||||||
}
|
|
||||||
putData(msg, data);
|
|
||||||
if (wildcard === true){
|
|
||||||
msg.setParameter('throw-keyids', true);
|
|
||||||
}
|
|
||||||
if (additional){
|
|
||||||
let additional_Keys = Object.keys(additional);
|
|
||||||
for (let k = 0; k < additional_Keys.length; k++) {
|
|
||||||
msg.setParameter(additional_Keys[k],
|
|
||||||
additional[additional_Keys[k]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg.isComplete() === true){
|
|
||||||
return msg.post();
|
|
||||||
} else {
|
|
||||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts a Message
|
|
||||||
* @param {String|Object} data text/data to be decrypted. Accepts
|
|
||||||
* 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
|
|
||||||
* @returns {Promise<decrypt_result>} Decrypted Message and information
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.decrypt = function (data, base64=false){
|
|
||||||
if (data === undefined){
|
|
||||||
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
|
||||||
}
|
|
||||||
let msg = createMessage('decrypt');
|
|
||||||
|
|
||||||
if (msg instanceof Error){
|
|
||||||
return Promise.reject(msg);
|
|
||||||
}
|
|
||||||
if (base64 === true){
|
|
||||||
msg.setParameter('base64', true);
|
|
||||||
}
|
|
||||||
putData(msg, data);
|
|
||||||
if (base64 === true){
|
|
||||||
msg.setParameter('base64', true);
|
|
||||||
}
|
|
||||||
return new Promise(function(resolve, reject){
|
|
||||||
msg.post().then(function(result){
|
|
||||||
let _result = {data: result.data};
|
|
||||||
_result.base64 = result.base64 ? true: false;
|
|
||||||
_result.is_mime = result.is_mime ? true: false;
|
|
||||||
if (result.file_name){
|
|
||||||
_result.file_name = result.file_name;
|
|
||||||
} else {
|
|
||||||
_result.file_name = null;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
result.hasOwnProperty('signatures') &&
|
|
||||||
Array.isArray(result.signatures)
|
|
||||||
) {
|
|
||||||
_result.signatures = collectSignatures(
|
|
||||||
result.signatures);
|
|
||||||
}
|
|
||||||
resolve(_result);
|
|
||||||
}, function(error){
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign a Message
|
|
||||||
* @param {String|Object} data text/data to be signed. Accepts Strings
|
|
||||||
* and Objects with a getText method.
|
|
||||||
* @param {inputKeys} keys The key/keys to use for signing
|
|
||||||
* @param {String} mode The signing mode. Currently supported:
|
|
||||||
* 'clearsign':The Message is embedded into the signature;
|
|
||||||
* 'detached': The signature is stored separately
|
|
||||||
* @param {Boolean} base64 input is considered base64
|
|
||||||
* @returns {Promise<signResult>}
|
|
||||||
* @async
|
|
||||||
*/
|
|
||||||
this.sign = function (data, keys, mode='clearsign', base64=false) {
|
|
||||||
if (data === undefined){
|
|
||||||
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
|
||||||
}
|
|
||||||
let key_arr = toKeyIdArray(keys);
|
|
||||||
if (key_arr.length === 0){
|
|
||||||
return Promise.reject(gpgme_error('MSG_NO_KEYS'));
|
|
||||||
}
|
|
||||||
let msg = createMessage('sign');
|
|
||||||
|
|
||||||
msg.setParameter('keys', key_arr);
|
|
||||||
if (base64 === true){
|
|
||||||
msg.setParameter('base64', true);
|
|
||||||
}
|
|
||||||
msg.setParameter('mode', mode);
|
|
||||||
putData(msg, data);
|
|
||||||
return new Promise(function(resolve,reject) {
|
|
||||||
if (mode ==='detached'){
|
|
||||||
msg.setExpect('base64');
|
|
||||||
}
|
|
||||||
msg.post().then( function(message) {
|
|
||||||
if (mode === 'clearsign'){
|
|
||||||
resolve({
|
|
||||||
data: message.data}
|
|
||||||
);
|
|
||||||
} else if (mode === 'detached') {
|
|
||||||
resolve({
|
|
||||||
data: data,
|
|
||||||
signature: message.data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(error){
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies data.
|
|
||||||
* @param {String|Object} data text/data to be verified. Accepts Strings
|
|
||||||
* and Objects with a getText method
|
|
||||||
* @param {String} (optional) A detached signature. If not present,
|
|
||||||
* opaque mode is assumed
|
|
||||||
* @param {Boolean} (optional) Data and signature are base64 encoded
|
|
||||||
* @returns {Promise<verifyResult>}
|
|
||||||
*@async
|
|
||||||
*/
|
|
||||||
this.verify= function (data, signature, base64 = false){
|
|
||||||
let msg = createMessage('verify');
|
|
||||||
let dt = putData(msg, data);
|
|
||||||
if (dt instanceof Error){
|
|
||||||
return Promise.reject(dt);
|
|
||||||
}
|
|
||||||
if (signature){
|
|
||||||
if (typeof(signature)!== 'string'){
|
|
||||||
return Promise.reject(gpgme_error('PARAM_WRONG'));
|
|
||||||
} else {
|
|
||||||
msg.setParameter('signature', signature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 = collectSignatures(
|
|
||||||
message.info.signatures);
|
|
||||||
_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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -314,14 +93,218 @@ export class GpgME {
|
|||||||
* @param {GPGME_Keyring} keyring A Keyring to use
|
* @param {GPGME_Keyring} keyring A Keyring to use
|
||||||
*/
|
*/
|
||||||
set Keyring(keyring){
|
set Keyring(keyring){
|
||||||
this.setKeyring(keyring);
|
if (keyring && keyring instanceof GPGME_Keyring){
|
||||||
|
this._Keyring = keyring;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accesses the {@link GPGME_Keyring}.
|
* Accesses the {@link GPGME_Keyring}.
|
||||||
*/
|
*/
|
||||||
get Keyring(){
|
get Keyring(){
|
||||||
return this.getKeyring();
|
if (!this._Keyring){
|
||||||
|
this._Keyring = new GPGME_Keyring;
|
||||||
|
}
|
||||||
|
return this._Keyring;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt (and optionally sign) data
|
||||||
|
* @param {String|Object} data text/data to be encrypted as String. Also
|
||||||
|
* accepts Objects with a getText method
|
||||||
|
* @param {inputKeys} publicKeys
|
||||||
|
* Keys used to encrypt the message
|
||||||
|
* @param {inputKeys} secretKeys (optional) Keys used to sign the
|
||||||
|
* message. If Keys are present, the operation requested is assumed
|
||||||
|
* to be 'encrypt and sign'
|
||||||
|
* @param {Boolean} base64 (optional) The data will be interpreted as
|
||||||
|
* base64 encoded data.
|
||||||
|
* @param {Boolean} armor (optional) Request the output as armored
|
||||||
|
* block.
|
||||||
|
* @param {Boolean} 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 (data, publicKeys, secretKeys, base64=false, armor=true,
|
||||||
|
wildcard=false, additional = {}){
|
||||||
|
let msg = createMessage('encrypt');
|
||||||
|
if (msg instanceof Error){
|
||||||
|
return Promise.reject(msg);
|
||||||
|
}
|
||||||
|
msg.setParameter('armor', armor);
|
||||||
|
msg.setParameter('always-trust', true);
|
||||||
|
if (base64 === true) {
|
||||||
|
msg.setParameter('base64', true);
|
||||||
|
}
|
||||||
|
let pubkeys = toKeyIdArray(publicKeys);
|
||||||
|
msg.setParameter('keys', pubkeys);
|
||||||
|
let sigkeys = toKeyIdArray(secretKeys);
|
||||||
|
if (sigkeys.length > 0) {
|
||||||
|
msg.setParameter('signing_keys', sigkeys);
|
||||||
|
}
|
||||||
|
putData(msg, data);
|
||||||
|
if (wildcard === true){
|
||||||
|
msg.setParameter('throw-keyids', true);
|
||||||
|
}
|
||||||
|
if (additional){
|
||||||
|
let additional_Keys = Object.keys(additional);
|
||||||
|
for (let k = 0; k < additional_Keys.length; k++) {
|
||||||
|
msg.setParameter(additional_Keys[k],
|
||||||
|
additional[additional_Keys[k]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg.isComplete() === true){
|
||||||
|
return msg.post();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a Message
|
||||||
|
* @param {String|Object} data text/data to be decrypted. Accepts
|
||||||
|
* 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
|
||||||
|
* @returns {Promise<decrypt_result>} Decrypted Message and information
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
decrypt (data, base64=false){
|
||||||
|
if (data === undefined){
|
||||||
|
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
||||||
|
}
|
||||||
|
let msg = createMessage('decrypt');
|
||||||
|
|
||||||
|
if (msg instanceof Error){
|
||||||
|
return Promise.reject(msg);
|
||||||
|
}
|
||||||
|
if (base64 === true){
|
||||||
|
msg.setParameter('base64', true);
|
||||||
|
}
|
||||||
|
putData(msg, data);
|
||||||
|
if (base64 === true){
|
||||||
|
msg.setParameter('base64', true);
|
||||||
|
}
|
||||||
|
return new Promise(function(resolve, reject){
|
||||||
|
msg.post().then(function(result){
|
||||||
|
let _result = {data: result.data};
|
||||||
|
_result.base64 = result.base64 ? true: false;
|
||||||
|
_result.is_mime = result.is_mime ? true: false;
|
||||||
|
if (result.file_name){
|
||||||
|
_result.file_name = result.file_name;
|
||||||
|
} else {
|
||||||
|
_result.file_name = null;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
result.hasOwnProperty('signatures') &&
|
||||||
|
Array.isArray(result.signatures)
|
||||||
|
) {
|
||||||
|
_result.signatures = collectSignatures(
|
||||||
|
result.signatures);
|
||||||
|
}
|
||||||
|
resolve(_result);
|
||||||
|
}, function(error){
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a Message
|
||||||
|
* @param {String|Object} data text/data to be signed. Accepts Strings
|
||||||
|
* and Objects with a getText method.
|
||||||
|
* @param {inputKeys} keys The key/keys to use for signing
|
||||||
|
* @param {String} mode The signing mode. Currently supported:
|
||||||
|
* 'clearsign':The Message is embedded into the signature;
|
||||||
|
* 'detached': The signature is stored separately
|
||||||
|
* @param {Boolean} base64 input is considered base64
|
||||||
|
* @returns {Promise<signResult>}
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
sign (data, keys, mode='clearsign', base64=false) {
|
||||||
|
if (data === undefined){
|
||||||
|
return Promise.reject(gpgme_error('MSG_EMPTY'));
|
||||||
|
}
|
||||||
|
let key_arr = toKeyIdArray(keys);
|
||||||
|
if (key_arr.length === 0){
|
||||||
|
return Promise.reject(gpgme_error('MSG_NO_KEYS'));
|
||||||
|
}
|
||||||
|
let msg = createMessage('sign');
|
||||||
|
|
||||||
|
msg.setParameter('keys', key_arr);
|
||||||
|
if (base64 === true){
|
||||||
|
msg.setParameter('base64', true);
|
||||||
|
}
|
||||||
|
msg.setParameter('mode', mode);
|
||||||
|
putData(msg, data);
|
||||||
|
return new Promise(function(resolve,reject) {
|
||||||
|
if (mode ==='detached'){
|
||||||
|
msg.expected ='base64';
|
||||||
|
}
|
||||||
|
msg.post().then( function(message) {
|
||||||
|
if (mode === 'clearsign'){
|
||||||
|
resolve({
|
||||||
|
data: message.data}
|
||||||
|
);
|
||||||
|
} else if (mode === 'detached') {
|
||||||
|
resolve({
|
||||||
|
data: data,
|
||||||
|
signature: message.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, function(error){
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies data.
|
||||||
|
* @param {String|Object} data text/data to be verified. Accepts Strings
|
||||||
|
* and Objects with a getText method
|
||||||
|
* @param {String} (optional) A detached signature. If not present,
|
||||||
|
* opaque mode is assumed
|
||||||
|
* @param {Boolean} (optional) Data and signature are base64 encoded
|
||||||
|
* @returns {Promise<verifyResult>}
|
||||||
|
*@async
|
||||||
|
*/
|
||||||
|
verify (data, signature, base64 = false){
|
||||||
|
let msg = createMessage('verify');
|
||||||
|
let dt = putData(msg, data);
|
||||||
|
if (dt instanceof Error){
|
||||||
|
return Promise.reject(dt);
|
||||||
|
}
|
||||||
|
if (signature){
|
||||||
|
if (typeof(signature)!== 'string'){
|
||||||
|
return Promise.reject(gpgme_error('PARAM_WRONG'));
|
||||||
|
} else {
|
||||||
|
msg.setParameter('signature', signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = collectSignatures(
|
||||||
|
message.info.signatures);
|
||||||
|
_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);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +34,11 @@ import { Connection } from './Connection';
|
|||||||
*/
|
*/
|
||||||
function init(){
|
function init(){
|
||||||
return new Promise(function(resolve, reject){
|
return new Promise(function(resolve, reject){
|
||||||
const connection = Object.freeze(new Connection);
|
const connection = new Connection;
|
||||||
connection.checkConnection(false).then(
|
connection.checkConnection(false).then(
|
||||||
function(result){
|
function(result){
|
||||||
if (result === true) {
|
if (result === true) {
|
||||||
resolve(Object.freeze(new GpgME()));
|
resolve(new GpgME());
|
||||||
} else {
|
} else {
|
||||||
reject(gpgme_error('CONN_NO_CONNECT'));
|
reject(gpgme_error('CONN_NO_CONNECT'));
|
||||||
}
|
}
|
||||||
@ -48,5 +48,5 @@ function init(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportvalue = Object.freeze({init:init});
|
const exportvalue = {init:init};
|
||||||
export default exportvalue;
|
export default exportvalue;
|
@ -27,7 +27,7 @@ import { key_params as kp } from './unittest_inputvalues';
|
|||||||
import { Connection } from './src/Connection';
|
import { Connection } from './src/Connection';
|
||||||
import { gpgme_error } from './src/Errors';
|
import { gpgme_error } from './src/Errors';
|
||||||
import { toKeyIdArray , isFingerprint } from './src/Helpers';
|
import { toKeyIdArray , isFingerprint } from './src/Helpers';
|
||||||
import { GPGME_Key , createKey } from './src/Key';
|
import { createKey } from './src/Key';
|
||||||
import { GPGME_Keyring } from './src/Keyring';
|
import { GPGME_Keyring } from './src/Keyring';
|
||||||
import {GPGME_Message, createMessage} from './src/Message';
|
import {GPGME_Message, createMessage} from './src/Message';
|
||||||
|
|
||||||
@ -116,14 +116,6 @@ function unittests (){
|
|||||||
expect(test0).to.include(hp.validFingerprint);
|
expect(test0).to.include(hp.validFingerprint);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correct GPGME_Key', function(){
|
|
||||||
expect(hp.validGPGME_Key).to.be.an.instanceof(GPGME_Key);
|
|
||||||
let test0 = toKeyIdArray(hp.validGPGME_Key);
|
|
||||||
|
|
||||||
expect(test0).to.be.an('array');
|
|
||||||
expect(test0).to.include(hp.validGPGME_Key.fingerprint);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('openpgpjs-like object', function(){
|
it('openpgpjs-like object', function(){
|
||||||
let test0 = toKeyIdArray(hp.valid_openpgplike);
|
let test0 = toKeyIdArray(hp.valid_openpgplike);
|
||||||
|
|
||||||
@ -169,15 +161,9 @@ function unittests (){
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('GPGME_Key', function(){
|
describe('GPGME_Key', function(){
|
||||||
|
|
||||||
it('correct Key initialization', function(){
|
|
||||||
let key = createKey(kp.validKeyFingerprint);
|
|
||||||
expect(key).to.be.an.instanceof(GPGME_Key);
|
|
||||||
});
|
|
||||||
it('Key has data after a first refresh', function(done) {
|
it('Key has data after a first refresh', function(done) {
|
||||||
let key = createKey(kp.validKeyFingerprint);
|
let key = createKey(kp.validKeyFingerprint);
|
||||||
key.refreshKey().then(function(key2){
|
key.refreshKey().then(function(key2){
|
||||||
expect(key2).to.be.an.instanceof(GPGME_Key);
|
|
||||||
expect(key2.get).to.be.a('function');
|
expect(key2.get).to.be.a('function');
|
||||||
for (let i=0; i < kp.validKeyProperties.length; i++) {
|
for (let i=0; i < kp.validKeyProperties.length; i++) {
|
||||||
let prop = key2.get(kp.validKeyProperties[i]);
|
let prop = key2.get(kp.validKeyProperties[i]);
|
||||||
@ -220,7 +206,6 @@ function unittests (){
|
|||||||
|
|
||||||
it('Non-cached key async hasSecret (no secret in Key)', function (done){
|
it('Non-cached key async hasSecret (no secret in Key)', function (done){
|
||||||
let key = createKey(kp.validFingerprintNoSecret, true);
|
let key = createKey(kp.validFingerprintNoSecret, true);
|
||||||
expect(key).to.be.an.instanceof(GPGME_Key);
|
|
||||||
key.get('hasSecret').then(function(result){
|
key.get('hasSecret').then(function(result){
|
||||||
expect(result).to.be.a('boolean');
|
expect(result).to.be.a('boolean');
|
||||||
expect(result).to.equal(false);
|
expect(result).to.equal(false);
|
||||||
@ -246,32 +231,21 @@ function unittests (){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('malformed GPGME_Key cannot be used', function(){
|
// it('Overwriting getFingerprint does not work', function(){
|
||||||
for (let i=0; i < 4; i++){
|
// const evilFunction = function(){
|
||||||
let key = new GPGME_Key(wp.four_invalid_params[i]);
|
// return 'bad Data';
|
||||||
expect(key.fingerprint).to.be.an.instanceof(Error);
|
// };
|
||||||
expect(key.fingerprint.code).to.equal('KEY_INVALID');
|
// let key = createKey(kp.validKeyFingerprint, true);
|
||||||
}
|
// expect(key.fingerprint).to.equal(kp.validKeyFingerprint);
|
||||||
});
|
// try {
|
||||||
|
// key.getFingerprint = evilFunction;
|
||||||
it('Overwriting getFingerprint does not work', function(){
|
// }
|
||||||
const evilFunction = function(){
|
// catch(e) {
|
||||||
return 'bad Data';
|
// expect(e).to.be.an.instanceof(TypeError);
|
||||||
};
|
// }
|
||||||
let key = createKey(kp.validKeyFingerprint, true);
|
// expect(key.fingerprint).to.equal(kp.validKeyFingerprint);
|
||||||
expect(key.fingerprint).to.equal(kp.validKeyFingerprint);
|
// expect(key.getFingerprint).to.not.equal(evilFunction);
|
||||||
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);
|
|
||||||
});
|
|
||||||
// TODO: tests for subkeys
|
|
||||||
// TODO: tests for userids
|
|
||||||
// TODO: some invalid tests for key/keyring
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GPGME_Keyring', function(){
|
describe('GPGME_Keyring', function(){
|
||||||
@ -287,10 +261,7 @@ function unittests (){
|
|||||||
let keyring = new GPGME_Keyring;
|
let keyring = new GPGME_Keyring;
|
||||||
keyring.getKeys(null, true).then(function(result){
|
keyring.getKeys(null, true).then(function(result){
|
||||||
expect(result).to.be.an('array');
|
expect(result).to.be.an('array');
|
||||||
expect(result[0]).to.be.an.instanceof(GPGME_Key);
|
|
||||||
expect(result[0].get('hasSecret')).to.be.a('boolean');
|
expect(result[0].get('hasSecret')).to.be.a('boolean');
|
||||||
// expect(result[0].get('armored')).to.include(
|
|
||||||
// '-----END PGP PUBLIC KEY BLOCK-----');
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -302,7 +273,6 @@ function unittests (){
|
|||||||
keyring.getKeys(kp.validKeyFingerprint, true).then(
|
keyring.getKeys(kp.validKeyFingerprint, true).then(
|
||||||
function(result){
|
function(result){
|
||||||
expect(result).to.be.an('array');
|
expect(result).to.be.an('array');
|
||||||
expect(result[0]).to.be.an.instanceof(GPGME_Key);
|
|
||||||
expect(result[0].get('hasSecret')).to.be.a('boolean');
|
expect(result[0].get('hasSecret')).to.be.a('boolean');
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user