Merge commit 'refs/pullreqs/2239' into 2026.2.1-test

This commit is contained in:
Wolfgang Ginolas 2026-03-16 12:11:06 +01:00
commit 40f012a315
15 changed files with 443 additions and 338 deletions

View File

@ -23,6 +23,9 @@ server {
return 301 https://$host$request_uri;
}
# Websocket connections rate limiting
limit_req_zone $binary_remote_addr zone=wslimit:20m rate=30r/m;
server {
listen 443 ssl;
listen [::]:443 ssl;
@ -190,6 +193,10 @@ server {
# We prefer to serve static content from nginx directly and to leave the API server to handle
# the dynamic content that only it can manage. This is primarily an optimization
location ^~ /cryptpad_websocket {
# Websocket connections rate limiting
limit_req zone=wslimit burst=5 nodelay;
limit_req_status 429;
# XXX
# static assets like blobs and blocks are served by clustered workers in the API server
# Websocket traffic still needs to be handled by the main process, which means it needs

View File

@ -1028,6 +1028,17 @@ HK.onChannelMessage = function (Env, Server, channel, msgStruct, cb) {
if (!_metadata) { return; }
metadata = _metadata;
if (metadata?.restricted) {
const userId = msgStruct[1];
// If userId is defined (not a private message) and the user
// is not a member of this restricted channel, prevent them
// from broadcasting to the pad until they have joined it
if (userId && !Server.channelContainsUser(channel.id, userId)) {
cb('EFORBIDDEN');
return void w.abort();
}
}
// don't write messages to expired channels
if (checkExpired(Env, Server, channel)) {
cb('EEXPIRED');

259
package-lock.json generated
View File

@ -67,7 +67,7 @@
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-terser": "^1.0.0",
"@rollup/plugin-typescript": "^12.1.0",
"eslint": "^10.0.0",
"eslint-plugin-compat": "^6.0.1",
@ -627,16 +627,18 @@
}
},
"node_modules/@rollup/plugin-terser": {
"version": "0.4.4",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz",
"integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"serialize-javascript": "^6.0.1",
"serialize-javascript": "^7.0.3",
"smob": "^1.0.0",
"terser": "^5.17.4"
},
"engines": {
"node": ">=14.0.0"
"node": ">=20.0.0"
},
"peerDependencies": {
"rollup": "^2.0.0||^3.0.0||^4.0.0"
@ -694,9 +696,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
"cpu": [
"arm"
],
@ -708,9 +710,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
"cpu": [
"arm64"
],
@ -722,9 +724,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
"cpu": [
"arm64"
],
@ -736,9 +738,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
"cpu": [
"x64"
],
@ -750,9 +752,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
"cpu": [
"arm64"
],
@ -764,9 +766,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
"cpu": [
"x64"
],
@ -778,9 +780,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
"cpu": [
"arm"
],
@ -792,9 +794,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
"cpu": [
"arm"
],
@ -806,9 +808,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
"cpu": [
"arm64"
],
@ -820,9 +822,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
"cpu": [
"arm64"
],
@ -834,9 +836,23 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
"cpu": [
"loong64"
],
@ -848,9 +864,23 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
"cpu": [
"ppc64"
],
@ -862,9 +892,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
"cpu": [
"riscv64"
],
@ -876,9 +906,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
"cpu": [
"riscv64"
],
@ -890,9 +920,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
"cpu": [
"s390x"
],
@ -904,7 +934,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.53.3",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
"cpu": [
"x64"
],
@ -916,7 +948,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.53.3",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
"cpu": [
"x64"
],
@ -927,10 +961,24 @@
"linux"
]
},
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
"cpu": [
"arm64"
],
@ -942,9 +990,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
"cpu": [
"arm64"
],
@ -956,9 +1004,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
"cpu": [
"ia32"
],
@ -970,9 +1018,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
"cpu": [
"x64"
],
@ -984,9 +1032,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
"cpu": [
"x64"
],
@ -1128,9 +1176,9 @@
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3394,9 +3442,9 @@
}
},
"node_modules/minimatch": {
"version": "10.2.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz",
"integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==",
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.2"
@ -3906,14 +3954,6 @@
],
"license": "MIT"
},
"node_modules/randombytes": {
"version": "2.1.0",
"dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"license": "MIT",
@ -4038,7 +4078,9 @@
}
},
"node_modules/rollup": {
"version": "4.53.3",
"version": "4.59.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -4052,28 +4094,31 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.53.3",
"@rollup/rollup-android-arm64": "4.53.3",
"@rollup/rollup-darwin-arm64": "4.53.3",
"@rollup/rollup-darwin-x64": "4.53.3",
"@rollup/rollup-freebsd-arm64": "4.53.3",
"@rollup/rollup-freebsd-x64": "4.53.3",
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
"@rollup/rollup-linux-arm64-musl": "4.53.3",
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
"@rollup/rollup-linux-x64-gnu": "4.53.3",
"@rollup/rollup-linux-x64-musl": "4.53.3",
"@rollup/rollup-openharmony-arm64": "4.53.3",
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
"@rollup/rollup-win32-x64-gnu": "4.53.3",
"@rollup/rollup-win32-x64-msvc": "4.53.3",
"@rollup/rollup-android-arm-eabi": "4.59.0",
"@rollup/rollup-android-arm64": "4.59.0",
"@rollup/rollup-darwin-arm64": "4.59.0",
"@rollup/rollup-darwin-x64": "4.59.0",
"@rollup/rollup-freebsd-arm64": "4.59.0",
"@rollup/rollup-freebsd-x64": "4.59.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
"@rollup/rollup-linux-arm64-musl": "4.59.0",
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
"@rollup/rollup-linux-loong64-musl": "4.59.0",
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
"@rollup/rollup-linux-x64-gnu": "4.59.0",
"@rollup/rollup-linux-x64-musl": "4.59.0",
"@rollup/rollup-openbsd-x64": "4.59.0",
"@rollup/rollup-openharmony-arm64": "4.59.0",
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
"@rollup/rollup-win32-x64-gnu": "4.59.0",
"@rollup/rollup-win32-x64-msvc": "4.59.0",
"fsevents": "~2.3.2"
}
},
@ -4173,11 +4218,13 @@
}
},
"node_modules/serialize-javascript": {
"version": "6.0.2",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz",
"integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/serve-static": {

View File

@ -70,7 +70,7 @@
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-terser": "^1.0.0",
"@rollup/plugin-typescript": "^12.1.0",
"eslint": "^10.0.0",
"eslint-plugin-compat": "^6.0.1",

View File

@ -102,7 +102,7 @@ const factory = (UserObject, Util, Hash,
// Folder is being deleted by its owner, don't deprecate it
return;
}
if (Env.user.userObject.readOnly) {
if (Env.user.userObject.readOnly || !reason) {
// In a read-only team, we can't deprecate a shared folder
// Use a empty object with a deprecated flag...
var lm = { proxy: { deprecated: true } };
@ -143,10 +143,10 @@ const factory = (UserObject, Util, Hash,
var _ownedByMe = function (Env, owners) {
return Array.isArray(owners) && owners.indexOf(Env.edPublic) !== -1;
};
var _ownedByOther = function (Env, owners) {
return Array.isArray(owners) && owners.length &&
(!Env.edPublic || owners.indexOf(Env.edPublic) === -1);
};
// var _ownedByOther = function (Env, owners) {
// return Array.isArray(owners) && owners.length &&
// (!Env.edPublic || owners.indexOf(Env.edPublic) === -1);
// };
var _getUserObjects = function (Env) {
var userObjects = [Env.user.userObject];
@ -1307,37 +1307,30 @@ const factory = (UserObject, Util, Hash,
*/
var excludeInvalidIdentifiers = function (result) {
return result.filter(function (channel) {
const filter = (channel) => {
if (typeof(channel) !== 'string') { return; }
return [32, 48].indexOf(channel.length) !== -1;
});
};
let newSet = new Set();
for (var channel of result) {
if(filter(channel)) { newSet.add(channel); }
}
return newSet;
};
// Get the list of channels filtered by a type (expirable channels, owned channels, pin list)
var getChannelsList = function (Env, type) {
var result = [];
//var result = [];
let result = new Set();
var addChannel = function (userObject) {
if (type === 'expirable') {
return function (fileId) {
var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't push duplicates
if (result.indexOf(data.channel) !== -1) { return; }
// Return pads owned by someone else or expired by time
if (_ownedByOther(Env, data.owners) || (data.expire && data.expire < (+new Date()))) {
result.push(data.channel);
}
};
}
if (type === 'owned') {
return function (fileId) {
var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't push duplicates
if (result.indexOf(data.channel) !== -1) { return; }
// Return owned pads
if (_ownedByMe(Env, data.owners)) {
result.push(data.channel);
result.add(data.channel);
}
};
}
@ -1345,37 +1338,31 @@ const factory = (UserObject, Util, Hash,
return function (fileId) {
var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't pin pads owned by someone else
//if (_ownedByOther(Env, data.owners)) { return; }
// Pin onlyoffice checkpoints
if (data.lastVersion) {
var otherChan = Hash.hrefToHexChannelId(data.lastVersion);
if (result.indexOf(otherChan) === -1) {
result.push(otherChan);
}
result.add(otherChan);
}
// Pin form answers channels
if (data.answersChannel && result.indexOf(data.answersChannel) === -1) {
result.push(data.answersChannel);
if (data.answersChannel) {
result.add(data.answersChannel);
}
// Pin onlyoffice realtime patches
if (data.rtChannel && result.indexOf(data.rtChannel) === -1) {
result.push(data.rtChannel);
if (data.rtChannel) {
result.add(data.rtChannel);
}
// Pin onlyoffice images
if (data.ooImages && Array.isArray(data.ooImages)) {
Array.prototype.push.apply(result, data.ooImages);
data.ooImages.forEach(id => result.add(id));
}
// Pin the pad
if (result.indexOf(data.channel) === -1) {
result.push(data.channel);
}
result.add(data.channel);
};
}
};
if (type === 'owned' && !Env.edPublic) { return excludeInvalidIdentifiers(result); }
if (type === 'pin' && !Env.edPublic) { return excludeInvalidIdentifiers(result); }
if (type === 'owned' && !Env.edPublic) { return result; }
if (type === 'pin' && !Env.edPublic) { return result; }
// Get the list of user objects
var userObjects = _getUserObjects(Env);
@ -1393,7 +1380,7 @@ const factory = (UserObject, Util, Hash,
}).map(function (fId) {
return Env.user.proxy[UserObject.SHARED_FOLDERS][fId].channel;
});
Array.prototype.push.apply(result, sfOwned);
sfOwned.forEach(id => result.add(id));
}
if (type === "pin") {
var sfChannels = Object.keys(Env.folders).map(function (fId) {
@ -1403,7 +1390,7 @@ const factory = (UserObject, Util, Hash,
console.error(err);
}
}).filter(Boolean);
Array.prototype.push.apply(result, sfChannels);
sfChannels.forEach(id => result.add(id));
}
return excludeInvalidIdentifiers(result);

View File

@ -5,7 +5,7 @@
const factory = (Sortify, UserObject, ProxyManager,
Migrate, Hash, Util, Constants, Feedback,
Realtime, Messaging, Pinpad, Rpc, Cryptget, Cache,
SF, AccountTS, DriveTS, PadTS, Cursor,
SF, AccountTS, DriveTS, PadTS, Form, Cursor,
Support, Integration, OnlyOffice,
Mailbox, Profile, Team, Messenger, History,
Calendar, BadgeTS, Block, NetConfig,
@ -70,6 +70,9 @@ const factory = (Sortify, UserObject, ProxyManager,
Store.drive = Drive.initAPI({
Store, store, postMessage, broadcast
});
Store.form = Form.init({
Store, store, postMessage, broadcast
});
// Drive clients
var driveEventClients = [];
@ -213,31 +216,36 @@ const factory = (Sortify, UserObject, ProxyManager,
});
};
var getUserChannelList = function () {
var userChannel = `${store.driveChannel}#drive`;
var getUserChannelList = function (compareHash) {
// If compareHash is true, we're going to compare our local
// hash with the server one. We must remove the "#drive" tag
// and the block (which isn't a channel)
var userChannel = compareHash ? store.driveChannel
: `${store.driveChannel}#drive`;
if (!userChannel) { return null; }
// Get the list of pads' channel ID in your drive
// This list is filtered so that it doesn't include pad owned by other users
// It now includes channels from shared folders
var list = store.manager.getChannelsList('pin');
var list = store.manager.getChannelsList('pin'); // "list" is a Set
// Get the avatar & profile
var profile = store.proxy.profile;
if (profile) {
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
if (profileChan) { list.push(profileChan); }
if (profileChan) { list.add(profileChan); }
var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar, null) : null;
if (avatarChan) { list.push(avatarChan); }
if (avatarChan) { list.add(avatarChan); }
}
if (store.proxy.todo) {
list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
list.add(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
}
if (store.proxy.friends) {
var fList = Messaging.getFriendChannelsList(store.proxy);
list = list.concat(fList);
fList.forEach(id => list.add(id));
}
if (store.proxy.mailboxes) {
@ -245,34 +253,23 @@ const factory = (Sortify, UserObject, ProxyManager,
if (m === "broadcast" && !store.isAdmin) { return; }
return store.proxy.mailboxes[m].channel;
}).filter(Boolean);
list = list.concat(mList);
mList.forEach(id => list.add(id));
}
if (store.proxy.calendars) {
var cList = Object.keys(store.proxy.calendars).map(function (c) {
return store.proxy.calendars[c].channel;
});
list = list.concat(cList);
cList.forEach(id => list.add(id));
}
list.push(userChannel);
list.add(userChannel);
if (store.data && store.data.blockId) {
list.push(`${store.data.blockId}#block`);
if (store.data && store.data.blockId && !compareHash) {
list.add(`${store.data.blockId}#block`);
}
list.sort();
return list;
};
var getExpirableChannelList = function () {
return store.manager.getChannelsList('expirable');
};
var getCanonicalChannelList = function (expirable) {
var list = expirable ? getExpirableChannelList() : getUserChannelList();
return Util.deduplicateString(list).sort();
return Array.from(list).sort();
};
//////////////////////////////////////////////////////////////////
@ -352,7 +349,7 @@ const factory = (Sortify, UserObject, ProxyManager,
var arePinsSynced = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList(false);
var list = getUserChannelList(true);
var local = Hash.hashChannelList(list);
store.rpc.getServerHash(function (e, hash) {
if (e) { return void cb(e); }
@ -363,7 +360,7 @@ const factory = (Sortify, UserObject, ProxyManager,
var resetPins = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList(false);
var list = getUserChannelList();
store.rpc.reset(list, function (e) {
if (e) { return void cb(e); }
cb(null);
@ -524,7 +521,7 @@ const factory = (Sortify, UserObject, ProxyManager,
Store.getDeletedPads = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
var list = (data && data.list) || getCanonicalChannelList(true);
var list = data?.list;
if (!Array.isArray(list)) {
return void cb({error: 'INVALID_FILE_LIST'});
}
@ -705,8 +702,8 @@ const factory = (Sortify, UserObject, ProxyManager,
};
var getOwnedPads = function (account) {
var list = [];
if (account) {
var list = [];
if (store.proxy.todo) {
// No password for todo
list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
@ -718,29 +715,17 @@ const factory = (Sortify, UserObject, ProxyManager,
if (store.proxy.mailboxes) {
Object.keys(store.proxy.mailboxes || {}).forEach(function (id) {
if (id === 'supportadmin') { return; }
if (id === 'supportteam') { return; }
var m = store.proxy.mailboxes[id];
list.push(m.channel);
});
}
} else {
list = store.manager.getChannelsList('owned');
/*
if (store.proxy.teams) {
Object.keys(store.proxy.teams || {}).forEach(function (id) {
var t = store.proxy.teams[id];
if (t.owner) {
list.push(t.channel);
list.push(t.keys.roster.channel);
list.push(t.keys.chat.channel);
}
});
}
*/
return list.filter(function (channel) {
if (typeof(channel) !== 'string') { return; }
return [32, 48].indexOf(channel.length) !== -1;
});
}
return list.filter(function (channel) {
if (typeof(channel) !== 'string') { return; }
return [32, 48].indexOf(channel.length) !== -1;
});
return Array.from(store.manager.getChannelsList('owned'));
};
var removeOwnedPads = function (account, waitFor) {
// Delete owned pads
@ -928,7 +913,7 @@ const factory = (Sortify, UserObject, ProxyManager,
// Reset the drive part of the userObject (from settings)
Store.resetDrive = function (clientId, data, cb) {
nThen(function (waitFor) {
removeOwnedPads(waitFor);
removeOwnedPads(false, waitFor);
}).nThen(function () {
store.proxy.drive = store.userObject.getStructure();
sendDriveEvent('DRIVE_CHANGE', {
@ -3057,6 +3042,7 @@ module.exports = factory(
require('./components/account'), // .ts
require('./components/drive'), // .ts
require('./components/pad'), // .ts
require('./components/form'),
require('./modules/cursor'),
require('./modules/support'),
require('./modules/integration'),

View File

@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: 2026 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
const factory = (Util, Nacl, CPNetflux, Crypto) => {
const Form = {};
const u8_slice = (A, start, end) => {
return new Uint8Array(Array.prototype.slice.call(A, start, end));
};
const checkAnonProof = (proofObj, channel, curvePrivate) => {
const pub = proofObj.key;
const proofTxt = proofObj.proof;
try {
let u8_bundle = Util.decodeBase64(proofTxt);
let u8_nonce = u8_slice(u8_bundle, 0, Nacl.box.nonceLength);
let u8_cipher = u8_slice(u8_bundle, Nacl.box.nonceLength);
let u8_plain = Nacl.box.open(
u8_cipher,
u8_nonce,
Util.decodeBase64(pub),
Util.decodeBase64(curvePrivate)
);
return channel === Util.encodeUTF8(u8_plain);
} catch (e) {
console.error(e);
return false;
}
};
const getResponses = (ctx, data, cb) => {
const { store, Store } = ctx;
const {
cryptoKeys, // encryptor keys
channel, // form responses channel id
edPublic, // my edPublic
validateKey, // form responses secondaryValidateKey
deleteLines,
cantEdit
} = data;
const curvePrivate = cryptoKeys.curvePrivate;
const crypto = Crypto.Mailbox.createEncryptor(cryptoKeys);
let config = {
network: store.network,
channel,
noChainPad: true,
validateKey,
owners: [edPublic],
crypto: crypto,
metadata: {
deleteLines: true
}
};
let cpNf;
let results = {};
config.onError = (info) => {
cb({ error: info.type });
cpNf?.stop();
};
config.onRejected = Store.onRejected;
config.onReady = function () {
cb({ results });
cpNf?.stop();
};
config.onMessage = (msg, peer, vKey, isCp, hash, senderCurve, cfg) => {
let parsed = Util.tryParse(msg);
if (!parsed) { return; }
let uid = parsed._uid || '000';
// If we have a "non-anonymous" answer, it may be the edition of a
// previous anonymous answer. Check if a previous anonymous answer exists
// with the same uid and delete it.
if (parsed._proof) {
const check = checkAnonProof(parsed._proof, channel, curvePrivate);
const theirAnonKey = parsed._proof.key;
if (check && results[theirAnonKey] && results[theirAnonKey][uid]) {
delete results[theirAnonKey][uid];
}
}
parsed._time = cfg && cfg.time;
if (deleteLines) { parsed._hash = hash; }
if (cantEdit && results[senderCurve]
&& results[senderCurve][uid]) { return; }
results[senderCurve] = results[senderCurve] || {};
results[senderCurve][uid] = {
msg: parsed,
hash: hash,
time: cfg && cfg.time
};
};
cpNf = CPNetflux.start(config);
};
Form.init = (config) => {
const { store, Store } = config;
const ctx = { store, Store };
const form = {}
form.getResponses = (cId, data, cb) => {
return getResponses(ctx, data, cb);
};
return form;
};
return Form;
};
module.exports = factory(
require("../../common/common-util"),
require('tweetnacl/nacl-fast'),
require("chainpad-netflux"),
require("chainpad-crypto")
);

View File

@ -85,6 +85,8 @@ const factory = AStore => {
CHANGE_PAD_PASSWORD_PIN: Store.changePadPasswordPin,
GET_SNAPSHOT: Store.getSnapshot,
DELETE_MAILBOX_MESSAGE: Store.deleteMailboxMessage,
// Form
FORM_GET_RESPONSES: Store.form?.getResponses,
// Drive
DRIVE_USEROBJECT: Store.userObjectCommand,
GET_DRIVE: Store.drive.get,

View File

@ -14,7 +14,7 @@ const factory = (Util, Hash,
var TYPES = [
'notifications',
'supportteam',
//'broadcast'
'broadcast'
];
var BLOCKING_TYPES = [
];

View File

@ -123,41 +123,41 @@ const factory = (Util, Hash, Constants, Realtime, ProxyManager,
}
};
var getTeamChannelList = function (ctx, id) {
var getTeamChannelList = function (ctx, compareHash, id) {
// Get the list of pads' channel ID in your drive
// This list is filtered so that it doesn't include pad owned by other users
// It now includes channels from shared folders
var store = ctx.teams[id];
if (!store) { return null; }
var list = store.manager.getChannelsList('pin');
var list = store.manager.getChannelsList('pin'); // list is a Set
var team = ctx.store.proxy.teams[id];
list.push(`${team.channel}#drive`);
const teamChan = compareHash ? team.channel : `${team.channel}#drive`;
list.add(teamChan);
var chatChannel = Util.find(team, ['keys', 'chat', 'channel']);
var membersChannel = Util.find(team, ['keys', 'roster', 'channel']);
var mailboxChannel = Util.find(team, ['keys', 'mailbox', 'channel']);
if (chatChannel) { list.push(chatChannel); }
if (membersChannel) { list.push(membersChannel); }
if (mailboxChannel) { list.push(mailboxChannel); }
if (chatChannel) { list.add(chatChannel); }
if (membersChannel) { list.add(membersChannel); }
if (mailboxChannel) { list.add(mailboxChannel); }
if (store.proxy.calendars) {
var cList = Object.keys(store.proxy.calendars).map(function (c) {
return store.proxy.calendars[c].channel;
});
list = list.concat(cList);
cList.forEach(id => list.add(id));
}
var state = store.roster.getState();
if (state.members) {
Object.keys(state.members).forEach(function (curve) {
var m = state.members[curve];
if (m.inviteChannel && m.pending) { list.push(m.inviteChannel); }
if (m.previewChannel && m.pending) { list.push(m.previewChannel); }
if (m.inviteChannel && m.pending) { list.add(m.inviteChannel); }
if (m.previewChannel && m.pending) { list.add(m.previewChannel); }
});
}
list.sort();
return list;
return Array.from(list).sort();
};
var handleSharedFolder = function (ctx, id, sfId, rt) {
@ -365,14 +365,15 @@ const factory = (Util, Hash, Constants, Realtime, ProxyManager,
});
}).nThen(function () {
if (!team.rpc) { return; }
var list = getTeamChannelList(ctx, id);
var list = getTeamChannelList(ctx, true, id);
var local = Hash.hashChannelList(list);
// Check pin list
team.rpc.getServerHash(function (e, hash) {
if (e) { return void console.warn(e); }
if (hash !== local) {
// Reset pin list
team.rpc.reset(list, function (e/*, hash*/) {
var list2 = getTeamChannelList(ctx, false, id);
team.rpc.reset(list2, function (e/*, hash*/) {
if (e) { console.warn(e); }
});
}
@ -853,7 +854,7 @@ const factory = (Util, Hash, Constants, Realtime, ProxyManager,
// For each pad, check on the server if there are other owners.
// If yes, then remove yourself as an owner
// If no, delete the pad
var ownedPads = team.manager.getChannelsList('owned');
var ownedPads = Array.from(team.manager.getChannelsList('owned'));
var sem = Util.Saferphore.create(10);
ownedPads.forEach(function (c) {
var w = waitFor();

View File

@ -289,6 +289,10 @@ define([
});
});
};
common.getFormResponses = (data, cb) => {
postMessage("FORM_GET_RESPONSES", data, cb);
};
common.muteChannel = function (channel, state, cb) {
var mutedChannels = [];
nThen(function (waitFor) {

View File

@ -1960,51 +1960,65 @@ define([
// It seems we have performance issues when we open and close a lot of channels over
// the same network, maybe a memory leak. To fix this, we kill and create a new
// network every 30 cryptget calls (1 call = 1 channel)
var cgNetwork;
var whenCGReady = function (cb) {
if (cgNetwork && cgNetwork !== true) { console.log(cgNetwork); return void cb(); }
setTimeout(function () {
whenCGReady(cb);
}, 500);
};
var i = 0;
const cgNetworkStatus = {};
let cgNetworkId = 0;
let cgNetworkIndex = 0;
let cgNetwork;
sframeChan.on('Q_CRYPTGET', function (data, cb) {
var keys;
var todo = function () {
data.opts.network = cgNetwork;
var todo = function (network) {
data.opts.network = network;
data.opts.accessKeys = keys;
Cryptget.get(data.hash, function (err, val) {
cb({
error: err,
data: val
// Use promises to know when all the cryptget are done
// so that we can disconnect the network
cgNetworkStatus[cgNetworkId] ||= [];
cgNetworkStatus.push(new Promise((res) => {
Cryptget.get(data.hash, function (err, val) {
res(network);
cb({
error: err,
data: val
});
}, data.opts, function (progress) {
sframeChan.event("EV_CRYPTGET_PROGRESS", {
hash: data.hash,
progress: progress,
});
});
}, data.opts, function (progress) {
sframeChan.event("EV_CRYPTGET_PROGRESS", {
hash: data.hash,
progress: progress,
});
});
}));
};
//return void todo();
if (i > 30) {
i = 0;
// Every 30 cryptget, make a new network
if (cgNetworkIndex > 30) {
cgNetworkIndex = 0;
// Make sure all previous command are done and disconnect
const prom = cpNetworkStatus[cgNetworkId] || [];
Promise.all(prom).then((nw) => {
let network = nw[0];
if (typeof(network?.disconnect) === "function") {
network.disconnect();
}
});
cgNetwork = undefined;
cgNetworkId ++;
}
i++;
cgNetworkIndex++;
Cryptpad.getAccessKeys(function (_keys) {
keys = _keys;
if (!cgNetwork) {
cgNetwork = true;
return void Cryptpad.makeNetwork(function (err, nw) {
console.log(nw);
cgNetwork = nw;
todo();
cgNetwork = new Promise((res) => {
Cryptpad.makeNetwork(function (err, nw) {
res(nw);
//cgNetwork = nw;
todo(nw);
});
});
} else if (cgNetwork === true) {
return void whenCGReady(todo);
return;
}
todo();
cgNetwork.then(todo);
});
});
sframeChan.on('EV_CRYPTGET_DISCONNECT', function () {

File diff suppressed because one or more lines are too long

View File

@ -135,28 +135,6 @@ define([
});
});
});
var u8_slice = function (A, start, end) {
return new Uint8Array(Array.prototype.slice.call(A, start, end));
};
var checkAnonProof = function (proofObj, channel, curvePrivate) {
var pub = proofObj.key;
var proofTxt = proofObj.proof;
try {
var u8_bundle = Util.decodeBase64(proofTxt);
var u8_nonce = u8_slice(u8_bundle, 0, Nacl.box.nonceLength);
var u8_cipher = u8_slice(u8_bundle, Nacl.box.nonceLength);
var u8_plain = Nacl.box.open(
u8_cipher,
u8_nonce,
Util.decodeBase64(pub),
Util.decodeBase64(curvePrivate)
);
return channel === Util.encodeUTF8(u8_plain);
} catch (e) {
console.error(e);
return false;
}
};
sframeChan.on('Q_FORM_FETCH_ANSWERS', function (data, _cb) {
var formHref = data.href;
var cb = Utils.Util.once(_cb);
@ -178,7 +156,6 @@ define([
Cryptpad.getAccessKeys(w(function (_keys) {
if (!Array.isArray(_keys)) { return; }
accessKeys = _keys;
_keys.some(function (_k) {
if ((personalDrive && !_k.id) || Cryptpad.initialTeam === Number(_k.id)) {
myKeys = _k;
@ -194,14 +171,10 @@ define([
}
myFormKeys = keys;
}));
Cryptpad.makeNetwork(w(function (err, nw) {
network = nw;
}));
Cryptpad.getPadMetadata({channel: data.channel}, w(function (md) {
if (md && md.deleteLines) { deleteLines = true; }
}));
}).nThen(function () {
if (!network) { return void cb({error: "E_CONNECT"}); }
if (myFormKeys.formSeed) {
myFormKeys = Cryptpad.getAnonymousKeys(myFormKeys.formSeed, data.channel, Utils);
}
@ -220,86 +193,33 @@ define([
publicKey = formData?.form_public;
var curvePrivate = privateKey || data.privateKey;
if (!curvePrivate) { return void cb({error: 'EFORBIDDEN'}); }
var crypto = Utils.Crypto.Mailbox.createEncryptor({
var cryptoKeys = {
curvePrivate: curvePrivate,
curvePublic: publicKey || data.publicKey,
validateKey: data.validateKey
});
};
var config = {
network: network,
Cryptpad.getFormResponses({
cryptoKeys,
channel: data.channel,
noChainPad: true,
edPublic: myKeys.edPublic,
validateKey: keys.secondaryValidateKey,
owners: [myKeys.edPublic],
crypto: crypto,
metadata: {
deleteLines: true
}
//Cache: Utils.Cache // TODO enable cache for form responses when the cache stops evicting old answers
};
var results = {};
config.onError = function (info) {
cb({ error: info.type });
};
config.onRejected = function (data, cb) {
if (!Array.isArray(data) || !data.length || data[0].length !== 16) {
return void cb(true);
}
if (!Array.isArray(accessKeys)) { return void cb(true); }
network.historyKeeper = data[0];
nThen(function (waitFor) {
accessKeys.forEach(function (obj) {
Pinpad.create(network, obj, waitFor(function (e) {
if (e) { console.error(e); }
}));
});
}).nThen(function () {
cb();
});
};
config.onReady = function () {
var myKey;
cantEdit: data.cantEdit,
deleteLines
}, (obj) => {
if (obj?.error) { return void cb(obj); }
const results = obj.results;
// If we have submitted an anonymous answer, retrieve it
let myKey;
if (myFormKeys.curvePublic && results[myFormKeys.curvePublic]) {
myKey = myFormKeys.curvePublic;
}
cb({
noDriveAnswered: noDriveAnswered,
myKey: myKey,
results: results
noDriveAnswered, myKey, results
});
network.disconnect();
};
config.onMessage = function (msg, peer, vKey, isCp, hash, senderCurve, cfg) {
var parsed = Utils.Util.tryParse(msg);
if (!parsed) { return; }
var uid = parsed._uid || '000';
// If we have a "non-anonymous" answer, it may be the edition of a
// previous anonymous answer. Check if a previous anonymous answer exists
// with the same uid and delete it.
if (parsed._proof) {
var check = checkAnonProof(parsed._proof, data.channel, curvePrivate);
var theirAnonKey = parsed._proof.key;
if (check && results[theirAnonKey] && results[theirAnonKey][uid]) {
delete results[theirAnonKey][uid];
}
}
parsed._time = cfg && cfg.time;
if (deleteLines) { parsed._hash = hash; }
if (data.cantEdit && results[senderCurve]
&& results[senderCurve][uid]) { return; }
results[senderCurve] = results[senderCurve] || {};
results[senderCurve][uid] = {
msg: parsed,
hash: hash,
time: cfg && cfg.time
};
};
CPNetflux.start(config);
});
});
});
var noDriveSeed = Utils.Hash.createChannelId();

View File

@ -25,6 +25,7 @@ define([
'/common/diffMarked.js',
'/common/sframe-common-codemirror.js',
'/common/text-cursor.js',
'/common/visible.js',
'cm/lib/codemirror',
'/components/chainpad/chainpad.dist.js',
'tui-date-picker',
@ -73,6 +74,7 @@ define([
DiffMd,
SFCodeMirror,
TextCursor,
Visible,
CMeditor,
ChainPad,
DatePicker,
@ -3280,6 +3282,8 @@ define([
h('span.cp-button-name', Messages._getKey('form_results', [l])),
]));
var it = setInterval(function () {
let visible = Visible.currently();
if (!visible) { return; }
sframeChan.query("Q_FORM_FETCH_ANSWERS", content.answers, function (err, obj) {
var answers = obj && obj.results;
var l = getAnswersLength(answers);