@vex-chat/spire 0.8.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -26
- package/dist/ClientManager.d.ts +23 -25
- package/dist/ClientManager.js +230 -249
- package/dist/ClientManager.js.map +1 -0
- package/dist/Database.d.ts +49 -47
- package/dist/Database.js +698 -773
- package/dist/Database.js.map +1 -0
- package/dist/Spire.d.ts +22 -14
- package/dist/Spire.js +496 -236
- package/dist/Spire.js.map +1 -0
- package/dist/__tests__/Database.spec.js +116 -75
- package/dist/__tests__/Database.spec.js.map +1 -0
- package/dist/db/schema.d.ts +134 -0
- package/dist/db/schema.js +2 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -0
- package/dist/middleware/validate.d.ts +12 -0
- package/dist/middleware/validate.js +35 -0
- package/dist/middleware/validate.js.map +1 -0
- package/dist/migrations/2026-04-06_initial-schema.d.ts +3 -0
- package/dist/migrations/2026-04-06_initial-schema.js +192 -0
- package/dist/migrations/2026-04-06_initial-schema.js.map +1 -0
- package/dist/run.js +26 -21
- package/dist/run.js.map +1 -0
- package/dist/server/avatar.d.ts +3 -4
- package/dist/server/avatar.js +64 -64
- package/dist/server/avatar.js.map +1 -0
- package/dist/server/errors.d.ts +59 -0
- package/dist/server/errors.js +94 -0
- package/dist/server/errors.js.map +1 -0
- package/dist/server/file.d.ts +3 -4
- package/dist/server/file.js +81 -62
- package/dist/server/file.js.map +1 -0
- package/dist/server/index.d.ts +8 -10
- package/dist/server/index.js +414 -405
- package/dist/server/index.js.map +1 -0
- package/dist/server/invite.d.ts +4 -5
- package/dist/server/invite.js +18 -52
- package/dist/server/invite.js.map +1 -0
- package/dist/server/openapi.d.ts +2 -0
- package/dist/server/openapi.js +40 -0
- package/dist/server/openapi.js.map +1 -0
- package/dist/server/permissions.d.ts +16 -0
- package/dist/server/permissions.js +22 -0
- package/dist/server/permissions.js.map +1 -0
- package/dist/server/rateLimit.d.ts +28 -0
- package/dist/server/rateLimit.js +58 -0
- package/dist/server/rateLimit.js.map +1 -0
- package/dist/server/user.d.ts +4 -7
- package/dist/server/user.js +55 -66
- package/dist/server/user.js.map +1 -0
- package/dist/server/utils.d.ts +35 -7
- package/dist/server/utils.js +50 -6
- package/dist/server/utils.js.map +1 -0
- package/dist/types/express.d.ts +20 -0
- package/dist/types/express.js +2 -0
- package/dist/types/express.js.map +1 -0
- package/dist/utils/createLogger.js +13 -19
- package/dist/utils/createLogger.js.map +1 -0
- package/dist/utils/createUint8UUID.js +6 -10
- package/dist/utils/createUint8UUID.js.map +1 -0
- package/dist/utils/jwtSecret.d.ts +7 -0
- package/dist/utils/jwtSecret.js +15 -0
- package/dist/utils/jwtSecret.js.map +1 -0
- package/dist/utils/loadEnv.js +7 -22
- package/dist/utils/loadEnv.js.map +1 -0
- package/dist/utils/msgpack.d.ts +2 -0
- package/dist/utils/msgpack.js +4 -0
- package/dist/utils/msgpack.js.map +1 -0
- package/package.json +91 -65
- package/src/ClientManager.ts +434 -0
- package/src/Database.ts +925 -0
- package/src/Spire.ts +878 -0
- package/src/__tests__/Database.spec.ts +167 -0
- package/src/ambient-modules.d.ts +1 -0
- package/src/db/schema.ts +165 -0
- package/src/index.ts +3 -0
- package/src/middleware/validate.ts +38 -0
- package/src/migrations/2026-04-06_initial-schema.ts +218 -0
- package/src/run.ts +37 -0
- package/src/server/avatar.ts +141 -0
- package/src/server/errors.ts +133 -0
- package/src/server/file.ts +172 -0
- package/src/server/index.ts +855 -0
- package/src/server/invite.ts +65 -0
- package/src/server/openapi.ts +51 -0
- package/src/server/permissions.ts +40 -0
- package/src/server/rateLimit.ts +86 -0
- package/src/server/user.ts +125 -0
- package/src/server/utils.ts +59 -0
- package/src/types/express.ts +23 -0
- package/src/utils/createLogger.ts +47 -0
- package/src/utils/createUint8UUID.ts +9 -0
- package/src/utils/jwtSecret.ts +16 -0
- package/src/utils/loadEnv.ts +15 -0
- package/src/utils/msgpack.ts +4 -0
- package/avatars/052242d0-4129-4a6e-8076-22709c157549 +0 -0
- package/avatars/0a677c9a-4986-4b2c-ae2e-12faf22f55db +0 -0
- package/avatars/0ba21b91-decb-4a3e-ac86-4dd54d805a9a +0 -0
- package/avatars/0c48d8b6-1d1b-4297-a6c6-2fe50af6fc35 +0 -0
- package/avatars/0d993cdf-19a6-4299-a4ee-a06579d106cf +0 -0
- package/avatars/17b000e4-ac38-46ec-9dec-d2568086129a +0 -0
- package/avatars/19dc5594-0f06-4ac6-af18-8740dd39ef6b +0 -0
- package/avatars/20444fa3-6d5e-429e-b55f-b81c3d2c61ee +0 -0
- package/avatars/21c0512a-5630-4931-9442-d66db66737be +0 -0
- package/avatars/22830a60-0b6f-4912-83a5-72245465f332 +0 -0
- package/avatars/243639ce-f59f-4404-a1f1-4ec0eb5d2af3 +0 -0
- package/avatars/30d2c01d-7b7f-4ea9-9859-1c90837a23f7 +0 -0
- package/avatars/315a04f0-9a6f-4b0f-bb9f-5fa774c4752b +0 -0
- package/avatars/3563d333-53fe-4885-ac2d-9a4f761db85e +0 -0
- package/avatars/36a10c00-3b4c-437f-8e1f-4428ecde0003 +0 -0
- package/avatars/40b83eeb-c6e8-4268-82ab-69799a796405 +0 -0
- package/avatars/45b5ddb9-ad2c-4404-8ab3-cb4699e6d61c +0 -0
- package/avatars/4e4f0ffb-9a75-479a-bccb-446d0bf85020 +0 -0
- package/avatars/4e62c3bd-08c6-4fdd-bd65-f01c7322ed64 +0 -0
- package/avatars/5004d2e7-51af-44af-8776-6c71f7019843 +0 -0
- package/avatars/5041eb29-5c4b-4dea-8c1b-31ba4473161a +0 -0
- package/avatars/5065cf78-31c5-46cb-8d5c-c0b6be2d994e +0 -0
- package/avatars/51b91d2c-8956-4d73-b4ad-ca6a8d9da9a8 +0 -0
- package/avatars/58264a2c-5651-4a42-8ca2-a9907b311e48 +0 -0
- package/avatars/58c2357c-8080-4725-a0ce-182c96b037c4 +0 -0
- package/avatars/59b5f6dd-8e04-4d15-b4dc-c1c652558a74 +0 -0
- package/avatars/5b417a78-b274-48bc-98a4-6e54b74ee62d +0 -0
- package/avatars/611f5a93-1ed4-45a1-bc8e-e8e413f9b171 +0 -0
- package/avatars/65abe919-9921-46f6-9bc9-183e9cc53c8a +0 -0
- package/avatars/6934202d-1546-4270-8a15-97ba8b8c6fa9 +0 -0
- package/avatars/6acd24be-f4b7-4399-9e7c-807821828d29 +0 -0
- package/avatars/6b2d6ac5-e35c-4297-994e-f0eb6fe56740 +0 -0
- package/avatars/6cae9ddd-f163-44e7-a632-30425716a159 +0 -0
- package/avatars/6d90e79e-b9c1-4b89-843b-96636de8d26b +0 -0
- package/avatars/6f82c7bb-a974-4372-8a64-ce287e668c8c +0 -0
- package/avatars/74a45091-5a76-4bb7-ae8a-cd7373adc128 +0 -0
- package/avatars/7d071ab2-e0b5-4dbb-8bf5-1fae50c3663f +0 -0
- package/avatars/7de818c8-bda1-4f51-976e-160fc087184b +0 -0
- package/avatars/873937df-8cb1-427a-92bf-f829f4259624 +0 -0
- package/avatars/8b45ffa5-3322-4109-bfa0-1be088336135 +0 -0
- package/avatars/8efaa426-22a9-42a2-b4ac-a275717b812f +0 -0
- package/avatars/903fd1a6-d6ea-431c-b98f-f21e424a2852 +0 -0
- package/avatars/943d8533-5174-4199-990f-1ec69e5d60c4 +0 -0
- package/avatars/952d014e-3804-4cd2-a4a0-ffe40a11e4ac +0 -0
- package/avatars/95d3acb0-724d-4413-b20f-edad55812d5d +0 -0
- package/avatars/9641a946-f613-471b-bedd-c1730b96b51e +0 -0
- package/avatars/9b01cbbf-f6b2-43fb-b569-589b6f2a8134 +0 -0
- package/avatars/9cd4424d-a34f-4467-acc0-93cf82703e0d +0 -0
- package/avatars/9d9ad3b0-e5a6-420a-a6c5-fb9085b70376 +0 -0
- package/avatars/9e9e34b5-4e63-4c4b-9722-c7f5674b47aa +0 -0
- package/avatars/a387d5c1-59eb-4a6b-80c1-a8982ed12c33 +0 -0
- package/avatars/a3e86d21-d881-4824-8ebf-45e3bf0f9186 +0 -0
- package/avatars/a8d5cc1c-3f42-4b7b-8d33-f9a9ef77f96b +0 -0
- package/avatars/a91d815f-badc-4604-a7be-6c7a44e6101d +0 -0
- package/avatars/aa8d0324-bcec-4737-a8c4-bdbff914148d +0 -0
- package/avatars/abb8a941-8b6b-47d7-a2f9-8b153ba44aa2 +0 -0
- package/avatars/b011bb38-1ef3-4d22-82fa-8bf60faf7b5d +0 -0
- package/avatars/b24bcbc1-11f0-473d-a8b9-ba8ce4ca127d +0 -0
- package/avatars/b2607346-af1c-4e98-b725-7650a766db2a +0 -0
- package/avatars/b6300f7c-cb37-459b-b1bf-8a0a0e797a52 +0 -0
- package/avatars/b7d3cff3-84dd-4547-93a1-de1aaa8aa34c +0 -0
- package/avatars/baa4b51c-e97f-4f51-bcb3-f27bc506cfaf +0 -0
- package/avatars/be7022e4-e292-4515-80d5-f9b61ebeb4ce +0 -0
- package/avatars/bed596a3-7569-4854-9e76-f52d33c0a541 +0 -0
- package/avatars/bf69992f-3f72-4930-99bb-0ffe17f3aebf +0 -0
- package/avatars/ca00c250-c6d4-464d-a6de-1c8467a18fe8 +0 -0
- package/avatars/ca19d78f-c0bc-4bd5-b26f-6923cb19996d +0 -0
- package/avatars/cda4d6e1-e0a4-4024-ac95-6de98e713b98 +0 -0
- package/avatars/cf72c30d-2da8-4e81-aa71-735b9e714274 +0 -0
- package/avatars/d5a35b78-99b3-4564-b6b9-b2ccab28c470 +0 -0
- package/avatars/dadb38c1-2a9d-47a3-8d92-b56b6166973c +0 -0
- package/avatars/e68705c7-375d-4423-9a86-29a16bd3ee0e +0 -0
- package/avatars/e9af3e4c-1f62-4302-8b99-b68ce93b7a86 +0 -0
- package/avatars/ea7e7331-e845-4189-8248-5f5b1d63f5e3 +0 -0
- package/avatars/ef4f8dcb-ef6c-4e7a-9be1-0476161bfce5 +0 -0
- package/avatars/ef7d0917-a206-4f88-8b60-93f8253774dc +0 -0
- package/avatars/f1a554d6-1db3-4ff5-b0dc-b607d6c3b4ff +0 -0
- package/avatars/f1fecc21-c81f-49a8-88f3-f942a0a679f6 +0 -0
- package/avatars/f30a2427-1755-4053-813e-129a179e1dd3 +0 -0
- package/avatars/f5370717-5109-46a5-a8d7-e1dd996d0615 +0 -0
- package/avatars/f6dd7126-1144-4998-bbd3-d4e0fbee2e95 +0 -0
- package/avatars/f83413d5-0003-4756-9ece-745fd61cc468 +0 -0
- package/avatars/f9b3149e-7ec8-4bb3-a9b9-dcbe66dac197 +0 -0
- package/avatars/fa41d70b-857e-4423-bd7d-26ddcddc13b9 +0 -0
- package/avatars/fb551ee8-99c7-400b-8e1d-322ce4619998 +0 -0
- package/avatars/fe83a6d4-abb0-4ab0-b61d-76a7cc08be84 +0 -0
- package/dist/migrations/20210103192527_users.d.ts +0 -3
- package/dist/migrations/20210103192527_users.js +0 -30
- package/dist/migrations/20210103193502_mail.d.ts +0 -3
- package/dist/migrations/20210103193502_mail.js +0 -35
- package/dist/migrations/20210103193525_preKeys.d.ts +0 -3
- package/dist/migrations/20210103193525_preKeys.js +0 -30
- package/dist/migrations/20210103193553_oneTimeKeys.d.ts +0 -3
- package/dist/migrations/20210103193553_oneTimeKeys.js +0 -30
- package/dist/migrations/20210103193615_servers.d.ts +0 -3
- package/dist/migrations/20210103193615_servers.js +0 -28
- package/dist/migrations/20210103193729_channels.d.ts +0 -3
- package/dist/migrations/20210103193729_channels.js +0 -28
- package/dist/migrations/20210103193749_permissions.d.ts +0 -3
- package/dist/migrations/20210103193749_permissions.js +0 -30
- package/dist/migrations/20210103193801_files.d.ts +0 -3
- package/dist/migrations/20210103193801_files.js +0 -28
- package/emoji/04d98632-2c86-421b-a407-17f14fe86f8f +0 -0
- package/emoji/1160ed6e-1163-4043-9808-4029e863ed30 +0 -0
- package/emoji/1547ab18-1635-4a80-a82d-ebbb767b9932 +0 -0
- package/emoji/16922521-f6cb-4de4-860c-27916b22c6ba +0 -0
- package/emoji/198a9432-0e41-4866-994a-448d4775afcb +0 -0
- package/emoji/1be886b3-c9c5-4593-b516-f357ed931f96 +0 -0
- package/emoji/1c2b3d1d-637f-4103-b066-4bc4511a3ad7 +0 -0
- package/emoji/1efd27e7-b15f-475c-8b32-9159d26b169d +0 -0
- package/emoji/270b9409-0ea5-4be2-a239-a8dce13f9c31 +0 -0
- package/emoji/27812f76-fee2-49dd-a217-363de6d159dc +0 -0
- package/emoji/297ec202-8c24-44c6-aead-689d6d461883 +0 -0
- package/emoji/2bf06d86-17cb-4f40-a5ef-bd75d239a1a3 +0 -0
- package/emoji/31a75163-1cce-4dc1-b0a2-ecad6a4c500b +0 -0
- package/emoji/35235635-fdbd-4273-8428-f3cb3e1e8fd3 +0 -0
- package/emoji/3690fff2-6824-4403-a6e3-16a6a54979a9 +0 -0
- package/emoji/391014c2-59e0-46a8-85ec-7a7fdaca1d2d +0 -0
- package/emoji/3b383dcb-6e76-4e85-8e16-7c68040c06c2 +0 -0
- package/emoji/42d617a7-b104-42f5-9618-473181f752cf +0 -0
- package/emoji/482495d3-cce9-4f88-bf2a-f6003f03a9b5 +0 -0
- package/emoji/48390e06-0efb-404c-89bd-5f2be241bd50 +0 -0
- package/emoji/4b808d8d-3248-4149-b919-71b108391bcf +0 -0
- package/emoji/4bc13544-d82a-4e32-bd17-a70592274314 +0 -0
- package/emoji/4fcebf70-8623-4343-8243-67c8547b2edd +0 -0
- package/emoji/509d09aa-1214-459c-8081-50918a17b9af +0 -0
- package/emoji/5272abd8-d4d7-4b90-acd2-bf30e6c27243 +0 -0
- package/emoji/53c272ce-48bd-4d7e-bfb8-a6482b88be54 +0 -0
- package/emoji/5b279e65-06f7-4b26-8b4c-d1b48fba728d +0 -0
- package/emoji/5bd141f9-4394-4108-9376-66ebbc2c2bc1 +0 -0
- package/emoji/5c769156-f9cb-40bd-ab89-4edeece613fd +0 -0
- package/emoji/5c85fba9-8ba7-4fc9-b1b2-48dc30d24a1b +0 -0
- package/emoji/61a5e565-d20b-40ba-a139-b0c73a6027f3 +0 -0
- package/emoji/6913f43d-dd45-456c-9641-a126104d9ae5 +0 -0
- package/emoji/6957e74e-9622-492d-a950-242db3752260 +0 -0
- package/emoji/6a14bab5-26af-4bfa-9c17-be7c2511976d +0 -0
- package/emoji/6be09439-509e-4095-a30a-b1c7c573895d +0 -0
- package/emoji/6cc435b1-fe53-433c-b5a9-2b2019053997 +0 -0
- package/emoji/74f1b2af-bc7e-4a0f-802a-64ded185d5e2 +0 -0
- package/emoji/7890ba09-f02f-428e-807d-006d03d51d4a +0 -0
- package/emoji/7dc69179-6b3c-4f40-b20b-0ff573deea2d +0 -0
- package/emoji/7dd1b6b1-439d-4279-916a-995408863172 +0 -0
- package/emoji/820498ad-a2c8-43a2-ab83-d26f9c2246d4 +0 -0
- package/emoji/8319469c-2787-44e5-91a6-c8c39810dd7c +0 -0
- package/emoji/86745d1d-9e59-4607-b2b0-46c741079be1 +0 -0
- package/emoji/887b3cff-ae9e-4b5f-ad00-3ca9fc72f689 +0 -0
- package/emoji/8c6cf621-71d6-4fca-abe6-e19f4dd7f883 +0 -0
- package/emoji/8ca6d32e-a1ef-4956-a416-d8d0d680f085 +0 -0
- package/emoji/8d979f5e-38a2-4dd1-b3e4-80938bbe499b +0 -0
- package/emoji/99f68ea0-e3fe-4f03-9cc3-5f7f5315404d +0 -0
- package/emoji/9ad3aedc-7f79-4d68-a144-82e5b5dc3033 +0 -0
- package/emoji/9e418c2f-1f0f-46c4-be39-3bda38a28545 +0 -0
- package/emoji/a1f616bf-7402-4e24-9111-18acaebabb48 +0 -0
- package/emoji/a25ed9c1-3f9c-4e5f-ade2-7b159fb9fbf4 +0 -0
- package/emoji/a5176bc2-39a8-467b-8c75-6fbbc81b59c7 +0 -0
- package/emoji/a584215c-6547-438b-8ae8-dd490b51890e +0 -0
- package/emoji/a739895f-cf61-4b7c-b350-8e8283aaf751 +0 -0
- package/emoji/aaa10dd2-02a2-499e-9e17-c83787436508 +0 -0
- package/emoji/ae90baf2-a0ef-4d4d-9cc4-94f8ddd60f45 +0 -0
- package/emoji/b0564c48-feae-431a-95f9-df597c6c124c +0 -0
- package/emoji/b218bb93-e69c-4793-a669-83316650c4e7 +0 -0
- package/emoji/b2998c27-85d5-4598-ab41-469aa8e0fcad +0 -0
- package/emoji/b3da08ba-4179-4b5d-826f-5fc15e1a3ad2 +0 -0
- package/emoji/b840eb6a-a917-4bb2-854b-8f1022e7904b +0 -0
- package/emoji/b84baa76-b4b0-4b83-bc83-78661cb4f1d4 +0 -0
- package/emoji/baf69d80-8b1d-4032-855f-605cf0d489c3 +0 -0
- package/emoji/bb4d372c-ccd0-4a47-b157-b6a3b9f763e2 +0 -0
- package/emoji/bdbd1627-c81d-42d9-b3f5-8979e2ab74dc +0 -0
- package/emoji/c257388f-8b85-450b-b168-ebdf8d8c3026 +0 -0
- package/emoji/c573fde1-faa9-4c1d-a172-e283645afcfd +0 -0
- package/emoji/c8e27810-e8ea-47ce-b7ec-cef0a6becb28 +0 -0
- package/emoji/cdeef182-b220-4850-9ecf-5d7c472fd754 +0 -0
- package/emoji/d59c1aa9-6f81-4c07-96dd-9953401ff211 +0 -0
- package/emoji/dd407dbf-a077-40ba-957f-337b3c5efdc7 +0 -0
- package/emoji/e01f6e06-5728-4e2c-90fb-314a5827b766 +0 -0
- package/emoji/e1f9ed12-a2ce-433d-b454-b833438a1f9c +0 -0
- package/emoji/e697e5c4-acd6-41cd-a43e-edee8da3ab7b +0 -0
- package/emoji/e8182220-3464-4e31-8c08-466baead7bfc +0 -0
- package/emoji/eb0f3fd5-abc9-4abf-b816-d8458aeb7ec8 +0 -0
- package/emoji/eb38ecf7-0d13-4c51-b96a-3777f79321c4 +0 -0
- package/emoji/ee515c85-b7ce-4493-a427-994cc0af0d59 +0 -0
- package/emoji/f485cef2-d3fa-4d59-88af-b79a3105cacf +0 -0
- package/emoji/ff0dab2a-7015-4e8c-b0d0-3569058359dc +0 -0
- package/files/01087968-07b6-4fdb-9aeb-fa9dc061be94 +0 -0
- package/files/030455b3-17cc-415f-b3b3-2bb56c92ee8b +0 -0
- package/files/06129f52-a858-4031-ad85-4d7f2bb793af +0 -0
- package/files/0a6155a9-069f-45e9-8a06-56992fe55187 +0 -0
- package/files/12b9dda5-feb1-4f20-a987-ad422db5ba73 +0 -0
- package/files/13c8fa1e-8821-4628-b607-9e4fa4510df7 +0 -0
- package/files/159b0ad3-1a30-419d-af22-28a1096ce825 +0 -0
- package/files/1699c563-6769-431b-8041-99a6a4386f25 +0 -0
- package/files/176b916c-0dd9-4b93-bfdc-b8ccabf15a96 +0 -0
- package/files/1a27dad9-8cc9-4a0c-9d4e-7bde63adda60 +0 -0
- package/files/1d29832c-059a-4190-bca6-b83ac77540d9 +0 -0
- package/files/1dcde013-8833-4369-8726-81236e4eb30e +0 -0
- package/files/2080fc9f-d2c4-4fbc-af84-232fe4900a4f +0 -0
- package/files/20889623-6869-46a2-999b-c07708c12521 +0 -0
- package/files/2107e243-c378-418d-a183-7df13873c65b +0 -0
- package/files/225ed61e-8f8c-4d17-b675-9a9f9918d5b4 +0 -0
- package/files/29ffba15-5acc-4ef8-b5a4-5ce61d3f6e85 +0 -0
- package/files/2a69434c-1d8a-4e9d-90d4-569aaeaae7e3 +0 -0
- package/files/2aec8fcf-25bf-478e-b2f6-fe67ad753071 +0 -0
- package/files/2c64490e-c7de-4cb2-b22e-70e2ac69d88f +0 -0
- package/files/2d80b4f4-6389-4f5d-8d32-f0ed93820907 +0 -0
- package/files/2f9dd26e-363f-4445-8ee5-28548007a33a +0 -0
- package/files/360dd8f5-76c4-4e86-ba22-9025dc7ca2a4 +0 -0
- package/files/3a0a7f5b-45a5-4340-ba7c-6a0fa2c63871 +0 -0
- package/files/3a8fa6be-8acf-4b7b-b653-25edc6b28cdc +0 -5
- package/files/3d9e191b-2c15-42aa-9928-c2cdbb5e14ca +0 -0
- package/files/3dd0f2ef-0d4e-4837-bffc-22aa645cbe85 +0 -0
- package/files/402c4b9b-adbf-4ab6-a21d-c17369b48abf +0 -0
- package/files/4685d988-33eb-4902-872f-3b824f497c8b +0 -0
- package/files/495f6c55-07f8-4713-a444-a2261a789b94 +0 -0
- package/files/4acba8e3-567b-4062-b81b-340e205a01de +0 -0
- package/files/4c0a10cc-395b-474a-8140-677ed607da89 +0 -0
- package/files/537584d9-25ad-4830-808a-a1e3d63e2a52 +0 -0
- package/files/5519f10d-745e-4474-8ca8-6c111693704c +0 -0
- package/files/5563cf92-a5e3-4be3-867d-9647a02298d4 +0 -0
- package/files/55b70d9b-fd58-4800-832c-d6b4521ba6d0 +0 -0
- package/files/5623cff3-ce9b-403b-9915-50d2bcbc981c +0 -0
- package/files/576314ba-2a1a-4753-8d77-2a9e04f509d1 +0 -0
- package/files/58ed97ae-0eac-4e04-add1-76646effa2d5 +0 -0
- package/files/68638efd-5389-481d-a841-36164c62c078 +0 -0
- package/files/6936d34b-a1f8-4a9d-b005-5544dbdcf5e5 +0 -0
- package/files/6bda9e88-3a28-47f7-994e-900ede6bf984 +0 -0
- package/files/7024a3b9-a863-4618-9dbd-fa6502017ae0 +0 -0
- package/files/707caccb-3780-456d-9056-c20bfdfc0e5b +0 -0
- package/files/74b8c73c-032b-4640-a5b3-d30dd270cbcb +0 -0
- package/files/767cb262-2974-40f8-8182-f7770b431923 +0 -0
- package/files/7a669935-cb48-4349-b26b-7705f8a04fbc +0 -0
- package/files/7bc8f678-6ee7-454c-a1f8-bb9358b89c95 +0 -0
- package/files/7ccc2699-07ec-4177-a9ce-ee7dc952fda1 +0 -0
- package/files/7e0eabf4-b334-4683-8156-ab8d949a0532 +0 -0
- package/files/7f0644ab-02a3-4121-adfc-29a7c55cf804 +0 -0
- package/files/7ff3266d-f103-48ce-90dd-95b9dfe5fcc9 +0 -0
- package/files/836e2e8e-aefd-4b4a-a9b9-bf7436158a8c +0 -0
- package/files/875f7ae5-fa23-4fc5-b04a-8433a7f7089c +0 -0
- package/files/8ca62da9-f204-49e3-b418-9451661b2904 +0 -0
- package/files/9283054c-107f-474d-b61e-f1d0061bcb86 +0 -0
- package/files/93b1ce7f-9566-452b-b4be-30f87d3de150 +0 -0
- package/files/93fb51c7-e19b-4ac1-9dc3-aeb8da0672ed +0 -0
- package/files/9b54a3a1-534a-4ed5-b016-3c74ed4c9edd +0 -0
- package/files/9b5beb6f-712d-4969-b127-fd66c9b2a9c6 +0 -0
- package/files/9e964fbf-d063-498e-b2e3-79f8d6afcf5f +0 -0
- package/files/a66b7a9f-58c2-47a8-a429-a6f0647c6fe9 +0 -0
- package/files/a7cbda7d-81ba-40f7-a997-51146af63e5f +0 -0
- package/files/ac01e83a-e572-41b6-81ab-c992cff7c170 +0 -0
- package/files/ad11a58f-f963-4233-bd29-1658b6b7e600 +0 -0
- package/files/ae60a4a8-08b9-4521-a0a3-d015a8b3ed08 +0 -0
- package/files/b1d3cf27-8d76-4cf9-aa51-d7c6bfd1b3bf +0 -0
- package/files/b2c68863-8554-4ac6-8e99-821f0267cf91 +0 -0
- package/files/b3043e01-a771-44af-bf19-5327646ff929 +0 -0
- package/files/b6d01b89-def5-4c7c-8e97-a3d88617f8f4 +0 -0
- package/files/b8760b32-bb1e-4cd7-a9d6-29c6e0b071bc +0 -0
- package/files/ba5e0470-44f7-47b3-bcb5-eeab3ca8c292 +0 -0
- package/files/c3969b5f-43ae-43f3-9bdd-d3959c79ca01 +0 -0
- package/files/caecd488-dbe6-4a30-a400-bced2ba8dae6 +0 -0
- package/files/d7d865b8-3a05-4ed1-b95d-b93dc1ebb9a9 +0 -0
- package/files/dbca5f31-cf38-4c1e-83b0-5ec8473196fc +0 -0
- package/files/dbf07e82-fff6-4985-bebe-d62c0458bfd0 +0 -0
- package/files/dd759c20-eead-4e57-9e74-4d3a2b978e91 +0 -5
- package/files/de0b2cf1-981b-4e4a-a04e-ac185d1620cd +0 -0
- package/files/de6837fe-5aa2-4ff9-a067-2646a008c780 +0 -0
- package/files/e2fde852-91cb-4e01-88a2-ee086b5f227c +0 -0
- package/files/e391d1ce-8d39-460c-a462-791730131f7f +0 -0
- package/files/e6d9b60f-2b1b-4c6f-ba6d-02f6de90d40f +0 -0
- package/files/f693c62d-2ac8-49fd-aa38-30904e013e3c +0 -0
- package/files/f749fdf5-193e-41f7-b643-5696f67c6402 +0 -0
- package/files/f8910384-e75c-4d65-825f-52a6748f6475 +0 -0
- package/files/fad8826b-e952-4acb-a509-3e6543b94d61 +0 -0
- package/jest.config.js +0 -13
- package/spire.sqlite +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
export async function down(db) {
|
|
3
|
+
const tables = [
|
|
4
|
+
"service_metrics",
|
|
5
|
+
"invites",
|
|
6
|
+
"emojis",
|
|
7
|
+
"files",
|
|
8
|
+
"permissions",
|
|
9
|
+
"channels",
|
|
10
|
+
"servers",
|
|
11
|
+
"oneTimeKeys",
|
|
12
|
+
"preKeys",
|
|
13
|
+
"mail",
|
|
14
|
+
"devices",
|
|
15
|
+
"users",
|
|
16
|
+
];
|
|
17
|
+
for (const table of tables) {
|
|
18
|
+
await db.schema.dropTable(table).ifExists().execute();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function up(db) {
|
|
22
|
+
await db.schema
|
|
23
|
+
.createTable("users")
|
|
24
|
+
.ifNotExists()
|
|
25
|
+
.addColumn("userID", "varchar(255)", (cb) => cb.primaryKey())
|
|
26
|
+
.addColumn("username", "varchar(255)", (cb) => cb.unique())
|
|
27
|
+
.addColumn("passwordHash", "text")
|
|
28
|
+
.addColumn("passwordSalt", "text")
|
|
29
|
+
.addColumn("lastSeen", "text")
|
|
30
|
+
.execute();
|
|
31
|
+
await db.schema
|
|
32
|
+
.createTable("devices")
|
|
33
|
+
.ifNotExists()
|
|
34
|
+
.addColumn("deviceID", "varchar(255)", (cb) => cb.primaryKey())
|
|
35
|
+
.addColumn("signKey", "varchar(255)", (cb) => cb.unique())
|
|
36
|
+
.addColumn("owner", "varchar(255)")
|
|
37
|
+
.addColumn("name", "varchar(255)")
|
|
38
|
+
.addColumn("lastLogin", "text")
|
|
39
|
+
.addColumn("deleted", "integer", (cb) => cb.defaultTo(0))
|
|
40
|
+
.execute();
|
|
41
|
+
await db.schema
|
|
42
|
+
.createTable("mail")
|
|
43
|
+
.ifNotExists()
|
|
44
|
+
.addColumn("nonce", "varchar(255)", (cb) => cb.primaryKey())
|
|
45
|
+
.addColumn("recipient", "varchar(255)")
|
|
46
|
+
.addColumn("mailID", "varchar(255)")
|
|
47
|
+
.addColumn("sender", "varchar(255)")
|
|
48
|
+
.addColumn("header", "text")
|
|
49
|
+
.addColumn("cipher", "text")
|
|
50
|
+
.addColumn("group", "varchar(255)")
|
|
51
|
+
.addColumn("extra", "text")
|
|
52
|
+
.addColumn("mailType", "integer")
|
|
53
|
+
.addColumn("time", "text")
|
|
54
|
+
.addColumn("forward", "integer", (cb) => cb.defaultTo(0))
|
|
55
|
+
.addColumn("authorID", "varchar(255)")
|
|
56
|
+
.addColumn("readerID", "varchar(255)")
|
|
57
|
+
.execute();
|
|
58
|
+
await db.schema
|
|
59
|
+
.createIndex("mail_recipient_idx")
|
|
60
|
+
.ifNotExists()
|
|
61
|
+
.on("mail")
|
|
62
|
+
.column("recipient")
|
|
63
|
+
.execute();
|
|
64
|
+
await db.schema
|
|
65
|
+
.createTable("preKeys")
|
|
66
|
+
.ifNotExists()
|
|
67
|
+
.addColumn("keyID", "varchar(255)", (cb) => cb.primaryKey())
|
|
68
|
+
.addColumn("userID", "varchar(255)")
|
|
69
|
+
.addColumn("deviceID", "varchar(255)", (cb) => cb.unique())
|
|
70
|
+
.addColumn("publicKey", "text")
|
|
71
|
+
.addColumn("signature", "text")
|
|
72
|
+
.addColumn("index", "integer")
|
|
73
|
+
.execute();
|
|
74
|
+
await db.schema
|
|
75
|
+
.createIndex("preKeys_userID_idx")
|
|
76
|
+
.ifNotExists()
|
|
77
|
+
.on("preKeys")
|
|
78
|
+
.column("userID")
|
|
79
|
+
.execute();
|
|
80
|
+
await db.schema
|
|
81
|
+
.createIndex("preKeys_deviceID_idx")
|
|
82
|
+
.ifNotExists()
|
|
83
|
+
.on("preKeys")
|
|
84
|
+
.column("deviceID")
|
|
85
|
+
.execute();
|
|
86
|
+
await db.schema
|
|
87
|
+
.createTable("oneTimeKeys")
|
|
88
|
+
.ifNotExists()
|
|
89
|
+
.addColumn("keyID", "varchar(255)", (cb) => cb.primaryKey())
|
|
90
|
+
.addColumn("userID", "varchar(255)")
|
|
91
|
+
.addColumn("deviceID", "varchar(255)")
|
|
92
|
+
.addColumn("publicKey", "text")
|
|
93
|
+
.addColumn("signature", "text")
|
|
94
|
+
.addColumn("index", "integer")
|
|
95
|
+
.execute();
|
|
96
|
+
await db.schema
|
|
97
|
+
.createIndex("oneTimeKeys_userID_idx")
|
|
98
|
+
.ifNotExists()
|
|
99
|
+
.on("oneTimeKeys")
|
|
100
|
+
.column("userID")
|
|
101
|
+
.execute();
|
|
102
|
+
await db.schema
|
|
103
|
+
.createIndex("oneTimeKeys_deviceID_idx")
|
|
104
|
+
.ifNotExists()
|
|
105
|
+
.on("oneTimeKeys")
|
|
106
|
+
.column("deviceID")
|
|
107
|
+
.execute();
|
|
108
|
+
await db.schema
|
|
109
|
+
.createTable("servers")
|
|
110
|
+
.ifNotExists()
|
|
111
|
+
.addColumn("serverID", "varchar(255)", (cb) => cb.primaryKey())
|
|
112
|
+
.addColumn("name", "varchar(255)")
|
|
113
|
+
.addColumn("icon", "varchar(255)")
|
|
114
|
+
.execute();
|
|
115
|
+
await db.schema
|
|
116
|
+
.createTable("channels")
|
|
117
|
+
.ifNotExists()
|
|
118
|
+
.addColumn("channelID", "varchar(255)", (cb) => cb.primaryKey())
|
|
119
|
+
.addColumn("serverID", "varchar(255)")
|
|
120
|
+
.addColumn("name", "varchar(255)")
|
|
121
|
+
.execute();
|
|
122
|
+
await db.schema
|
|
123
|
+
.createTable("permissions")
|
|
124
|
+
.ifNotExists()
|
|
125
|
+
.addColumn("permissionID", "varchar(255)", (cb) => cb.primaryKey())
|
|
126
|
+
.addColumn("userID", "varchar(255)")
|
|
127
|
+
.addColumn("resourceType", "varchar(255)")
|
|
128
|
+
.addColumn("resourceID", "varchar(255)")
|
|
129
|
+
.addColumn("powerLevel", "integer")
|
|
130
|
+
.execute();
|
|
131
|
+
await db.schema
|
|
132
|
+
.createIndex("permissions_userID_idx")
|
|
133
|
+
.ifNotExists()
|
|
134
|
+
.on("permissions")
|
|
135
|
+
.column("userID")
|
|
136
|
+
.execute();
|
|
137
|
+
await db.schema
|
|
138
|
+
.createIndex("permissions_resourceID_idx")
|
|
139
|
+
.ifNotExists()
|
|
140
|
+
.on("permissions")
|
|
141
|
+
.column("resourceID")
|
|
142
|
+
.execute();
|
|
143
|
+
await db.schema
|
|
144
|
+
.createTable("files")
|
|
145
|
+
.ifNotExists()
|
|
146
|
+
.addColumn("fileID", "varchar(255)", (cb) => cb.primaryKey())
|
|
147
|
+
.addColumn("owner", "varchar(255)")
|
|
148
|
+
.addColumn("nonce", "varchar(255)")
|
|
149
|
+
.execute();
|
|
150
|
+
await db.schema
|
|
151
|
+
.createIndex("files_owner_idx")
|
|
152
|
+
.ifNotExists()
|
|
153
|
+
.on("files")
|
|
154
|
+
.column("owner")
|
|
155
|
+
.execute();
|
|
156
|
+
await db.schema
|
|
157
|
+
.createTable("emojis")
|
|
158
|
+
.ifNotExists()
|
|
159
|
+
.addColumn("emojiID", "varchar(255)", (cb) => cb.primaryKey())
|
|
160
|
+
.addColumn("owner", "varchar(255)")
|
|
161
|
+
.addColumn("name", "varchar(255)")
|
|
162
|
+
.execute();
|
|
163
|
+
await db.schema
|
|
164
|
+
.createIndex("emojis_owner_idx")
|
|
165
|
+
.ifNotExists()
|
|
166
|
+
.on("emojis")
|
|
167
|
+
.column("owner")
|
|
168
|
+
.execute();
|
|
169
|
+
await db.schema
|
|
170
|
+
.createTable("invites")
|
|
171
|
+
.ifNotExists()
|
|
172
|
+
.addColumn("inviteID", "varchar(255)", (cb) => cb.primaryKey())
|
|
173
|
+
.addColumn("serverID", "varchar(255)")
|
|
174
|
+
.addColumn("owner", "varchar(255)")
|
|
175
|
+
.addColumn("expiration", "text")
|
|
176
|
+
.execute();
|
|
177
|
+
await db.schema
|
|
178
|
+
.createIndex("invites_serverID_idx")
|
|
179
|
+
.ifNotExists()
|
|
180
|
+
.on("invites")
|
|
181
|
+
.column("serverID")
|
|
182
|
+
.execute();
|
|
183
|
+
await db.schema
|
|
184
|
+
.createTable("service_metrics")
|
|
185
|
+
.ifNotExists()
|
|
186
|
+
.addColumn("metric_key", "varchar(255)", (cb) => cb.primaryKey())
|
|
187
|
+
.addColumn("metric_value", "bigint", (cb) => cb.notNull().defaultTo(0))
|
|
188
|
+
.execute();
|
|
189
|
+
// Seed the requests_total metric row
|
|
190
|
+
await sql `INSERT OR IGNORE INTO service_metrics (metric_key, metric_value) VALUES ('requests_total', 0)`.execute(db);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=2026-04-06_initial-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"2026-04-06_initial-schema.js","sourceRoot":"","sources":["../../src/migrations/2026-04-06_initial-schema.ts"],"names":[],"mappings":"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"}
|
package/dist/run.js
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const Spire_1 = require("./Spire");
|
|
13
|
-
const loadEnv_1 = require("./utils/loadEnv");
|
|
1
|
+
import { Spire } from "./Spire.js";
|
|
2
|
+
import { loadEnv } from "./utils/loadEnv.js";
|
|
14
3
|
function main() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
4
|
+
// load the environment variables — loadEnv() exits if required vars are missing
|
|
5
|
+
loadEnv();
|
|
6
|
+
const spk = process.env["SPK"];
|
|
7
|
+
if (!spk) {
|
|
8
|
+
throw new Error("SPK must be set (loadEnv should have caught this).");
|
|
9
|
+
}
|
|
10
|
+
const apiPort = process.env["API_PORT"];
|
|
11
|
+
const dbType = parseDbType(process.env["DB_TYPE"]);
|
|
12
|
+
new Spire(spk, {
|
|
13
|
+
...(apiPort !== undefined ? { apiPort: Number(apiPort) } : {}),
|
|
14
|
+
...(dbType !== undefined ? { dbType } : {}),
|
|
15
|
+
logLevel: "info",
|
|
23
16
|
});
|
|
24
17
|
}
|
|
18
|
+
function parseDbType(value) {
|
|
19
|
+
switch (value) {
|
|
20
|
+
case "mysql":
|
|
21
|
+
case "sqlite":
|
|
22
|
+
case "sqlite3":
|
|
23
|
+
case "sqlite3mem":
|
|
24
|
+
return value;
|
|
25
|
+
default:
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
25
29
|
main();
|
|
30
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,SAAS,IAAI;IACT,gFAAgF;IAChF,OAAO,EAAE,CAAC;IAEV,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAEnD,IAAI,KAAK,CAAC,GAAG,EAAE;QACX,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,QAAQ,EAAE,MAAM;KACnB,CAAC,CAAC;AACP,CAAC;AAED,SAAS,WAAW,CAAC,KAAyB;IAC1C,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,KAAK,YAAY;YACb,OAAO,KAAK,CAAC;QACjB;YACI,OAAO,SAAS,CAAC;IACzB,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC"}
|
package/dist/server/avatar.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import winston from "winston";
|
|
3
|
-
|
|
4
|
-
export declare const getAvatarRouter: (db: Database, log: winston.Logger) => import("express-ws").Router;
|
|
1
|
+
import type { Database } from "../Database.ts";
|
|
2
|
+
import type winston from "winston";
|
|
3
|
+
export declare const getAvatarRouter: (db: Database, log: winston.Logger) => import("express-serve-static-core").Router;
|
package/dist/server/avatar.js
CHANGED
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
router.get("/:userID", (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
-
const stream = fs_1.default.createReadStream("./avatars/" + req.params.userID);
|
|
26
|
-
stream.on("error", (err) => {
|
|
27
|
-
// log.error(err.toString());
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as fsp from "node:fs/promises";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import { XUtils } from "@vex-chat/crypto";
|
|
5
|
+
import { FilePayloadSchema } from "@vex-chat/types";
|
|
6
|
+
import { fileTypeFromBuffer, fileTypeFromFile } from "file-type";
|
|
7
|
+
import multer from "multer";
|
|
8
|
+
import { z } from "zod/v4";
|
|
9
|
+
import { uploadLimiter } from "./rateLimit.js";
|
|
10
|
+
import { getParam, getUser } from "./utils.js";
|
|
11
|
+
import { ALLOWED_IMAGE_TYPES, protect } from "./index.js";
|
|
12
|
+
const safePathParam = z.string().regex(/^[a-zA-Z0-9._-]+$/);
|
|
13
|
+
export const getAvatarRouter = (db, log) => {
|
|
14
|
+
const router = express.Router();
|
|
15
|
+
router.get("/:userID", async (req, res) => {
|
|
16
|
+
const safeId = safePathParam.safeParse(getParam(req, "userID"));
|
|
17
|
+
if (!safeId.success) {
|
|
18
|
+
res.sendStatus(400);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const filePath = "./avatars/" + safeId.data;
|
|
22
|
+
const typeDetails = await fileTypeFromFile(filePath).catch(() => null);
|
|
23
|
+
if (!typeDetails) {
|
|
28
24
|
res.sendStatus(404);
|
|
29
|
-
|
|
30
|
-
const typeDetails = yield file_type_1.default.fromStream(stream);
|
|
31
|
-
if (typeDetails) {
|
|
32
|
-
res.set("Content-type", typeDetails.mime);
|
|
25
|
+
return;
|
|
33
26
|
}
|
|
27
|
+
res.set("Content-type", typeDetails.mime);
|
|
34
28
|
res.set("Cache-control", "public, max-age=31536000");
|
|
35
|
-
const
|
|
36
|
-
|
|
29
|
+
const stream = fs.createReadStream(filePath);
|
|
30
|
+
stream.on("error", (err) => {
|
|
37
31
|
log.error(err.toString());
|
|
38
32
|
res.sendStatus(500);
|
|
39
33
|
});
|
|
40
|
-
|
|
41
|
-
})
|
|
42
|
-
router.post("/:userID/json",
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
stream.pipe(res);
|
|
35
|
+
});
|
|
36
|
+
router.post("/:userID/json", protect, async (req, res) => {
|
|
37
|
+
const parsed = FilePayloadSchema.safeParse(req.body);
|
|
38
|
+
if (!parsed.success) {
|
|
39
|
+
res.status(400).json({
|
|
40
|
+
error: "Invalid file payload",
|
|
41
|
+
issues: parsed.error.issues,
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const payload = parsed.data;
|
|
46
|
+
const userDetails = getUser(req);
|
|
47
|
+
const deviceDetails = req.device;
|
|
47
48
|
if (!deviceDetails) {
|
|
48
49
|
res.sendStatus(401);
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
if (!payload.file) {
|
|
52
|
-
|
|
53
|
+
log.warn("MISSING FILE");
|
|
53
54
|
res.sendStatus(400);
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
56
|
-
const buf = Buffer.from(
|
|
57
|
-
const mimeType =
|
|
58
|
-
if (!
|
|
57
|
+
const buf = Buffer.from(XUtils.decodeBase64(payload.file));
|
|
58
|
+
const mimeType = await fileTypeFromBuffer(buf);
|
|
59
|
+
if (!ALLOWED_IMAGE_TYPES.includes(mimeType?.mime || "no/type")) {
|
|
59
60
|
res.status(400).send({
|
|
60
|
-
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or svg but received " +
|
|
61
|
+
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or svg but received " +
|
|
62
|
+
String(mimeType?.ext),
|
|
61
63
|
});
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
try {
|
|
65
67
|
// write the file to disk
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
});
|
|
68
|
+
await fsp.writeFile("avatars/" + userDetails.userID, buf);
|
|
69
|
+
log.info("Wrote new avatar " + userDetails.userID);
|
|
69
70
|
res.sendStatus(200);
|
|
70
71
|
}
|
|
71
72
|
catch (err) {
|
|
72
|
-
log.warn(err);
|
|
73
|
+
log.warn(String(err));
|
|
73
74
|
res.sendStatus(500);
|
|
74
75
|
}
|
|
75
|
-
})
|
|
76
|
-
router.post("/:userID",
|
|
77
|
-
const userDetails = req
|
|
78
|
-
const deviceDetails = req
|
|
79
|
-
.device;
|
|
76
|
+
});
|
|
77
|
+
router.post("/:userID", uploadLimiter, protect, multer().single("avatar"), async (req, res) => {
|
|
78
|
+
const userDetails = getUser(req);
|
|
79
|
+
const deviceDetails = req.device;
|
|
80
80
|
if (!deviceDetails) {
|
|
81
81
|
res.sendStatus(401);
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
84
|
if (!req.file) {
|
|
85
|
-
|
|
85
|
+
log.warn("MISSING FILE");
|
|
86
86
|
res.sendStatus(400);
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
-
const mimeType =
|
|
90
|
-
if (!
|
|
89
|
+
const mimeType = await fileTypeFromBuffer(req.file.buffer);
|
|
90
|
+
if (!ALLOWED_IMAGE_TYPES.includes(mimeType?.mime || "no/type")) {
|
|
91
91
|
res.status(400).send({
|
|
92
|
-
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or svg but received " +
|
|
92
|
+
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or svg but received " +
|
|
93
|
+
String(mimeType?.ext),
|
|
93
94
|
});
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
96
97
|
try {
|
|
97
98
|
// write the file to disk
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
99
|
+
await fsp.writeFile("avatars/" + userDetails.userID, req.file.buffer);
|
|
100
|
+
log.info("Wrote new avatar " + userDetails.userID);
|
|
101
101
|
res.sendStatus(200);
|
|
102
102
|
}
|
|
103
103
|
catch (err) {
|
|
104
|
-
log.warn(err);
|
|
104
|
+
log.warn(String(err));
|
|
105
105
|
res.sendStatus(500);
|
|
106
106
|
}
|
|
107
|
-
})
|
|
107
|
+
});
|
|
108
108
|
return router;
|
|
109
109
|
};
|
|
110
|
-
|
|
110
|
+
//# sourceMappingURL=avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.js","sourceRoot":"","sources":["../../src/server/avatar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized HTTP error handling.
|
|
3
|
+
*
|
|
4
|
+
* Fixes two classes of CodeQL findings:
|
|
5
|
+
*
|
|
6
|
+
* - **CWE-209 / CWE-497 — Information exposure through stack trace.**
|
|
7
|
+
* Previously, every route catch block did
|
|
8
|
+
* `res.status(500).send(String(err))`, leaking raw error objects
|
|
9
|
+
* (which include database internals, file paths, and stack traces)
|
|
10
|
+
* back to the client. The new pattern: throw `AppError(status, msg)`
|
|
11
|
+
* or let an unknown error propagate, and the single 4-arg middleware
|
|
12
|
+
* below converts it into a JSON response with a generic message
|
|
13
|
+
* while logging the full internals server-side via winston.
|
|
14
|
+
*
|
|
15
|
+
* - **CWE-79 / CWE-116 — Exception text reinterpreted as HTML.** Express's
|
|
16
|
+
* default finalhandler sends thrown `Error` objects as
|
|
17
|
+
* `Content-Type: text/html`, which means `throw new Error("bad param: "
|
|
18
|
+
* + req.params.name)` became reflected XSS when the error page
|
|
19
|
+
* rendered. The handler below ALWAYS sends `application/json`, so
|
|
20
|
+
* even if a message somehow contains user input, the browser can't
|
|
21
|
+
* execute it. The companion fix is `getParam()` in `utils.ts` now
|
|
22
|
+
* throwing `AppError(400, "Missing route parameter")` with no user
|
|
23
|
+
* input in the message string.
|
|
24
|
+
*
|
|
25
|
+
* Express 5 has native async support, so throwing from an async
|
|
26
|
+
* handler auto-forwards to `next(err)` and hits this middleware. No
|
|
27
|
+
* `express-async-errors` shim needed.
|
|
28
|
+
*/
|
|
29
|
+
import type { ErrorRequestHandler } from "express";
|
|
30
|
+
import type winston from "winston";
|
|
31
|
+
/**
|
|
32
|
+
* Operational HTTP errors that are safe to surface to the client.
|
|
33
|
+
*
|
|
34
|
+
* - `status` — HTTP status code (400, 401, 403, 404, 409, etc.)
|
|
35
|
+
* - `message` — client-safe message, MUST NOT contain request data
|
|
36
|
+
* (route params, body fields, query strings). Anything operator-
|
|
37
|
+
* only (database errors, file paths) belongs in winston logs, not
|
|
38
|
+
* in this string.
|
|
39
|
+
*
|
|
40
|
+
* Anything that isn't an `AppError` (raw `Error`, `TypeError`, a
|
|
41
|
+
* rejected promise from a DB query, etc.) is treated by the central
|
|
42
|
+
* handler as a **programmer error** — the client gets a generic 500
|
|
43
|
+
* with no detail, and the real error is logged server-side.
|
|
44
|
+
*/
|
|
45
|
+
export declare class AppError extends Error {
|
|
46
|
+
readonly status: number;
|
|
47
|
+
constructor(status: number, message: string);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Factory producing the central Express 5 error middleware.
|
|
51
|
+
*
|
|
52
|
+
* Register this as the LAST middleware in the app, after every
|
|
53
|
+
* route and router has been mounted:
|
|
54
|
+
*
|
|
55
|
+
* api.use("/user", userRouter);
|
|
56
|
+
* // ... all other routers ...
|
|
57
|
+
* api.use(errorHandler(log));
|
|
58
|
+
*/
|
|
59
|
+
export declare const errorHandler: (log: winston.Logger) => ErrorRequestHandler;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ZodError } from "zod/v4";
|
|
3
|
+
/**
|
|
4
|
+
* Operational HTTP errors that are safe to surface to the client.
|
|
5
|
+
*
|
|
6
|
+
* - `status` — HTTP status code (400, 401, 403, 404, 409, etc.)
|
|
7
|
+
* - `message` — client-safe message, MUST NOT contain request data
|
|
8
|
+
* (route params, body fields, query strings). Anything operator-
|
|
9
|
+
* only (database errors, file paths) belongs in winston logs, not
|
|
10
|
+
* in this string.
|
|
11
|
+
*
|
|
12
|
+
* Anything that isn't an `AppError` (raw `Error`, `TypeError`, a
|
|
13
|
+
* rejected promise from a DB query, etc.) is treated by the central
|
|
14
|
+
* handler as a **programmer error** — the client gets a generic 500
|
|
15
|
+
* with no detail, and the real error is logged server-side.
|
|
16
|
+
*/
|
|
17
|
+
export class AppError extends Error {
|
|
18
|
+
status;
|
|
19
|
+
constructor(status, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "AppError";
|
|
22
|
+
this.status = status;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Factory producing the central Express 5 error middleware.
|
|
27
|
+
*
|
|
28
|
+
* Register this as the LAST middleware in the app, after every
|
|
29
|
+
* route and router has been mounted:
|
|
30
|
+
*
|
|
31
|
+
* api.use("/user", userRouter);
|
|
32
|
+
* // ... all other routers ...
|
|
33
|
+
* api.use(errorHandler(log));
|
|
34
|
+
*/
|
|
35
|
+
export const errorHandler = (log) => (err, req, res, _next) => {
|
|
36
|
+
// If headers already went out there's nothing safe to do except
|
|
37
|
+
// let Express's default handler close the socket.
|
|
38
|
+
if (res.headersSent) {
|
|
39
|
+
_next(err);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const requestId = randomUUID();
|
|
43
|
+
let status = 500;
|
|
44
|
+
let clientMessage = "Internal Server Error";
|
|
45
|
+
let details;
|
|
46
|
+
if (err instanceof ZodError) {
|
|
47
|
+
// Validation failure at a trust boundary. The issue list is
|
|
48
|
+
// structured JSON (no raw user input as a rendered string),
|
|
49
|
+
// so it's safe to surface to help clients fix their payload.
|
|
50
|
+
status = 400;
|
|
51
|
+
clientMessage = "Validation failed";
|
|
52
|
+
details = err.issues;
|
|
53
|
+
}
|
|
54
|
+
else if (err instanceof AppError) {
|
|
55
|
+
status = err.status;
|
|
56
|
+
clientMessage = err.message;
|
|
57
|
+
}
|
|
58
|
+
// Log the full internals server-side. `err instanceof Error` also
|
|
59
|
+
// catches AppError (extends Error), so we get stacks and messages
|
|
60
|
+
// for every branch in the logs.
|
|
61
|
+
if (err instanceof Error) {
|
|
62
|
+
log.error("request failed", {
|
|
63
|
+
error: {
|
|
64
|
+
message: err.message,
|
|
65
|
+
name: err.name,
|
|
66
|
+
stack: err.stack,
|
|
67
|
+
},
|
|
68
|
+
method: req.method,
|
|
69
|
+
path: req.path,
|
|
70
|
+
requestId,
|
|
71
|
+
status,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
log.error("request failed", {
|
|
76
|
+
error: String(err),
|
|
77
|
+
method: req.method,
|
|
78
|
+
path: req.path,
|
|
79
|
+
requestId,
|
|
80
|
+
status,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// ALWAYS JSON — prevents the exception-text-as-HTML XSS vector.
|
|
84
|
+
res.status(status)
|
|
85
|
+
.type("application/json")
|
|
86
|
+
.json({
|
|
87
|
+
error: {
|
|
88
|
+
message: clientMessage,
|
|
89
|
+
requestId,
|
|
90
|
+
...(details !== undefined ? { details } : {}),
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/server/errors.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACf,MAAM,CAAS;IAE/B,YAAY,MAAc,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GACrB,CAAC,GAAmB,EAAuB,EAAE,CAC7C,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;IACrB,gEAAgE;IAChE,kDAAkD;IAClD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QAClB,KAAK,CAAC,GAAG,CAAC,CAAC;QACX,OAAO;IACX,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;IAE/B,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,aAAa,GAAG,uBAAuB,CAAC;IAC5C,IAAI,OAAgB,CAAC;IAErB,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC1B,4DAA4D;QAC5D,4DAA4D;QAC5D,6DAA6D;QAC7D,MAAM,GAAG,GAAG,CAAC;QACb,aAAa,GAAG,mBAAmB,CAAC;QACpC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;IACzB,CAAC;SAAM,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACpB,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,kEAAkE;IAClE,kEAAkE;IAClE,gCAAgC;IAChC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACvB,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE;YACxB,KAAK,EAAE;gBACH,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,KAAK,EAAE,GAAG,CAAC,KAAK;aACnB;YACD,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS;YACT,MAAM;SACT,CAAC,CAAC;IACP,CAAC;SAAM,CAAC;QACJ,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE;YACxB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;YAClB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS;YACT,MAAM;SACT,CAAC,CAAC;IACP,CAAC;IAED,gEAAgE;IAChE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;SACb,IAAI,CAAC,kBAAkB,CAAC;SACxB,IAAI,CAAC;QACF,KAAK,EAAE;YACH,OAAO,EAAE,aAAa;YACtB,SAAS;YACT,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChD;KACJ,CAAC,CAAC;AACX,CAAC,CAAC"}
|
package/dist/server/file.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import winston from "winston";
|
|
3
|
-
|
|
4
|
-
export declare const getFileRouter: (db: Database, log: winston.Logger) => import("express-ws").Router;
|
|
1
|
+
import type { Database } from "../Database.ts";
|
|
2
|
+
import type winston from "winston";
|
|
3
|
+
export declare const getFileRouter: (db: Database, log: winston.Logger) => import("express-serve-static-core").Router;
|