From 411039abebbb37406773348ff19070c9ca1b349c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 27 Jun 2024 16:26:57 +0200 Subject: [PATCH 1/4] Add support for a serverside crypto plugin --- lib/crypto.js | 24 ++++++++++++++++ lib/workers/db-worker.js | 11 ++++++-- scripts/testcrypto.js | 61 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 lib/crypto.js create mode 100644 scripts/testcrypto.js diff --git a/lib/crypto.js b/lib/crypto.js new file mode 100644 index 000000000..9219f7c5f --- /dev/null +++ b/lib/crypto.js @@ -0,0 +1,24 @@ +const Nacl = require('tweetnacl/nacl-fast'); +const CPCrypto = module.exports; +const plugins = require('./plugin-manager'); + +CPCrypto.init = (cb) => { + const crypto = {}; + crypto.open = (signedMsg, validateKey) => { + return Nacl.sign.open(signedMsg, validateKey); + }; + crypto.detachedVerify = (signedBuffer, signatureBuffer, validateKey) => { + return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); + }; + if (plugins.SODIUM && plugins.SODIUM.crypto) { + let c = plugins.SODIUM.crypto; + if (c.open) { crypto.open = c.open; } + if (c.detachedVerify) { crypto.detachedVerify = c.detachedVerify; } + } + + // Make async because we might need it later with libsodium's promise + // libsodium.ready.then(() => {}); + setTimeout(() => { + cb(void 0, crypto); + }); +}; diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 63b2a8497..398260d61 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -16,6 +16,7 @@ const Logger = require("../log"); const Tasks = require("../storage/tasks"); const Nacl = require('tweetnacl/nacl-fast'); const Eviction = require("../eviction"); +const CPCrypto = require('../crypto'); const Env = { Log: {}, @@ -101,6 +102,10 @@ const init = function (config, _cb) { } Env.tasks = tasks; })); + }).nThen(function (w) { + CPCrypto.init(w(function (err, crypto) { + Env.crypto = crypto; + })); }).nThen(function () { cb(); }); @@ -680,7 +685,8 @@ COMMANDS.INLINE = function (data, cb) { return void cb("E_BADKEY"); } // validate the message - const validated = Nacl.sign.open(signedMsg, validateKey); + //const validated = Nacl.sign.open(signedMsg, validateKey); + const validated = Env.crypto.open(signedMsg, validateKey); if (!validated) { return void cb("FAILED"); } @@ -720,7 +726,8 @@ const checkDetachedSignature = function (signedMsg, signature, publicKey) { throw new Error("INVALID_SIGNATURE_LENGTH"); } - if (Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer) !== true) { + //if (Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer) !== true) { + if (Env.crypto.detachedVerify(signedBuffer, signatureBuffer, pubBuffer) !== true) { throw new Error("FAILED"); } }; diff --git a/scripts/testcrypto.js b/scripts/testcrypto.js new file mode 100644 index 000000000..893ab6ec8 --- /dev/null +++ b/scripts/testcrypto.js @@ -0,0 +1,61 @@ +let SodiumNative = require('sodium-native'); +let Nacl = require('tweetnacl/nacl-fast'); +let LibSodium = require('libsodium-wrappers'); + + +let msgStr = "This is a test"; +let keys = Nacl.sign.keyPair(); +let pub = keys.publicKey; + +let msg = Nacl.util.decodeUTF8(msgStr); +let signedMsg = Nacl.sign(msg, keys.secretKey); +let sig = signedMsg.subarray(0, 64); + +LibSodium.ready.then(() => { + +/* +console.log('tweetnacl open'); +console.log(!!Nacl.sign.open(signedMsg, pub)); +console.log('tweetnacl detached'); +console.log(Nacl.sign.detached.verify(msg, sig, pub)); +console.log('sodium-native open'); +console.log(SodiumNative.crypto_sign_open(msg, signedMsg, pub)); +console.log('sodium-native detached'); +console.log(SodiumNative.crypto_sign_verify_detached(sig, msg, pub)); +LibSodium.ready.then(() => { +console.log('libsodium open'); +console.log(!!LibSodium.crypto_sign_open(signedMsg, pub)); +console.log('libsodium detached'); +console.log(LibSodium.crypto_sign_verify_detached(sig, msg, pub)); +}); +*/ + + const n = 10000; + let a; + + console.log('start sodium-native'); + a = +new Date(); + for (var i = 0; i < n; i++) { + SodiumNative.crypto_sign_open(msg, signedMsg, pub); + SodiumNative.crypto_sign_verify_detached(sig, msg, pub); + } + console.log('end sodium-native ', (+new Date() - a), ' ms'); + + console.log('start libsodium'); + a = +new Date(); + for (var i = 0; i < n; i++) { + LibSodium.crypto_sign_open(signedMsg, pub); + LibSodium.crypto_sign_verify_detached(sig, msg, pub); + } + console.log('end libsodium ', (+new Date() - a), ' ms'); + + console.log('start tweetnacl'); + a = +new Date(); + for (var i = 0; i < n; i++) { + Nacl.sign.open(signedMsg, pub); + Nacl.sign.detached.verify(msg, sig, pub); + } + + console.log('end tweetnacl ', (+new Date() - a), ' ms'); +}); + From 8c11b8c4c645da78af37b4ee1054d50fb23af68e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jul 2024 11:08:44 +0200 Subject: [PATCH 2/4] lint compliance --- lib/crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crypto.js b/lib/crypto.js index 9219f7c5f..7cac2f33d 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -8,7 +8,7 @@ CPCrypto.init = (cb) => { return Nacl.sign.open(signedMsg, validateKey); }; crypto.detachedVerify = (signedBuffer, signatureBuffer, validateKey) => { - return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); + return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, validateKey); }; if (plugins.SODIUM && plugins.SODIUM.crypto) { let c = plugins.SODIUM.crypto; From a266770e253376ce45465872f289b53e2d0e2b7f Mon Sep 17 00:00:00 2001 From: Wolfgang Ginolas Date: Mon, 30 Sep 2024 11:10:44 +0200 Subject: [PATCH 3/4] Ignore unknown fields in diagram document https://github.com/cryptpad/cryptpad/issues/1665 --- www/diagram/export.js | 9 ++------- www/diagram/inner.js | 6 ++---- www/diagram/util.js | 14 +++++++++++++- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/www/diagram/export.js b/www/diagram/export.js index 79f9c7be7..09e5da30b 100644 --- a/www/diagram/export.js +++ b/www/diagram/export.js @@ -3,15 +3,10 @@ // SPDX-License-Identifier: AGPL-3.0-or-later define([ - '/components/x2js/x2js.js', '/diagram/util.js', ], function ( - X2JS, DiagramUtil ) { - const x2js = new X2JS(); - const jsonContentAsXML = (content) => x2js.js2xml(content); - const parseDrawioStyle = (styleAttrValue) => { if (!styleAttrValue) { return; @@ -70,12 +65,12 @@ define([ } return doc; }; - + return { main: function(userDoc, cb) { delete userDoc.metadata; - const xml = jsonContentAsXML(userDoc); + const xml = DiagramUtil.jsonContentAsXML(userDoc); let doc; try { diff --git a/www/diagram/inner.js b/www/diagram/inner.js index 5030bf491..b6176c1cf 100644 --- a/www/diagram/inner.js +++ b/www/diagram/inner.js @@ -95,11 +95,9 @@ define([ drawioFrame.contentWindow.postMessage(JSON.stringify(msg), '*'); }; - const jsonContentAsXML = (content) => x2js.js2xml(content); - var onDrawioInit = function() { drawIoInitalized = true; - var xmlStr = jsonContentAsXML(lastContent); + var xmlStr = DiagramUtil.jsonContentAsXML(lastContent); postMessageToDrawio({ action: 'load', xml: xmlStr, @@ -165,7 +163,7 @@ define([ // This is the function from which you will receive updates from CryptPad framework.onContentUpdate(function (newContent) { lastContent = newContent; - var xmlStr = jsonContentAsXML(lastContent); + var xmlStr = DiagramUtil.jsonContentAsXML(lastContent); postMessageToDrawio({ action: 'merge', xml: xmlStr, diff --git a/www/diagram/util.js b/www/diagram/util.js index c56562236..72acda93a 100644 --- a/www/diagram/util.js +++ b/www/diagram/util.js @@ -6,12 +6,15 @@ define([ '/common/common-util.js', '/file/file-crypto.js', '/common/outer/cache-store.js', + '/components/x2js/x2js.js', ], function ( Util, FileCrypto, - Cache + Cache, + X2JS, ) { const Nacl = window.nacl; + const x2js = new X2JS(); const parseCryptPadUrl = function(href) { const url = new URL(href); @@ -38,9 +41,18 @@ define([ return fixedBlob; }; + const jsonContentAsXML = (content) => { + + // Sometimes `content` has additional fiels, that break the XML output. Only grab mxfile here. + const cleaned = { mxfile: content.mxfile }; + + return x2js.js2xml(cleaned); + }; + return { parseCryptPadUrl, getCryptPadUrl, + jsonContentAsXML, loadImage: function(href) { return new Promise((resolve, reject) => { From 5d887b53a9fd59a487edbf5a16466e41fa167bd6 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 30 Sep 2024 17:42:45 +0200 Subject: [PATCH 4/4] Add missing licenses --- lib/crypto.js | 4 ++++ scripts/testcrypto.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/crypto.js b/lib/crypto.js index 7cac2f33d..2d8e5862c 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + const Nacl = require('tweetnacl/nacl-fast'); const CPCrypto = module.exports; const plugins = require('./plugin-manager'); diff --git a/scripts/testcrypto.js b/scripts/testcrypto.js index 893ab6ec8..0ee9d0fb7 100644 --- a/scripts/testcrypto.js +++ b/scripts/testcrypto.js @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + let SodiumNative = require('sodium-native'); let Nacl = require('tweetnacl/nacl-fast'); let LibSodium = require('libsodium-wrappers');