js: change the write access for js class methods
authorMaximilian Krambach <maximilian.krambach@intevation.de>
Fri, 27 Jul 2018 18:36:21 +0000 (20:36 +0200)
committerMaximilian Krambach <maximilian.krambach@intevation.de>
Fri, 27 Jul 2018 18:36:21 +0000 (20:36 +0200)
--
* src/ [Connection, Error, Key, Keyring, MEssage, Signature, gpgmejs]:
    Functions and values that are not meant to be overwritten are now
    moved into their constructors, thus eliminating the possibility of
    overwrites after initialization.

* Key: The mode of use (synchronous cached, or async promises) ivs now
  determined at initialization of that Key. The property Key.isAsync
  reflects this state.

* unittests: fixed old Key syntax for testing.

* Message.js isComplete is now a method and not a getter anymore.

* Added some startup tests.

lang/js/BrowserTestExtension/tests/inputvalues.js
lang/js/BrowserTestExtension/tests/startup.js
lang/js/src/Connection.js
lang/js/src/Errors.js
lang/js/src/Key.js
lang/js/src/Keyring.js
lang/js/src/Message.js
lang/js/src/Signature.js
lang/js/src/gpgmejs.js
lang/js/unittest_inputvalues.js
lang/js/unittests.js

index 5289eab..9d956b6 100644 (file)
@@ -86,7 +86,9 @@ const inputvalues = {// eslint-disable-line no-unused-vars
         'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' +
         '=ioB6\n' +
         '-----END PGP SIGNATURE-----\n',
-    }
+    },
+
+    someInputParameter: 'bad string'
 };
 
 // (Pseudo-)Random String covering all of utf8.
@@ -158,27 +160,6 @@ function slightlyLessBoringString(megabytes, set){
     return string.join('');
 }
 
-// Take a gpg looking string and destroy it a bit by changing random values
-// eslint-disable-next-line no-unused-vars
-function destroylegitimateGpg(string, mutations=5){
-    const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/\n';
-    for (let i=0; i < mutations.length; i++){
-        // leave the first and last 35 chars (header/footer) intact
-        let position = Math.floor(Math.random() *(string.length - 70)) + 35;
-        let str0 = string.substring(0,position - 1);
-        let str1 = string.substring(position, position + 1);
-        let str2 = string.substring(position +1);
-        let success = false;
-        while (!success){
-            let newchar = Math.floor(Math.random() * allowed.length);
-            if (newchar !== str1){
-                string = str0 + newchar + str2;
-                success = true;
-            }
-        }
-    }
-}
-
 // Data encrypted with testKey
 const encryptedData =// eslint-disable-line no-unused-vars
     '-----BEGIN PGP MESSAGE-----\n' +
index dae9402..1e2784d 100644 (file)
  *     Maximilian Krambach <mkrambach@intevation.de>
  */
 
-/* global describe, it, expect, Gpgmejs */
+/* global describe, it, expect, Gpgmejs, inputvalues */
 
 describe('GPGME context', function(){
     it('Starting a GpgME instance', function(done){
         let prm = Gpgmejs.init();
+        const input = inputvalues.someInputParameter;
         prm.then(
             function(context){
                 expect(context).to.be.an('object');
                 expect(context.encrypt).to.be.a('function');
                 expect(context.decrypt).to.be.a('function');
+                expect(context.sign).to.be.a('function');
+                expect(context.verify).to.be.a('function');
+                context.Keyring = input;
+                expect(context.Keyring).to.be.an('object');
+                expect(context.Keyring).to.not.equal(input);
+                expect(context._Keyring).to.equal(context.Keyring);
+                expect(context.Keyring.getKeys).to.be.a('function');
+                expect(context.Keyring.getDefaultKey).to.be.a('function');
+                expect(context.Keyring.importKey).to.be.a('function');
+                expect(context.Keyring.generateKey).to.be.a('function');
                 done();
             });
     });
-});
+});
\ No newline at end of file
index d89fa72..d482667 100644 (file)
@@ -38,8 +38,19 @@ import { GPGME_Message, createMessage } from './Message';
 export class Connection{
 
     constructor(){
-        this.connect();
-    }
+        let _connection = chrome.runtime.connectNative('gpgmejson');
+
+
+        /**
+         * Immediately closes an open port.
+         */
+        this.disconnect = function () {
+            if (_connection){
+                _connection.disconnect();
+                _connection = null;
+            }
+        };
+
 
     /**
      * @typedef {Object} backEndDetails
@@ -63,14 +74,15 @@ export class Connection{
      * backend
      * @async
      */
-    checkConnection(details = true){
+    this.checkConnection = function(details = true){
+        const msg = createMessage('version');
         if (details === true) {
-            return this.post(createMessage('version'));
+            return this.post(msg);
         } else {
             let me = this;
             return new Promise(function(resolve) {
                 Promise.race([
-                    me.post(createMessage('version')),
+                    me.post(msg),
                     new Promise(function(resolve, reject){
                         setTimeout(function(){
                             reject(gpgme_error('CONN_TIMEOUT'));
@@ -83,26 +95,7 @@ export class Connection{
                 });
             });
         }
-    }
-
-    /**
-     * Immediately closes an open port.
-     */
-    disconnect() {
-        if (this._connection){
-            this._connection.disconnect();
-            this._connection = null;
-        }
-    }
-
-    /**
-     * Opens a nativeMessaging port.
-     */
-    connect(){
-        if (!this._connection){
-            this._connection = chrome.runtime.connectNative('gpgmejson');
-        }
-    }
+    };
 
     /**
      * Sends a {@link GPGME_Message} via tghe nativeMessaging port. It resolves
@@ -113,65 +106,65 @@ export class Connection{
      * @returns {Promise<Object>} The collected answer
      * @async
      */
-    post(message){
+    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){
+        if (message.isComplete() !== true){
             this.disconnect();
             return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
         }
-        let me = this;
         let chunksize = message.chunksize;
         return new Promise(function(resolve, reject){
             let answer = new Answer(message);
             let listener = function(msg) {
                 if (!msg){
-                    me._connection.onMessage.removeListener(listener);
-                    me._connection.disconnect();
+                    _connection.onMessage.removeListener(listener);
+                    _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();
+                        _connection.onMessage.removeListener(listener);
+                        _connection.disconnect();
                         reject(answer_result);
                     } else {
                         if (msg.more === true){
-                            me._connection.postMessage({
+                            _connection.postMessage({
                                 'op': 'getmore',
                                 'chunksize': chunksize
                             });
                         } else {
-                            me._connection.onMessage.removeListener(listener);
-                            me._connection.disconnect();
-                            if (answer.message instanceof Error){
-                                reject(answer.message);
+                            _connection.onMessage.removeListener(listener);
+                            _connection.disconnect();
+                            const message = answer.getMessage();
+                            if (message instanceof Error){
+                                reject(message);
                             } else {
-                                resolve(answer.message);
+                                resolve(message);
                             }
                         }
                     }
                 }
             };
-            me._connection.onMessage.addListener(listener);
+            _connection.onMessage.addListener(listener);
             if (permittedOperations[message.operation].pinentry){
-                return me._connection.postMessage(message.message);
+                return _connection.postMessage(message.message);
             } else {
                 return Promise.race([
-                    me._connection.postMessage(message.message),
+                    _connection.postMessage(message.message),
                     function(resolve, reject){
                         setTimeout(function(){
-                            me._connection.disconnect();
+                            _connection.disconnect();
                             reject(gpgme_error('CONN_TIMEOUT'));
                         }, 5000);
                     }]).then(function(result){
                     return result;
                 }, function(reject){
                     if(!(reject instanceof Error)) {
-                        me._connection.disconnect();
+                        _connection.disconnect();
                         return gpgme_error('GNUPG_ERROR', reject);
                     } else {
                         return reject;
@@ -179,7 +172,8 @@ export class Connection{
                 });
             }
         });
-    }
+    };
+}
 }
 
 /**
@@ -193,10 +187,16 @@ class Answer{
      * @param {GPGME_Message} message
      */
     constructor(message){
-        this.operation = message.operation;
-        this.expect = message.expect;
-    }
+        const operation = message.operation;
+        const expect = message.expect;
+        let response_b64 = null;
 
+        this.getOperation = function(){
+            return operation;
+        };
+        this.getExpect = function(){
+            return expect;
+        };
     /**
      * Adds incoming base64 encoded data to the existing response
      * @param {*} msg base64 encoded data.
@@ -204,34 +204,30 @@ class Answer{
      *
      * @private
      */
-    collect(msg){
+    this.collect = function (msg){
         if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
             return gpgme_error('CONN_UNEXPECTED_ANSWER');
         }
-        if (this._responseb64 === undefined){
-            //this._responseb64 = [msg.response];
-            this._responseb64 = msg.response;
+        if (response_b64 === null){
+            response_b64 = msg.response;
             return true;
         } else {
-            //this._responseb64.push(msg.response);
-            this._responseb64 += msg.response;
+            response_b64 += msg.response;
             return true;
         }
-    }
-
-    /**
+    };
+     /**
      * Returns the base64 encoded answer data with the content verified against
      * {@link permittedOperations}.
      */
-    get message(){
-        if (this._responseb64 === undefined){
+    this.getMessage = function (){
+        if (response_b64 === undefined){
             return gpgme_error('CONN_UNEXPECTED_ANSWER');
         }
-        // let _decodedResponse = JSON.parse(atob(this._responseb64.join('')));
-        let _decodedResponse = JSON.parse(atob(this._responseb64));
+        let _decodedResponse = JSON.parse(atob(response_b64));
         let _response = {};
         let messageKeys = Object.keys(_decodedResponse);
-        let poa = permittedOperations[this.operation].answer;
+        let poa = permittedOperations[this.getOperation()].answer;
         if (messageKeys.length === 0){
             return gpgme_error('CONN_UNEXPECTED_ANSWER');
         }
@@ -262,7 +258,7 @@ class Answer{
                 }
                 if (_decodedResponse.base64 === true
                     && poa.data[key] === 'string'
-                    && this.expect === undefined
+                    && this.getExpect() === undefined
                 ){
                     _response[key] = decodeURIComponent(
                         atob(_decodedResponse[key]).split('').map(
@@ -277,5 +273,6 @@ class Answer{
             }
         }
         return _response;
-    }
+    };
+}
 }
index cb5c94c..0cf1af1 100644 (file)
@@ -143,7 +143,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
  * @extends Error
  */
 class GPGME_Error extends Error{
-    constructor(code, msg=''){
+    constructor(code = 'GENERIC_ERROR', msg=''){
         if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){
             super(msg);
         } else if (err_list.hasOwnProperty(code)){
@@ -155,12 +155,12 @@ class GPGME_Error extends Error{
         } else {
             super(err_list['GENERIC_ERROR'].msg);
         }
-        this.code = code || 'GENERIC_ERROR';
-    }
-    set code(value){
-        this._code = value;
+        this.getCode = function(){
+            return code;
+        };
     }
+
     get code(){
-        return this._code;
+        return this.getCode();
     }
 }
\ No newline at end of file
index b024a77..a7f7dd2 100644 (file)
@@ -28,13 +28,16 @@ import { createMessage } from './Message';
 /**
  * Validates the given fingerprint and creates a new {@link GPGME_Key}
  * @param {String} fingerprint
+ * @param {Boolean} async If True, Key properties (except fingerprint) will be
+ * queried from gnupg on each call, making the operation up-to-date, the
+ * answers will be Promises, and the performance will likely suffer
  * @returns {GPGME_Key|GPGME_Error}
  */
-export function createKey(fingerprint){
-    if (!isFingerprint(fingerprint)){
+export function createKey(fingerprint, async = false){
+    if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){
         return gpgme_error('PARAM_WRONG');
     }
-    else return new GPGME_Key(fingerprint);
+    else return new GPGME_Key(fingerprint, async);
 }
 
 /**
@@ -48,31 +51,30 @@ export function createKey(fingerprint){
  */
 export class GPGME_Key {
 
-    constructor(fingerprint){
-        this.fingerprint = fingerprint;
-    }
+    constructor(fingerprint, async){
 
-    set fingerprint(fpr){
-        if (isFingerprint(fpr) === true) {
-            if (this._data === undefined) {
-                this._data = {fingerprint:  fpr};
-            } else {
-                if (this._data.fingerprint === undefined){
-                    this._data.fingerprint = fpr;
-                }
+        /**
+         * @property {Boolean} If true, most answers will be asynchronous
+         */
+        this.isAsync = async;
+
+        let _data = {fingerprint: fingerprint};
+        this.getFingerprint = function(){
+            if (!_data.fingerprint || !isFingerprint(_data.fingerprint)){
+                return gpgme_error('KEY_INVALID');
             }
-        }
-    }
+            return _data.fingerprint;
+        };
 
     /**
-     * @returns {String} The fingerprint defining this Key
+     * 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.
      */
-    get fingerprint(){
-        if (!this._data || !this._data.fingerprint){
-            return gpgme_error('KEY_INVALID');
-        }
-        return this._data.fingerprint;
-    }
+    this.hasSecret= function (){
+        return this.get('hasSecret', true);
+    };
 
     /**
      * @param {Object} data Bulk set the data for this key, with an Object sent
@@ -81,97 +83,89 @@ export class GPGME_Key {
      * error if something went wrong
      * @private
      */
-    setKeyData(data){
-        if (this._data === undefined) {
-            this._data = {};
+    this.setKeyData = function (data){
+        if (typeof(data) !== 'object') {
+            return gpgme_error('KEY_INVALID');
         }
-        if (
-            typeof(data) !== 'object') {
+        if (!data.fingerprint || data.fingerprint !== _data.fingerprint){
             return gpgme_error('KEY_INVALID');
         }
-        if (!this._data.fingerprint && isFingerprint(data.fingerprint)){
-            if (data.fingerprint !== this.fingerprint){
-                return gpgme_error('KEY_INVALID');
-            }
-            this._data.fingerprint = data.fingerprint;
-        } else if (this._data.fingerprint !== data.fingerprint){
+        let keys = Object.keys(data);
+        for (let i=0; i< keys.length; i++){
+            if (!validKeyProperties.hasOwnProperty(keys[i])){
             return gpgme_error('KEY_INVALID');
         }
-        let dataKeys = Object.keys(data);
-        for (let i=0; i< dataKeys.length; i++){
-            if (!validKeyProperties.hasOwnProperty(dataKeys[i])){
-                return gpgme_error('KEY_INVALID');
-            }
-            if (validKeyProperties[dataKeys[i]](data[dataKeys[i]]) !== true ){
-                return gpgme_error('KEY_INVALID');
-            }
-            switch (dataKeys[i]){
+        //running the defined validation function
+        if (validKeyProperties[keys[i]](data[keys[i]]) !== true ){
+            return gpgme_error('KEY_INVALID');
+        }
+        switch (keys[i]){
             case 'subkeys':
-                this._data.subkeys = [];
+                _data.subkeys = [];
                 for (let i=0; i< data.subkeys.length; i++) {
-                    this._data.subkeys.push(
+                    _data.subkeys.push(
                         new GPGME_Subkey(data.subkeys[i]));
                 }
                 break;
             case 'userids':
-                this._data.userids = [];
+                _data.userids = [];
                 for (let i=0; i< data.userids.length; i++) {
-                    this._data.userids.push(
+                    _data.userids.push(
                         new GPGME_UserId(data.userids[i]));
                 }
                 break;
             case 'last_update':
-                this._data[dataKeys[i]] = new Date( data[dataKeys[i]] * 1000 );
+                _data[keys[i]] = new Date( data[keys[i]] * 1000 );
                 break;
             default:
-                this._data[dataKeys[i]] = data[dataKeys[i]];
+                    _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
-     * @param {Boolean} cached (optional) if false, the data will be directly
-     * queried from gnupg, and the operation will be asynchronous. Else, the
-     * data will be fetched from the state of the initialization of the Key.
-     * The cached mode may contain outdated information, but can be used as
-     * synchronous operation, where the backend is not expected to change Keys
-     * during a session. The key still can be reloaded by invoking
-     * {@link refreshKey}.
      * @returns {*|Promise<*>} the value (Boolean, String, Array, Object).
      * If 'cached' is false, the value will be resolved as a Promise.
      */
-    get(property, cached=true) {
-        if (cached === false) {
+    this.get = function(property) {
+        if (this.isAsync === true) {
             let me = this;
             return new Promise(function(resolve, reject) {
-                if (!validKeyProperties.hasOwnProperty(property)){
-                    reject('PARAM_WRONG');
-                } else if (property === 'armored'){
+                if (property === 'armored'){
                     resolve(me.getArmor());
                 } else if (property === 'hasSecret'){
                     resolve(me.getHasSecret());
-                } else {
-                    me.refreshKey().then(function(key){
-                        resolve(key.get(property, true));
+                } 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(error);
+                        reject(gpgme_error(error));
                     });
+                } else {
+                    reject(gpgme_error('PARAM_WRONG'));
                 }
             });
         } else {
             if (!validKeyProperties.hasOwnProperty(property)){
                 return gpgme_error('PARAM_WRONG');
             }
-            if (!this._data.hasOwnProperty(property)){
+            if (!_data.hasOwnProperty(property)){
                 return gpgme_error('KEY_NO_INIT');
             } else {
-                return (this._data[property]);
+                    return (_data[property]);
             }
         }
-    }
+    };
 
     /**
      * Reloads the Key information from gnupg. This is only useful if you use
@@ -181,15 +175,15 @@ export class GPGME_Key {
      * @returns {Promise<GPGME_Key|GPGME_Error>}
      * @async
      */
-    refreshKey() {
+    this.refreshKey = function() {
         let me = this;
         return new Promise(function(resolve, reject) {
-            if (!me._data.fingerprint){
+            if (!_data.fingerprint){
                 reject(gpgme_error('KEY_INVALID'));
             }
             let msg = createMessage('keylist');
             msg.setParameter('sigs', true);
-            msg.setParameter('keys', me._data.fingerprint);
+            msg.setParameter('keys', _data.fingerprint);
             msg.post().then(function(result){
                 if (result.keys.length === 1){
                     me.setKeyData(result.keys[0]);
@@ -209,7 +203,7 @@ export class GPGME_Key {
                 reject(gpgme_error('GNUPG_ERROR'), error);
             });
         });
-    }
+    };
 
     /**
      * Query the armored block of the Key directly from gnupg. Please note that
@@ -217,23 +211,22 @@ export class GPGME_Key {
      * @returns {Promise<String|GPGME_Error>}
      * @async
      */
-    getArmor(){
-        let me = this;
+    this.getArmor = function(){
         return new Promise(function(resolve, reject) {
-            if (!me._data.fingerprint){
+            if (!_data.fingerprint){
                 reject(gpgme_error('KEY_INVALID'));
             }
             let msg = createMessage('export');
             msg.setParameter('armor', true);
-            msg.setParameter('keys', me._data.fingerprint);
+            msg.setParameter('keys', _data.fingerprint);
             msg.post().then(function(result){
-                me._data.armored = result.data;
+                _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
@@ -244,59 +237,32 @@ export class GPGME_Key {
      * available in the gnupg Keyring
      * @async
      */
-    getHasSecret(){
-        let me = this;
+    this.getHasSecret = function (){
         return new Promise(function(resolve, reject) {
-            if (!me._data.fingerprint){
+            if (!_data.fingerprint){
                 reject(gpgme_error('KEY_INVALID'));
             }
             let msg = createMessage('keylist');
-            msg.setParameter('keys', me._data.fingerprint);
+            msg.setParameter('keys', _data.fingerprint);
             msg.setParameter('secret', true);
             msg.post().then(function(result){
-                me._data.hasSecret = null;
+                _data.hasSecret = null;
                 if (
                     result.keys &&
                     result.keys.length === 1 &&
                     result.keys[0].secret === true
                 ) {
-                    me._data.hasSecret = true;
+                    _data.hasSecret = true;
                     resolve(true);
                 } else {
-                    me._data.hasSecret = false;
+                    _data.hasSecret = false;
                     resolve(false);
                 }
             }, function(error){
                 reject(error);
             });
         });
-    }
-
-    /**
-     * Convenience functions to be directly used as properties of the Key
-     * Notice that these rely on cached info and may be outdated. Use the async
-     * get(property, false) if you need the most current info
-     */
-
-    /**
-     * Property for the export of armored Key. If the armored Key is not
-     * cached, it returns an {@link GPGME_Error} with code 'KEY_NO_INIT'.
-     * Running {@link refreshKey} may help in this case.
-     * @returns {String|GPGME_Error} The armored public Key block.
-     */
-    get armored(){
-        return this.get('armored', 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.
-     */
-    get hasSecret(){
-        return this.get('hasSecret', true);
-    }
+    };
 
     /**
      * Deletes the (public) Key from the GPG Keyring. Note that a deletion of a
@@ -304,20 +270,37 @@ export class GPGME_Key {
      * @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
      * rejects with a GPG error otherwise.
      */
-    delete(){
-        let me = this;
+    this.delete= function (){
         return new Promise(function(resolve, reject){
-            if (!me._data.fingerprint){
+            if (!_data.fingerprint){
                 reject(gpgme_error('KEY_INVALID'));
             }
             let msg = createMessage('delete');
-            msg.setParameter('key', me._data.fingerprint);
+            msg.setParameter('key', _data.fingerprint);
             msg.post().then(function(result){
                 resolve(result.success);
             }, function(error){
                 reject(error);
             });
         });
+    };
+    }
+
+    /**
+     * @returns {String} The fingerprint defining this Key
+     */
+    get fingerprint(){
+        return this.getFingerprint();
+    }
+
+    /**
+     * Property for the export of armored Key. If the armored Key is not
+     * cached, it returns an {@link GPGME_Error} with code 'KEY_NO_INIT'.
+     * Running {@link refreshKey} may help in this case.
+     * @returns {String|GPGME_Error} The armored public Key block.
+     */
+    get armored(){
+        return this.get('armored', true);
     }
 }
 
@@ -334,44 +317,45 @@ class GPGME_Subkey {
      * @private
      */
     constructor(data){
+        let _data = {};
         let keys = Object.keys(data);
-        for (let i=0; i< keys.length; i++) {
-            this.setProperty(keys[i], data[keys[i]]);
-        }
-    }
 
-    /**
+            /**
      * Validates a subkey property against {@link validSubKeyProperties} and
      * sets it if validation is successful
      * @param {String} property
      * @param {*} value
      * @param private
      */
-    setProperty(property, value){
-        if (!this._data){
-            this._data = {};
-        }
+    const setProperty = function (property, value){
         if (validSubKeyProperties.hasOwnProperty(property)){
             if (validSubKeyProperties[property](value) === true) {
                 if (property === 'timestamp' || property === 'expires'){
-                    this._data[property] = new Date(value * 1000);
+                    _data[property] = new Date(value * 1000);
                 } else {
-                    this._data[property] = value;
+                    _data[property] = value;
                 }
             }
         }
+    };
+    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}
      */
-    get(property) {
-        if (this._data.hasOwnProperty(property)){
-            return (this._data[property]);
+    this.get = function(property) {
+        if (_data.hasOwnProperty(property)){
+            return (_data[property]);
         }
-    }
+    };
+}
+
 }
 
 /**
@@ -387,11 +371,23 @@ class GPGME_UserId {
      * @private
      */
     constructor(data){
+        let _data = {};
         let keys = Object.keys(data);
+        const setProperty = function(property, value){
+            if (validUserIdProperties.hasOwnProperty(property)){
+                if (validUserIdProperties[property](value) === true) {
+                    if (property === 'last_update'){
+                        _data[property] = new Date(value*1000);
+                    } else {
+                        _data[property] = value;
+                    }
+                }
+            }
+        };
         for (let i=0; i< keys.length; i++) {
-            this.setProperty(keys[i], data[keys[i]]);
+            setProperty(keys[i], data[keys[i]]);
         }
-    }
+
     /**
      * Validates a subkey property against {@link validUserIdProperties} and
      * sets it if validation is successful
@@ -399,34 +395,21 @@ class GPGME_UserId {
      * @param {*} value
      * @param private
      */
-    setProperty(property, value){
-        if (!this._data){
-            this._data = {};
-        }
-        if (validUserIdProperties.hasOwnProperty(property)){
-            if (validUserIdProperties[property](value) === true) {
-                if (property === 'last_update'){
-                    this._data[property] = new Date(value*1000);
-                } else {
-                    this._data[property] = value;
-                }
-            }
-        }
 
-    }
 
     /**
      * 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]);
+    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
index f2a7138..d863fe7 100644 (file)
@@ -32,7 +32,6 @@ import { gpgme_error } from './Errors';
  */
 export class GPGME_Keyring {
     constructor(){
-    }
 
     /**
      * Queries Keys (all Keys or a subset) from gnupg.
@@ -50,7 +49,7 @@ export class GPGME_Keyring {
      * @static
      * @async
      */
-    getKeys(pattern, prepare_sync=false, search=false){
+    this.getKeys = function(pattern, prepare_sync=false, search=false){
         return new Promise(function(resolve, reject) {
             let msg = createMessage('keylist');
             if (pattern !== undefined && pattern !== null){
@@ -107,7 +106,7 @@ export class GPGME_Keyring {
                 }
             });
         });
-    }
+    };
 
     /**
      * @typedef {Object} exportResult The result of a getKeysArmored operation.
@@ -131,7 +130,7 @@ export class GPGME_Keyring {
      * @static
      * @async
      */
-    getKeysArmored(pattern, with_secret_fpr) {
+    this.getKeysArmored = function(pattern, with_secret_fpr) {
         return new Promise(function(resolve, reject) {
             let msg = createMessage('export');
             msg.setParameter('armor', true);
@@ -153,7 +152,7 @@ export class GPGME_Keyring {
                 reject(error);
             });
         });
-    }
+    };
 
     /**
      * Returns the Key used by default in gnupg.
@@ -165,7 +164,7 @@ export class GPGME_Keyring {
      * @async
      * @static
      */
-    getDefaultKey() {
+    this.getDefaultKey = function() {
         let me = this;
         return new Promise(function(resolve, reject){
             let msg = createMessage('config_opt');
@@ -206,7 +205,7 @@ export class GPGME_Keyring {
                 reject(error);
             });
         });
-    }
+    };
 
     /**
      * @typedef {Object} importResult The result of a Key update
@@ -244,7 +243,7 @@ export class GPGME_Keyring {
      * @async
      * @static
      */
-    importKey(armored, prepare_sync) {
+    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',
@@ -323,7 +322,7 @@ export class GPGME_Keyring {
         });
 
 
-    }
+    };
 
     /**
      * Convenience function for deleting a Key. See {@link Key.delete} for
@@ -333,14 +332,14 @@ export class GPGME_Keyring {
      * @async
      * @static
      */
-    deleteKey(fingerprint){
+    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
@@ -356,7 +355,7 @@ export class GPGME_Keyring {
      * @return {Promise<Key|GPGME_Error>}
      * @async
      */
-    generateKey(userId, algo = 'default', expires){
+    this.generateKey = function (userId, algo = 'default', expires){
         if (
             typeof(userId) !== 'string' ||
             supportedKeyAlgos.indexOf(algo) < 0 ||
@@ -385,7 +384,8 @@ export class GPGME_Keyring {
                 reject(error);
             });
         });
-    }
+    };
+}
 }
 
 /**
index 2e38142..cf9f84e 100644 (file)
@@ -52,22 +52,14 @@ export function createMessage(operation){
 export class GPGME_Message {
 
     constructor(operation){
-        this.operation = operation;
-    }
+        let _msg = {
+            op: operation,
+            chunksize: 1023* 1024
+        };
 
-    set operation (op){
-        if (typeof(op) === 'string'){
-            if (!this._msg){
-                this._msg = {};
-            }
-            if (!this._msg.op & permittedOperations.hasOwnProperty(op)){
-                this._msg.op = op;
-            }
-        }
-    }
-    get operation(){
-        return this._msg.op;
-    }
+        this.getOperation = function(){
+            return _msg.op;
+        };
 
     /**
      * The maximum size of responses from gpgme in bytes. As of July 2018,
@@ -78,41 +70,23 @@ export class GPGME_Message {
      * messages will be received in chunks.
      * If the value is not explicitly specified, 1023 KB is used.
      */
-    set chunksize(value){
+    this.setChunksize = function (value){
         if (
             Number.isInteger(value) &&
             value > 10 * 1024 &&
             value <= 1024 * 1024
         ){
-            this._chunksize = value;
-        }
-    }
-    get chunksize(){
-        if (this._chunksize === undefined){
-            return 1024 * 1023;
-        } else {
-            return this._chunksize;
+            _msg.chunksize = value;
         }
-    }
+    };
 
-    /**
-     * Expect indicates which format data is expected to be in. It currently
-     * only supports 'base64', indicating that the response data from gnupg are
-     * expected to be base64 encoded binary
-     */
-    set expect(value){
-        if (value ==='base64'){
-            this._expect = value;
-        }
-    }
-
-    get expect(){
-        if ( this._expect === 'base64'){
-            return this._expect;
-        }
-        return undefined;
-    }
+    this.getMsg = function(){
+        return _msg;
+    };
 
+    this.getChunksize= function() {
+        return _msg.chunksize;
+    };
 
     /**
      * Sets a parameter for the message. It validates with
@@ -121,11 +95,11 @@ export class GPGME_Message {
      * @param {any} value Value to set
      * @returns {Boolean} If the parameter was set successfully
      */
-    setParameter( param,value ){
+    this.setParameter = function ( param,value ){
         if (!param || typeof(param) !== 'string'){
             return gpgme_error('PARAM_WRONG');
         }
-        let po = permittedOperations[this._msg.op];
+        let po = permittedOperations[_msg.op];
         if (!po){
             return gpgme_error('MSG_WRONG_OP');
         }
@@ -195,59 +169,42 @@ export class GPGME_Message {
                 return gpgme_error('PARAM_WRONG');
             }
         }
-        this._msg[param] = value;
+        _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.
      */
-    get isComplete(){
-        if (!this._msg.op){
+    this.isComplete = function(){
+        if (!_msg.op){
             return false;
         }
         let reqParams = Object.keys(
-            permittedOperations[this._msg.op].required);
-        let msg_params = Object.keys(this._msg);
+            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;
-    }
-
-    /**
-     * Returns the prepared message with parameters and completeness checked
-     * @returns {Object|null} Object to be posted to gnupg, or null if
-     * incomplete
-     */
-    get message(){
-        if (this.isComplete === true){
-            this._msg.chunksize = this.chunksize;
-            return this._msg;
-        }
-        else {
-            return null;
-        }
-
-    }
-
+    };
     /**
      * Sends the Message via nativeMessaging and resolves with the answer.
      * @returns {Promise<Object|GPGME_Error>}
      * @async
      */
-    post(){
+    this.post = function(){
         let me = this;
         return new Promise(function(resolve, reject) {
-            if (me.isComplete === true) {
+            if (me.isComplete() === true) {
+
                 let conn  = new Connection;
-                if (me._msg.chunksize === undefined){
-                    me._msg.chunksize = me.chunksize;
-                }
                 conn.post(me).then(function(response) {
                     resolve(response);
                 }, function(reason) {
@@ -258,5 +215,27 @@ export class GPGME_Message {
                 reject(gpgme_error('MSG_INCOMPLETE'));
             }
         });
+    };
+}
+
+    /**
+     * Returns the prepared message with parameters and completeness checked
+     * @returns {Object|null} Object to be posted to gnupg, or null if
+     * incomplete
+     */
+    get message(){
+        if (this.isComplete() === true){
+            return this.getMsg();
+        }
+        else {
+            return null;
+        }
     }
+
+get operation(){
+    return this.getOperation();
+}
+get chunksize(){
+    return this.getChunksize();
+}
 }
index 191e00a..ff4278a 100644 (file)
@@ -82,44 +82,47 @@ export function createSignature(sigObject){
 class GPGME_Signature {
 
     constructor(sigObject){
-        this._rawSigObject = sigObject;
-    }
+        let _rawSigObject = sigObject;
 
-    get fingerprint(){
-        return this._rawSigObject.fingerprint;
-    }
+    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}
      */
-    get expiration(){
-        if (!this._rawSigObject.exp_timestamp){
+    this.getExpiration = function(){
+        if (!_rawSigObject.exp_timestamp){
             return null;
         }
-        return new Date(this._rawSigObject.exp_timestamp* 1000);
-    }
+        return new Date(_rawSigObject.exp_timestamp* 1000);
+    };
 
     /**
      * The creation date of this Signature in Javascript Date
      * @returns {Date}
      */
-    get timestamp(){
-        return new Date(this._rawSigObject.timestamp * 1000);
-    }
+    this.getTimestamp= function (){
+        return new Date(_rawSigObject.timestamp * 1000);
+    };
 
     /**
      * The overall validity of the key. If false, errorDetails may contain
      * additional information
      */
-    get valid() {
-        if (this._rawSigObject.summary.valid === true){
+    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
@@ -127,19 +130,54 @@ class GPGME_Signature {
      * details on the values
      * @returns {Object} Object with boolean properties
      */
-    get errorDetails(){
+    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 ( this._rawSigObject.hasOwnProperty(properties[i]) ){
-                result[properties[i]] = this._rawSigObject[properties[i]];
+            if ( _rawSigObject.hasOwnProperty(properties[i]) ){
+                result[properties[i]] = _rawSigObject[properties[i]];
             }
         }
         return result;
+    };
+}
+
+    /**
+     * Convenience getter for {@link getFingerprint}
+     */
+    get fingerprint(){
+        return this.getFingerprint();
     }
 
+    /**
+     * Convenience getter for {@link getExpiration}
+     */
+    get expiration(){
+        return this.getExpiration();
+    }
+
+    /**
+     * Convenience getter for {@link getTimeStamp}
+     */
+    get timestamp(){
+        return this.getTimestamp();
+    }
+
+    /**
+     * Convenience getter for {@link getValid}
+     */
+    get valid(){
+        return this.getValid();
+    }
+
+    /**
+     * Convenience getter for {@link getErrorDetails}
+     */
+    get errorDetails(){
+        return this.getErrorDetails();
+    }
 }
 
 /**
index 3f6dc94..f587e85 100644 (file)
@@ -22,8 +22,8 @@
  */
 
 
-import {GPGME_Message, createMessage} from './Message';
-import {toKeyIdArray} from './Helpers';
+import { GPGME_Message, createMessage } from './Message';
+import { toKeyIdArray } from './Helpers';
 import { gpgme_error } from './Errors';
 import { GPGME_Keyring } from './Keyring';
 import { createSignature } from './Signature';
@@ -85,23 +85,27 @@ import { createSignature } from './Signature';
 export class GpgME {
 
     constructor(){
-    }
+        let _Keyring = null;
 
-    set Keyring(keyring){
-        if (keyring && keyring instanceof GPGME_Keyring){
-            this._Keyring = keyring;
-        }
-    }
+        /**
+         * 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}.
-     */
-    get Keyring(){
-        if (!this._Keyring){
-            this._Keyring = new GPGME_Keyring;
-        }
-        return this._Keyring;
-    }
+        /**
+         * Accesses the {@link GPGME_Keyring}.
+         */
+        this.getKeyring = function(){
+            if (!_Keyring){
+                _Keyring = new GPGME_Keyring;
+            }
+            return _Keyring;
+        };
 
     /**
      * Encrypt (and optionally sign) data
@@ -123,8 +127,8 @@ export class GpgME {
      * message and additional info.
      * @async
      */
-    encrypt(data, publicKeys, secretKeys, base64=false, armor=true,
-        wildcard=false, additional = {}
+    this.encrypt = function (data, publicKeys, secretKeys, base64=false,
+        armor=true, wildcard=false, additional = {}
     ){
         let msg = createMessage('encrypt');
         if (msg instanceof Error){
@@ -152,12 +156,12 @@ export class GpgME {
                     additional[additional_Keys[k]]);
             }
         }
-        if (msg.isComplete === true){
+        if (msg.isComplete() === true){
             return msg.post();
         } else {
             return Promise.reject(gpgme_error('MSG_INCOMPLETE'));
         }
-    }
+    };
 
     /**
     * Decrypts a Message
@@ -168,7 +172,7 @@ export class GpgME {
     * @returns {Promise<decrypt_result>} Decrypted Message and information
     * @async
     */
-    decrypt(data, base64=false){
+    this.decrypt = function (data, base64=false){
         if (data === undefined){
             return Promise.reject(gpgme_error('MSG_EMPTY'));
         }
@@ -203,7 +207,7 @@ export class GpgME {
                 reject(error);
             });
         });
-    }
+    };
 
     /**
      * Sign a Message
@@ -217,7 +221,7 @@ export class GpgME {
      * @returns {Promise<signResult>}
      * @async
      */
-    sign(data, keys, mode='clearsign', base64=false) {
+    this.sign = function (data, keys, mode='clearsign', base64=false) {
         if (data === undefined){
             return Promise.reject(gpgme_error('MSG_EMPTY'));
         }
@@ -252,7 +256,7 @@ export class GpgME {
                 reject(error);
             });
         });
-    }
+    };
 
     /**
      * Verifies data.
@@ -264,7 +268,7 @@ export class GpgME {
      * @returns {Promise<verifyResult>}
      *@async
      */
-    verify(data, signature, base64 = false){
+    this.verify= function (data, signature, base64 = false){
         let msg = createMessage('verify');
         let dt = putData(msg, data);
         if (dt instanceof Error){
@@ -297,6 +301,25 @@ export class GpgME {
                 reject(error);
             });
         });
+    };
+}
+
+        /**
+     * setter for {@link setKeyring}.
+     * @param {GPGME_Keyring} keyring A Keyring to use
+     */
+    set Keyring(keyring){
+        this.setKeyring(keyring);
+    }
+
+    /**
+     * Accesses the {@link GPGME_Keyring}.
+     */
+    get Keyring(){
+        if (!this._Keyring){
+            this._Keyring = new GPGME_Keyring;
+        }
+        return this._Keyring;
     }
 }
 
@@ -309,7 +332,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){
index 07147ba..02bb532 100644 (file)
@@ -1,12 +1,9 @@
-import {Connection} from './src/Connection';
 import {createKey} from './src/Key';
 
-let conn = new Connection;
-
 export const helper_params = {
     validLongId: '0A0A0A0A0A0A0A0A',
     validKeys: ['A1E3BC45BDC8E87B74F4392D53B151A1368E50F3',
-        createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn),
+        createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'),
         'EE17AEE730F88F1DE7713C54BBE0A4FF7851650A'],
     validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
     validFingerprints: ['9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A',
@@ -15,11 +12,11 @@ export const helper_params = {
     invalidFingerprints: [{hello:'World'}, ['kekekeke'], new Uint32Array(40)],
     invalidKeyArray: {curiosity:'uncat'},
     invalidKeyArray_OneBad: [
-        createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn),
+        createKey('D41735B91236FDB882048C5A2301635EEFF0CB05'),
         'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A',
         '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'],
     invalidErrorCode: 'Please type in all your passwords.',
-    validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', conn),
+    validGPGME_Key: createKey('D41735B91236FDB882048C5A2301635EEFF0CB05', true),
     valid_openpgplike: { primaryKey: {
         getFingerprint: function(){
             return '85DE2A8BA5A5AB3A8A7BE2000B8AED24D7534BC2';}
@@ -36,7 +33,7 @@ export const message_params = {
         invalid_param_names: [22,'dance', {}],
         validparam_name_0: 'mime',
         invalid_values_0: [2134, 'All your passwords',
-            createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08', conn), null]
+            createKey('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), null]
     }
 };
 
index 04e15ef..6228993 100644 (file)
@@ -194,16 +194,16 @@ function unittests (){
         });
 
         it('Non-cached key async data retrieval', function (done){
-            let key = createKey(kp.validKeyFingerprint);
-            key.get('can_authenticate',false).then(function(result){
+            let key = createKey(kp.validKeyFingerprint, true);
+            key.get('can_authenticate').then(function(result){
                 expect(result).to.be.a('boolean');
                 done();
             });
         });
 
         it('Non-cached key async armored Key', function (done){
-            let key = createKey(kp.validKeyFingerprint);
-            key.get('armored', false).then(function(result){
+            let key = createKey(kp.validKeyFingerprint, true);
+            key.get('armored').then(function(result){
                 expect(result).to.be.a('string');
                 expect(result).to.include('KEY BLOCK-----');
                 done();
@@ -211,17 +211,17 @@ function unittests (){
         });
 
         it('Non-cached key async hasSecret', function (done){
-            let key = createKey(kp.validKeyFingerprint);
-            key.get('hasSecret', false).then(function(result){
+            let key = createKey(kp.validKeyFingerprint, true);
+            key.get('hasSecret').then(function(result){
                 expect(result).to.be.a('boolean');
                 done();
             });
         });
 
         it('Non-cached key async hasSecret (no secret in Key)', function (done){
-            let key = createKey(kp.validFingerprintNoSecret);
+            let key = createKey(kp.validFingerprintNoSecret, true);
             expect(key).to.be.an.instanceof(GPGME_Key);
-            key.get('hasSecret', false).then(function(result){
+            key.get('hasSecret').then(function(result){
                 expect(result).to.be.a('boolean');
                 expect(result).to.equal(false);
                 done();
@@ -317,7 +317,7 @@ function unittests (){
             let test0 = createMessage('encrypt');
 
             expect(test0).to.be.an.instanceof(GPGME_Message);
-            expect(test0.isComplete).to.be.false;
+            expect(test0.isComplete()).to.be.false;
         });
 
         it('Message is complete after setting mandatory data', function(){
@@ -325,14 +325,14 @@ function unittests (){
             test0.setParameter('data', mp.valid_encrypt_data);
             test0.setParameter('keys', hp.validFingerprints);
 
-            expect(test0.isComplete).to.be.true;
+            expect(test0.isComplete()).to.be.true;
         });
 
         it('Message is not complete after mandatory data is empty', function(){
             let test0 = createMessage('encrypt');
             test0.setParameter('data', '');
             test0.setParameter('keys', hp.validFingerprints);
-            expect(test0.isComplete).to.be.false;
+            expect(test0.isComplete()).to.be.false;
         });
 
         it('Complete Message contains the data that was set', function(){