diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html new file mode 100644 index 00000000..d2c6396f --- /dev/null +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -0,0 +1,23 @@ + + + + + + + +

Browsertest

+
+ + + + + + + + + + + + + + diff --git a/lang/js/BrowserTestExtension/manifest.json b/lang/js/BrowserTestExtension/manifest.json new file mode 100644 index 00000000..a9e605bc --- /dev/null +++ b/lang/js/BrowserTestExtension/manifest.json @@ -0,0 +1,13 @@ +{ + "manifest_version": 2, + + "name": "Browsertests for gpgmejs", + "description": "Run the browsertests.", + "version": "0.1", + "content_security_policy": "default-src 'self' filesystem:", + "browser_action": { + "default_icon": "testicon.png", + "default_popup": "popup.html" + }, + "permissions": ["nativeMessaging", "activeTab"] + } diff --git a/lang/js/testapplication_index.html b/lang/js/BrowserTestExtension/popup.html similarity index 65% copy from lang/js/testapplication_index.html copy to lang/js/BrowserTestExtension/popup.html index 866b1135..f17f262a 100644 --- a/lang/js/testapplication_index.html +++ b/lang/js/BrowserTestExtension/popup.html @@ -1,9 +1,9 @@ - + \ No newline at end of file diff --git a/lang/js/test_index.js b/lang/js/BrowserTestExtension/popup.js similarity index 51% copy from lang/js/test_index.js copy to lang/js/BrowserTestExtension/popup.js index 9119d271..4764df55 100644 --- a/lang/js/test_index.js +++ b/lang/js/BrowserTestExtension/popup.js @@ -1,25 +1,44 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ + */ +/* gpgme.js - Javascript integration for gpgme + * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * + * GPGME is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ */ + document.addEventListener('DOMContentLoaded', function() { chrome.tabs.create({ - url: './ui2.html' + url: './browsertest.html' }); }); diff --git a/lang/js/test_index.js b/lang/js/BrowserTestExtension/runbrowsertest.js similarity index 87% copy from lang/js/test_index.js copy to lang/js/BrowserTestExtension/runbrowsertest.js index 9119d271..39bc3fb9 100644 --- a/lang/js/test_index.js +++ b/lang/js/BrowserTestExtension/runbrowsertest.js @@ -1,25 +1,21 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ - * */ -document.addEventListener('DOMContentLoaded', function() { - chrome.tabs.create({ - url: './ui2.html' - }); -}); + +mocha.run(); diff --git a/lang/js/test_index.js b/lang/js/BrowserTestExtension/setup_testing.js similarity index 87% copy from lang/js/test_index.js copy to lang/js/BrowserTestExtension/setup_testing.js index 9119d271..7f70d347 100644 --- a/lang/js/test_index.js +++ b/lang/js/BrowserTestExtension/setup_testing.js @@ -1,25 +1,22 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ - * */ -document.addEventListener('DOMContentLoaded', function() { - chrome.tabs.create({ - url: './ui2.html' - }); -}); +mocha.setup('bdd'); +var expect = chai.expect; +chai.config.includeStack = true; \ No newline at end of file diff --git a/lang/js/testicon.png b/lang/js/BrowserTestExtension/testicon.png similarity index 100% copy from lang/js/testicon.png copy to lang/js/BrowserTestExtension/testicon.png diff --git a/lang/js/test_index.js b/lang/js/BrowserTestExtension/tests/inputvalues.js similarity index 83% copy from lang/js/test_index.js copy to lang/js/BrowserTestExtension/tests/inputvalues.js index 9119d271..47600c84 100644 --- a/lang/js/test_index.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -1,25 +1,28 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ - * */ -document.addEventListener('DOMContentLoaded', function() { - chrome.tabs.create({ - url: './ui2.html' - }); -}); + +var inputvalues = { + encrypt: { + good:{ + data : 'Hello World.', + keyid : 'CDC3A2B2860625CCBFC5A5A9FC6D1B604967FC40' + } + } +}; diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js new file mode 100644 index 00000000..14d12c0a --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -0,0 +1,51 @@ +/* gpgme.js - Javascript integration for gpgme + * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + + describe('GPGME context', function(){ + it('Starting a GpgME instance', function(done){ + Gpgmejs.init().then( + function(context){ + expect(context.connection).to.not.be.undefined; + expect(context).to.be.an('object'); + expect(context.connection).to.be.an('object'); + expect(context.Keyring).to.be.undefined; + expect(context.encrypt).to.be.a('function'); + expect(context.decrypt).to.be.a('function'); + done(); + }, function(err){ + done(err); + }); + }); + it('Starting an openpgp mode GPGME instance', function(done){ + Gpgmejs.init({api_style:"gpgme_openpgpjs"}).then( + function(context){ + console.log(context); + done(); + // expect(context).to.be.an('object'); + // expect(context.connection).to.be.undefined; + // expect(context.Keyring).to.be.an('object'); + // expect(context.encrypt).to.be.a('function'); + // expect(context.decrypt).to.be.a('function'); + // done(); + }, function(err){ + done(err); + }); + }); + }); diff --git a/lang/js/CHECKLIST b/lang/js/CHECKLIST index 49b17265..75664ae5 100644 --- a/lang/js/CHECKLIST +++ b/lang/js/CHECKLIST @@ -1,28 +1,28 @@ NativeConnection: [X] nativeConnection: successfully sending an encrypt request, receiving an answer [X] nativeConnection successfull on Chromium, chrome and firefox [*] nativeConnection successfull on Windows, macOS, Linux [*] nativeConnection with delayed, multipart (> 1MB) answer replicating Openpgpjs API: - [*] Message handling (encrypt, verify, sign) - [x] encrypt + [*] Message handling (encrypt, decrypt verify, sign) + [x] encrypt, decrypt [ ] verify [ ] sign [*] Key handling (import/export, modifying, status queries) [ ] Configuration handling [ ] check for completeness [*] handling of differences to openpgpjs Communication with other implementations [ ] option to export SECRET Key into localstore used by e.g. mailvelope Management: [*] Define the gpgme interface - [ ] check Permissions (e.g. csp) for the different envs + [x] check Permissions (e.g. csp) for the different envs [X] agree on license - [ ] tests + [*] tests diff --git a/lang/js/CHECKLIST_build b/lang/js/CHECKLIST_build index 19eb2146..a7c8d08d 100644 --- a/lang/js/CHECKLIST_build +++ b/lang/js/CHECKLIST_build @@ -1,9 +1,3 @@ - Checklist for build/install: browsers' manifests (see README) need allowedextension added, and the path set - -manifest.json/ csp needs adaption - -/dist should be built which is used by the example app. - -csp in manifest.json MUST NOT contain "unsafe-eval" in production! diff --git a/lang/js/test_index.js b/lang/js/DemoExtension/entry.js similarity index 96% copy from lang/js/test_index.js copy to lang/js/DemoExtension/entry.js index 9119d271..7e5e1ffe 100644 --- a/lang/js/test_index.js +++ b/lang/js/DemoExtension/entry.js @@ -1,25 +1,25 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * */ document.addEventListener('DOMContentLoaded', function() { chrome.tabs.create({ - url: './ui2.html' + url: './uimainui.html' }); }); diff --git a/lang/js/testapplication.js b/lang/js/DemoExtension/maindemo.js similarity index 100% rename from lang/js/testapplication.js rename to lang/js/DemoExtension/maindemo.js diff --git a/lang/js/ui2.html b/lang/js/DemoExtension/mainui.html similarity index 89% rename from lang/js/ui2.html rename to lang/js/DemoExtension/mainui.html index 8d0abd97..d85e7a46 100644 --- a/lang/js/ui2.html +++ b/lang/js/DemoExtension/mainui.html @@ -1,33 +1,33 @@ - - + +
  • Text:
  • Public key ID:


  • Encrypted armored Text:


Result data:

diff --git a/lang/js/manifest.json b/lang/js/DemoExtension/manifest.json similarity index 54% rename from lang/js/manifest.json rename to lang/js/DemoExtension/manifest.json index e5e17aa5..9e057b35 100644 --- a/lang/js/manifest.json +++ b/lang/js/DemoExtension/manifest.json @@ -1,14 +1,14 @@ { "manifest_version": 2, "name": "gpgme-json with native Messaging", - "description": "This should be able to encrypt a text using gpgme-json", + "description": "A simple demo application", "version": "0.1", - "content_security_policy": "default-src 'self' 'unsafe-eval' filesystem:", + "content_security_policy": "default-src 'self' filesystem:", "browser_action": { "default_icon": "testicon.png", "default_title": "gpgme.js", - "default_popup": "testapplication_index.html" + "default_popup": "popup.html" }, "permissions": ["nativeMessaging", "activeTab"] } diff --git a/lang/js/testapplication_index.html b/lang/js/DemoExtension/popup.html similarity index 100% rename from lang/js/testapplication_index.html rename to lang/js/DemoExtension/popup.html diff --git a/lang/js/testicon.png b/lang/js/DemoExtension/testicon.png similarity index 100% rename from lang/js/testicon.png rename to lang/js/DemoExtension/testicon.png diff --git a/lang/js/ui.css b/lang/js/DemoExtension/ui.css similarity index 100% rename from lang/js/ui.css rename to lang/js/DemoExtension/ui.css diff --git a/lang/js/build_extensions.sh b/lang/js/build_extensions.sh new file mode 100755 index 00000000..be7b0584 --- /dev/null +++ b/lang/js/build_extensions.sh @@ -0,0 +1,14 @@ +#/!bin/bash + +npx webpack --config webpack.conf.js +mkdir -p BrowserTestExtension/libs +cp node_modules/chai/chai.js \ + node_modules/mocha/mocha.css \ + node_modules/mocha/mocha.js \ + build/gpgmejs.bundle.js BrowserTestExtension/libs +mkdir -p build/extensions +zip -r build/extensions/browsertest.zip BrowserTestExtension + +mkdir -p DemoExtension/libs +cp build/gpgmejs.bundle.js DemoExtension/libs +zip -r build/extensions/demoextension.zip DemoExtension diff --git a/lang/js/test_index.js b/lang/js/src/Config.js similarity index 74% rename from lang/js/test_index.js rename to lang/js/src/Config.js index 9119d271..e18728de 100644 --- a/lang/js/test_index.js +++ b/lang/js/src/Config.js @@ -1,25 +1,31 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ - * */ -document.addEventListener('DOMContentLoaded', function() { - chrome.tabs.create({ - url: './ui2.html' - }); -}); + +export const availableConf = { + api_style: ['gpgme', 'gpgme_openpgpjs'], + null_expire_is_never: [true, false], + unconsidered_params: ['warn','reject', 'ignore'], +}; + +export const defaultConf = { + api_style: 'gpgme', + null_expire_is_never: false, + unconsidered_params: 'reject', +}; \ No newline at end of file diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 470eeeec..364bfb46 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -1,156 +1,157 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import {createMessage} from './Message' import {GPGME_Key} from './Key' import { isFingerprint, isLongId } from './Helpers'; import { gpgme_error } from './Errors'; +import { Connection } from './Connection'; export class GPGME_Keyring { constructor(connection){ this.connection = connection; } set connection(connection){ if (!this._connection && connection instanceof Connection){ this._connection = connection; } } get connection(){ if (this._connection instanceof Connection){ if (this._connection.isConnected){ return this._connection; } return gpgme_error('CONN_DISCONNECTED'); } return gpgme_error('CONN_NO_CONNECT'); } /** * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds * @param {Boolean} (optional) Include listing of secret keys * @returns {Promise.>} * */ getKeys(pattern, include_secret){ let msg = createMessage('listkeys'); if (msg instanceof Error){ return Promise.reject(msg); } if (pattern && typeof(pattern) === 'string'){ msg.setParameter('pattern', pattern); } if (include_secret){ msg.setParameter('with-secret', true); } this.connection.post(msg).then(function(result){ let fpr_list = []; let resultset = []; if (!Array.isArray(result.keys)){ //TODO check assumption keys = Array fpr_list = [result.keys]; } else { fpr_list = result.keys; } for (let i=0; i < fpr_list.length; i++){ let newKey = new GPGME_Key(fpr_list[i]); if (newKey instanceof GPGME_Key){ resultset.push(newKey); } } return Promise.resolve(resultset); }); } /** * @param {Object} flags subset filter expecting at least one of the * filters described below. True will filter on the condition, False will * reverse the filter, if not present or undefined, the filter will not be * considered. Please note that some combination may not make sense * @param {Boolean} flags.secret Only Keys containing a secret part. * @param {Boolean} flags.revoked revoked Keys only * @param {Boolean} flags.expired Expired Keys only * @param {String} (optional) pattern A pattern to search for, in userIds or KeyIds * @returns {Promise Array} * */ getSubset(flags, pattern){ if (flags === undefined) { throw('ERR_WRONG_PARAM'); }; let secretflag = false; if (flags.hasOwnProperty(secret) && flags.secret){ secretflag = true; } this.getKeys(pattern, secretflag).then(function(queryset){ let resultset = []; for (let i=0; i < queryset.length; i++ ){ let conditions = []; let anticonditions = []; if (secretflag === true){ conditions.push('hasSecret'); } else if (secretflag === false){ anticonditions.push('hasSecret'); } /** if (flags.defaultKey === true){ conditions.push('isDefault'); } else if (flags.defaultKey === false){ anticonditions.push('isDefault'); } */ /** * if (flags.valid === true){ anticonditions.push('isInvalid'); } else if (flags.valid === false){ conditions.push('isInvalid'); } */ if (flags.revoked === true){ conditions.push('isRevoked'); } else if (flags.revoked === false){ anticonditions.push('isRevoked'); } if (flags.expired === true){ conditions.push('isExpired'); } else if (flags.expired === false){ anticonditions.push('isExpired'); } let decision = undefined; for (let con = 0; con < conditions.length; con ++){ if (queryset[i][conditions[con]] !== true){ decision = false; } } for (let acon = 0; acon < anticonditions.length; acon ++){ if (queryset[i][anticonditions[acon]] === true){ decision = false; } } if (decision !== false){ resultset.push(queryset[i]); } } return Promise.resolve(resultset); }); } }; diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 4d242277..9e7a8835 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -1,110 +1,110 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import { permittedOperations } from './permittedOperations' import { gpgme_error } from './Errors' export function createMessage(operation){ if (typeof(operation) !== 'string'){ return gpgme_error('PARAM_WRONG'); } if (permittedOperations.hasOwnProperty(operation)){ return new GPGME_Message(operation); } else { return gpgme_error('MSG_WRONG_OP'); } } /** * Prepares a communication request. It checks operations and parameters in * ./permittedOperations. * @param {String} operation */ -class GPGME_Message { +export class GPGME_Message { //TODO getter constructor(operation){ this.operation = operation; } set operation (op){ } get operation(){ return this._msg.op; } /** * 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 * @param {String} param Parameter to set * @param {any} value Value to set //TODO: Some type checking * @returns {Boolean} If the parameter was set successfully */ setParameter(param,value){ if (!param || typeof(param) !== 'string'){ return gpgme_error('PARAM_WRONG'); } let po = permittedOperations[this._msg.op]; if (!po){ return gpgme_error('MSG_WRONG_OP'); } if (po.required.indexOf(param) >= 0 || po.optional.indexOf(param) >= 0){ this._msg[param] = value; return true; } return gpgme_error('PARAM_WRONG'); } /** * Check if the message has the minimum requirements to be sent, according * to the definitions in permittedOperations * @returns {Boolean} */ get isComplete(){ if (!this._msg.op){ return false; } let reqParams = permittedOperations[this._msg.op].required; for (let i=0; i < reqParams.length; i++){ if (!this._msg.hasOwnProperty(reqParams[i])){ console.log(reqParams[i] + 'missing'); 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){ return this._msg; } else { return null; } } } diff --git a/lang/js/src/gpgmejs_openpgpjs.js b/lang/js/src/gpgmejs_openpgpjs.js index 4e5e1ea0..cc2afde1 100644 --- a/lang/js/src/gpgmejs_openpgpjs.js +++ b/lang/js/src/gpgmejs_openpgpjs.js @@ -1,281 +1,275 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ /** * This is a compatibility API to be used as openpgpjs syntax. * Non-implemented options will throw an error if set (not null or undefined) * TODO Some info about differences */ import { GpgME } from "./gpgmejs"; import {GPGME_Keyring} from "./Keyring" import { GPGME_Key } from "./Key"; import { isFingerprint } from "./Helpers" import { gpgme_error } from "./Errors" export class GpgME_openpgpmode { constructor(connection, config = {}){ this.initGpgME(connection, config); } get Keyring(){ if (this._keyring){ return this._keyring; } return undefined; } initGpgME(connection, config = {}){ if (connection && typeof(config) ==='object'){ this._config = config; if (!this._GPGME){ this._GpgME = new GpgME(connection, config); } - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring_openpgpmode(connection); + if (!this._keyring){ + this._keyring = new GPGME_Keyring_openpgpmode(connection); } } } - get GpgME(){ - if (this._GpGME){ - return this._GpGME; - } - } - /** * Encrypt Message * Supported: * @param {String|Uint8Array} data * //an openpgp Message also accepted here. TODO: is this wanted? * @param {Key|Array} publicKeys * //Strings of Fingerprints * @param {Boolean} wildcard * TODO: * @param {Key|Array} privateKeys // -> encryptsign * @param {module:enums.compression} compression //TODO accepts integer, if 0 (no compression) it won't compress * @param {Boolean} armor // TODO base64 switch * @param {Boolean} detached // --> encryptsign * unsupported: * @param {String|Array} passwords * @param {Object} sessionKey * @param {Signature} signature * @param {Boolean} returnSessionKey * @param {String} filename * * Can be set, but will be ignored: * * @returns {Promise} * {data: ASCII armored message, * signature: detached signature if 'detached' is true * } * @async * @static */ encrypt({data = '', publicKeys = '', privateKeys, passwords=null, sessionKey = null, filename, compression, armor=true, detached=false, signature=null, returnSessionKey=null, wildcard=false, date=null}) { if (passwords !== null || sessionKey !== null || signature !== null || returnSessionKey !== null || date !== null ){ return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); } if ( privateKeys || compression || armor === false || detached == true){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); } if (filename){ if (this._config.unconsidered_params === 'warn'){ GPMGEJS_Error('PARAM_IGNORED'); } else if (this._config.unconsidered_params === 'error'){ return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); } } - return this.GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard); + return this._GpgME.encrypt(data, translateKeyInput(publicKeys), wildcard); } /** Decrypt Message * supported openpgpjs parameters: * @param {Message|Uint8Array|String} message Message object from openpgpjs * Unsupported: * @param {String|Array} passwords * @param {Key|Array} privateKeys * @param {Object|Array} sessionKeys * Not yet supported, but planned * @param {String} format (optional) return data format either as 'utf8' or 'binary' * @param {Signature} signature (optional) detached signature for verification * Ignored values: can be safely set, but have no effect * @param {Date} date * @param {Key|Array} publicKeys * * @returns {Promise} decrypted and verified message in the form: * { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] } * @async * @static */ decrypt({ message, privateKeys, passwords=null, sessionKeys, publicKeys, format='utf8', signature=null, date= null}) { if (passwords !== null || sessionKeys || privateKeys){ return Promise.reject(gpgme_error('NOT_IMPLEMENTED')); } if ( format !== 'utf8' || signature){ return Promise.reject(gpgme_error('NOT_YET_IMPLEMENTED')); } if (date !== null || publicKeys){ if (this._config.unconsidered_params === 'warn'){ GPMGEJS_Error('PARAM_IGNORED'); } else if (this._config.unconsidered_params === 'reject'){ return Promise.reject(GPMGEJS_Error('NOT_IMPLEMENTED')); } } - return this.GpgME.decrypt(message); + return this._GpgME.decrypt(message); // TODO: translate between: // openpgp: // { data:Uint8Array|String, // filename:String, // signatures:[{ keyid:String, valid:Boolean }] } // and gnupg: // data: The decrypted data. This may be base64 encoded. // base64: Boolean indicating whether data is base64 encoded. // mime: A Boolean indicating whether the data is a MIME object. // info: An optional object with extra information. } } /** * Translation layer offering basic Keyring API to be used in Mailvelope. * It may still be changed/expanded/merged with GPGME_Keyring */ class GPGME_Keyring_openpgpmode { constructor(connection){ this._gpgme_keyring = new GPGME_Keyring(connection); } /** * Returns a GPGME_Key Object for each Key in the gnupg Keyring. This * includes keys openpgpjs considers 'private' (usable for signing), with * the difference that Key.armored will NOT contain any secret information. * Please also note that a GPGME_Key does not offer full openpgpjs- Key * compatibility. * @returns {Array} * //TODO: Check if IsDefault is also always hasSecret * TODO Check if async is required */ getPublicKeys(){ return translateKeys( this._gpgme_keyring.getKeys(null, true)); } /** * Returns the Default Key used for crypto operation in gnupg. * Please note that the armored property does not contained secret key blocks, * despite secret blocks being part of the key itself. * @returns {Promise } */ getDefaultKey(){ this._gpgme_keyring.getSubset({defaultKey: true}).then(function(result){ if (result.length === 1){ return Promise.resolve( translateKeys(result)[0]); } else { // TODO: Can there be "no default key"? // TODO: Can there be several default keys? return gpgme_error('TODO'); } }); } /** * Deletes a Key * @param {Object} Object identifying key * @param {String} key.fingerprint - fingerprint of the to be deleted key * @param {Boolean} key.secret - indicator if private key should be deleted as well * @returns {Promise., Error>} TBD: Not sure what is wanted TODO @throws {Error} error.code = ‘KEY_NOT_EXIST’ - there is no key for the given fingerprint TODO @throws {Error} error.code = ‘NO_SECRET_KEY’ - secret indicator set, but no secret key exists */ deleteKey(key){ if (typeof(key) !== "object"){ return Promise.reject(gpgme_error('PARAM_WRONG')); } if ( !key.fingerprint || ! isFingerprint(key.fingerprint)){ return Promise.reject(gpgme_error('PARAM_WRONG')); } let key_to_delete = new GPGME_Key(key.fingerprint); return key_to_delete.deleteKey(key.secret); } } /** * TODO error handling. * Offers the Key information as the openpgpmode wants */ class GPGME_Key_openpgpmode { constructor(value){ this.init = value; } set init (value){ if (!this._GPGME_Key && value instanceof GPGME_Key){ this._GPGME_Key = value; } else if (!this._GPGME_Key && isFingerprint(value)){ this._GPGME_Key = new GPGME_Key(value); } } get fingerprint(){ return this._GPGME_Key.fingerprint; } get armor(){ return this._GPGME_Key.armored; } get secret(){ return this._GPGME_Key.hasSecret; } get default(){ return this._GPGME_Key.isDefault; } } /** * creates GPGME_Key_openpgpmode from GPGME_Keys */ function translateKeys(input){ if (!Array.isArray(input)){ input = [input]; } let resultset; for (let i=0; i< input.length; i++){ resultset.push(new GPGME_Key_openpgpmode(input[i])); } return resultset; } \ No newline at end of file diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 48904316..4de98457 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -1,59 +1,83 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import { GpgME } from "./gpgmejs"; import { gpgme_error } from "./Errors"; import { GpgME_openpgpmode } from "./gpgmejs_openpgpjs"; import { Connection } from "./Connection"; +import { defaultConf, availableConf } from "./Config"; /** * Initializes a nativeMessaging Connection and returns a GPGMEjs object - * @param {*} conf Configuration. TBD + * @param {Object} config Configuration. See Config.js for available parameters. Still TODO */ -function init( config = { - api_style: 'gpgme', // | gpgme_openpgpjs - null_expire_is_never: true, // Boolean - unconsidered_params: 'warn'//'warn' || 'reject' - }){ - return new Promise(function(resolve, reject){ - let connection = new Connection; - // TODO: Delayed reaction is ugly. We need to listen to the port's - // event listener in isConnected, but this takes some time (<5ms) to - // disconnect if there is no successfull connection. - let delayedreaction = function(){ - if (connection.isConnected === true){ - let gpgme = null; - if (config.api_style && config.api_style === 'gpgme_openpgpjs'){ - resolve( - new GpgME_openpgpmode(connection, config)); - } else { - resolve(new GpgME(connection)); - } +function init(config){ + let _conf = parseconfiguration(config); + if (_conf instanceof Error){ + return Promise.reject(_conf); + } + return new Promise(function(resolve, reject){ + let connection = new Connection; + // TODO: Delayed reaction is ugly. We need to listen to the port's + // event listener in isConnected, but this takes some time (<5ms) to + // disconnect if there is no successfull connection. + let delayedreaction = function(){ + if (connection.isConnected === true){ + if (_conf.api_style && _conf.api_style === 'gpgme_openpgpjs'){ + resolve(new GpgME_openpgpmode(connection, _conf)); } else { - reject(gpgme_error('CONN_NO_CONNECT')); + resolve(new GpgME(connection)); } - }; - setTimeout(delayedreaction, 5); + } else { + reject(gpgme_error('CONN_NO_CONNECT')); + } + }; + setTimeout(delayedreaction, 5); }); +} + +function parseconfiguration(config){ + if (!config){ + return defaultConf; + } + if ( typeof(config) !== 'object'){ + return gpgme_error('PARAM_WRONG'); + }; + let result_config = defaultConf; + let conf_keys = Object.keys(config); + for (let i=0; i < conf_keys; i++){ + if (availableConf.hasOwnProperty(conf_keys[i])){ + let value = config[conf_keys[i]]; + if (availableConf[conf_keys[i]].indexOf(value) < 0){ + return gpgme_error('PARAM_WRONG'); + } else { + result_config[conf_keys[i]] = value; + } + } + else { + return gpgme_error('PARAM_WRONG'); + } + } + return result_config; }; export default { init: init } \ No newline at end of file diff --git a/lang/js/test/Helpers.js b/lang/js/test/Helpers.js index 590f9f65..5d8909f9 100644 --- a/lang/js/test/Helpers.js +++ b/lang/js/test/Helpers.js @@ -1,110 +1,97 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import { expect } from "../node_modules/chai/chai"; import { gpgme_error} from "../src/Errors"; import { GPGME_Key } from "../src/Key"; import { isLongId, isFingerprint, toKeyIdArray } from "../src/Helpers" +import { helper_params } from "./inputvalues"; -const helper_params = { - validLongId: '0A0A0A0A0A0A0A0A', - validGPGME_Key: new GPGME_Key('ADDBC303B6D31026F5EB4591A27EABDF283121BB'), - validKeys: [new GPGME_Key('A1E3BC45BDC8E87B74F4392D53B151A1368E50F3'), - 'ADDBC303B6D31026F5EB4591A27EABDF283121BB', - new GPGME_Key('EE17AEE730F88F1DE7713C54BBE0A4FF7851650A')], - validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', - invalidLongId: '9A9A7A7A8A9A9A7A7A8A', - invalidFingerprint: [{hello:'World'}], - invalidKeyArray: {curiosity:'uncat'}, - invalidKeyArray_OneBad: [ - new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), - 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', - '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], - invalidErrorCode: 'Please type in all your passwords.' -} - -describe('Error Object handling', function(){ - it('check the Timeout error', function(){ - let test0 = gpgme_error('CONN_TIMEOUT'); - expect(test0).to.be.an.instanceof(Error); - expect(test0.code).to.equal('CONN_TIMEOUT'); - }); - it('Error Object returns generic code if code is not listed', function(){ - let test0 = gpgme_error(helper_params.invalidErrorCode); - expect(test0).to.be.an.instanceof(Error); - expect(test0.code).to.equal('GENERIC_ERROR'); - }); - - it('Warnings like PARAM_IGNORED should not return errors', function(){ - let test0 = gpgme_error('PARAM_IGNORED'); - expect(test0).to.be.null; - }); -}); - -describe('Fingerprint checking', function(){ - it('isFingerprint(): valid Fingerprint', function(){ - let test0 = isFingerprint(helper_params.validFingerprint); - expect(test0).to.be.true; - }); - it('isFingerprint(): invalid Fingerprint', function(){ - let test0 = isFingerprint(helper_params.invalidFingerprint); - expect(test0).to.be.false; - }); -}); -describe('Converting to Fingerprint', function(){ - it('Correct Inputs', function(){ - it('Fingerprint string', function(){ - let test0 = toKeyIdArray(helper_params.validFingerprint); - expect(test0).to.be.an('array'); - expect(test0).to.include(helper_params.validFingerprint); +function Helpertest(){ + describe('Error Object handling', function(){ + it('check the Timeout error', function(){ + let test0 = gpgme_error('CONN_TIMEOUT'); + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('CONN_TIMEOUT'); }); - it('GPGME_Key', function(){ - expect(helper_params.validGPGME_Key).to.be.an.instanceof(GPGME_Key); - let test0 = toKeyIdArray(helper_params.validGPGME_Key); - expect(test0).to.be.an('array'); - expect(test0).to.include(helper_params.validGPGME_Key.fingerprint); + it('Error Object returns generic code if code is not listed', function(){ + let test0 = gpgme_error(helper_params.invalidErrorCode); + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('GENERIC_ERROR'); }); - it('Array of valid inputs', function(){ - let test0 = toKeyIdArray(helper_params.validKeys); - expect(test0).to.be.an('array'); - expect(test0).to.have.lengthOf(helper_params.validKeys.length); + + it('Warnings like PARAM_IGNORED should not return errors', function(){ + let test0 = gpgme_error('PARAM_IGNORED'); + expect(test0).to.be.null; }); }); - describe('Incorrect inputs', function(){ - it('valid Long ID', function(){ - let test0 = toKeyIdArray(helper_params.validLongId); - expect(test0).to.be.empty; + + describe('Fingerprint checking', function(){ + it('isFingerprint(): valid Fingerprint', function(){ + let test0 = isFingerprint(helper_params.validFingerprint); + expect(test0).to.be.true; }); - it('invalidFingerprint', function(){ - let test0 = toKeyIdArray(helper_params.invalidFingerprint); - expect(test0).to.be.empty; + it('isFingerprint(): invalid Fingerprint', function(){ + let test0 = isFingerprint(helper_params.invalidFingerprint); + expect(test0).to.be.false; }); - it('invalidKeyArray', function(){ - let test0 = toKeyIdArray(helper_params.invalidKeyArray); - expect(test0).to.be.empty; + }); + describe('Converting to Fingerprint', function(){ + it('Correct Inputs', function(){ + it('Fingerprint string', function(){ + let test0 = toKeyIdArray(helper_params.validFingerprint); + expect(test0).to.be.an('array'); + expect(test0).to.include(helper_params.validFingerprint); + }); + it('GPGME_Key', function(){ + expect(helper_params.validGPGME_Key).to.be.an.instanceof(GPGME_Key); + let test0 = toKeyIdArray(helper_params.validGPGME_Key); + expect(test0).to.be.an('array'); + expect(test0).to.include(helper_params.validGPGME_Key.fingerprint); + }); + it('Array of valid inputs', function(){ + let test0 = toKeyIdArray(helper_params.validKeys); + expect(test0).to.be.an('array'); + expect(test0).to.have.lengthOf(helper_params.validKeys.length); + }); }); - it('Partially invalid array', function(){ - let test0 = toKeyIdArray(helper_params.invalidKeyArray_OneBad); - expect(test0).to.be.an('array'); - expect(test0).to.have.lengthOf( - helper_params.invalidKeyArray_OneBad.length - 1); + describe('Incorrect inputs', function(){ + it('valid Long ID', function(){ + let test0 = toKeyIdArray(helper_params.validLongId); + expect(test0).to.be.empty; + }); + it('invalidFingerprint', function(){ + let test0 = toKeyIdArray(helper_params.invalidFingerprint); + expect(test0).to.be.empty; + }); + it('invalidKeyArray', function(){ + let test0 = toKeyIdArray(helper_params.invalidKeyArray); + expect(test0).to.be.empty; + }); + it('Partially invalid array', function(){ + let test0 = toKeyIdArray(helper_params.invalidKeyArray_OneBad); + expect(test0).to.be.an('array'); + expect(test0).to.have.lengthOf( + helper_params.invalidKeyArray_OneBad.length - 1); + }); }); }); -}); +}; +export default Helpertest; \ No newline at end of file diff --git a/lang/js/test/Message.js b/lang/js/test/Message.js index 454b8ca3..44206fba 100644 --- a/lang/js/test/Message.js +++ b/lang/js/test/Message.js @@ -1,42 +1,43 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ import { expect } from "../node_modules/chai/chai"; import { GPGME_Message, createMessage } from "../src/Message"; -const message_params = { - invalid_op_action : 'dance', - invalid_op_type : [234, 34, '<>'], -} +import { message_params } from "./inputvalues"; -describe('Message Object', function(){ - describe('incorrect initialization', function(){ - it('non-allowed operation', function(){ - let test0 = createMessage(message_params.invalid_op_action); - expect(test0).to.be.an.instanceof(Error); - expect(test0.code).to.equal('MSG_WRONG_OP'); - }); - it('wrong parameter type in constructor', function(){ - let test0 = createMessage(message_params.invalid_op_type); - expect(test0).to.be.an.instanceof(Error); - expect(test0.code).to.equal('PARAM_WRONG'); +function Messagetest(){ + + describe('Message Object', function(){ + describe('incorrect initialization', function(){ + it('non-allowed operation', function(){ + let test0 = createMessage(message_params.invalid_op_action); + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('MSG_WRONG_OP'); + }); + it('wrong parameter type in constructor', function(){ + let test0 = createMessage(message_params.invalid_op_type); + expect(test0).to.be.an.instanceof(Error); + expect(test0.code).to.equal('PARAM_WRONG'); + }); }); }); -}); +}; +export default Messagetest; \ No newline at end of file diff --git a/lang/js/test/inputvalues.js b/lang/js/test/inputvalues.js new file mode 100644 index 00000000..a50c8162 --- /dev/null +++ b/lang/js/test/inputvalues.js @@ -0,0 +1,29 @@ + +import {GPGME_Key} from "../src/Key" + +export const helper_params = { + validLongId: '0A0A0A0A0A0A0A0A', + validGPGME_Key: new GPGME_Key('ADDBC303B6D31026F5EB4591A27EABDF283121BB'), + validKeys: [new GPGME_Key('A1E3BC45BDC8E87B74F4392D53B151A1368E50F3'), + 'ADDBC303B6D31026F5EB4591A27EABDF283121BB', + new GPGME_Key('EE17AEE730F88F1DE7713C54BBE0A4FF7851650A')], + validFingerprint: '9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A9A9A7A7A8A', + invalidLongId: '9A9A7A7A8A9A9A7A7A8A', + invalidFingerprint: [{hello:'World'}], + invalidKeyArray: {curiosity:'uncat'}, + invalidKeyArray_OneBad: [ + new GPGME_Key('12AE9F3E41B33BF77DF52B6BE8EE1992D7909B08'), + 'E1D18E6E994FA9FE9360Bx0E687B940FEFEB095A', + '3AEA7FE4F5F416ED18CEC63DD519450D9C0FAEE5'], + invalidErrorCode: 'Please type in all your passwords.' +} + +export const message_params = { + invalid_op_action : 'dance', + invalid_op_type : [234, 34, '<>'], +} + +export default { + helper_params: helper_params, + message_params: message_params +} \ No newline at end of file diff --git a/lang/js/webpack.conf.js b/lang/js/webpack.conf.js index 7a5392ee..b2ad9098 100644 --- a/lang/js/webpack.conf.js +++ b/lang/js/webpack.conf.js @@ -1,35 +1,35 @@ /* gpgme.js - Javascript integration for gpgme * Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * GPGME is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ * * This is the configuration file for building the gpgmejs-Library with webpack */ const path = require('path'); module.exports = { entry: './src/index.js', // mode: 'development', mode: 'production', output: { - path: path.resolve(__dirname, 'dist'), + path: path.resolve(__dirname, 'build'), filename: 'gpgmejs.bundle.js', libraryTarget: 'var', libraryExport: 'default', library: 'Gpgmejs' } };