diff --git a/docs/example-advanced.nginx.conf b/docs/example-advanced.nginx.conf index cb827b4b0..c59cf2273 100644 --- a/docs/example-advanced.nginx.conf +++ b/docs/example-advanced.nginx.conf @@ -166,11 +166,6 @@ server { # We've applied other sandboxing techniques to mitigate the risk of running WebAssembly in this privileged scope if ($uri ~ ^\/unsafeiframe\/inner\.html.*$) { set $unsafe 1; } - # draw.io uses inline script tags in it's index.html. The hashes are added here. - if ($uri ~ ^\/components\/drawio\/src\/main\/webapp\/index.html.*$) { - set $scriptSrc "'self' 'sha256-dLMFD7ijAw6AVaqecS7kbPcFFzkxQ+yeZSsKpOdLxps=' 'sha256-6g514VrT/cZFZltSaKxIVNFF46+MFaTSDTPB8WfYK+c=' resource: https://${main_domain}"; - } - # privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied if ($unsafe) { set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: https://${main_domain}"; diff --git a/lib/defaults.js b/lib/defaults.js index b34c6e4e1..3d342a659 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -52,10 +52,6 @@ Default.padContentSecurity = function (Env) { return (Default.commonCSP(Env).join('; ') + "script-src 'self' 'unsafe-eval' 'unsafe-inline' resource: " + Env.httpUnsafeOrigin).replace(/\s+/g, ' '); }; -Default.diagramContentSecurity = function (Env) { - return (Default.commonCSP(Env).join('; ') + "script-src 'self' 'sha256-dLMFD7ijAw6AVaqecS7kbPcFFzkxQ+yeZSsKpOdLxps=' 'sha256-6g514VrT/cZFZltSaKxIVNFF46+MFaTSDTPB8WfYK+c=' resource: " + Env.httpUnsafeOrigin).replace(/\s+/g, ' '); -}; - Default.httpHeaders = function (Env) { return { "X-XSS-Protection": "1; mode=block", diff --git a/lib/http-worker.js b/lib/http-worker.js index 185ae748e..f5b4040ce 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -134,8 +134,6 @@ var getHeaders = function (Env, type) { var csp; if (type === 'office') { csp = Default.padContentSecurity(Env); - } else if (type === 'diagram') { - csp = Default.diagramContentSecurity(Env); } else { csp = Default.contentSecurity(Env); } @@ -158,8 +156,6 @@ var setHeaders = function (req, res) { type = 'office'; } else if (/^\/api\/(broadcast|config)/.test(req.url)) { type = 'api'; - } else if (/^\/components\/drawio\/src\/main\/webapp\/index.html.*$/.test(req.url)) { - type = 'diagram'; } else { type = 'standard'; } diff --git a/package-lock.json b/package-lock.json index 2476d1545..19db91c09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "cookie-parser": "^1.4.6", "croppie": "^2.5.0", "dragula": "3.7.2", - "drawio": "cryptpad/drawio-npm#npm", + "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+4", "express": "~4.18.2", "file-saver": "1.3.1", "fs-extra": "^7.0.0", @@ -204,9 +204,9 @@ "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==" }, "node_modules/@types/http-proxy": { - "version": "1.17.12", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.12.tgz", - "integrity": "sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dependencies": { "@types/node": "*" } @@ -228,9 +228,12 @@ "integrity": "sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ==" }, "node_modules/@types/node": { - "version": "20.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.3.tgz", - "integrity": "sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==" + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/passport": { "version": "1.0.14", @@ -962,12 +965,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1115,66 +1119,17 @@ "node": ">=0.10.0" } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/cli": { @@ -1205,9 +1160,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.15", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.15.tgz", - "integrity": "sha512-YC4EHbbwQeubZzxLl5G4nlbLc1T21QTrKGaOal/Pkm9dVDMZXMH7+ieSPEOZCtO9I68i8/oteJKOxzHC2zR+0g==" + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" }, "node_modules/collection-visit": { "version": "1.0.0", @@ -1228,9 +1183,12 @@ "dev": true }, "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/components-font-awesome": { "version": "4.7.0", @@ -1411,6 +1369,19 @@ "node": ">=0.10" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", @@ -1534,9 +1505,8 @@ } }, "node_modules/drawio": { - "name": "drawio-cp", - "version": "21.7.5", - "resolved": "git+ssh://git@github.com/cryptpad/drawio-npm.git#b430ab78be9944f19721c3489c9ce95bc1abe2ca" + "version": "21.8.2+4", + "resolved": "git+ssh://git@github.com/cryptpad/drawio-npm.git#5555df31ce3a1c6220cefa3aaa16b9a7880bf8b8" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", @@ -1651,66 +1621,17 @@ "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/express": { @@ -2113,9 +2034,12 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gar": { "version": "1.0.4", @@ -2135,14 +2059,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2241,20 +2165,31 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz", "integrity": "sha512-zGRpnr2l5w/s8PxkrquUJoVeR06KvqPelrYqiSyQV7QEBqCYivpb6UzXYWC6JDBVtNFOT0rzJRFhkfJgxzmILA==" }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dependencies": { - "function-bind": "^1.1.1" + "get-intrinsic": "^1.2.2" }, - "engines": { - "node": ">= 0.4.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { @@ -2342,6 +2277,17 @@ "node": ">=0.10.0" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", @@ -2499,22 +2445,14 @@ } }, "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dependencies": { - "kind-of": "^6.0.0" + "hasown": "^2.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, "node_modules/is-arrayish": { @@ -2529,43 +2467,26 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "dependencies": { - "kind-of": "^6.0.0" + "hasown": "^2.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/is-directory": { @@ -3363,47 +3284,16 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/object-copy/node_modules/kind-of": { @@ -3426,9 +3316,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4210,6 +4100,20 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-getter": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", @@ -4351,66 +4255,17 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/snapdragon/node_modules/source-map": { @@ -4423,9 +4278,9 @@ } }, "node_modules/sortablejs": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", - "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.1.tgz", + "integrity": "sha512-P5Cjvb0UG1ZVNiDPj/n4V+DinttXG6K8n7vM/HQf0C25K3YKQTQY6fsr/sEGsJGpQ9exmPxluHxKBc0mLKU1lQ==" }, "node_modules/sortify": { "version": "1.0.4", @@ -4531,61 +4386,16 @@ "node": ">=0.10.0" } }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, "node_modules/statuses": { @@ -4859,6 +4669,11 @@ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/package.json b/package.json index 0c1cb79e1..3bb8fd661 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "requirejs-plugins": "^1.0.2", "scrypt-async": "1.2.0", "sortablejs": "^1.6.0", - "drawio": "cryptpad/drawio-npm#npm", + "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+4", "pako": "^2.1.0", "x2js": "^3.4.4" }, diff --git a/scripts/copy-components.js b/scripts/copy-components.js index d3cb06618..bba138518 100644 --- a/scripts/copy-components.js +++ b/scripts/copy-components.js @@ -50,5 +50,6 @@ Fse.rmSync(oldComponentsPath, { recursive: true, force: true }); ].forEach(l => { const source = Path.join("node_modules", l); const destination = Path.join(componentsPath, l); + Fs.rmSync(destination, { recursive: true, force: true }); Fs.cpSync(source, destination, { recursive: true }); }); diff --git a/www/common/inner/image-dialog.js b/www/common/inner/image-dialog.js new file mode 100644 index 000000000..31de9b6a5 --- /dev/null +++ b/www/common/inner/image-dialog.js @@ -0,0 +1,23 @@ +define([], function() { + + const openImageDialog = function(common, integrationChannel, data, cb) { + if (integrationChannel) { + const handleImage = (_, image) => { + cb(image); + }; + integrationChannel.query('Q_INTEGRATION_ON_INSERT_IMAGE', data, handleImage, {raw: true}); + return; + } + common.openFilePicker({ + types: ['file'], + where: ['root'], + filter: { + fileType: ['image/'] + } + }, cb); + }; + + return { + openImageDialog, + }; +}); diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 05590ce47..9945d8138 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -88,6 +88,7 @@ define([ var state = STATE.DISCONNECTED; var firstConnection = true; var integration; + let integrationChannel; var toolbarContainer = options.toolbarContainer || (function () { throw new Error("toolbarContainer must be specified"); }()); @@ -623,12 +624,12 @@ define([ if (privateDat.integration) { common.openIntegrationChannel(onLocal); - var sframeChan = common.getSframeChannel(); + integrationChannel = common.getSframeChannel(); var integrationSave = function (cb) { var ext = privateDat.integrationConfig.fileType; var upload = Util.once(function (_blob) { - sframeChan.query('Q_INTEGRATION_SAVE', { + integrationChannel.query('Q_INTEGRATION_SAVE', { blob: _blob }, cb, { raw: true @@ -645,7 +646,7 @@ define([ } }; const integrationHasUnsavedChanges = function(unsavedChanges, cb) { - sframeChan.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb); + integrationChannel.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb); }; var inte = common.createIntegration(onLocal, cpNfInner.chainpad, integrationSave, integrationHasUnsavedChanges); @@ -656,7 +657,7 @@ define([ }); } if (firstConnection) { - sframeChan.on('Q_INTEGRATION_NEEDSAVE', function (data, cb) { + integrationChannel.on('Q_INTEGRATION_NEEDSAVE', function (data, cb) { integrationSave(function (obj) { if (obj && obj.error) { console.error(obj.error); } cb(); @@ -1124,9 +1125,18 @@ define([ // Call this after all of the handlers are setup. start: evStart.fire, + // Call this, when the user wants to add an image from drive. + insertImage: function(data, cb) { + require(['/common/inner/image-dialog.js'], function(imageDialog) { + imageDialog.openImageDialog(common, integrationChannel, data, cb); + }); + }, + // Determine the internal state of the framework. getState: function () { return state; }, + isIntegrated: function() { return cpNfInner.metadataMgr.getPrivateData().integration; }, + // Internals _: { sfCommon: common, diff --git a/www/common/sframe-common-file.js b/www/common/sframe-common-file.js index 48a94f007..47ad53718 100644 --- a/www/common/sframe-common-file.js +++ b/www/common/sframe-common-file.js @@ -96,6 +96,7 @@ define([ var data = {}; data.name = file.metadata.name; + data.fileType = file.metadata.type; data.url = href; data.password = file.password; if (file.metadata.type.slice(0,6) === 'image/') { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 19f340fee..d597c66c9 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -2081,6 +2081,11 @@ define([ cfg.integrationUtils.onHasUnsavedChanges(obj, cb); } }); + sframeChan.on('Q_INTEGRATION_ON_INSERT_IMAGE', function (data, cb) { + if (cfg.integrationUtils && cfg.integrationUtils.onInsertImage) { + cfg.integrationUtils.onInsertImage(data, cb); + } + }); integrationSave = function (cb) { sframeChan.query('Q_INTEGRATION_NEEDSAVE', null, cb); }; diff --git a/www/cryptpad-api.js b/www/cryptpad-api.js index 67e232a23..783353917 100644 --- a/www/cryptpad-api.js +++ b/www/cryptpad-api.js @@ -166,6 +166,9 @@ config.events.onHasUnsavedChanges(unsavedChanges); cb(); }); + chan.on('ON_INSERT_IMAGE', function(data, cb) { + config.events.onInsertImage(data, cb); + }); }); }); @@ -184,6 +187,7 @@ * @param {object} config.events Event handlers. * @param {function} events.onSave (blob, callback) The save function to store the document when edited. * @param {function} events.onNewKey (data, callback) The function called when a new key is used. + * @param {function} events.onInsertImage (data, callback) The function called the user wants to add an image. * @param {string} config.documentType The editor to load in CryptPad. * @return {promise} */ @@ -206,7 +210,7 @@ if (!config) { return reject('Missing args: no data provided'); } if(['document.url', 'document.fileType', 'documentType', 'events.onSave', 'events.onHasUnsavedChanges', - 'events.onNewKey'].some(function (k) { + 'events.onNewKey', 'events.onInsertImage'].some(function (k) { var s = k.split('.'); var c = config; return s.some(function (key) { diff --git a/www/diagram/export.js b/www/diagram/export.js index 1b7089559..6f59957b0 100644 --- a/www/diagram/export.js +++ b/www/diagram/export.js @@ -4,15 +4,92 @@ define([ '/components/x2js/x2js.js', + '/diagram/util.js', ], function ( - X2JS) { + X2JS, + DiagramUtil +) { const x2js = new X2JS(); const jsonContentAsXML = (content) => x2js.js2xml(content); + const parseDrawioStyle = (styleAttrValue) => { + if (!styleAttrValue) { + return; + } + + const result = {}; + for (const part of styleAttrValue.split(';')) { + const s = part.split(/=(.*)/); + result[s[0]] = s[1]; + } + + return result; + }; + + const stringifyDrawioStyle = (styleAttrValue) => { + const parts = []; + for (const [key, value] of Object.entries(styleAttrValue)) { + parts.push(`${key}=${value}`); + } + return parts.join(';'); + }; + + const blobToImage = (blob) => { + return new Promise((resolve) => { + const reader = new FileReader(); + reader.onloadend = function() { + resolve(reader.result); + }; + reader.readAsDataURL(blob); + }); + }; + + const loadImage = (url) => { + return DiagramUtil.loadImage(url).then((blob) => blobToImage(blob)); + }; + + const loadCryptPadImages = (doc) => { + return Array.from(doc .querySelectorAll('mxCell')) + .map((element) => [element, parseDrawioStyle(element.getAttribute('style'))]) + .filter(([element, style]) => style && style.image && style.image.startsWith('cryptpad://')) + .map(([element, style]) => { + return loadImage(style.image) + .then((dataUrl) => { + style.image = dataUrl.replace(';base64', ''); // ';' breaks draw.ios style format + element.setAttribute('style', stringifyDrawioStyle(style)); + }); + }); + }; + + const parseXML = (xmlStr) => { + const parser = new DOMParser(); + const doc = parser.parseFromString(xmlStr, "application/xml"); + const errorNode = doc.querySelector("parsererror"); + if (errorNode) { + throw Error("error while parsing " + errorNode); + } + return doc; + }; + return { main: function(userDoc, cb) { delete userDoc.metadata; - cb(jsonContentAsXML(userDoc), '.drawio'); + + const xml = jsonContentAsXML(userDoc); + + let doc; + try { + doc = parseXML(xml); + } catch(e) { + console.error(e); + return; + } + + const promises = loadCryptPadImages(doc); + + Promise.all(promises).then(() => { + cb(new XMLSerializer().serializeToString(doc), '.drawio'); + }); } }; }); diff --git a/www/diagram/inner.js b/www/diagram/inner.js index 7439218ef..266123df8 100644 --- a/www/diagram/inner.js +++ b/www/diagram/inner.js @@ -8,6 +8,7 @@ define([ '/customize/messages.js', // translation keys '/components/pako/dist/pako.min.js', '/components/x2js/x2js.js', + '/diagram/util.js', '/components/tweetnacl/nacl-fast.min.js', 'less!/diagram/app-diagram.less', 'css!/diagram/drawio.css', @@ -15,8 +16,11 @@ define([ Framework, Messages, pako, - X2JS) { + X2JS, + DiagramUtil +) { const Nacl = window.nacl; + const APP = window.APP = {}; // As described here: https://drawio-app.com/extracting-the-xml-from-mxfiles/ const decompressDrawioXml = function(xmlDocStr) { @@ -125,6 +129,21 @@ define([ autosave: onDrawioAutosave, }; + APP.loadImage = DiagramUtil.loadImage; + APP.addImage = function() { + return new Promise((resolve) => { + framework.insertImage({}, (imageData) => { + if (imageData.blob) { + resolve(imageData.blob); + } else if (imageData.url) { + resolve(imageData.url); + } else { + resolve(DiagramUtil.getCryptPadUrl(imageData.src, imageData.key, imageData.fileType)); + } + }); + }); + }; + // This is the function from which you will receive updates from CryptPad framework.onContentUpdate(function (newContent) { lastContent = newContent; @@ -151,9 +170,13 @@ define([ framework.setFileExporter( '.drawio', - () => { - return new Blob([jsonContentAsXML(lastContent)], {type: 'application/x-drawio'}); - } + (cb) => { + require(['/diagram/export.js'], (exporter) => { + exporter.main(lastContent, (xml) => { + cb(new Blob([xml], {type: 'application/x-drawio'})); + }); + }); + }, true ); framework.onEditableChange(function () { @@ -170,13 +193,12 @@ define([ drawioFrame.src = '/components/drawio/src/main/webapp/index.html?' + new URLSearchParams({ - // pages: 0, - // dev: 1, test: 1, stealth: 1, embed: 1, drafts: 0, - plugins: 0, + p: 'cryptpad', + integrated: framework.isIntegrated() ? 'true' : 'false', chrome: framework.isReadOnly() ? 0 : 1, dark: window.CryptPad_theme === "dark" ? 1 : 0, @@ -185,6 +207,10 @@ define([ noSaveBtn: 1, saveAndExit: 0, noExitBtn: 1, + browser: 0, + + noDevice: 1, + filesupport: 0, modified: 'unsavedChanges', proto: 'json', diff --git a/www/diagram/util.js b/www/diagram/util.js new file mode 100644 index 000000000..ec0249446 --- /dev/null +++ b/www/diagram/util.js @@ -0,0 +1,66 @@ +define([ + '/common/common-util.js', + '/file/file-crypto.js', + '/common/outer/cache-store.js', +], function ( + Util, + FileCrypto, + Cache +) { + const Nacl = window.nacl; + + const parseCryptPadUrl = function(href) { + const url = new URL(href); + const protocol = url.searchParams.get('protocol'); + const key = url.hash.substring(1); // remove leading '#' + const type = url.searchParams.get('type'); + url.search = ''; + url.hash = ''; + return { src: url.href.replace(/cryptpad?:\/\//, `${protocol}//`), key, type }; + }; + + const getCryptPadUrl = function(src, key, type) { + const url = new URL(src); + const params = new URLSearchParams(); + params.set('type', type); + params.set('protocol', url.protocol); + url.search = params.toString(); + url.hash = key; + return url.href.replace(/https?:\/\//, 'cryptpad://'); + }; + + const setBlobType = (blob, mimeType) => { + const fixedBlob = new Blob([blob], {type: mimeType}); + return fixedBlob; + }; + + return { + parseCryptPadUrl, + getCryptPadUrl, + + loadImage: function(href) { + return new Promise((resolve, reject) => { + const { src, key, type } = parseCryptPadUrl(href); + Util.fetch(src, function (err, u8) { + if (err) { + console.error(err); + return void reject(err); + } + try { + FileCrypto.decrypt(u8, Nacl.util.decodeBase64(key), (err, res) => { + if (err || !res.content) { + console.error("Decrypting failed"); + return void reject(err); + } + + resolve(setBlobType(res.content, type)); + }); + } catch (e) { + console.error(e); + reject(err); + } + }, void 0, Cache); + }); + } + }; +}); diff --git a/www/integration/main.js b/www/integration/main.js index 126ff9727..cb02f5a61 100644 --- a/www/integration/main.js +++ b/www/integration/main.js @@ -14,7 +14,7 @@ define([ console.warn('INIT'); var p = window.parent; var txid = getTxid(); - p.postMessage(JSON.stringify({ q: 'INTEGRATION_READY', txid: txid }), '*'); + p.postMessage({ q: 'INTEGRATION_READY', txid: txid }, '*'); var makeChan = function () { var handlers = {}; @@ -38,6 +38,7 @@ define([ // On new command var msg = data.msg; + if (!msg) { return; } var txid = data.txid; if (commands[msg.q]) { commands[msg.q](msg.data, function (args) { @@ -122,6 +123,9 @@ define([ var onHasUnsavedChanges = function (unsavedChanges, cb) { chan.send('HAS_UNSAVED_CHANGES', unsavedChanges, cb); }; + var onInsertImage = function (data, cb) { + chan.send('ON_INSERT_IMAGE', data, cb); + }; chan.on('START', function (data) { console.warn('INNER START', data); @@ -139,7 +143,8 @@ define([ utils: { save: save, reload: reload, - onHasUnsavedChanges: onHasUnsavedChanges + onHasUnsavedChanges: onHasUnsavedChanges, + onInsertImage: onInsertImage } }; require(['/common/sframe-app-outer.js'], function () { diff --git a/www/secureiframe/inner.js b/www/secureiframe/inner.js index 14c393b4b..ec9989069 100644 --- a/www/secureiframe/inner.js +++ b/www/secureiframe/inner.js @@ -121,6 +121,7 @@ define([ var key = Hash.encodeBase64(secret.keys.cryptKey); sframeChan.event("EV_SECURE_ACTION", { type: parsed.type, + fileType: data.fileType, href: data.url, src: src, name: data.name, @@ -234,7 +235,7 @@ define([ if (data.static) { $span.attr('title', Util.fixHTML(data.href)); } $span.click(function () { if (typeof onFilePicked === "function") { - onFilePicked({url: data.href, name: name, static: data.static, password: data.password}); + onFilePicked({url: data.href, name: name, static: data.static, password: data.password, fileType: data.fileType}); } });