Ported most routes to fastify.

This commit is contained in:
SamTV12345 2024-03-18 10:43:04 +01:00
parent d7869f5014
commit b3741470ed
16 changed files with 813 additions and 288 deletions

548
pnpm-lock.yaml generated
View file

@ -124,6 +124,12 @@ importers:
src:
dependencies:
'@fastify/express':
specifier: ^2.3.0
version: 2.3.0
'@fastify/static':
specifier: ^7.0.1
version: 7.0.1
async:
specifier: ^3.2.5
version: 3.2.5
@ -160,6 +166,12 @@ importers:
fast-deep-equal:
specifier: ^3.1.3
version: 3.1.3
fastify:
specifier: ^4.26.2
version: 4.26.2
fastify-socket.io:
specifier: ^5.0.0
version: 5.0.0(fastify@4.26.2)
find-root:
specifier: 1.1.0
version: 1.1.0
@ -199,6 +211,12 @@ importers:
openapi-backend:
specifier: ^5.10.6
version: 5.10.6
pino:
specifier: ^8.19.0
version: 8.19.0
pino-pretty:
specifier: ^10.3.1
version: 10.3.1
proxy-addr:
specifier: ^2.0.7
version: 2.0.7
@ -211,6 +229,9 @@ importers:
rehype-minify-whitespace:
specifier: ^6.0.0
version: 6.0.0
require-from-url:
specifier: ^3.1.3
version: 3.1.3
resolve:
specifier: 1.22.8
version: 1.22.8
@ -785,6 +806,65 @@ packages:
- supports-color
dev: false
/@fastify/accept-negotiator@1.1.0:
resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
engines: {node: '>=14'}
dev: false
/@fastify/ajv-compiler@3.5.0:
resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==}
dependencies:
ajv: 8.12.0
ajv-formats: 2.1.1
fast-uri: 2.3.0
dev: false
/@fastify/error@3.4.1:
resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==}
dev: false
/@fastify/express@2.3.0:
resolution: {integrity: sha512-jvvjlPPCfJsSHfF6tQDyARJ3+c3xXiqcxVZu6bi3xMWCWB3fl07vrjFDeaqnwqKhLZ9+m6cog5dw7gIMKEsTnQ==}
dependencies:
express: 4.18.3
fastify-plugin: 4.5.1
transitivePeerDependencies:
- supports-color
dev: false
/@fastify/fast-json-stringify-compiler@4.3.0:
resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
dependencies:
fast-json-stringify: 5.13.0
dev: false
/@fastify/merge-json-schemas@0.1.1:
resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==}
dependencies:
fast-deep-equal: 3.1.3
dev: false
/@fastify/send@2.1.0:
resolution: {integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==}
dependencies:
'@lukeed/ms': 2.0.2
escape-html: 1.0.3
fast-decode-uri-component: 1.0.1
http-errors: 2.0.0
mime: 3.0.0
dev: false
/@fastify/static@7.0.1:
resolution: {integrity: sha512-i1p/nELMknAisNfnjo7yhfoUOdKzA+n92QaMirv2NkZrJ1Wl12v2nyTYlDwPN8XoStMBAnRK/Kx6zKmfrXUPXw==}
dependencies:
'@fastify/accept-negotiator': 1.1.0
'@fastify/send': 2.1.0
content-disposition: 0.5.4
fastify-plugin: 4.5.1
fastq: 1.17.1
glob: 10.3.10
dev: false
/@humanwhocodes/config-array@0.11.14:
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
@ -805,6 +885,18 @@ packages:
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
dev: true
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
dependencies:
string-width: 5.1.2
string-width-cjs: /string-width@4.2.3
strip-ansi: 7.1.0
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: false
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}
@ -862,6 +954,11 @@ packages:
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
dev: false
/@lukeed/ms@2.0.2:
resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==}
engines: {node: '>=8'}
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -883,6 +980,13 @@ packages:
fastq: 1.17.1
dev: true
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
dev: false
optional: true
/@playwright/test@1.42.1:
resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==}
engines: {node: '>=16'}
@ -2179,6 +2283,17 @@ packages:
- '@swc/helpers'
dev: true
/abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
dependencies:
event-target-shim: 5.0.1
dev: false
/abstract-logging@2.0.1:
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
dev: false
/accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@ -2209,13 +2324,8 @@ packages:
- supports-color
dev: false
/ajv-formats@2.1.1(ajv@8.12.0):
/ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta:
ajv:
optional: true
dependencies:
ajv: 8.12.0
dev: false
@ -2246,7 +2356,11 @@ packages:
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
dev: false
/ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
@ -2261,6 +2375,11 @@ packages:
dependencies:
color-convert: 2.0.1
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
dev: false
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@ -2269,6 +2388,10 @@ packages:
picomatch: 2.3.1
dev: true
/archy@1.0.0:
resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
dev: false
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@ -2372,6 +2495,11 @@ packages:
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
/atomic-sleep@1.0.0:
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
engines: {node: '>=8.0.0'}
dev: false
/available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@ -2379,6 +2507,17 @@ packages:
possible-typed-array-names: 1.0.0
dev: true
/avvio@8.3.0:
resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==}
dependencies:
'@fastify/error': 3.4.1
archy: 1.0.0
debug: 4.3.4(supports-color@8.1.1)
fastq: 1.17.1
transitivePeerDependencies:
- supports-color
dev: false
/axios@1.6.8:
resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==}
dependencies:
@ -2396,6 +2535,10 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/base64id@2.0.0:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9}
@ -2471,6 +2614,13 @@ packages:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: false
/buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: false
/builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
@ -2592,6 +2742,10 @@ packages:
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
dev: false
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@ -2655,6 +2809,11 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/cookie@0.6.0:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
dev: false
/cookiejar@2.1.4:
resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
@ -2714,6 +2873,10 @@ packages:
engines: {node: '>=4.0'}
dev: false
/dateformat@4.6.3:
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
dev: false
/debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
@ -2855,6 +3018,10 @@ packages:
tslib: 2.6.2
dev: true
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: false
/ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: false
@ -2873,13 +3040,22 @@ packages:
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: false
/encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
dev: false
/end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
dev: false
/engine.io-client@6.5.3:
resolution: {integrity: sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==}
dependencies:
@ -3470,6 +3646,16 @@ packages:
mime: 1.6.0
dev: false
/event-target-shim@5.0.1:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
dev: false
/events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
dev: false
/express-rate-limit@7.2.0(express@4.18.3):
resolution: {integrity: sha512-T7nul1t4TNyfZMJ7pKRKkdeVJWa2CqB8NA1P8BwYaoDI5QSBZARv5oMS43J7b7I5P+4asjVXjb7ONuwDKucahg==}
engines: {node: '>= 16'}
@ -3522,6 +3708,18 @@ packages:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
/fast-content-type-parse@1.1.0:
resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
dev: false
/fast-copy@3.0.2:
resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
dev: false
/fast-decode-uri-component@1.0.1:
resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@ -3540,18 +3738,82 @@ packages:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
/fast-json-stringify@5.13.0:
resolution: {integrity: sha512-XjTDWKHP3GoMQUOfnjYUbqeHeEt+PvYgvBdG2fRSmYaORILbSr8xTJvZX+w1YSAP5pw2NwKrGRmQleYueZEoxw==}
dependencies:
'@fastify/merge-json-schemas': 0.1.1
ajv: 8.12.0
ajv-formats: 2.1.1
fast-deep-equal: 3.1.3
fast-uri: 2.3.0
json-schema-ref-resolver: 1.0.1
rfdc: 1.3.1
dev: false
/fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: true
/fast-querystring@1.1.2:
resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
dependencies:
fast-decode-uri-component: 1.0.1
dev: false
/fast-redact@3.4.0:
resolution: {integrity: sha512-2gwPvyna0zwBdxKnng1suu/dTL5s8XEy2ZqH8mwDUwJdDkV8w5kp+JV26mupdK68HmPMbm6yjW9m7/Ys/BHEHg==}
engines: {node: '>=6'}
dev: false
/fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
/fast-uri@2.3.0:
resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==}
dev: false
/fastify-plugin@4.5.1:
resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==}
dev: false
/fastify-socket.io@5.0.0(fastify@4.26.2):
resolution: {integrity: sha512-BQKGLVSsLn9s4IXLWjwZRGTNuFbXt5bPY2qeXJUFYFtu/0BxLqcE2WMOrWUZdFWy12kuEvXC76ObsilQKeSfqg==}
requiresBuild: true
peerDependencies:
fastify: 4.x.x
dependencies:
fastify: 4.26.2
fastify-plugin: 4.5.1
tslib: 2.6.2
dev: false
/fastify@4.26.2:
resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==}
dependencies:
'@fastify/ajv-compiler': 3.5.0
'@fastify/error': 3.4.1
'@fastify/fast-json-stringify-compiler': 4.3.0
abstract-logging: 2.0.1
avvio: 8.3.0
fast-content-type-parse: 1.1.0
fast-json-stringify: 5.13.0
find-my-way: 8.1.0
light-my-request: 5.12.0
pino: 8.19.0
process-warning: 3.0.0
proxy-addr: 2.0.7
rfdc: 1.3.1
secure-json-parse: 2.7.0
semver: 7.6.0
toad-cache: 3.7.0
transitivePeerDependencies:
- supports-color
dev: false
/fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
dependencies:
reusify: 1.0.4
dev: true
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@ -3588,6 +3850,15 @@ packages:
- supports-color
dev: false
/find-my-way@8.1.0:
resolution: {integrity: sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==}
engines: {node: '>=14'}
dependencies:
fast-deep-equal: 3.1.3
fast-querystring: 1.1.2
safe-regex2: 2.0.0
dev: false
/find-root@1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
dev: false
@ -3633,6 +3904,14 @@ packages:
is-callable: 1.2.7
dev: true
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@ -3790,6 +4069,18 @@ packages:
is-glob: 4.0.3
dev: true
/glob@10.3.10:
resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
dependencies:
foreground-child: 3.1.1
jackspeak: 2.3.6
minimatch: 9.0.3
minipass: 5.0.0
path-scurry: 1.10.1
dev: false
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
@ -4005,6 +4296,10 @@ packages:
hasBin: true
dev: true
/help-me@5.0.0:
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
dev: false
/hexoid@1.0.0:
resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
engines: {node: '>=8'}
@ -4083,6 +4378,10 @@ packages:
safer-buffer: 2.1.2
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
/ignore@5.3.1:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
@ -4196,7 +4495,6 @@ packages:
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
@ -4303,6 +4601,15 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/jackspeak@2.3.6:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'}
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
dev: false
/jake@10.8.7:
resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==}
engines: {node: '>=10'}
@ -4314,6 +4621,11 @@ packages:
minimatch: 3.1.2
dev: false
/joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
dev: false
/js-cookie@3.0.5:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
@ -4379,6 +4691,12 @@ packages:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: true
/json-schema-ref-resolver@1.0.1:
resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==}
dependencies:
fast-deep-equal: 3.1.3
dev: false
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true
@ -4456,6 +4774,14 @@ packages:
type-check: 0.4.0
dev: true
/light-my-request@5.12.0:
resolution: {integrity: sha512-P526OX6E7aeCIfw/9UyJNsAISfcFETghysaWHQAlQYayynShT08MOj4c6fBCvTWBrHXSvqBAKDp3amUPSCQI4w==}
dependencies:
cookie: 0.6.0
process-warning: 3.0.0
set-cookie-parser: 2.6.0
dev: false
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
@ -4544,6 +4870,11 @@ packages:
tslib: 2.6.2
dev: true
/lru-cache@10.2.0:
resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
engines: {node: 14 || >=16.14}
dev: false
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
@ -4660,6 +4991,12 @@ packages:
engines: {node: '>=4.0.0'}
hasBin: true
/mime@3.0.0:
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
engines: {node: '>=10.0.0'}
hasBin: true
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@ -4684,11 +5021,9 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
dev: true
/minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
@ -4891,6 +5226,11 @@ packages:
resolution: {integrity: sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==}
dev: false
/on-exit-leak-free@2.1.2:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
dev: false
/on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
@ -4936,7 +5276,7 @@ packages:
resolution: {integrity: sha512-xTHOmxU/VQGUgo7Cm0jhwbklOKobXby+/237EG967+3TQEYJztMgX9Q5UE2taZKwyKPUq0j11dngpGjUuxz1hQ==}
dependencies:
ajv: 8.12.0
ajv-formats: 2.1.1(ajv@8.12.0)
ajv-formats: 2.1.1
lodash.merge: 4.6.2
openapi-types: 12.1.3
dev: false
@ -5019,6 +5359,14 @@ packages:
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
/path-scurry@1.10.1:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
lru-cache: 10.2.0
minipass: 5.0.0
dev: false
/path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
dev: false
@ -5041,6 +5389,54 @@ packages:
engines: {node: '>=8.6'}
dev: true
/pino-abstract-transport@1.1.0:
resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==}
dependencies:
readable-stream: 4.5.2
split2: 4.2.0
dev: false
/pino-pretty@10.3.1:
resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==}
hasBin: true
dependencies:
colorette: 2.0.20
dateformat: 4.6.3
fast-copy: 3.0.2
fast-safe-stringify: 2.1.1
help-me: 5.0.0
joycon: 3.1.1
minimist: 1.2.8
on-exit-leak-free: 2.1.2
pino-abstract-transport: 1.1.0
pump: 3.0.0
readable-stream: 4.5.2
secure-json-parse: 2.7.0
sonic-boom: 3.8.0
strip-json-comments: 3.1.1
dev: false
/pino-std-serializers@6.2.2:
resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==}
dev: false
/pino@8.19.0:
resolution: {integrity: sha512-oswmokxkav9bADfJ2ifrvfHUwad6MLp73Uat0IkQWY3iAw5xTRoznXbXksZs8oaOUMpmhVWD+PZogNzllWpJaA==}
hasBin: true
dependencies:
atomic-sleep: 1.0.0
fast-redact: 3.4.0
on-exit-leak-free: 2.1.2
pino-abstract-transport: 1.1.0
pino-std-serializers: 6.2.2
process-warning: 3.0.0
quick-format-unescaped: 4.0.4
real-require: 0.2.0
safe-stable-stringify: 2.4.3
sonic-boom: 3.8.0
thread-stream: 2.4.1
dev: false
/playwright-core@1.42.1:
resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==}
engines: {node: '>=16'}
@ -5076,6 +5472,15 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
/process-warning@3.0.0:
resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==}
dev: false
/process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
dev: false
/promise@1.3.0:
resolution: {integrity: sha512-R9WrbTF3EPkVtWjp7B7umQGVndpsi+rsDAfrR4xAALQpFLa/+2OriecLhawxzvii2gd9+DZFwROWDuUUaqS5yA==}
dependencies:
@ -5102,6 +5507,13 @@ packages:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
dev: false
/pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
dev: false
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@ -5127,6 +5539,10 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
dev: false
/rambda@7.5.0:
resolution: {integrity: sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==}
dev: true
@ -5282,6 +5698,17 @@ packages:
loose-envify: 1.4.0
dev: true
/readable-stream@4.5.2:
resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
abort-controller: 3.0.0
buffer: 6.0.3
events: 3.3.0
process: 0.11.10
string_decoder: 1.3.0
dev: false
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -5289,6 +5716,11 @@ packages:
picomatch: 2.3.1
dev: true
/real-require@0.2.0:
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
engines: {node: '>= 12.13.0'}
dev: false
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: true
@ -5348,6 +5780,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/require-from-url@3.1.3:
resolution: {integrity: sha512-SWYVQr6rZMumhsE0MGL3caGtBNDBPQRm7JV4fsxb8Nc+LR42QkmLPP56P+Y9jncZLNrrk4SpE/Ozaf8Jo3ialA==}
engines: {node: '>=8.11.1'}
dev: false
/requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
dev: false
@ -5368,10 +5805,14 @@ packages:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
/ret@0.2.2:
resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==}
engines: {node: '>=4'}
dev: false
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/rfdc@1.3.1:
resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
@ -5439,6 +5880,17 @@ packages:
is-regex: 1.1.4
dev: true
/safe-regex2@2.0.0:
resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==}
dependencies:
ret: 0.2.2
dev: false
/safe-stable-stringify@2.4.3:
resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==}
engines: {node: '>=10'}
dev: false
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
@ -5456,6 +5908,10 @@ packages:
loose-envify: 1.4.0
dev: true
/secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
dev: false
/security@1.0.0:
resolution: {integrity: sha512-5qfoAgfRWS1sUn+fUJtdbbqM1BD/LoQGa+smPTDjf9OqHyuJqi6ewtbYL0+V1S1RaU6OCOCMWGZocIfz2YK4uw==}
dev: false
@ -5513,7 +5969,6 @@ packages:
/set-cookie-parser@2.6.0:
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
dev: true
/set-function-length@1.2.1:
resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==}
@ -5563,6 +6018,11 @@ packages:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: false
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
dev: false
/sinon@17.0.1:
resolution: {integrity: sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==}
dependencies:
@ -5650,6 +6110,12 @@ packages:
- utf-8-validate
dev: false
/sonic-boom@3.8.0:
resolution: {integrity: sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==}
dependencies:
atomic-sleep: 1.0.0
dev: false
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
@ -5675,6 +6141,11 @@ packages:
resolution: {integrity: sha512-ELtFtxc3r5we5GZfe6Fi0BFFxIi2M6BY1YEntBscKRDD3zx4JVHqx2VnTRSQu1BixCYSTH3MTjKd4esI2R7EgQ==}
dev: true
/split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
dev: false
/statuses@2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
engines: {node: '>= 0.8'}
@ -5698,7 +6169,15 @@ packages:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
dev: false
/string.prototype.trim@1.2.8:
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
@ -5725,6 +6204,12 @@ packages:
es-abstract: 1.22.4
dev: true
/string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: false
/stringify-entities@4.0.3:
resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==}
dependencies:
@ -5737,7 +6222,13 @@ packages:
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
dev: false
/strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
@ -5747,7 +6238,6 @@ packages:
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
dev: true
/superagent@8.1.2:
resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==}
@ -5843,6 +6333,12 @@ packages:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
/thread-stream@2.4.1:
resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==}
dependencies:
real-require: 0.2.0
dev: false
/threads@1.7.0:
resolution: {integrity: sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==}
dependencies:
@ -5880,6 +6376,11 @@ packages:
is-number: 7.0.0
dev: true
/toad-cache@3.7.0:
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
engines: {node: '>=12'}
dev: false
/toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
@ -5938,7 +6439,6 @@ packages:
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
/tsutils@3.21.0(typescript@5.4.2):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
@ -6380,7 +6880,15 @@ packages:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
dependencies:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
dev: false
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}

View file

@ -7,7 +7,6 @@ import _ from 'underscore';
// @ts-ignore
import cookieParser from 'cookie-parser';
import events from 'events';
import express from 'express';
// @ts-ignore
import expressSession from 'express-session';
import fs from 'fs';
@ -18,7 +17,7 @@ const settings = require('../utils/Settings');
const stats = require('../stats')
import util from 'util';
const webaccess = require('./express/webaccess');
import Fastify from 'fastify';
import SecretRotator from '../security/SecretRotator';
let secretRotator: SecretRotator|null = null;
@ -100,7 +99,21 @@ exports.createServer = async () => {
exports.restartServer = async () => {
await closeServer();
const app = express(); // New syntax for express v3
console.log('Starting Etherpad...');
const fastify = Fastify({
logger: {
level: 'error',
transport: {
target: 'pino-pretty',
options: {
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
},
}
}
});
await fastify.register(require('@fastify/express'))
if (settings.ssl) {
console.log('SSL -- enabled');
@ -119,142 +132,140 @@ exports.restartServer = async () => {
options.ca.push(fs.readFileSync(caFileName));
}
}
const https = require('https');
exports.server = https.createServer(options, app);
} else {
const http = require('http');
exports.server = http.createServer(app);
}
app.use((req, res, next) => {
// res.header("X-Frame-Options", "deny"); // breaks embedded pads
if (settings.ssl) {
// we use SSL
res.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
exports.server = fastify.server
// Stop IE going into compatability mode
// https://github.com/ether/etherpad-lite/issues/2547
res.header('X-UA-Compatible', 'IE=Edge,chrome=1');
fastify.use((req, res, next) => {
// res.header("X-Frame-Options", "deny"); // breaks embedded pads
if (settings.ssl) {
// we use SSL
res.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
// Enable a strong referrer policy. Same-origin won't drop Referers when
// loading local resources, but it will drop them when loading foreign resources.
// It's still a last bastion of referrer security. External URLs should be
// already marked with rel="noreferer" and user-generated content pages are already
// marked with <meta name="referrer" content="no-referrer">
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
// https://github.com/ether/etherpad-lite/pull/3636
res.header('Referrer-Policy', 'same-origin');
// Stop IE going into compatability mode
// https://github.com/ether/etherpad-lite/issues/2547
res.header('X-UA-Compatible', 'IE=Edge,chrome=1');
// send git version in the Server response header if exposeVersion is true.
if (settings.exposeVersion) {
res.header('Server', serverName);
}
// Enable a strong referrer policy. Same-origin won't drop Referers when
// loading local resources, but it will drop them when loading foreign resources.
// It's still a last bastion of referrer security. External URLs should be
// already marked with rel="noreferer" and user-generated content pages are already
// marked with <meta name="referrer" content="no-referrer">
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
// https://github.com/ether/etherpad-lite/pull/3636
res.header('Referrer-Policy', 'same-origin');
next();
});
// send git version in the Server response header if exposeVersion is true.
if (settings.exposeVersion) {
res.header('Server', serverName);
}
if (settings.trustProxy) {
/*
* If 'trust proxy' === true, the clients IP address in req.ip will be the
* left-most entry in the X-Forwarded-* header.
*
* Source: https://expressjs.com/en/guide/behind-proxies.html
*/
app.enable('trust proxy');
}
// Measure response time
app.use((req, res, next) => {
const stopWatch = stats.timer('httpRequests').start();
const sendFn = res.send.bind(res);
res.send = (...args) => { stopWatch.end(); return sendFn(...args); };
next();
});
// If the log level specified in the config file is WARN or ERROR the application server never
// starts listening to requests as reported in issue #158. Not installing the log4js connect
// logger when the log level has a higher severity than INFO since it would not log at that level
// anyway.
if (!(settings.loglevel === 'WARN' && settings.loglevel === 'ERROR')) {
app.use(log4js.connectLogger(logger, {
level: log4js.levels.DEBUG.levelStr,
format: ':status, :method :url',
}));
}
const {keyRotationInterval, sessionLifetime} = settings.cookie;
let secret = settings.sessionKey;
if (keyRotationInterval && sessionLifetime) {
secretRotator = new SecretRotator(
'expressSessionSecrets', keyRotationInterval, sessionLifetime, settings.sessionKey);
await secretRotator.start();
secret = secretRotator.secrets;
}
if (!secret) throw new Error('missing cookie signing secret');
app.use(cookieParser(secret, {}));
sessionStore = new SessionStore(settings.cookie.sessionRefreshInterval);
exports.sessionMiddleware = expressSession({
propagateTouch: true,
rolling: true,
secret,
store: sessionStore,
resave: false,
saveUninitialized: false,
// Set the cookie name to a javascript identifier compatible string. Makes code handling it
// cleaner :)
name: 'express_sid',
cookie: {
maxAge: sessionLifetime || null, // Convert 0 to null.
sameSite: settings.cookie.sameSite,
// The automatic express-session mechanism for determining if the application is being served
// over ssl is similar to the one used for setting the language cookie, which check if one of
// these conditions is true:
//
// 1. we are directly serving the nodejs application over SSL, using the "ssl" options in
// settings.json
//
// 2. we are serving the nodejs application in plaintext, but we are using a reverse proxy
// that terminates SSL for us. In this case, the user has to set trustProxy = true in
// settings.json, and the information wheter the application is over SSL or not will be
// extracted from the X-Forwarded-Proto HTTP header
//
// Please note that this will not be compatible with applications being served over http and
// https at the same time.
//
// reference: https://github.com/expressjs/session/blob/v1.17.0/README.md#cookiesecure
secure: 'auto',
},
});
// Give plugins an opportunity to install handlers/middleware before the express-session
// middleware. This allows plugins to avoid creating an express-session record in the database
// when it is not needed (e.g., public static content).
await hooks.aCallAll('expressPreSession', {app});
app.use(exports.sessionMiddleware);
app.use(webaccess.checkAccess);
await Promise.all([
hooks.aCallAll('expressConfigure', {app}),
hooks.aCallAll('expressCreateServer', {app, server: exports.server}),
]);
exports.server.on('connection', (socket:Socket) => {
sockets.add(socket);
socketsEvents.emit('updated');
socket.on('close', () => {
sockets.delete(socket);
socketsEvents.emit('updated');
next();
});
});
await util.promisify(exports.server.listen).bind(exports.server)(settings.port, settings.ip);
if (settings.trustProxy) {
/*
* If 'trust proxy' === true, the clients IP address in req.ip will be the
* left-most entry in the X-Forwarded-* header.
*
* Source: https://expressjs.com/en/guide/behind-proxies.html
*/
fastify.enable('trust proxy');
}
// Measure response time
fastify.use((req, res, next) => {
const stopWatch = stats.timer('httpRequests').start();
const sendFn = res.send.bind(res);
res.send = (...args) => {
stopWatch.end();
return sendFn(...args);
};
next();
});
// If the log level specified in the config file is WARN or ERROR the application server never
// starts listening to requests as reported in issue #158. Not installing the log4js connect
// logger when the log level has a higher severity than INFO since it would not log at that level
// anyway.
if (!(settings.loglevel === 'WARN' && settings.loglevel === 'ERROR')) {
}
const {keyRotationInterval, sessionLifetime} = settings.cookie;
let secret = settings.sessionKey;
if (keyRotationInterval && sessionLifetime) {
secretRotator = new SecretRotator(
'expressSessionSecrets', keyRotationInterval, sessionLifetime, settings.sessionKey);
await secretRotator.start();
secret = secretRotator.secrets;
}
if (!secret) throw new Error('missing cookie signing secret');
fastify.use(cookieParser(secret, {}));
sessionStore = new SessionStore(settings.cookie.sessionRefreshInterval);
exports.sessionMiddleware = expressSession({
propagateTouch: true,
rolling: true,
secret,
store: sessionStore,
resave: false,
saveUninitialized: false,
// Set the cookie name to a javascript identifier compatible string. Makes code handling it
// cleaner :)
name: 'express_sid',
cookie: {
maxAge: sessionLifetime || null, // Convert 0 to null.
sameSite: settings.cookie.sameSite,
// The automatic express-session mechanism for determining if the application is being served
// over ssl is similar to the one used for setting the language cookie, which check if one of
// these conditions is true:
//
// 1. we are directly serving the nodejs application over SSL, using the "ssl" options in
// settings.json
//
// 2. we are serving the nodejs application in plaintext, but we are using a reverse proxy
// that terminates SSL for us. In this case, the user has to set trustProxy = true in
// settings.json, and the information wheter the application is over SSL or not will be
// extracted from the X-Forwarded-Proto HTTP header
//
// Please note that this will not be compatible with applications being served over http and
// https at the same time.
//
// reference: https://github.com/expressjs/session/blob/v1.17.0/README.md#cookiesecure
secure: 'auto',
},
});
// Give plugins an opportunity to install handlers/middleware before the express-session
// middleware. This allows plugins to avoid creating an express-session record in the database
// when it is not needed (e.g., public static content).
await hooks.aCallAll('expressPreSession', {app:fastify});
fastify.use(exports.sessionMiddleware);
fastify.use(webaccess.checkAccess);
await Promise.all([
hooks.aCallAll('expressConfigure', {app: fastify}),
hooks.aCallAll('expressCreateServer', {app:fastify, server: fastify}),
]);
exports.server.on('connection', (socket: Socket) => {
sockets.add(socket);
socketsEvents.emit('updated');
socket.on('close', () => {
sockets.delete(socket);
socketsEvents.emit('updated');
});
});
// Run the server!
await fastify.listen({
port: settings.port,
})
startTime.setValue(Date.now());
logger.info('HTTP server listening for connections');
};
logger.info('HTTP server listening for connections');
}
exports.shutdown = async (hookName:string, context: any) => {
await closeServer();

View file

@ -24,9 +24,8 @@ exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Functio
},
});
// handle export requests
args.app.use('/p/:pad/:rev?/export/:type', limiter);
args.app.get('/p/:pad/:rev?/export/:type', (req:any, res:any, next:Function) => {
const handleImport = (req:any, res:any, next:Function) => {
(async () => {
const types = ['pdf', 'doc', 'txt', 'html', 'odt', 'etherpad'];
// send a 404 if we don't support this filetype
@ -38,12 +37,12 @@ exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Functio
if (settings.exportAvailable() === 'no' &&
['odt', 'pdf', 'doc'].indexOf(req.params.type) !== -1) {
console.error(`Impossible to export pad "${req.params.pad}" in ${req.params.type} format.` +
' There is no converter configured');
' There is no converter configured');
// ACHTUNG: do not include req.params.type in res.send() because there is
// no HTML escaping and it would lead to an XSS
res.send('This export is not enabled at this Etherpad instance. Set the path to Abiword' +
' or soffice (LibreOffice) in settings.json to enable this feature');
' or soffice (LibreOffice) in settings.json to enable this feature');
return;
}
@ -68,22 +67,26 @@ exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Functio
await exportHandler.doExport(req, res, padId, readOnlyId, req.params.type);
}
})().catch((err) => next(err || new Error(err)));
});
};
// handle export requests
args.app.use('/p/:pad/export/:type', limiter);
args.app.use('/p/:pad/:rev/export/:type', limiter);
args.app.get('/p/:pad/:rev/export/:type', handleImport);
args.app.get('/p/:pad/export/:type', handleImport);
// handle import requests
args.app.use('/p/:pad/import', limiter);
args.app.post('/p/:pad/import', (req:any, res:any, next:Function) => {
(async () => {
// @ts-ignore
const {session: {user} = {}} = req;
const {accessStatus, authorID: authorId} = await securityManager.checkAccess(
req.params.pad, req.cookies.sessionID, req.cookies.token, user);
if (accessStatus !== 'grant' || !webaccess.userCanModify(req.params.pad, req)) {
return res.status(403).send('Forbidden');
}
await importHandler.doImport(req, res, req.params.pad, authorId);
})().catch((err) => next(err || new Error(err)));
});
args.app.post('/p/:pad/import', async (req: any, res: any, next: Function) => {
const {session: {user} = {}} = req;
const {accessStatus, authorID: authorId} = await securityManager.checkAccess(
req.params.pad, req.cookies.sessionID, req.cookies.token, user);
if (accessStatus !== 'grant' || !webaccess.userCanModify(req.params.pad, req)) {
return res.status(403).send('Forbidden');
}
await importHandler.doImport(req, res, req.params.pad, authorId);
})
return cb();
};

View file

@ -6,27 +6,5 @@ const padManager = require('../../db/PadManager');
exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => {
// redirects browser to the pad's sanitized url if needed. otherwise, renders the html
args.app.param('pad', (req:any, res:any, next:Function, padId:string) => {
(async () => {
// ensure the padname is valid and the url doesn't end with a /
if (!padManager.isValidPadId(padId) || /\/$/.test(req.url)) {
res.status(404).send('Such a padname is forbidden');
return;
}
const sanitizedPadId = await padManager.sanitizePadId(padId);
if (sanitizedPadId === padId) {
// the pad id was fine, so just render it
next();
} else {
// the pad id was sanitized, so we redirect to the sanitized version
const realURL =
encodeURIComponent(sanitizedPadId) + new URL(req.url, 'http://invalid.invalid').search;
res.header('Location', realURL);
res.status(302).send(`You should be redirected to <a href="${realURL}">${realURL}</a>`);
}
})().catch((err) => next(err || new Error(err)));
});
return cb();
};

View file

@ -70,7 +70,7 @@ export const expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Fu
// there shouldn't be a browser that isn't compatible to all
// transports in this list at once
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
io = new Server(args.server,{
io = new Server(args.server.server,{
transports: settings.socketTransportProtocols,
cookie: false,
maxHttpBufferSize: settings.socketIo.maxHttpBufferSize,

View file

@ -22,61 +22,59 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
});
app.get('/stats', (req:any, res:any) => {
res.json(require('../../stats').toJSON());
require('../../stats');
});
app.get('/javascript', (req:any, res:any) => {
res.send(eejs.require('ep_etherpad-lite/templates/javascript.html', {req}));
res.type('text/html').send(eejs.require('ep_etherpad-lite/templates/javascript.html', {req}))
});
app.get('/robots.txt', (req:any, res:any) => {
let filePath =
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'robots.txt');
res.sendFile(filePath, (err:any) => {
// there is no custom robots.txt, send the default robots.txt which dissallows all
if (err) {
filePath = path.join(settings.root, 'src', 'static', 'robots.txt');
res.sendFile(filePath);
}
});
fs.stat(filePath, (err:any, stats:any) => {
if (err) {
filePath = path.join(settings.root, 'src', 'static', 'robots.txt');
}
const buffer = fs.readFileSync(filePath) // sync just for DEMO
res.type('text/plain').send(buffer, {req})
})
});
app.get('/favicon.ico', (req:any, res:any, next:Function) => {
(async () => {
/*
If this is a url we simply redirect to that one.
*/
if (settings.favicon && settings.favicon.startsWith('http')) {
res.redirect(settings.favicon);
res.send();
return;
}
app.get('/favicon.ico', async (req: any, res: any) => {
/*
If this is a url we simply redirect to that one.
*/
if (settings.favicon && settings.favicon.startsWith('http')) {
res.redirect(settings.favicon);
res.send();
return;
}
const fns = [
...(settings.favicon ? [path.resolve(settings.root, settings.favicon)] : []),
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'),
path.join(settings.root, 'src', 'static', 'favicon.ico'),
];
for (const fn of fns) {
try {
await fsp.access(fn, fs.constants.R_OK);
} catch (err) {
continue;
}
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
await util.promisify(res.sendFile.bind(res))(fn);
return;
const fns = [
...(settings.favicon ? [path.resolve(settings.root, settings.favicon)] : []),
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'),
path.join(settings.root, 'src', 'static', 'favicon.ico'),
];
for (const fn of fns) {
try {
await fsp.access(fn, fs.constants.R_OK);
} catch (err) {
continue;
}
next();
})().catch((err) => next(err || new Error(err)));
res.header('Cache-Control', `public, max-age=${settings.maxAge}`);
return fs.readFileSync(fn)
}
});
};
exports.expressCreateServer = (hookName:string, args:any, cb:Function) => {
// serve index.html under /
args.app.get('/', (req:any, res:any) => {
res.send(eejs.require('ep_etherpad-lite/templates/index.html', {req}));
res.type('text/html').send(eejs.require('ep_etherpad-lite/templates/index.html', {req}))
//res.send(eejs.require('ep_etherpad-lite/templates/index.html', {req}));
});
// serve pad.html under /p
@ -91,11 +89,11 @@ exports.expressCreateServer = (hookName:string, args:any, cb:Function) => {
// can be removed when require-kernel is dropped
res.header('Feature-Policy', 'sync-xhr \'self\'');
res.send(eejs.require('ep_etherpad-lite/templates/pad.html', {
res.type('text/html').send(eejs.require('ep_etherpad-lite/templates/pad.html', {
req,
toolbar,
isReadOnly,
}));
}), {req})
});
// serve timeslider.html under /p/$padname/timeslider
@ -103,11 +101,8 @@ exports.expressCreateServer = (hookName:string, args:any, cb:Function) => {
hooks.callAll('padInitToolbar', {
toolbar,
});
res.send(eejs.require('ep_etherpad-lite/templates/timeslider.html', {
req,
toolbar,
}));
res.type('text/html').send(eejs.require('ep_etherpad-lite/templates/pad.html',
{req, toolbar}));
});
// The client occasionally polls this endpoint to get an updated expiration for the express_sid

View file

@ -36,12 +36,40 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
// Cache both minified and static.
const assetCache = new CachingMiddleware();
// Cache static assets
app.all(/\/js\/(.*)/, assetCache.handle.bind(assetCache));
app.all(/\/css\/(.*)/, assetCache.handle.bind(assetCache));
app.get('/static/js/require-kernel.js', (req:any, res:any) => {
res.header('Content-Type', 'application/javascript; charset=utf-8');
res.header('Cache-Control', `public, max-age=${settings.maxAge}`);
const file = fs.readFile(path.join(settings.root, 'src/static/js/require-kernel.js'), 'utf8');
res.send();
})
app.route({
method: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
url: '/js/*',
handler: assetCache.handle.bind(assetCache)
});
app.route({
method: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
url: '/css/*',
handler: assetCache.handle.bind(assetCache)
});
/*app.register(require('@fastify/static'), {
root: path.join(settings.root, 'src', 'static'),
prefix: '/static/', // optional: default '/'
constraints: {} // optional: default {}
})*/
// Minify will serve static files compressed (minify enabled). It also has
// file-specific hacks for ace/require-kernel/etc.
app.all('/static/:filename(*)', minify.minify);
app.route({
method: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
url: '/static/*',
handler: minify.minify
});
// Setup middleware that will package JavaScript files served by minify for
// CommonJS loader on the client-side.
@ -73,9 +101,9 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
// @ts-ignore
delete clientPlugins[name].package;
}
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.write(JSON.stringify({plugins: clientPlugins, parts: clientParts}));
res.end();
res.header('Content-Type', 'application/json; charset=utf-8')
res.header('Cache-Control', `public, max-age=${settings.maxAge}`)
return {plugins: clientPlugins, parts: clientParts};
});
};

View file

@ -133,8 +133,8 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
// works with /locale/en and /locale/en.json requests
const locale = req.params.locale.split('.')[0];
if (Object.prototype.hasOwnProperty.call(exports.availableLangs, locale)) {
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.header('Cache-Control', `public, max-age=${settings.maxAge}`);
res.header('Content-Type', 'application/json; charset=utf-8');
res.send(`{"${locale}":${JSON.stringify(locales[locale])}}`);
} else {
res.status(404).send('Language not available');
@ -142,8 +142,8 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
});
app.get('/locales.json', (req: any, res:any) => {
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.header('Cache-Control', `public, max-age=${settings.maxAge}`);
res.header('Content-Type', 'application/json; charset=utf-8');
res.send(localeIndex);
});
};

View file

@ -15,13 +15,11 @@
* limitations under the License.
*/
import log4js from 'log4js';
const Changeset = require('../../static/js/Changeset');
const contentcollector = require('../../static/js/contentcollector');
import jsdom from 'jsdom';
import {PadType} from "../types/PadType";
const apiLogger = log4js.getLogger('ImportHtml');
let processor:any;
exports.setPadHTML = async (pad: PadType, html:string, authorId = '') => {
@ -38,8 +36,8 @@ exports.setPadHTML = async (pad: PadType, html:string, authorId = '') => {
// below the last line of an import
document.body.appendChild(document.createElement('p'));
apiLogger.debug('html:');
apiLogger.debug(html);
console.debug('html:');
console.debug(html);
// Convert a dom tree into a list of lines and attribute liens
// using the content collector object
@ -48,24 +46,24 @@ exports.setPadHTML = async (pad: PadType, html:string, authorId = '') => {
// we use a try here because if the HTML is bad it will blow up
cc.collectContent(document.body);
} catch (err: any) {
apiLogger.warn(`Error processing HTML: ${err.stack || err}`);
console.warn(`Error processing HTML: ${err.stack || err}`);
throw err;
}
const result = cc.finish();
apiLogger.debug('Lines:');
console.debug('Lines:');
let i;
for (i = 0; i < result.lines.length; i++) {
apiLogger.debug(`Line ${i + 1} text: ${result.lines[i]}`);
apiLogger.debug(`Line ${i + 1} attributes: ${result.lineAttribs[i]}`);
console.debug(`Line ${i + 1} text: ${result.lines[i]}`);
console.debug(`Line ${i + 1} attributes: ${result.lineAttribs[i]}`);
}
// Get the new plain text and its attributes
const newText = result.lines.join('\n');
apiLogger.debug('newText:');
apiLogger.debug(newText);
console.debug('newText:');
console.debug(newText);
const newAttribs = `${result.lineAttribs.join('|1+1')}|1+1`;
// create a new changeset with a helper builder object
@ -88,7 +86,7 @@ exports.setPadHTML = async (pad: PadType, html:string, authorId = '') => {
// the changeset is ready!
const theChangeset = builder.toString();
apiLogger.debug(`The changeset: ${theChangeset}`);
console.debug(`The changeset: ${theChangeset}`);
await pad.setText('\n', authorId);
await pad.appendRevision(theChangeset, authorId);
};

View file

@ -126,9 +126,7 @@ const minify = async (req, res) => {
filename = sanitizePathname(filename);
} catch (err) {
logger.error(`sanitization of pathname "${filename}" failed: ${err.stack || err}`);
res.writeHead(404, {});
res.end();
return;
return res.status(404).send();
}
// Backward compatibility for plugins that require() files from old paths.
@ -174,12 +172,12 @@ const minify = async (req, res) => {
const [date, exists] = await statFile(filename, 3);
if (date) {
date.setMilliseconds(0);
res.setHeader('last-modified', date.toUTCString());
res.setHeader('date', (new Date()).toUTCString());
res.header('last-modified', date.toUTCString());
res.header('date', (new Date()).toUTCString());
if (settings.maxAge !== undefined) {
const expiresDate = new Date(Date.now() + settings.maxAge * 1000);
res.setHeader('expires', expiresDate.toUTCString());
res.setHeader('cache-control', `max-age=${settings.maxAge}`);
res.header('expires', expiresDate.toUTCString());
res.header('cache-control', `max-age=${settings.maxAge}`);
}
}
@ -317,7 +315,7 @@ const getFile = async (filename) => {
return await fs.readFile(path.resolve(ROOT_DIR, filename));
};
exports.minify = (req, res, next) => minify(req, res).catch((err) => next(err || new Error(err)));
exports.minify = (req, res, next) => minify(req, res);
exports.requestURIs = requestURIs;

View file

@ -28,7 +28,6 @@
*/
const absolutePaths = require('./AbsolutePaths');
const deepEqual = require('fast-deep-equal/es6');
const fs = require('fs');
const os = require('os');
const path = require('path');

View file

@ -157,14 +157,14 @@ export default class CachingMiddleware {
}
const _headers:Headers = {};
oldRes.setHeader = res.setHeader;
res.setHeader = (key: string, value: string) => {
oldRes.header = res.header;
res.header = (key: string, value: string) => {
// Don't set cookies, see issue #707
if (key.toLowerCase() === 'set-cookie') return;
_headers[key.toLowerCase()] = value;
// @ts-ignore
oldRes.setHeader.call(res, key, value);
oldRes.header.call(res, key, value);
};
oldRes.writeHead = res.writeHead;
@ -175,7 +175,7 @@ export default class CachingMiddleware {
let buffer = '';
Object.keys(headers || {}).forEach((key) => {
res.setHeader(key, headers[key]);
res.header(key, headers[key]);
});
headers = _headers;

View file

@ -1,10 +1,11 @@
'use strict';
const path = require('path');
import path from 'path';
// Normalizes p and ensures that it is a relative path that does not reach outside. See
// https://nvd.nist.gov/vuln/detail/CVE-2015-3297 for additional context.
module.exports = (p: string, pathApi = path) => {
console.log('p:', p);
// The documentation for path.normalize() says that it resolves '..' and '.' segments. The word
// "resolve" implies that it examines the filesystem to resolve symbolic links, so 'a/../b' might
// not be the same thing as 'b'. Most path normalization functions from other libraries (e.g.,

View file

@ -30,6 +30,8 @@
}
],
"dependencies": {
"@fastify/express": "^2.3.0",
"@fastify/static": "^7.0.1",
"async": "^3.2.5",
"axios": "^1.6.8",
"clean-css": "^5.3.3",
@ -42,6 +44,8 @@
"express-rate-limit": "^7.2.0",
"express-session": "npm:@etherpad/express-session@^1.18.2",
"fast-deep-equal": "^3.1.3",
"fastify": "^4.26.2",
"fastify-socket.io": "^5.0.0",
"find-root": "1.1.0",
"formidable": "^3.5.1",
"http-errors": "^2.0.0",
@ -55,10 +59,13 @@
"measured-core": "^2.0.0",
"mime-types": "^2.1.35",
"openapi-backend": "^5.10.6",
"pino": "^8.19.0",
"pino-pretty": "^10.3.1",
"proxy-addr": "^2.0.7",
"rate-limiter-flexible": "^5.0.0",
"rehype": "^13.0.1",
"rehype-minify-whitespace": "^6.0.0",
"require-from-url": "^3.1.3",
"resolve": "1.22.8",
"security": "1.0.0",
"semver": "^7.6.0",
@ -79,15 +86,16 @@
"etherpad-lite": "node/server.ts"
},
"devDependencies": {
"@playwright/test": "^1.42.1",
"@types/async": "^3.2.24",
"@types/express": "^4.17.21",
"@types/http-errors": "^2.0.4",
"@types/jsdom": "^21.1.6",
"@types/mocha": "^10.0.6",
"@types/node": "^20.11.28",
"@types/semver": "^7.5.8",
"@types/sinon": "^17.0.3",
"@types/supertest": "^6.0.2",
"@types/semver": "^7.5.8",
"@types/underscore": "^1.11.15",
"eslint": "^8.57.0",
"eslint-config-etherpad": "^3.0.22",
@ -96,7 +104,6 @@
"mocha-froth": "^0.2.10",
"nodeify": "^1.0.1",
"openapi-schema-validation": "^0.4.2",
"@playwright/test": "^1.42.1",
"set-cookie-parser": "^2.6.0",
"sinon": "^17.0.1",
"split-grid": "^1.0.11",

View file

@ -23,12 +23,13 @@
*/
let socket;
const requireFromUrl = require('require-from-url/sync');
// These jQuery things should create local references, but for now `require()`
// assigns to the global `$` and augments it with plugins.
require('./vendors/jquery');
require('./vendors/farbtastic');
require('./vendors/gritter');
requireFromUrl('./vendors/jquery');
requireFromUrl('./vendors/farbtastic');
requireFromUrl('./vendors/gritter');
const Cookies = require('./pad_utils').Cookies;
const chat = require('./chat').chat;

View file

@ -1,6 +1,5 @@
'use strict';
import log4js from "log4js";
import axios, {AxiosResponse} from "axios";
import {PackageData, PackageInfo} from "../../../node/types/PackageInfo";
@ -17,7 +16,6 @@ const settings = require('../../../node/utils/Settings');
import {LinkInstaller} from "./LinkInstaller";
const {findEtherpadRoot} = require('../../../node/utils/AbsolutePaths');
const logger = log4js.getLogger('plugins');
export const pluginInstallPath = path.join(settings.root, 'src','plugin_packages');
export const node_modules = path.join(findEtherpadRoot(),'src', 'node_modules');
@ -51,7 +49,7 @@ const wrapTaskCb = (cb:Function|null) => {
};
const migratePluginsFromNodeModules = async () => {
logger.info('start migration of plugins in node_modules');
console.info('start migration of plugins in node_modules');
// Notes:
// * Do not pass `--prod` otherwise `npm ls` will fail if there is no `package.json`.
// * The `--no-production` flag is required (or the `NODE_ENV` environment variable must be
@ -75,7 +73,7 @@ const migratePluginsFromNodeModules = async () => {
};
export const checkForMigration = async () => {
logger.info('check installed plugins for migration');
console.info('check installed plugins for migration');
// Initialize linkInstaller
await linkInstaller.init()
@ -101,15 +99,15 @@ export const checkForMigration = async () => {
const moduleName = path.basename(file);
try {
await fs.access(path.join(node_modules, moduleName), fs.constants.F_OK);
logger.debug(`plugin ${moduleName} already exists in node_modules`);
console.debug(`plugin ${moduleName} already exists in node_modules`);
} catch (err) {
// Create symlink to node_modules
logger.debug(`create symlink for ${file} to ${path.join(node_modules,moduleName)}`)
console.debug(`create symlink for ${file} to ${path.join(node_modules,moduleName)}`)
await fs.symlink(path.join(pluginInstallPath,file), path.join(node_modules,moduleName), 'dir')
}
}
}).catch(()=>{
logger.debug('plugin directory does not exist');
console.debug('plugin directory does not exist');
})
const fileContent = await fs.readFile(installedPluginsPath);
const installedPlugins = JSON.parse(fileContent.toString());
@ -137,19 +135,19 @@ const persistInstalledPlugins = async () => {
export const uninstall = async (pluginName: string, cb:Function|null = null) => {
cb = wrapTaskCb(cb);
logger.info(`Uninstalling plugin ${pluginName}...`);
console.info(`Uninstalling plugin ${pluginName}...`);
await linkInstaller.uninstallPlugin(pluginName);
logger.info(`Successfully uninstalled plugin ${pluginName}`);
console.info(`Successfully uninstalled plugin ${pluginName}`);
await hooks.aCallAll('pluginUninstall', {pluginName});
cb(null);
};
export const install = async (pluginName: string, cb:Function|null = null) => {
cb = wrapTaskCb(cb);
logger.info(`Installing plugin ${pluginName}...`);
console.info(`Installing plugin ${pluginName}...`);
await linkInstaller.installPlugin(pluginName);
logger.info(`Successfully installed plugin ${pluginName}`);
console.info(`Successfully installed plugin ${pluginName}`);
await hooks.aCallAll('pluginInstall', {pluginName});
cb(null);
};
@ -195,7 +193,7 @@ export const search = (searchTerm: string, maxCacheAge: number) => getAvailableP
!~results[pluginName].description.toLowerCase().indexOf(searchTerm))
) {
if (typeof results[pluginName].description === 'undefined') {
logger.debug(`plugin without Description: ${results[pluginName].name}`);
console.debug(`plugin without Description: ${results[pluginName].name}`);
}
continue;