js: documentation
authorMaximilian Krambach <maximilian.krambach@intevation.de>
Tue, 10 Jul 2018 12:32:26 +0000 (14:32 +0200)
committerMaximilian Krambach <maximilian.krambach@intevation.de>
Tue, 10 Jul 2018 12:32:26 +0000 (14:32 +0200)
--

* Fixed errors:
- src/Message.js post(): Set chunksize to defined default value instead
  of hardcoded
- src/Keys.js: added getHasSecret() to refreshKey operation.

* Reviewed and updated the documentation

* non-documentation changes which do not affect functionality:
- src/Errors: disabled a console.warn that is only useful for debugging
- helpers.js: renamed "string" to "value" in isFingerprint and isLongId
  to avoid confusion
- src/Keyring: prepare_sync, search are both explicitly set to false by
  default

lang/js/README
lang/js/src/Connection.js
lang/js/src/Errors.js
lang/js/src/Helpers.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/src/index.js
lang/js/src/permittedOperations.js

index 86d2616..b7cd3d7 100644 (file)
@@ -1,10 +1,17 @@
-gpgmejs, as contained in this directory, is a javascript library for direct use
+gpgme.js, as contained in this directory, is a javascript library for direct use
 of gnupg in browsers, with the help of nativeMessaging.
 
-Installation
--------------
-gpgmejs uses webpack, and thus depends on nodejs for building. All dependencies
-will be installed (in a local subdirectory) with the command `npm install`.
+Prerequisites:
+--------------
+gpgme.js will make use of the application gpgme-json, which is distributed with
+gpgme. Gpgme-json needs to be installed; it will further need to accept the
+browser extension in the manifest file.
+
+Building gpgme.js
+-----------------
+gpgme.js uses webpack, and thus depends on nodejs for building. All
+dependencies will be installed (in a local subdirectory) with the command
+`npm install`.
 
 To create a current version of the package, the command is
 `npx webpack --config webpack.conf.js`.
@@ -14,7 +21,7 @@ in webpack.conf.js.
 Demo and Test WebExtension:
 ---------------------------
 
-The Demo Extension shows simple examples of the usage of gpgmejs.
+The Demo Extension shows simple examples of the usage of gpgme.js.
 
 The BrowsertestExtension runs more intensive tests (using the mocha and chai
 frameworks). Tests from BrowserTestExtension/tests will be run against the
@@ -22,11 +29,11 @@ gpgmejs.bundle.js itself. They aim to test the outward facing functionality
 and API.
 
 Unittests as defined in ./unittests.js will be bundled in
-gpgmejs_unittests.bundle.js, and test the separate components of gpgmejs,
+gpgmejs_unittests.bundle.js, and test the separate components of gpgme.js,
 which mostly are not exported.
 
-. The file `build_extension.sh` may serve as a pointer on how to
-build and assemble these two Extensions and their dependencies. It can directly
+The file `build_extension.sh` may serve as a pointer on how to build and
+assemble these two Extensions and their dependencies. It can directly
 be used in most linux systems.
 
 The resulting folders can just be included in the extensions tab of the browser
@@ -46,7 +53,7 @@ is needed, with the following content:
   ```
   {
     "name": "gpgmejson",
-    "description": "This is a test application for gpgmejs",
+    "description": "This is a test application for gpgme.js",
     "path": "/usr/bin/gpgme-json",
     "type": "stdio",
     "allowed_origins": ["chrome-extension://ExtensionIdentifier/"]
@@ -61,7 +68,7 @@ is needed, with the following content:
   ```
   {
     "name": "gpgmejson",
-    "description": "This is a test application for gpgmejs",
+    "description": "This is a test application for gpgme.js",
     "path": "/usr/bin/gpgme-json",
     "type": "stdio",
     "allowed_extensions": ["ExtensionIdentifier@temporary-addon"]
index 945932e..ef54dd6 100644 (file)
@@ -28,7 +28,12 @@ import { gpgme_error } from './Errors';
 import { GPGME_Message, createMessage } from './Message';
 
 /**
- * A Connection handles the nativeMessaging interaction.
+ * A Connection handles the nativeMessaging interaction via a port. As the
+ * protocol only allows up to 1MB of message sent from the nativeApp to the
+ * browser, the connection will stay open until all parts of a communication
+ * are finished. For a new request, a new port will open, to avoid mixing
+ * contexts.
+ * @class
  */
 export class Connection{
 
@@ -37,19 +42,26 @@ export class Connection{
     }
 
     /**
-     * Retrieves the information about the backend.
-     * @param {Boolean} details (optional) If set to false, the promise will
-     *  just return a connection status
-     * @returns {Promise<Object>} result
-     * @returns {String} result.gpgme Version number of gpgme
-     * @returns {Array<Object>} result.info Further information about the
-     * backends.
-     *      Example:
+     * @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
      */
     checkConnection(details = true){
         if (details === true) {
@@ -74,7 +86,7 @@ export class Connection{
     }
 
     /**
-     * Immediately closes the open port.
+     * Immediately closes an open port.
      */
     disconnect() {
         if (this._connection){
@@ -93,10 +105,13 @@ export class Connection{
     }
 
     /**
-     * Sends a message and resolves with the answer.
+     * 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 gnupg answer, or rejection with error
-     * information.
+     * @returns {Promise<Object>} The collected answer
+     * @async
      */
     post(message){
         if (!message || !(message instanceof GPGME_Message)){
@@ -170,16 +185,25 @@ export class Connection{
 /**
  * A class for answer objects, checking and processing the return messages of
  * the nativeMessaging communication.
- * @param {String} operation The operation, to look up validity of returning
- * messages
+ * @protected
  */
 class Answer{
 
+    /**
+     * @param {GPGME_Message} message
+     */
     constructor(message){
         this.operation = message.operation;
         this.expect = message.expect;
     }
 
+    /**
+     * Adds incoming base64 encoded data to the existing response
+     * @param {*} msg base64 encoded data.
+     * @returns {Boolean}
+     *
+     * @private
+     */
     collect(msg){
         if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) {
             return gpgme_error('CONN_UNEXPECTED_ANSWER');
@@ -195,6 +219,10 @@ class Answer{
         }
     }
 
+    /**
+     * Returns the base64 encoded answer data with the content verified against
+     * {@link permittedOperations}.
+     */
     get message(){
         if (this._responseb64 === undefined){
             return gpgme_error('CONN_UNEXPECTED_ANSWER');
index a8cd8b5..cb5c94c 100644 (file)
@@ -21,6 +21,9 @@
  *     Maximilian Krambach <mkrambach@intevation.de>
  */
 
+/**
+ * Listing of all possible error codes and messages of a {@link GPGME_Error}.
+ */
 const err_list = {
     // Connection
     'CONN_NO_CONNECT': {
@@ -107,10 +110,11 @@ const err_list = {
 };
 
 /**
- * Checks the given error code and returns an error object with some
- * information about meaning and origin
+ * Checks the given error code and returns an {@link GPGME_Error} error object
+ * with some information about meaning and origin
  * @param {*} code Error code. Should be in err_list or 'GNUPG_ERROR'
  * @param {*} info Error message passed through if code is 'GNUPG_ERROR'
+ * @returns {GPGME_Error}
  */
 export function gpgme_error(code = 'GENERIC_ERROR', info){
     if (err_list.hasOwnProperty(code)){
@@ -119,7 +123,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
         }
         if (err_list[code].type === 'warning'){
             // eslint-disable-next-line no-console
-            console.warn(code + ': ' + err_list[code].msg);
+            // console.warn(code + ': ' + err_list[code].msg);
         }
         return null;
     } else if (code === 'GNUPG_ERROR'){
@@ -130,6 +134,14 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){
     }
 }
 
+/**
+ * An error class with additional info about the origin of the error, as string
+ * @property {String} code Short description of origin and type of the error
+ * @property {String} msg Additional info
+ * @class
+ * @protected
+ * @extends Error
+ */
 class GPGME_Error extends Error{
     constructor(code, msg=''){
         if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){
index b01fbc3..0fd1499 100644 (file)
@@ -26,11 +26,11 @@ import { GPGME_Key } from './Key';
 
 /**
  * Tries to return an array of fingerprints, either from input fingerprints or
- * from Key objects (openpgp Keys or GPGME_Keys are both expected)
- * @param {Object |Array<Object>| String|Array<String>} input
- * @returns {Array<String>} Array of fingerprints.
+ * from Key objects (openpgp Keys or GPGME_Keys are both accepted).
+ *
+ * @param {Object | Array<Object> | String | Array<String>} input
+ * @returns {Array<String>} Array of fingerprints, or an empty array
  */
-
 export function toKeyIdArray(input){
     if (!input){
         return [];
@@ -44,6 +44,8 @@ export function toKeyIdArray(input){
             if (isFingerprint(input[i]) === true){
                 result.push(input[i]);
             } else {
+                // MSG_NOT_A_FPR is just a console warning if warning enabled
+                // in src/Errors.js
                 gpgme_error('MSG_NOT_A_FPR');
             }
         } else if (typeof(input[i]) === 'object'){
@@ -71,9 +73,11 @@ export function toKeyIdArray(input){
 }
 
 /**
- * check if values are valid hexadecimal values of a specified length
- * @param {*} key input value.
+ * Check if values are valid hexadecimal values of a specified length
+ * @param {String} key input value.
  * @param {int} len the expected length of the value
+ * @returns {Boolean} true if value passes test
+ * @private
  */
 function hextest(key, len){
     if (!key || typeof(key) !== 'string'){
@@ -87,15 +91,21 @@ function hextest(key, len){
 }
 
 /**
- * check if the input is a valid Hex string with a length of 40
+ * check if the input is a valid Fingerprint
+ *      (Hex string with a length of 40 characters)
+ * @param {String} value to check
+ * @returns {Boolean} true if value passes test
  */
-export function isFingerprint(string){
-    return hextest(string, 40);
+export function isFingerprint(value){
+    return hextest(value, 40);
 }
 
 /**
- *  check if the input is a valid Hex string with a length of 16
+ * check if the input is a valid gnupg long ID (Hex string with a length of 16
+ * characters)
+ * @param {String} value to check
+ * @returns {Boolean} true if value passes test
  */
-export function isLongId(string){
-    return hextest(string, 16);
+export function isLongId(value){
+    return hextest(value, 16);
 }
index 88c2b92..30f507c 100644 (file)
@@ -26,8 +26,9 @@ import { gpgme_error } from './Errors';
 import { createMessage } from './Message';
 
 /**
- * Validates the fingerprint.
+ * Validates the given fingerprint and creates a new {@link GPGME_Key}
  * @param {String} fingerprint
+ * @returns {GPGME_Key|GPGME_Error}
  */
 export function createKey(fingerprint){
     if (!isFingerprint(fingerprint)){
@@ -37,12 +38,13 @@ export function createKey(fingerprint){
 }
 
 /**
- * Representing the Keys as stored in GPG
+ * Represents the Keys as stored in the gnupg backend
  * It allows to query almost all information defined in gpgme Key Objects
- * Refer to validKeyProperties for available information, and the gpgme
+ * Refer to {@link validKeyProperties} for available information, and the gpgme
  * documentation on their meaning
  * (https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html)
  *
+ * @class
  */
 export class GPGME_Key {
 
@@ -62,6 +64,9 @@ export class GPGME_Key {
         }
     }
 
+    /**
+     * @returns {String} The fingerprint defining this Key
+     */
     get fingerprint(){
         if (!this._data || !this._data.fingerprint){
             return gpgme_error('KEY_INVALID');
@@ -70,11 +75,11 @@ export class GPGME_Key {
     }
 
     /**
-     *
-     * @param {Object} data Bulk set data for this key, with the Object as sent
+     * @param {Object} data Bulk set the data for this key, with an Object sent
      * by gpgme-json.
-     * @returns {GPGME_Key|GPGME_Error} The Key object itself after values have
-     * been set
+     * @returns {GPGME_Key|GPGME_Error} Itself after values have been set, an
+     * error if something went wrong
+     * @private
      */
     setKeyData(data){
         if (this._data === undefined) {
@@ -126,12 +131,17 @@ export class GPGME_Key {
     }
 
     /**
-     * Query any property of the Key list
-     * @param {String} property Key property to be retreived
-     * @param {*} cached (optional) if false, the data will be directly queried
-     * from gnupg.
-     *  @returns {*|Promise<*>} the value, or if not cached, a Promise
-     * resolving on the value
+     * 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 true, the value will be resolved as a Promise.
      */
     get(property, cached=true) {
         if (cached === false) {
@@ -164,7 +174,12 @@ export class GPGME_Key {
     }
 
     /**
-     * Reloads the Key from gnupg
+     * 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
      */
     refreshKey() {
         let me = this;
@@ -178,7 +193,12 @@ export class GPGME_Key {
             msg.post().then(function(result){
                 if (result.keys.length === 1){
                     me.setKeyData(result.keys[0]);
-                    resolve(me);
+                    me.getHasSecret().then(function(){
+                        //TODO retrieve armored Key
+                        resolve(me);
+                    }, function(error){
+                        reject(error);
+                    });
                 } else {
                     reject(gpgme_error('KEY_NOKEY'));
                 }
@@ -189,9 +209,9 @@ export class GPGME_Key {
     }
 
     /**
-     * Query the armored block of the non- secret parts of the Key directly
-     * from gpg.
-     * @returns {Promise<String>}
+     * 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
      */
     getArmor(){
@@ -213,9 +233,12 @@ export class GPGME_Key {
     }
 
     /**
-     * Find out if the Key includes a secret part
-     * @returns {Promise<Boolean>}
-     *
+     * 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
      */
     getHasSecret(){
@@ -253,25 +276,30 @@ export class GPGME_Key {
      */
 
     /**
-     * @returns {String} The armored public Key block
+     * 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);
     }
 
     /**
-     * @returns {Boolean} If the key is considered a "private Key",
-     * i.e. owns a secret subkey.
+     * 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
+     * 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>} Success if key was deleted, rejects with a
-     * GPG error otherwise
+     * @returns {Promise<Boolean|GPGME_Error>} Success if key was deleted,
+     * rejects with a GPG error otherwise.
      */
     delete(){
         let me = this;
@@ -291,10 +319,17 @@ export class GPGME_Key {
 }
 
 /**
- * The subkeys of a Key. Currently, they cannot be refreshed separately
+ * Representing a subkey of a Key.
+ * @class
+ * @protected
  */
 class GPGME_Subkey {
 
+    /**
+     * Initializes with the json data sent by gpgme-json
+     * @param {Object} data
+     * @private
+     */
     constructor(data){
         let keys = Object.keys(data);
         for (let i=0; i< keys.length; i++) {
@@ -302,6 +337,13 @@ class GPGME_Subkey {
         }
     }
 
+    /**
+     * 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 = {};
@@ -318,10 +360,9 @@ class GPGME_Subkey {
     }
 
     /**
-     *
+     * Fetches any information about this subkey
      * @param {String} property Information to request
-     * @returns {String | Number}
-     * TODO: date properties are numbers with Date in seconds
+     * @returns {String | Number | Date}
      */
     get(property) {
         if (this._data.hasOwnProperty(property)){
@@ -330,15 +371,31 @@ class GPGME_Subkey {
     }
 }
 
+/**
+ * Representing user attributes associated with a Key or subkey
+ * @class
+ * @protected
+ */
 class GPGME_UserId {
 
+    /**
+     * Initializes with the json data sent by gpgme-json
+     * @param {Object} data
+     * @private
+     */
     constructor(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 validUserIdProperties} and
+     * sets it if validation is successful
+     * @param {String} property
+     * @param {*} value
+     * @param private
+     */
     setProperty(property, value){
         if (!this._data){
             this._data = {};
@@ -356,10 +413,9 @@ class GPGME_UserId {
     }
 
     /**
-     *
+     * Fetches information about the user
      * @param {String} property Information to request
      * @returns {String | Number}
-     * TODO: date properties are numbers with Date in seconds
      */
     get(property) {
         if (this._data.hasOwnProperty(property)){
@@ -368,6 +424,13 @@ class GPGME_UserId {
     }
 }
 
+/**
+ * Validation definition for userIds. Each valid userId property is represented
+ * as a key- Value pair, with their value being a validation function to check
+ * against
+ * @protected
+ * @const
+ */
 const validUserIdProperties = {
     'revoked': function(value){
         return typeof(value) === 'boolean';
@@ -419,6 +482,12 @@ const validUserIdProperties = {
     }
 };
 
+/**
+ * Validation definition for subKeys. Each valid userId property is represented
+ * as a key-value pair, with the value being a validation function
+ * @protected
+ * @const
+ */
 const validSubKeyProperties = {
     'invalid': function(value){
         return typeof(value) === 'boolean';
@@ -471,8 +540,14 @@ const validSubKeyProperties = {
         return (Number.isInteger(value) && value > 0);
     }
 };
+
+/**
+ * Validation definition for Keys. Each valid Key property is represented
+ * as a key-value pair, with their value being a validation function
+ * @protected
+ * @const
+ */
 const validKeyProperties = {
-    //TODO better validation?
     'fingerprint': function(value){
         return isFingerprint(value);
     },
index 09c43f7..a0bdfcb 100644 (file)
@@ -27,24 +27,30 @@ import {createKey} from './Key';
 import { isFingerprint } from './Helpers';
 import { gpgme_error } from './Errors';
 
+/**
+ * This class offers access to the gnupg keyring
+ */
 export class GPGME_Keyring {
     constructor(){
     }
 
     /**
-     * @param {String} pattern (optional) pattern A pattern to search for,
-     * in userIds or KeyIds
-     * @param {Boolean} prepare_sync (optional, default true) if set to true,
-     * Key.armor and Key.hasSecret will be called, so they can be used
-     * inmediately. This allows for full synchronous use. If set to false,
-     * these will initially only be available as Promises in getArmor() and
-     * getHasSecret()
-     * @param {Boolean} search (optional) retrieve the Keys from servers with
-     * the method(s) defined in gnupg (e.g. WKD/HKP lookup)
-     * @returns {Promise.<Array<GPGME_Key>>}
+     * 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
      */
-    getKeys(pattern, prepare_sync, search){
+    getKeys(pattern, prepare_sync=false, search=false){
         return new Promise(function(resolve, reject) {
             let msg = createMessage('keylist');
             if (pattern !== undefined){
@@ -102,10 +108,15 @@ export class GPGME_Keyring {
     }
 
     /**
-     * Fetches the armored public Key blocks for all Keys matchin the pattern
-     * (if no pattern is given, fetches all known to gnupg)
-     * @param {String|Array<String>} pattern (optional)
-     * @returns {Promise<String>} Armored Key blocks
+     * Fetches the armored public Key blocks for all Keys matching the pattern
+     * (if no pattern is given, fetches all keys known to gnupg). Note that the
+     * result may be one big armored block, instead of several smaller armored
+     * blocks
+     * @param {String|Array<String>} pattern (optional) The Pattern to search
+     * for
+     * @returns {Promise<String|GPGME_Error>} Armored Key blocks
+     * @static
+     * @async
      */
     getKeysArmored(pattern) {
         return new Promise(function(resolve, reject) {
@@ -123,15 +134,14 @@ export class GPGME_Keyring {
     }
 
     /**
-     * Returns the Key to be used by default for signing operations,
-     * looking up the gpg configuration, or returning the first key that
-     * contains a secret key.
-     * @returns {Promise<GPGME_Key>}
-     *
+     * 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.
      *
-     * TODO: getHasSecret always returns false at this moment, so this fucntion
-     * still does not fully work as intended.
-     * * @async
+     * @returns {Promise<GPGME_Key|GPGME_Error>}
+     * @async
+     * @static
      */
     getDefaultKey() {
         let me = this;
@@ -177,30 +187,40 @@ export class GPGME_Keyring {
     }
 
     /**
+     * @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 getKeys()).
-     *
-     * @returns {Promise<Object>} result: A summary and an array of Keys
-     * considered
-     *
-     * @returns result.summary: Numerical summary of the result. See the
-     * feedbackValues variable for available values and the gnupg documentation
-     * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html
-     * for details on their meaning.
-     * @returns {Array<Object>} result.Keys: Array of objects containing:
-     * @returns {GPGME_Key} Key.key The resulting key
-     * @returns {String} Key.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.
-     * @returns {Boolean} Key.changes.userId: userIds changed
-     * @returns {Boolean} Key.changes.signature: signatures changed
-     * @returns {Boolean} Key.changes.subkey: subkeys changed
+     * (see {@link getKeys}).
+     * @returns {Promise<importResult>} A summary and Keys considered.
+     * @async
+     * @static
      */
     importKey(armored, prepare_sync) {
         let feedbackValues = ['considered', 'no_user_id', 'imported',
@@ -283,25 +303,36 @@ export class GPGME_Keyring {
 
     }
 
+    /**
+     * Convenience function for deleting a Key. See {@link Key.delete} for
+     * further information about the return values.
+     * @param {String} fingerprint
+     * @returns {Promise<Boolean|GPGME_Error>}
+     * @async
+     * @static
+     */
     deleteKey(fingerprint){
         if (isFingerprint(fingerprint) === true) {
             let key = createKey(fingerprint);
-            key.delete();
+            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_ from inside gpgmejs.
+     * 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 {*} algo (optional) algorithm (and optionally key size to be
-     *  used. See {@link supportedKeyAlgos } below for supported values.
+     * @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>}
+     * @return {Promise<Key|GPGME_Error>}
+     * @async
      */
     generateKey(userId, algo = 'default', expires){
         if (
@@ -336,7 +367,8 @@ export class GPGME_Keyring {
 }
 
 /**
- * A list of algorithms supported for key generation.
+ * List of algorithms supported for key generation. Please refer to the gnupg
+ * documentation for details
  */
 const supportedKeyAlgos = [
     'default',
index 7ccf7ef..2e38142 100644 (file)
@@ -25,6 +25,12 @@ import { permittedOperations } from './permittedOperations';
 import { gpgme_error } from './Errors';
 import { Connection } from './Connection';
 
+/**
+ * Initializes a message for gnupg, validating the message's purpose with
+ *   {@link permittedOperations} first
+ * @param {String} operation
+ * @returns {GPGME_Message|GPGME_Error} The Message object
+ */
 export function createMessage(operation){
     if (typeof(operation) !== 'string'){
         return gpgme_error('PARAM_WRONG');
@@ -37,12 +43,13 @@ export function createMessage(operation){
 }
 
 /**
- * Prepares a communication request. It checks operations and parameters in
- * ./permittedOperations.
- * @param {String} operation
+ * A Message collects, validates and handles all information required to
+ * successfully establish a meaningful communication with gpgme-json via
+ * {@link Connection.post}. The definition on which communication is available
+ * can be found in {@link permittedOperations}.
+ * @class
  */
 export class GPGME_Message {
-    //TODO getter
 
     constructor(operation){
         this.operation = operation;
@@ -63,9 +70,13 @@ export class GPGME_Message {
     }
 
     /**
-     * Set the maximum size of responses from gpgme in bytes. Values allowed
-     * range from 10kB to 1MB. The lower limit is arbitrary, the upper limit
-     * fixed by browsers' nativeMessaging specifications
+     * 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.
      */
     set chunksize(value){
         if (
@@ -85,8 +96,9 @@ export class GPGME_Message {
     }
 
     /**
-     * If expect is set to 'base64', the response is expected to be base64
-     * encoded binary
+     * 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'){
@@ -103,13 +115,13 @@ export class GPGME_Message {
 
 
     /**
-     * Sets a parameter for the message. Note that the operation has to be set
-     * first, to be able to check if the parameter is permittted
+     * Sets a parameter for the message. It validates with
+     *      {@link permittedOperations}
      * @param {String} param Parameter to set
-     * @param {any} value Value to set //TODO: Some type checking
+     * @param {any} value Value to set
      * @returns {Boolean} If the parameter was set successfully
      */
-    setParameter(param,value){
+    setParameter( param,value ){
         if (!param || typeof(param) !== 'string'){
             return gpgme_error('PARAM_WRONG');
         }
@@ -125,6 +137,7 @@ export class GPGME_Message {
         } else {
             return gpgme_error('PARAM_WRONG');
         }
+        // check incoming value for correctness
         let checktype = function(val){
             switch(typeof(val)){
             case 'string':
@@ -187,9 +200,9 @@ export class GPGME_Message {
     }
 
     /**
-     * Check if the message has the minimum requirements to be sent, according
-     * to the definitions in permittedOperations
-     * @returns {Boolean}
+     * 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){
@@ -222,13 +235,18 @@ export class GPGME_Message {
 
     }
 
+    /**
+     * Sends the Message via nativeMessaging and resolves with the answer.
+     * @returns {Promise<Object|GPGME_Error>}
+     * @async
+     */
     post(){
         let me = this;
         return new Promise(function(resolve, reject) {
             if (me.isComplete === true) {
                 let conn  = new Connection;
                 if (me._msg.chunksize === undefined){
-                    me._msg.chunksize = 1023*1024;
+                    me._msg.chunksize = me.chunksize;
                 }
                 conn.post(me).then(function(response) {
                     resolve(response);
index c3c511a..191e00a 100644 (file)
  * Author(s):
  *     Maximilian Krambach <mkrambach@intevation.de>
  */
+import { gpgme_error } from './Errors';
 
 /**
- * Validates a signature object and returns
+ * Validates an object containing a signature, as sent by the nativeMessaging
+ * interface
  * @param {Object} sigObject Object as returned by gpgme-json. The definition
- * of the expected values are to be found in the constants 'expKeys', 'expSum',
- * 'expNote' in this file.
- * @returns {GPGME_Signature} Signature Object
+ * of the expected values are to be found in {@link expKeys}, {@link expSum},
+ * {@link expNote}.
+ * @returns {GPGME_Signature|GPGME_Error} Signature Object
  */
-
-import { gpgme_error } from './Errors';
-
 export function createSignature(sigObject){
     if (
         typeof(sigObject) !=='object' ||
@@ -72,18 +71,20 @@ export function createSignature(sigObject){
 
 
 /**
- * Representing the details of a signature. It is supposed to be read-only. The
- * full details as given by gpgme-json can be accessed from the _rawSigObject.
- * )
+ * Representing the details of a signature. The full details as given by
+ * gpgme-json can be read from the _rawSigObject.
+ *
+ * Note to reviewers: This class should be read only except via
+ * {@link createSignature}
+ * @protected
+ * @class
  */
 class GPGME_Signature {
+
     constructor(sigObject){
         this._rawSigObject = sigObject;
     }
 
-    /**
-     * The signatures' fingerprint
-     */
     get fingerprint(){
         return this._rawSigObject.fingerprint;
     }
@@ -105,7 +106,7 @@ class GPGME_Signature {
      * @returns {Date}
      */
     get timestamp(){
-        return new Date(this._rawSigObject.timestamp* 1000);
+        return new Date(this._rawSigObject.timestamp * 1000);
     }
 
     /**
index f49361d..3f6dc94 100644 (file)
@@ -28,10 +28,62 @@ import { gpgme_error } from './Errors';
 import { GPGME_Keyring } from './Keyring';
 import { createSignature } from './Signature';
 
+/**
+ * @typedef {Object} decrypt_result
+ * @property {String} data The decrypted data
+ * @property {Boolean} base64 indicating whether data is base64 encoded.
+ * @property {Boolean} is_mime (optional) the data claims to be a MIME
+ * object.
+ * @property {String} file_name (optional) the original file name
+ * @property {signatureDetails} signatures Verification details for
+ * signatures
+ */
+
+/**
+ * @typedef {Object} signatureDetails
+ * @property {Boolean} all_valid Summary if all signatures are fully valid
+ * @property {Number} count Number of signatures found
+ * @property {Number} failures Number of invalid signatures
+ * @property {Array<GPGME_Signature>} signatures.good All valid signatures
+ * @property {Array<GPGME_Signature>} signatures.bad All invalid signatures
+ */
+
+/**
+ * @typedef {Object} encrypt_result The result of an encrypt operation
+ * @property {String} data The encrypted message
+ * @property {Boolean} base64 Indicating whether data is base64 encoded.
+ */
+
+/**
+ * @typedef { GPGME_Key | String | Object } inputKeys
+ * Accepts different identifiers of a gnupg Key that can be parsed by
+ * {@link toKeyIdArray}. Expected inputs are: One or an array of
+ * GPGME_Keys; one or an array of fingerprint strings; one or an array of
+ * openpgpjs Key objects.
+ */
+
+/**
+ * @typedef {Object} signResult The result of a signing operation
+ * @property {String} data The resulting data. Includes the signature in
+ *  clearsign mode
+ * @property {String} signature The detached signature (if in detached mode)
+ */
+
+/** @typedef {Object} verifyResult The result of a verification
+ * @property {Boolean} data: The verified data
+ * @property {Boolean} is_mime (optional) the data claims to be a MIME
+ * object.
+ * @property {String} file_name (optional) the original file name
+ * @property {signatureDetails} signatures Verification details for
+ * signatures
+ */
+
+/**
+ * The main entry point for gpgme.js.
+ * @class
+ */
 export class GpgME {
-    /**
-     * initializes GpgME by opening a nativeMessaging port
-     */
+
     constructor(){
     }
 
@@ -41,6 +93,9 @@ export class GpgME {
         }
     }
 
+    /**
+     * Accesses the {@link GPGME_Keyring}.
+     */
     get Keyring(){
         if (!this._Keyring){
             this._Keyring = new GPGME_Keyring;
@@ -49,23 +104,23 @@ export class GpgME {
     }
 
     /**
-     * Encrypt (and optionally sign) a Message
+     * Encrypt (and optionally sign) data
      * @param {String|Object} data text/data to be encrypted as String. Also
      * accepts Objects with a getText method
-     * @param  {GPGME_Key|String|Array<String>|Array<GPGME_Key>} publicKeys
+     * @param {inputKeys} publicKeys
      * Keys used to encrypt the message
-     * @param  {GPGME_Key|String|Array<String>|Array<GPGME_Key>} secretKeys
-     * (optional) Keys used to sign 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
+     * 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 gpg options
-     * (refer to src/permittedOperations)
-     * @returns {Promise<Object>} Encrypted message:
-     *   data: The encrypted message
-     *   base64: Boolean indicating whether data is base64 encoded.
+     * not be added to the message.
+     * @param {Object} additional use additional valid gpg options as defined
+     * in {@link permittedOperations}
+     * @returns {Promise<encrypt_result>} Object containing the encrypted
+     * message and additional info.
      * @async
      */
     encrypt(data, publicKeys, secretKeys, base64=false, armor=true,
@@ -105,28 +160,12 @@ export class GpgME {
     }
 
     /**
-    * Decrypt a Message
+    * 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<Object>} result: Decrypted Message and information
-    * @returns {String} result.data: The decrypted data.
-    * @returns {Boolean} result.base64: indicating whether data is base64
-    *   encoded.
-    * @returns {Boolean} result.is_mime: Indicating whether the data is a MIME
-    *   object.
-    * @returns {String} result.file_name: The optional original file name
-    * @returns {Object} message.signatures Verification details for signatures:
-    * @returns {Boolean} message.signatures.all_valid: true if all signatures
-    *   are valid
-    * @returns {Number} message.signatures.count: Number of signatures found
-    * @returns {Number} message.signatures.failures Number of invalid
-    *   signatures
-    * @returns {Array<Object>} message.signatures.signatures. Two arrays
-    *   (good & bad) of {@link GPGME_Signature} objects, offering further
-    *   information.
-    *
+    * @returns {Promise<decrypt_result>} Decrypted Message and information
     * @async
     */
     decrypt(data, base64=false){
@@ -169,16 +208,13 @@ export class GpgME {
     /**
      * Sign a Message
      * @param {String|Object} data text/data to be signed. Accepts Strings
-     * and Objects with a gettext methos
-     * @param {GPGME_Key|String|Array<String>|Array<GPGME_Key>} keys The
-     * key/keys to use for signing
-     * @param {*} mode The signing mode. Currently supported:
-     *      'clearsign': (default) The Message is embedded into the signature
-     *      'detached': The signature is stored separately
-     * @param {*} base64 input is considered base64
-     * @returns {Promise<Object>}
-     *    data: The resulting data. Includes the signature in clearsign mode
-     *    signature: The detached signature (if in detached mode)
+     * and Objects with a getText method.
+     * @param {inputKeys} keys The key/keys to use for signing
+     * @param {String} mode The signing mode. Currently supported:
+     *  'clearsign':The Message is embedded into the signature;
+     *  'detached': The signature is stored separately
+     * @param {Boolean} base64 input is considered base64
+     * @returns {Promise<signResult>}
      * @async
      */
     sign(data, keys, mode='clearsign', base64=false) {
@@ -221,20 +257,12 @@ export class GpgME {
     /**
      * Verifies data.
      * @param {String|Object} data text/data to be verified. Accepts Strings
-     * and Objects with a gettext method
+     * 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
-     * // TODO verify if signature really is assumed to be base64
-     * @returns {Promise<Object>} result:
-     * @returns {Boolean} result.data: The verified data
-     * @returns {Boolean} result.is_mime: The message claims it is MIME
-     * @returns {String} result.file_name: The optional filename of the message
-     * @returns {Boolean} result.all_valid: true if all signatures are valid
-     * @returns {Number} result.count: Number of signatures found
-     * @returns {Number} result.failures Number of unsuccessful signatures
-     * @returns {Array<Object>} result.signatures. Two arrays (good & bad) of
-     *      {@link GPGME_Signature} objects, offering further information.
+     * @returns {Promise<verifyResult>}
+     *@async
      */
     verify(data, signature, base64 = false){
         let msg = createMessage('verify');
@@ -275,7 +303,10 @@ export class GpgME {
 /**
  * Sets the data of the message, setting flags according on the data type
  * @param {GPGME_Message} message The message where this data will be set
- * @param {*} data The data to enter
+ * @param { String| Object } data The data to enter. Expects either a string of
+ * data, or an object with a getText method
+ * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise
+ * @private
  */
 function putData(message, data){
     if (!message || !(message instanceof GPGME_Message) ) {
@@ -301,6 +332,11 @@ function putData(message, data){
     }
 }
 
+/**
+ * Parses, validates and converts incoming objects into signatures.
+ * @param {Array<Object>} sigs
+ * @returns {signatureDetails} Details about the signatures
+ */
 function collectSignatures(sigs){
     if (!Array.isArray(sigs)){
         return gpgme_error('SIG_NO_SIGS');
index 6db2873..dc613fc 100644 (file)
@@ -27,8 +27,8 @@ import { gpgme_error } from './Errors';
 import { Connection } from './Connection';
 
 /**
- * Tests nativeMessaging once and returns a GpgME object if successful.
- * @returns {GpgME | Error}
+ * Initializes gpgme.js by testing the nativeMessaging connection once.
+ * @returns {Promise<GpgME> | GPGME_Error}
  *
  * @async
  */
index e7f5396..0b9c891 100644 (file)
  */
 
 /**
-  * Definition of the possible interactions with gpgme-json.
-  * operation: <Object>
-      required: Array<Object>
-            <String> name The name of the property
-            allowed: Array of allowed types. Currently accepted values:
-                ['number', 'string', 'boolean', 'Uint8Array']
-            array_allowed: Boolean. If the value can be an array of the above
-            allowed_data: <Array> If present, restricts to the given value
-      optional: Array<Object>
-            see 'required', with these parameters not being mandatory for a
-            complete message
-      pinentry: boolean If a pinentry dialog is expected, and a timeout of
-                5000 ms would be too short
-      answer: <Object>
-          type: <String< The content type of answer expected
-          data: <Object>
-            the properties expected and their type, eg: {'data':'string'}
-      }
-  }
-*/
+ * @typedef {Object} messageProperty
+ * A message Property is defined by it's key.
+ * @property {Array<String>} allowed Array of allowed types.
+ * Currently accepted values are 'number', 'string', 'boolean'.
+ * @property {Boolean} array_allowed If the value can be an array of types
+ *      defined in allowed
+ * @property {<Array>} allowed_data (optional) restricts to the given values
+  */
 
+/**
+ * Definition of the possible interactions with gpgme-json.
+ * @param {Object} operation Each operation is named by a key and contains
+ * the following properties:
+ * @property {messageProperty} required An object with all required parameters
+ * @property {messageProperty} optional An object with all optional parameters
+ * @property {Boolean} pinentry (optional) If true, a password dialog is
+ *      expected, thus a connection tuimeout is not advisable
+ * @property {Object} answer The definition on what to expect as answer, if the
+ *      answer is not an error
+ * @property {Array<String>} answer.type the type(s) as reported by gpgme-json.
+ * @property {Object} answer.data key-value combinations of expected properties
+ * of an answer and their type ('boolean', 'string', object)
+  @const
+*/
 export const permittedOperations = {
     encrypt: {
         pinentry: true, //TODO only with signing_keys