diff --git a/lib/commands/invitation.js b/lib/commands/invitation.js index 2624389e7..337e56bec 100644 --- a/lib/commands/invitation.js +++ b/lib/commands/invitation.js @@ -7,9 +7,10 @@ const Invitation = module.exports; const Invite = require('../storage/invite'); const Util = require("../common-util"); const Users = require("./users"); +const Crypto = require('node:crypto'); const getUid = () => { - return Util.uid() + Util.uid() + Util.uid(); + return Crypto.randomBytes(18).toString('hex'); }; Invitation.getAll = (Env, cb) => { diff --git a/lib/http-commands.js b/lib/http-commands.js index 2d2ad7436..d577940af 100644 --- a/lib/http-commands.js +++ b/lib/http-commands.js @@ -129,7 +129,7 @@ var handleCommand = function (Env, req, res) { COMMANDS[command](Env, body, function (err) { if (err) { Env.Log.error('CHALLENGE_COMMAND_EXECUTION_ERROR', { - body: body, + command, error: Util.serializeError(err), }); // errors returned from commands are passed back to the client @@ -229,16 +229,6 @@ var handleResponse = function (Env, req, res) { }); } - // garbage collection can clean this up later - Challenge.delete(Env, txid, function (err) { - if (err) { - Env.Log.error("CHALLENGE_DELETION_ERROR", { - txid: txid, - error: Util.serializeError(err), - }); - } - }); - var json = Util.tryParse(text); if (!json) { @@ -284,8 +274,7 @@ var handleResponse = function (Env, req, res) { u8_publicKey = Util.decodeBase64(publicKey); } catch (err3) { Env.Log.error('CHALLENGE_RESPONSE_DECODING_ERROR', { - text: text, - sig: sig, + command: json.command, publicKey: publicKey, error: Util.serializeError(err3), }); @@ -305,6 +294,16 @@ var handleResponse = function (Env, req, res) { }); } + // garbage collection can clean this up later + Challenge.delete(Env, txid, function (err) { + if (err) { + Env.Log.error("CHALLENGE_DELETION_ERROR", { + txid: txid, + error: Util.serializeError(err), + }); + } + }); + // execute the command action(Env, json, function (err, content) { if (err) { diff --git a/lib/http-worker.js b/lib/http-worker.js index b1768016f..03dac79c7 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -258,7 +258,7 @@ app.use('/ssoauth', (req, res, next) => { Log.error('E_SSO_WRITE_REQ', err); return res.sendStatus(500); } - let value = `samltoken="${token}"; SameSite=Strict; HttpOnly`; + let value = `samltoken="${token}"; SameSite=Strict; HttpOnly; Path=/; Secure`; res.setHeader('Set-Cookie', value); next(); }); @@ -750,22 +750,6 @@ var send500 = function (res, path) { }); }; -app.get('/api/updatequota', function (req, res) { - if (!Env.accounts_api) { - res.status(404); - return void send404(res); - } - sendMessage({ - command: 'UPDATE_QUOTA', - }, (err) => { - if (err) { - res.status(500); - return void send500(res); - } - res.send(); - }); -}); - app.get('/api/profiling', function (req, res) { if (!Env.enableProfiling) { return void send404(res); } sendMessage({ diff --git a/lib/storage/basic.js b/lib/storage/basic.js index 96e353e76..667c6498b 100644 --- a/lib/storage/basic.js +++ b/lib/storage/basic.js @@ -89,3 +89,7 @@ Basic.restore = function (Env, archivePath, path, cb) { cb(err); }); }; + +Basic.isValidId = id => { + return id && typeof(id) === "string" && /^[a-zA-Z0-9-+=]+$/.test(id); +}; diff --git a/lib/storage/challenge.js b/lib/storage/challenge.js index 914284e00..8217f5c5e 100644 --- a/lib/storage/challenge.js +++ b/lib/storage/challenge.js @@ -22,7 +22,9 @@ const Challenge = module.exports; */ const pathFromId = function (Env, id) { - if (!id || typeof(id) !== 'string') { return void console.error('CHALLENGE_BAD_ID', id); } + if (!Basic.isValidId(id)) { + return void console.error('CHALLENGE_BAD_ID', id); + } return Path.join(Env.paths.base, "challenges", id.slice(0, 2), id); }; diff --git a/lib/storage/invite.js b/lib/storage/invite.js index 90220eb94..2ef2c4316 100644 --- a/lib/storage/invite.js +++ b/lib/storage/invite.js @@ -17,7 +17,9 @@ const Invite = module.exports; */ const pathFromId = function (Env, id) { - if (!id || typeof(id) !== 'string') { return void console.error('INVITE_BAD_ID', id); } + if (!Basic.isValidId(id)) { + return void console.error('INVITE_BAD_ID', id); + } return Path.join(Env.paths.base, "invitations", id.slice(0, 2), id); }; diff --git a/lib/storage/mfa.js b/lib/storage/mfa.js index d84539f69..572dc3c28 100644 --- a/lib/storage/mfa.js +++ b/lib/storage/mfa.js @@ -28,6 +28,7 @@ so that it can be accessed quickly. var pathFromId = function (Env, id) { if (!id || typeof(id) !== 'string') { return; } id = Util.escapeKeyCharacters(id); + if (!Basic.isValidId(id)) { return; } return Path.join(Env.paths.base, "mfa", id.slice(0, 2), `${id}.json`); }; diff --git a/lib/storage/moderator.js b/lib/storage/moderator.js index b889497c1..6ae0b214e 100644 --- a/lib/storage/moderator.js +++ b/lib/storage/moderator.js @@ -14,7 +14,9 @@ const Moderator = module.exports; */ const pathFromId = function (Env, id) { - if (!id || typeof(id) !== 'string') { return void console.error('KNWONUSER_BAD_ID', id); } + if (!Basic.isValidId(id)) { + return void console.error('MODERATOR_BAD_ID', id); + } return Path.join(Env.paths.base, "support", id.slice(0, 2), id); }; diff --git a/lib/storage/sessions.js b/lib/storage/sessions.js index 85ac3c1b1..f2deacec3 100644 --- a/lib/storage/sessions.js +++ b/lib/storage/sessions.js @@ -25,6 +25,7 @@ const Sessions = module.exports; var pathFromId = function (Env, id, ref) { if (!id || typeof(id) !== 'string') { return; } + if (!Basic.isValidId(ref)) { return; } id = Util.escapeKeyCharacters(id); return Path.join(Env.paths.base, "sessions", id.slice(0, 2), id, ref); }; diff --git a/lib/storage/sso.js b/lib/storage/sso.js index ba9de3b6a..a2bda171f 100644 --- a/lib/storage/sso.js +++ b/lib/storage/sso.js @@ -20,6 +20,7 @@ The path for the user database is based on their persistent identifier (id) from var pathFromId = function (Env, id, subPath) { if (!id || typeof(id) !== 'string') { return; } id = Util.escapeKeyCharacters(id); + if (!Basic.isValidId(id)) { return; } return Path.join(Env.paths.base, subPath, id.slice(0, 2), `${id}.json`); }; var reqPathFromId = function (Env, id) { diff --git a/lib/storage/user.js b/lib/storage/user.js index a1dc4a15a..659541d54 100644 --- a/lib/storage/user.js +++ b/lib/storage/user.js @@ -14,7 +14,9 @@ const User = module.exports; */ const pathFromId = function (Env, id) { - if (!id || typeof(id) !== 'string') { return void console.error('KNWONUSER_BAD_ID', id); } + if (!Basic.isValidId(id)) { + return void console.error('USER_BAD_ID', id); + } return Path.join(Env.paths.base, "users", id.slice(0, 2), id); }; diff --git a/package-lock.json b/package-lock.json index c2b8bcd43..39339e1c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "chainpad-crypto": "^0.3.0", "chainpad-listmap": "^1.2.0", "chainpad-netflux": "^1.3.0", - "chainpad-server": "^5.2.4", + "chainpad-server": "^5.3.0", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "connect-gzip-static": "^4.2.1", @@ -1598,7 +1598,9 @@ } }, "node_modules/chainpad-server": { - "version": "5.2.4" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.3.1.tgz", + "integrity": "sha512-yDDsN0Oa8ojtNNJRBpqy/AwnRWkettJfGxUxRGZmMf+bbbiKTPWum8ixP9l8UzErTlYR4wzaTZIKmNpWWcyOtg==" }, "node_modules/ckeditor": { "name": "ckeditor4", @@ -3537,7 +3539,9 @@ } }, "node_modules/netflux-websocket": { - "version": "1.3.0", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-1.3.1.tgz", + "integrity": "sha512-vom3V+3oXf6dnT6UkCkpi76zZLGYNXTaWA0Azg/CsIfMHP66owYynkOFXoZ8N2gaQNoEWMT6msz9xjSOnAH0cw==", "license": "LGPL-2.1" }, "node_modules/node-releases": { diff --git a/package.json b/package.json index be71fef22..7a72e7b69 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "chainpad-crypto": "^0.3.0", "chainpad-listmap": "^1.2.0", "chainpad-netflux": "^1.3.0", - "chainpad-server": "^5.2.4", + "chainpad-server": "^5.3.0", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "connect-gzip-static": "^4.2.1", diff --git a/src/common/cryptget.js b/src/common/cryptget.js index 3d4b60921..d73a7e3ef 100644 --- a/src/common/cryptget.js +++ b/src/common/cryptget.js @@ -61,7 +61,6 @@ const factory = (Crypto, CPNetflux, Netflux, Util, nThen(function (waitFor) { Session.accessKeys.forEach(function (obj) { Pinpad.create(config.network, obj, waitFor(function (e) { - console.log('done', obj); if (e) { console.error(e); } })); }); diff --git a/src/worker/core/interface.js b/src/worker/core/interface.js index 5d921861a..1d7cde100 100644 --- a/src/worker/core/interface.js +++ b/src/worker/core/interface.js @@ -62,7 +62,7 @@ const factory = (SRpc, Channel, Util) => { } catch (e) { console.error('Error in webworker when executing query ' + q); console.error(e); - console.log(data); + //console.log(data); } if (q === "DISCONNECT") { onClose(); @@ -99,7 +99,7 @@ const factory = (SRpc, Channel, Util) => { } catch (e) { console.error('Error in webworker when executing query JOIN_PAD'); console.error(e); - console.log(data); + //console.log(data); } }); chan.on('SEND_PAD_MSG', function (msg, cb) { @@ -112,7 +112,7 @@ const factory = (SRpc, Channel, Util) => { } catch (e) { console.error('Error in webworker when executing query SEND_PAD_MSG'); console.error(e); - console.log(data); + //console.log(data); } }); diff --git a/src/worker/modules/messenger.js b/src/worker/modules/messenger.js index ad55143a7..6b6af904a 100644 --- a/src/worker/modules/messenger.js +++ b/src/worker/modules/messenger.js @@ -116,7 +116,6 @@ const factory = (Crypto, Hash, Util, Realtime, Messaging, var getChannelMessagesSince = function (ctx, channel, data, keys) { var network = ctx.store.network; - console.log('Fetching [%s] messages since [%s]', channel.id, data.lastKnownHash || ''); if (channel.isPadChat || channel.isTeamChat) { // We need to use GET_HISTORY_RANGE to make sure we won't get the full history diff --git a/src/worker/modules/profile.js b/src/worker/modules/profile.js index e9c14b8b7..fe085d161 100644 --- a/src/worker/modules/profile.js +++ b/src/worker/modules/profile.js @@ -170,7 +170,6 @@ const factory = (Util, Hash, Constants, Realtime, ctx.emit('UPDATE', ctx.listmap.proxy, ctx.clients); }; profile.execCommand = function (clientId, obj, cb) { - console.log(obj); var cmd = obj.cmd; var data = obj.data; if (cmd === 'SUBSCRIBE') { diff --git a/www/common/common-login.js b/www/common/common-login.js index 141e25621..48f48da54 100644 --- a/www/common/common-login.js +++ b/www/common/common-login.js @@ -213,7 +213,6 @@ define([ opt.channelHex = secret.channel; } - console.warn(opt); return opt; }; diff --git a/www/common/media-tag.js b/www/common/media-tag.js index a50c22267..29eafdffd 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -120,6 +120,7 @@ var factory = function (Util) { var iframe = document.createElement('iframe'); if (cfg.pdf.viewer) { // PDFJS var viewerUrl = cfg.pdf.viewer + '?file=' + url; + iframe.setAttribute('sandbox', 'allow-scripts allow-downloads allow-same-origin'); iframe.src = viewerUrl + '#' + window.encodeURIComponent(metadata.name); iframe.onload = function () { if (!metadata.name) { return; } @@ -574,7 +575,11 @@ var factory = function (Util) { var copyAttributes = function (origin, dest) { Object.keys(origin.attributes).forEach(function (i) { if (!/^data-attr/.test(origin.attributes[i].name)) { return; } - var name = origin.attributes[i].name.slice(10); + var name = origin.attributes[i].name.slice(10).toLowerCase(); + // Ignore attributes filtered out by the sanitizer + if (name === "src") { return; } + if (name === "srcdoc") { return; } + if (/^on/i.test(name)) { return; } var value = origin.attributes[i].value; dest.setAttribute(name, value); }); diff --git a/www/cryptpad-api.js b/www/cryptpad-api.js index 7dfbffa71..a5a059760 100644 --- a/www/cryptpad-api.js +++ b/www/cryptpad-api.js @@ -5,6 +5,8 @@ (function () { 'use strict'; var factory = function (/*Hash*/) { + let devMode = false; + try { devMode = localStorage.CryptPad_dev === "1"; } catch (e) {} // This API is used to load a CryptPad editor for a provided document in // an external platform. @@ -48,7 +50,7 @@ var msg = data.msg; var txid = data.txid; if (commands[msg.q]) { - console.warn('OUTER RECEIVED QUERY', msg.q, msg.data); + if (devMode) { console.warn('OUTER RECEIVED QUERY', msg.q, msg.data); } commands[msg.q](msg.data, function (args) { _sendCb(txid, args); }); @@ -62,7 +64,7 @@ var txid = getTxid(); if (cb) { handlers[txid] = cb; } - console.warn('OUTER SENT QUERY', q, data); + if (devMode) { console.warn('OUTER SENT QUERY', q, data); } iWindow.postMessage({ msg: { q: q, data: data, diff --git a/www/integration/main.js b/www/integration/main.js index e8c49bbdc..f5d31daa7 100644 --- a/www/integration/main.js +++ b/www/integration/main.js @@ -14,7 +14,10 @@ define([ return Math.random().toString(16).replace('0.', ''); }; var init = function () { - console.warn('INIT'); + let devMode = false; + try { devMode = localStorage.CryptPad_dev === "1"; } catch (e) {} + if (devMode) { console.warn('INIT'); } + var p = window.parent; var txid = getTxid(); p.postMessage({ q: 'INTEGRATION_READY', txid: txid }, '*'); @@ -86,7 +89,7 @@ define([ http.open('HEAD', url); http.onreadystatechange = function() { if (this.readyState === this.DONE) { - console.error(oldKey, this.status); + if (devMode) { console.error(oldKey, this.status); } if (this.status === 200) { return cb({state: true}); } @@ -150,7 +153,7 @@ define([ } if (data.keepOld) { // they provide their own key, we must turn it into a hash var key = sanitizeKey(data.key) + "000000000000000000000000000000000"; - console.warn('KEY', key); + if (devMode) { console.warn('KEY', key); } let hash = `/2/integration/edit/${key.slice(0,24)}/`; return void cb({ key: hash, @@ -265,7 +268,7 @@ define([ xhr.responseType = 'blob'; //xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function () { - console.error(this.status); + if (devMode) { console.error(this.status); } if (this.status === 200) { cb(); } else { @@ -278,7 +281,7 @@ define([ xhr.send(blob); }; chan.on('START', function (data, cb) { - console.warn('INNER START', data); + if (devMode) { console.warn('INNER START', data); } // data.key is a hash var href = Hash.hashToHref(data.key, data.application); if (data.editorConfig.lang) { @@ -303,7 +306,7 @@ define([ }); }; - console.error(Hash.hrefToHexChannelId(href)); + if (devMode) { console.error(Hash.hrefToHexChannelId(href)); } let startApp = function (blob) { window.CP_integration_outer = { pathname: `/${data.application}/`, @@ -336,7 +339,6 @@ define([ path = '/common/onlyoffice/main.js'; } require([path], function () { - console.warn('SAO REQUIRED'); delete window.CP_integration_outer; cb(); });