js: fix indentaion
-- * doing the indentation changes that became neccesary in the last commit.
This commit is contained in:
parent
94ee0988d4
commit
522121ea7e
@ -52,128 +52,128 @@ export class Connection{
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} backEndDetails
|
||||
* @property {String} gpgme Version number of gpgme
|
||||
* @property {Array<Object>} info Further information about the backend
|
||||
* and the used applications (Example:
|
||||
* {
|
||||
* "protocol": "OpenPGP",
|
||||
* "fname": "/usr/bin/gpg",
|
||||
* "version": "2.2.6",
|
||||
* "req_version": "1.4.0",
|
||||
* "homedir": "default"
|
||||
* }
|
||||
*/
|
||||
/**
|
||||
* @typedef {Object} backEndDetails
|
||||
* @property {String} gpgme Version number of gpgme
|
||||
* @property {Array<Object>} info Further information about the backend
|
||||
* and the used applications (Example:
|
||||
* {
|
||||
* "protocol": "OpenPGP",
|
||||
* "fname": "/usr/bin/gpg",
|
||||
* "version": "2.2.6",
|
||||
* "req_version": "1.4.0",
|
||||
* "homedir": "default"
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the information about the backend.
|
||||
* @param {Boolean} details (optional) If set to false, the promise will
|
||||
* just return if a connection was successful.
|
||||
* @returns {Promise<backEndDetails>|Promise<Boolean>} Details from the
|
||||
* backend
|
||||
* @async
|
||||
*/
|
||||
this.checkConnection = function(details = true){
|
||||
const msg = createMessage('version');
|
||||
if (details === true) {
|
||||
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);
|
||||
/**
|
||||
* Retrieves the information about the backend.
|
||||
* @param {Boolean} details (optional) If set to false, the promise will
|
||||
* just return if a connection was successful.
|
||||
* @returns {Promise<backEndDetails>|Promise<Boolean>} Details from the
|
||||
* backend
|
||||
* @async
|
||||
*/
|
||||
this.checkConnection = function(details = true){
|
||||
const msg = createMessage('version');
|
||||
if (details === true) {
|
||||
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 resolves
|
||||
* with the completed answer after all parts have been received and
|
||||
* reassembled, or rejects with an {@link GPGME_Error}.
|
||||
*
|
||||
* @param {GPGME_Message} message
|
||||
* @returns {Promise<Object>} The collected answer
|
||||
* @async
|
||||
*/
|
||||
this.post = function (message){
|
||||
if (!message || !(message instanceof GPGME_Message)){
|
||||
this.disconnect();
|
||||
return Promise.reject(gpgme_error(
|
||||
'PARAM_WRONG', 'Connection.post'));
|
||||
}
|
||||
if (message.isComplete() !== true){
|
||||
this.disconnect();
|
||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
let chunksize = message.chunksize;
|
||||
return new Promise(function(resolve, reject){
|
||||
let answer = new Answer(message);
|
||||
let listener = function(msg) {
|
||||
if (!msg){
|
||||
_connection.onMessage.removeListener(listener);
|
||||
_connection.disconnect();
|
||||
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
|
||||
} else {
|
||||
let answer_result = answer.collect(msg);
|
||||
if (answer_result !== true){
|
||||
/**
|
||||
* Sends a {@link GPGME_Message} via tghe nativeMessaging port. It
|
||||
* resolves with the completed answer after all parts have been
|
||||
* received and reassembled, or rejects with an {@link GPGME_Error}.
|
||||
*
|
||||
* @param {GPGME_Message} message
|
||||
* @returns {Promise<Object>} The collected answer
|
||||
* @async
|
||||
*/
|
||||
this.post = function (message){
|
||||
if (!message || !(message instanceof GPGME_Message)){
|
||||
this.disconnect();
|
||||
return Promise.reject(gpgme_error(
|
||||
'PARAM_WRONG', 'Connection.post'));
|
||||
}
|
||||
if (message.isComplete() !== true){
|
||||
this.disconnect();
|
||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
let chunksize = message.chunksize;
|
||||
return new Promise(function(resolve, reject){
|
||||
let answer = new Answer(message);
|
||||
let listener = function(msg) {
|
||||
if (!msg){
|
||||
_connection.onMessage.removeListener(listener);
|
||||
_connection.disconnect();
|
||||
reject(answer_result);
|
||||
reject(gpgme_error('CONN_EMPTY_GPG_ANSWER'));
|
||||
} else {
|
||||
if (msg.more === true){
|
||||
_connection.postMessage({
|
||||
'op': 'getmore',
|
||||
'chunksize': chunksize
|
||||
});
|
||||
} else {
|
||||
let answer_result = answer.collect(msg);
|
||||
if (answer_result !== true){
|
||||
_connection.onMessage.removeListener(listener);
|
||||
_connection.disconnect();
|
||||
const message = answer.getMessage();
|
||||
if (message instanceof Error){
|
||||
reject(message);
|
||||
reject(answer_result);
|
||||
} else {
|
||||
if (msg.more === true){
|
||||
_connection.postMessage({
|
||||
'op': 'getmore',
|
||||
'chunksize': chunksize
|
||||
});
|
||||
} else {
|
||||
resolve(message);
|
||||
_connection.onMessage.removeListener(listener);
|
||||
_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.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();
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
return gpgme_error('GNUPG_ERROR', reject);
|
||||
} else {
|
||||
return reject;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,82 +197,84 @@ class Answer{
|
||||
this.getExpect = function(){
|
||||
return expect;
|
||||
};
|
||||
/**
|
||||
* Adds incoming base64 encoded data to the existing response
|
||||
* @param {*} msg base64 encoded data.
|
||||
* @returns {Boolean}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.collect = function (msg){
|
||||
if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
if (response_b64 === null){
|
||||
response_b64 = msg.response;
|
||||
return true;
|
||||
} else {
|
||||
response_b64 += msg.response;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Returns the base64 encoded answer data with the content verified against
|
||||
* {@link permittedOperations}.
|
||||
*/
|
||||
this.getMessage = function (){
|
||||
if (response_b64 === undefined){
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
let _decodedResponse = JSON.parse(atob(response_b64));
|
||||
let _response = {};
|
||||
let messageKeys = Object.keys(_decodedResponse);
|
||||
let poa = permittedOperations[this.getOperation()].answer;
|
||||
if (messageKeys.length === 0){
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
for (let i= 0; i < messageKeys.length; i++){
|
||||
let key = messageKeys[i];
|
||||
switch (key) {
|
||||
case 'type':
|
||||
if (_decodedResponse.type === 'error'){
|
||||
return (gpgme_error('GNUPG_ERROR',
|
||||
decodeURIComponent(escape(_decodedResponse.msg))));
|
||||
} else if (poa.type.indexOf(_decodedResponse.type) < 0){
|
||||
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() === undefined
|
||||
){
|
||||
_response[key] = decodeURIComponent(
|
||||
atob(_decodedResponse[key]).split('').map(
|
||||
function(c) {
|
||||
return '%' +
|
||||
('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
} else {
|
||||
_response[key] = _decodedResponse[key];
|
||||
}
|
||||
break;
|
||||
|
||||
/**
|
||||
* Adds incoming base64 encoded data to the existing response
|
||||
* @param {*} msg base64 encoded data.
|
||||
* @returns {Boolean}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
this.collect = function (msg){
|
||||
if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
}
|
||||
return _response;
|
||||
};
|
||||
}
|
||||
if (response_b64 === null){
|
||||
response_b64 = msg.response;
|
||||
return true;
|
||||
} else {
|
||||
response_b64 += msg.response;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Returns the base64 encoded answer data with the content verified
|
||||
* against {@link permittedOperations}.
|
||||
*/
|
||||
this.getMessage = function (){
|
||||
if (response_b64 === undefined){
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
let _decodedResponse = JSON.parse(atob(response_b64));
|
||||
let _response = {};
|
||||
let messageKeys = Object.keys(_decodedResponse);
|
||||
let poa = permittedOperations[this.getOperation()].answer;
|
||||
if (messageKeys.length === 0){
|
||||
return gpgme_error('CONN_UNEXPECTED_ANSWER');
|
||||
}
|
||||
for (let i= 0; i < messageKeys.length; i++){
|
||||
let key = messageKeys[i];
|
||||
switch (key) {
|
||||
case 'type':
|
||||
if (_decodedResponse.type === 'error'){
|
||||
return (gpgme_error('GNUPG_ERROR',
|
||||
decodeURIComponent(escape(_decodedResponse.msg))));
|
||||
} else if (poa.type.indexOf(_decodedResponse.type) < 0){
|
||||
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() === undefined
|
||||
){
|
||||
_response[key] = decodeURIComponent(
|
||||
atob(_decodedResponse[key]).split('').map(
|
||||
function(c) {
|
||||
return '%' +
|
||||
('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
} else {
|
||||
_response[key] = _decodedResponse[key];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _response;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -66,224 +66,226 @@ export class GPGME_Key {
|
||||
return _data.fingerprint;
|
||||
};
|
||||
|
||||
/**
|
||||
* Property indicating if the Key possesses a private/secret part. If this
|
||||
* information is not yet cached, it returns an {@link GPGME_Error} with
|
||||
* code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case.
|
||||
* @returns {Boolean} If the Key has a secret subkey.
|
||||
*/
|
||||
this.hasSecret= function (){
|
||||
return this.get('hasSecret', true);
|
||||
};
|
||||
/**
|
||||
* Property indicating if the Key possesses a private/secret part. If
|
||||
* this information is not yet cached, it returns an
|
||||
* {@link GPGME_Error} with code 'KEY_NO_INIT'. Running
|
||||
* {@link refreshKey} may help in this case.
|
||||
* @returns {Boolean} If the Key has a secret subkey.
|
||||
*/
|
||||
this.hasSecret= function (){
|
||||
return this.get('hasSecret', true);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} data Bulk set the data for this key, with an Object sent
|
||||
* by gpgme-json.
|
||||
* @returns {GPGME_Key|GPGME_Error} Itself after values have been set, an
|
||||
* error if something went wrong
|
||||
* @private
|
||||
*/
|
||||
this.setKeyData = function (data){
|
||||
if (typeof(data) !== 'object') {
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
if (!data.fingerprint || data.fingerprint !== _data.fingerprint){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
let keys = Object.keys(data);
|
||||
for (let i=0; i< keys.length; i++){
|
||||
if (!validKeyProperties.hasOwnProperty(keys[i])){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
//running the defined validation function
|
||||
if (validKeyProperties[keys[i]](data[keys[i]]) !== true ){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
switch (keys[i]){
|
||||
case 'subkeys':
|
||||
_data.subkeys = [];
|
||||
for (let i=0; i< data.subkeys.length; i++) {
|
||||
_data.subkeys.push(
|
||||
new GPGME_Subkey(data.subkeys[i]));
|
||||
}
|
||||
break;
|
||||
case 'userids':
|
||||
_data.userids = [];
|
||||
for (let i=0; i< data.userids.length; i++) {
|
||||
_data.userids.push(
|
||||
new GPGME_UserId(data.userids[i]));
|
||||
}
|
||||
break;
|
||||
case 'last_update':
|
||||
_data[keys[i]] = new Date( data[keys[i]] * 1000 );
|
||||
break;
|
||||
default:
|
||||
_data[keys[i]] = data[keys[i]];
|
||||
/**
|
||||
* @param {Object} data Bulk set the data for this key, with an Object
|
||||
* sent by gpgme-json.
|
||||
* @returns {GPGME_Key|GPGME_Error} Itself after values have been set,
|
||||
* an error if something went wrong.
|
||||
* @private
|
||||
*/
|
||||
this.setKeyData = function (data){
|
||||
if (typeof(data) !== 'object') {
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
if (!data.fingerprint || data.fingerprint !== _data.fingerprint){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
let keys = Object.keys(data);
|
||||
for (let i=0; i< keys.length; i++){
|
||||
if (!validKeyProperties.hasOwnProperty(keys[i])){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
//running the defined validation function
|
||||
if (validKeyProperties[keys[i]](data[keys[i]]) !== true ){
|
||||
return gpgme_error('KEY_INVALID');
|
||||
}
|
||||
switch (keys[i]){
|
||||
case 'subkeys':
|
||||
_data.subkeys = [];
|
||||
for (let i=0; i< data.subkeys.length; i++) {
|
||||
_data.subkeys.push(
|
||||
new GPGME_Subkey(data.subkeys[i]));
|
||||
}
|
||||
break;
|
||||
case 'userids':
|
||||
_data.userids = [];
|
||||
for (let i=0; i< data.userids.length; i++) {
|
||||
_data.userids.push(
|
||||
new GPGME_UserId(data.userids[i]));
|
||||
}
|
||||
break;
|
||||
case 'last_update':
|
||||
_data[keys[i]] = new Date( data[keys[i]] * 1000 );
|
||||
break;
|
||||
default:
|
||||
_data[keys[i]] = data[keys[i]];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Query any property of the Key listed in {@link validKeyProperties}
|
||||
* @param {String} property property to be retreived
|
||||
* @returns {*|Promise<*>} the value (Boolean, String, Array, Object).
|
||||
* If 'cached' is false, the value will be resolved as a Promise.
|
||||
*/
|
||||
this.get = function(property) {
|
||||
if (this.isAsync === true) {
|
||||
/**
|
||||
* Query any property of the Key listed in {@link validKeyProperties}
|
||||
* @param {String} property property to be retreived
|
||||
* @returns {*|Promise<*>} the value (Boolean, String, Array, Object).
|
||||
* If 'cached' is false, the value will be resolved as a Promise.
|
||||
*/
|
||||
this.get = function(property) {
|
||||
if (this.isAsync === true) {
|
||||
let me = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (property === 'armored'){
|
||||
resolve(me.getArmor());
|
||||
} else if (property === 'hasSecret'){
|
||||
resolve(me.getHasSecret());
|
||||
} else if (validKeyProperties.hasOwnProperty(property)){
|
||||
let msg = createMessage('keylist');
|
||||
msg.setParameter('keys', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
if (result.keys && result.keys.length === 1 &&
|
||||
result.keys[0].hasOwnProperty(property)){
|
||||
resolve(result.keys[0][property]);
|
||||
} else {
|
||||
reject(gpgme_error('CONN_UNEXPECTED_ANSWER'));
|
||||
}
|
||||
}, function(error){
|
||||
reject(gpgme_error(error));
|
||||
});
|
||||
} else {
|
||||
reject(gpgme_error('PARAM_WRONG'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!validKeyProperties.hasOwnProperty(property)){
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (!_data.hasOwnProperty(property)){
|
||||
return gpgme_error('KEY_NO_INIT');
|
||||
} else {
|
||||
return (_data[property]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reloads the Key information from gnupg. This is only useful if you
|
||||
* use the GPGME_Keys cached. Note that this is a performance hungry
|
||||
* operation. If you desire more than a few refreshs, it may be
|
||||
* advisable to run {@link Keyring.getKeys} instead.
|
||||
* @returns {Promise<GPGME_Key|GPGME_Error>}
|
||||
* @async
|
||||
*/
|
||||
this.refreshKey = function() {
|
||||
let me = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (property === 'armored'){
|
||||
resolve(me.getArmor());
|
||||
} else if (property === 'hasSecret'){
|
||||
resolve(me.getHasSecret());
|
||||
} else if (validKeyProperties.hasOwnProperty(property)){
|
||||
let msg = createMessage('keylist');
|
||||
msg.setParameter('keys', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
if (result.keys && result.keys.length === 1 &&
|
||||
result.keys[0].hasOwnProperty(property)){
|
||||
resolve(result.keys[0][property]);
|
||||
} else {
|
||||
reject(gpgme_error('CONN_UNEXPECTED_ANSWER'));
|
||||
}
|
||||
}, function(error){
|
||||
reject(gpgme_error(error));
|
||||
});
|
||||
} else {
|
||||
reject(gpgme_error('PARAM_WRONG'));
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!validKeyProperties.hasOwnProperty(property)){
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (!_data.hasOwnProperty(property)){
|
||||
return gpgme_error('KEY_NO_INIT');
|
||||
} else {
|
||||
return (_data[property]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reloads the Key information from gnupg. This is only useful if you use
|
||||
* the GPGME_Keys cached. Note that this is a performance hungry operation.
|
||||
* If you desire more than a few refreshs, it may be advisable to run
|
||||
* {@link Keyring.getKeys} instead.
|
||||
* @returns {Promise<GPGME_Key|GPGME_Error>}
|
||||
* @async
|
||||
*/
|
||||
this.refreshKey = function() {
|
||||
let me = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
let msg = createMessage('keylist');
|
||||
msg.setParameter('sigs', true);
|
||||
msg.setParameter('keys', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
if (result.keys.length === 1){
|
||||
me.setKeyData(result.keys[0]);
|
||||
me.getHasSecret().then(function(){
|
||||
me.getArmor().then(function(){
|
||||
resolve(me);
|
||||
let msg = createMessage('keylist');
|
||||
msg.setParameter('sigs', true);
|
||||
msg.setParameter('keys', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
if (result.keys.length === 1){
|
||||
me.setKeyData(result.keys[0]);
|
||||
me.getHasSecret().then(function(){
|
||||
me.getArmor().then(function(){
|
||||
resolve(me);
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
reject(gpgme_error('KEY_NOKEY'));
|
||||
} else {
|
||||
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'));
|
||||
}
|
||||
}, function (error) {
|
||||
reject(gpgme_error('GNUPG_ERROR'), error);
|
||||
let msg = createMessage('export');
|
||||
msg.setParameter('armor', true);
|
||||
msg.setParameter('keys', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
_data.armored = result.data;
|
||||
resolve(result.data);
|
||||
}, function(error){
|
||||
reject(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){
|
||||
_data.armored = result.data;
|
||||
resolve(result.data);
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Find out if the Key includes a secret part. Note that this is a rather
|
||||
* nonperformant operation, as it needs to query gnupg twice. If you want
|
||||
* this inforrmation about more than a few Keys, it may be advisable to run
|
||||
* {@link Keyring.getKeys} instead.
|
||||
* @returns {Promise<Boolean|GPGME_Error>} True if a secret/private Key is
|
||||
* available in the gnupg Keyring
|
||||
* @async
|
||||
*/
|
||||
this.getHasSecret = function (){
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
let msg = createMessage('keylist');
|
||||
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);
|
||||
/**
|
||||
* Find out if the Key includes a secret part. Note that this is a
|
||||
* rather nonperformant operation, as it needs to query gnupg twice.
|
||||
* If you want this inforrmation about more than a few Keys, it may be
|
||||
* advisable to run {@link Keyring.getKeys} instead.
|
||||
* @returns {Promise<Boolean|GPGME_Error>} True if a secret/private Key
|
||||
* is available in the gnupg Keyring
|
||||
* @async
|
||||
*/
|
||||
this.getHasSecret = function (){
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
}, function(error){
|
||||
reject(error);
|
||||
let msg = createMessage('keylist');
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
this.delete= function (){
|
||||
return new Promise(function(resolve, reject){
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
let msg = createMessage('delete');
|
||||
msg.setParameter('key', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
resolve(result.success);
|
||||
}, function(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.
|
||||
*/
|
||||
this.delete= function (){
|
||||
return new Promise(function(resolve, reject){
|
||||
if (!_data.fingerprint){
|
||||
reject(gpgme_error('KEY_INVALID'));
|
||||
}
|
||||
let msg = createMessage('delete');
|
||||
msg.setParameter('key', _data.fingerprint);
|
||||
msg.post().then(function(result){
|
||||
resolve(result.success);
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,42 +322,39 @@ class GPGME_Subkey {
|
||||
let _data = {};
|
||||
let keys = Object.keys(data);
|
||||
|
||||
/**
|
||||
* Validates a subkey property against {@link validSubKeyProperties} and
|
||||
* sets it if validation is successful
|
||||
* @param {String} property
|
||||
* @param {*} value
|
||||
* @param private
|
||||
*/
|
||||
const setProperty = function (property, value){
|
||||
if (validSubKeyProperties.hasOwnProperty(property)){
|
||||
if (validSubKeyProperties[property](value) === true) {
|
||||
if (property === 'timestamp' || property === 'expires'){
|
||||
_data[property] = new Date(value * 1000);
|
||||
} else {
|
||||
_data[property] = value;
|
||||
/**
|
||||
* Validates a subkey property against {@link validSubKeyProperties} and
|
||||
* sets it if validation is successful
|
||||
* @param {String} property
|
||||
* @param {*} value
|
||||
* @param private
|
||||
*/
|
||||
const setProperty = function (property, value){
|
||||
if (validSubKeyProperties.hasOwnProperty(property)){
|
||||
if (validSubKeyProperties[property](value) === true) {
|
||||
if (property === 'timestamp' || property === 'expires'){
|
||||
_data[property] = new Date(value * 1000);
|
||||
} else {
|
||||
_data[property] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (let i=0; i< keys.length; i++) {
|
||||
setProperty(keys[i], data[keys[i]]);
|
||||
}
|
||||
};
|
||||
for (let i=0; i< keys.length; 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}
|
||||
*/
|
||||
this.get = function(property) {
|
||||
if (_data.hasOwnProperty(property)){
|
||||
return (_data[property]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,28 +387,28 @@ class GPGME_UserId {
|
||||
setProperty(keys[i], data[keys[i]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a subkey property against {@link validUserIdProperties} and
|
||||
* sets it if validation is successful
|
||||
* @param {String} property
|
||||
* @param {*} value
|
||||
* @param private
|
||||
*/
|
||||
/**
|
||||
* Validates a subkey property against {@link validUserIdProperties} and
|
||||
* sets it if validation is successful
|
||||
* @param {String} property
|
||||
* @param {*} value
|
||||
* @param private
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
this.get = function (property) {
|
||||
if (_data.hasOwnProperty(property)){
|
||||
return (_data[property]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Validation definition for userIds. Each valid userId property is represented
|
||||
* as a key- Value pair, with their value being a validation function to check
|
||||
|
@ -33,359 +33,368 @@ import { gpgme_error } from './Errors';
|
||||
export class GPGME_Keyring {
|
||||
constructor(){
|
||||
|
||||
/**
|
||||
* Queries Keys (all Keys or a subset) from gnupg.
|
||||
*
|
||||
* @param {String | Array<String>} pattern (optional) A pattern to search
|
||||
* for in userIds or KeyIds.
|
||||
* @param {Boolean} prepare_sync (optional) if set to true, the 'hasSecret'
|
||||
* and 'armored' properties will be fetched for the Keys as well. These
|
||||
* require additional calls to gnupg, resulting in a performance hungry
|
||||
* operation. Calling them here enables direct, synchronous use of these
|
||||
* properties for all keys, without having to resort to a refresh() first.
|
||||
* @param {Boolean} search (optional) retrieve Keys from external servers
|
||||
* with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
|
||||
* @returns {Promise.<Array<GPGME_Key>|GPGME_Error>}
|
||||
* @static
|
||||
* @async
|
||||
*/
|
||||
this.getKeys = function(pattern, prepare_sync=false, search=false){
|
||||
return new Promise(function(resolve, reject) {
|
||||
let msg = createMessage('keylist');
|
||||
if (pattern !== undefined && pattern !== null){
|
||||
msg.setParameter('keys', pattern);
|
||||
}
|
||||
msg.setParameter('sigs', true);
|
||||
if (search === true){
|
||||
msg.setParameter('locate', true);
|
||||
}
|
||||
msg.post().then(function(result){
|
||||
let resultset = [];
|
||||
if (result.keys.length === 0){
|
||||
resolve([]);
|
||||
} else {
|
||||
let secondrequest;
|
||||
if (prepare_sync === true) {
|
||||
secondrequest = function() {
|
||||
let msg2 = createMessage('keylist');
|
||||
msg2.setParameter('keys', pattern);
|
||||
msg2.setParameter('secret', true);
|
||||
return msg2.post();
|
||||
};
|
||||
/**
|
||||
* Queries Keys (all Keys or a subset) from gnupg.
|
||||
*
|
||||
* @param {String | Array<String>} pattern (optional) A pattern to
|
||||
* search for in userIds or KeyIds.
|
||||
* @param {Boolean} prepare_sync (optional) if set to true, the
|
||||
* 'hasSecret' and 'armored' properties will be fetched for the Keys as
|
||||
* well. These require additional calls to gnupg, resulting in a
|
||||
* performance hungry operation. Calling them here enables direct,
|
||||
* synchronous use of these properties for all keys, without having to
|
||||
* resort to a refresh() first.
|
||||
* @param {Boolean} search (optional) retrieve Keys from external
|
||||
* servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup)
|
||||
* @returns {Promise.<Array<GPGME_Key>|GPGME_Error>}
|
||||
* @static
|
||||
* @async
|
||||
*/
|
||||
this.getKeys = function(pattern, prepare_sync=false, search=false){
|
||||
return new Promise(function(resolve, reject) {
|
||||
let msg = createMessage('keylist');
|
||||
if (pattern !== undefined && pattern !== null){
|
||||
msg.setParameter('keys', pattern);
|
||||
}
|
||||
msg.setParameter('sigs', true);
|
||||
if (search === true){
|
||||
msg.setParameter('locate', true);
|
||||
}
|
||||
msg.post().then(function(result){
|
||||
let resultset = [];
|
||||
if (result.keys.length === 0){
|
||||
resolve([]);
|
||||
} else {
|
||||
secondrequest = function() {
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
}
|
||||
secondrequest().then(function(answer) {
|
||||
for (let i=0; i < result.keys.length; i++){
|
||||
if (prepare_sync === true){
|
||||
result.keys[i].hasSecret = false;
|
||||
if (answer && answer.keys) {
|
||||
for (let j=0; j < answer.keys.length; j++ ){
|
||||
if (result.keys[i].fingerprint ===
|
||||
answer.keys[j].fingerprint
|
||||
) {
|
||||
if (answer.keys[j].secret === true){
|
||||
result.keys[i].hasSecret = true;
|
||||
let secondrequest;
|
||||
if (prepare_sync === true) {
|
||||
secondrequest = function() {
|
||||
let msg2 = createMessage('keylist');
|
||||
msg2.setParameter('keys', pattern);
|
||||
msg2.setParameter('secret', true);
|
||||
return msg2.post();
|
||||
};
|
||||
} else {
|
||||
secondrequest = function() {
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
}
|
||||
secondrequest().then(function(answer) {
|
||||
for (let i=0; i < result.keys.length; i++){
|
||||
if (prepare_sync === true){
|
||||
result.keys[i].hasSecret = false;
|
||||
if (answer && answer.keys) {
|
||||
for (let j=0;
|
||||
j < answer.keys.length; j++ ){
|
||||
const a = answer.keys[j];
|
||||
const b = result.keys[i];
|
||||
if (
|
||||
a.fingerprint === b.fingerprint
|
||||
) {
|
||||
if (a.secret === true){
|
||||
a.hasSecret = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// TODO getArmor() to be used in sync
|
||||
}
|
||||
// TODO getArmor() to be used in sync
|
||||
}
|
||||
let k = createKey(result.keys[i].fingerprint);
|
||||
k.setKeyData(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
|
||||
*/
|
||||
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() {
|
||||
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(response){
|
||||
if (response.value !== undefined
|
||||
&& response.value.hasOwnProperty('string')
|
||||
&& typeof(response.value.string) === 'string'
|
||||
){
|
||||
me.getKeys(response.value.string,true).then(
|
||||
function(keys){
|
||||
if(keys.length === 1){
|
||||
resolve(keys[0]);
|
||||
} else {
|
||||
reject(gpgme_error('KEY_NO_DEFAULT'));
|
||||
}
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
// TODO: this is overly 'expensive' in communication
|
||||
// and probably performance, too
|
||||
me.getKeys(null,true).then(function(keys){
|
||||
for (let i=0; i < keys.length; i++){
|
||||
if (keys[i].get('hasSecret') === true){
|
||||
resolve(keys[i]);
|
||||
break;
|
||||
}
|
||||
if (i === keys.length -1){
|
||||
reject(gpgme_error('KEY_NO_DEFAULT'));
|
||||
}
|
||||
}
|
||||
let k = createKey(result.keys[i].fingerprint);
|
||||
k.setKeyData(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
|
||||
*/
|
||||
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() {
|
||||
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(response){
|
||||
if (response.value !== undefined
|
||||
&& response.value.hasOwnProperty('string')
|
||||
&& typeof(response.value.string) === 'string'
|
||||
){
|
||||
me.getKeys(response.value.string,true).then(function(keys){
|
||||
if(keys.length === 1){
|
||||
resolve(keys[0]);
|
||||
} else {
|
||||
reject(gpgme_error('KEY_NO_DEFAULT'));
|
||||
}
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
// TODO: this is overly 'expensive' in communication
|
||||
// and probably performance, too
|
||||
me.getKeys(null,true).then(function(keys){
|
||||
for (let i=0; i < keys.length; i++){
|
||||
if (keys[i].get('hasSecret') === true){
|
||||
resolve(keys[i]);
|
||||
break;
|
||||
}
|
||||
if (i === 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 = [];
|
||||
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';
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
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
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
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++) {
|
||||
/**
|
||||
* @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 = [];
|
||||
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
|
||||
});
|
||||
}
|
||||
let summary = {};
|
||||
for (let i=0; i < feedbackValues.length; i++ ){
|
||||
summary[feedbackValues[i]] =
|
||||
response[feedbackValues[i]];
|
||||
}
|
||||
resolve({
|
||||
Keys:resultset,
|
||||
summary: summary
|
||||
});
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
for (let i=0; i < fprs.length; i++) {
|
||||
resultset.push({
|
||||
key: result[i],
|
||||
changes: infos[result[i].fingerprint].changes,
|
||||
status: infos[result[i].fingerprint].status
|
||||
key: createKey(fprs[i]),
|
||||
changes: infos[fprs[i]].changes,
|
||||
status: infos[fprs[i]].status
|
||||
});
|
||||
}
|
||||
let summary = {};
|
||||
for (let i=0; i < feedbackValues.length; i++ ){
|
||||
summary[feedbackValues[i]] =
|
||||
response[feedbackValues[i]];
|
||||
}
|
||||
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(resultset);
|
||||
}
|
||||
resolve(resultset);
|
||||
}
|
||||
|
||||
}, function(error){
|
||||
reject(error);
|
||||
}, 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));
|
||||
/**
|
||||
* 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'));
|
||||
}
|
||||
msg.post().then(function(response){
|
||||
me.getKeys(response.fingerprint, true).then(
|
||||
// TODO make prepare_sync (second parameter) optional here.
|
||||
function(result){
|
||||
resolve(result);
|
||||
}, function(error){
|
||||
reject(error);
|
||||
});
|
||||
}, function(error) {
|
||||
reject(error);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,162 +61,162 @@ export class GPGME_Message {
|
||||
return _msg.op;
|
||||
};
|
||||
|
||||
/**
|
||||
* The maximum size of responses from gpgme in bytes. As of July 2018,
|
||||
* 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 lower limit is set to 10 KB.
|
||||
* Messages smaller than the threshold will not encounter problems, larger
|
||||
* messages will be received in chunks.
|
||||
* If the value is not explicitly specified, 1023 KB is used.
|
||||
*/
|
||||
this.setChunksize = function (value){
|
||||
if (
|
||||
Number.isInteger(value) &&
|
||||
value > 10 * 1024 &&
|
||||
value <= 1024 * 1024
|
||||
){
|
||||
_msg.chunksize = value;
|
||||
}
|
||||
};
|
||||
|
||||
this.getMsg = function(){
|
||||
return _msg;
|
||||
};
|
||||
|
||||
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');
|
||||
/**
|
||||
* The maximum size of responses from gpgme in bytes. As of July 2018,
|
||||
* 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 lower limit is set to 10 KB. Messages smaller than the threshold
|
||||
* will not encounter problems, larger messages will be received in
|
||||
* chunks. If the value is not explicitly specified, 1023 KB is used.
|
||||
*/
|
||||
this.setChunksize = function (value){
|
||||
if (
|
||||
Number.isInteger(value) &&
|
||||
value > 10 * 1024 &&
|
||||
value <= 1024 * 1024
|
||||
){
|
||||
_msg.chunksize = value;
|
||||
}
|
||||
};
|
||||
let typechecked = checktype(value);
|
||||
if (typechecked !== true){
|
||||
return typechecked;
|
||||
}
|
||||
if (poparam.hasOwnProperty('allowed_data')){
|
||||
if (poparam.allowed_data.indexOf(value) < 0){
|
||||
|
||||
this.getMsg = function(){
|
||||
return _msg;
|
||||
};
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
_msg[param] = value;
|
||||
return true;
|
||||
};
|
||||
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){
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
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 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 = new Connection;
|
||||
conn.post(me).then(function(response) {
|
||||
resolve(response);
|
||||
}, function(reason) {
|
||||
reject(reason);
|
||||
});
|
||||
}
|
||||
else {
|
||||
reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
let conn = new Connection;
|
||||
conn.post(me).then(function(response) {
|
||||
resolve(response);
|
||||
}, function(reason) {
|
||||
reject(reason);
|
||||
});
|
||||
}
|
||||
else {
|
||||
reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prepared message with parameters and completeness checked
|
||||
@ -231,11 +231,10 @@ export class GPGME_Message {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
get operation(){
|
||||
return this.getOperation();
|
||||
}
|
||||
get chunksize(){
|
||||
return this.getChunksize();
|
||||
}
|
||||
get operation(){
|
||||
return this.getOperation();
|
||||
}
|
||||
get chunksize(){
|
||||
return this.getChunksize();
|
||||
}
|
||||
}
|
||||
|
@ -84,65 +84,65 @@ class GPGME_Signature {
|
||||
constructor(sigObject){
|
||||
let _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]];
|
||||
this.getFingerprint = function(){
|
||||
if (!_rawSigObject.fingerprint){
|
||||
return gpgme_error('SIG_WRONG');
|
||||
} else {
|
||||
return _rawSigObject.fingerprint;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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}
|
||||
|
@ -107,204 +107,207 @@ export class GpgME {
|
||||
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]]);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
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.mime ? true: false;
|
||||
if (result.file_name){
|
||||
_result.file_name = result.file_name;
|
||||
}
|
||||
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.expect= 'base64';
|
||||
msg.setParameter('armor', armor);
|
||||
msg.setParameter('always-trust', true);
|
||||
if (base64 === true) {
|
||||
msg.setParameter('base64', true);
|
||||
}
|
||||
msg.post().then( function(message) {
|
||||
if (mode === 'clearsign'){
|
||||
resolve({
|
||||
data: message.data}
|
||||
);
|
||||
} else if (mode === 'detached') {
|
||||
resolve({
|
||||
data: data,
|
||||
signature: message.data
|
||||
});
|
||||
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]]);
|
||||
}
|
||||
}, 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'));
|
||||
}
|
||||
if (msg.isComplete() === true){
|
||||
return msg.post();
|
||||
} else {
|
||||
msg.setParameter('signature', signature);
|
||||
return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
|
||||
}
|
||||
}
|
||||
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);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.mime ? true: false;
|
||||
if (result.file_name){
|
||||
_result.file_name = result.file_name;
|
||||
}
|
||||
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.expect= '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);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for {@link setKeyring}.
|
||||
* @param {GPGME_Keyring} keyring A Keyring to use
|
||||
*/
|
||||
@ -332,7 +335,7 @@ export class GpgME {
|
||||
* @private
|
||||
*/
|
||||
function putData(message, data){
|
||||
if (!message || !message instanceof GPGME_Message) {
|
||||
if (!message || !(message instanceof GPGME_Message)) {
|
||||
return gpgme_error('PARAM_WRONG');
|
||||
}
|
||||
if (!data){
|
||||
|
Loading…
Reference in New Issue
Block a user