@vex-chat/spire 3.0.1 → 4.1.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 +9 -8
- package/dist/Database.d.ts +20 -11
- package/dist/Database.js +229 -118
- package/dist/Database.js.map +1 -1
- package/dist/Spire.d.ts +4 -2
- package/dist/Spire.js +155 -72
- package/dist/Spire.js.map +1 -1
- package/dist/db/schema.d.ts +0 -2
- package/dist/migrations/2026-04-06_initial-schema.js +4 -5
- package/dist/migrations/2026-04-06_initial-schema.js.map +1 -1
- package/dist/migrations/{2026-04-14_argon2id-password-hashing.d.ts → 2026-07-14_query-indexes.d.ts} +1 -1
- package/dist/migrations/2026-07-14_query-indexes.js +31 -0
- package/dist/migrations/2026-07-14_query-indexes.js.map +1 -0
- package/dist/server/avatar.js +33 -6
- package/dist/server/avatar.js.map +1 -1
- package/dist/server/cliPasskeyPage.js +109 -11
- package/dist/server/cliPasskeyPage.js.map +1 -1
- package/dist/server/errors.js +8 -0
- package/dist/server/errors.js.map +1 -1
- package/dist/server/file.js +35 -12
- package/dist/server/file.js.map +1 -1
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +319 -56
- package/dist/server/index.js.map +1 -1
- package/dist/server/passkey.js +367 -29
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/passkeyDevices.js +1 -0
- package/dist/server/passkeyDevices.js.map +1 -1
- package/dist/server/password.d.ts +7 -0
- package/dist/server/password.js +58 -0
- package/dist/server/password.js.map +1 -0
- package/dist/server/permissions.d.ts +1 -0
- package/dist/server/permissions.js +11 -2
- package/dist/server/permissions.js.map +1 -1
- package/dist/server/rateLimit.d.ts +11 -0
- package/dist/server/rateLimit.js +43 -4
- package/dist/server/rateLimit.js.map +1 -1
- package/dist/server/serverIcon.d.ts +10 -0
- package/dist/server/serverIcon.js +158 -0
- package/dist/server/serverIcon.js.map +1 -0
- package/dist/server/user.d.ts +1 -1
- package/dist/server/user.js +40 -9
- package/dist/server/user.js.map +1 -1
- package/dist/types/express.d.ts +3 -4
- package/dist/types/express.js.map +1 -1
- package/dist/utils/authJwt.d.ts +8 -0
- package/dist/utils/authJwt.js +25 -0
- package/dist/utils/authJwt.js.map +1 -0
- package/dist/utils/loadEnv.js +4 -0
- package/dist/utils/loadEnv.js.map +1 -1
- package/dist/utils/preKeySignature.d.ts +1 -1
- package/dist/utils/preKeySignature.js +7 -11
- package/dist/utils/preKeySignature.js.map +1 -1
- package/package.json +7 -7
- package/src/Database.ts +294 -152
- package/src/Spire.ts +412 -285
- package/src/__tests__/Database.spec.ts +126 -3
- package/src/__tests__/browserPasskeyAuthentication.spec.ts +192 -0
- package/src/__tests__/browserPasskeyRegistration.spec.ts +182 -0
- package/src/__tests__/cliPasskeyPage.spec.ts +6 -0
- package/src/__tests__/connectAuth.spec.ts +146 -4
- package/src/__tests__/deviceTokenRevalidation.spec.ts +57 -3
- package/src/__tests__/passkeyDevices.spec.ts +94 -0
- package/src/__tests__/passkeys.spec.ts +7 -2
- package/src/__tests__/password.spec.ts +223 -0
- package/src/__tests__/permissions.spec.ts +50 -0
- package/src/__tests__/preKeySignature.spec.ts +20 -3
- package/src/__tests__/serverManagement.spec.ts +262 -0
- package/src/db/schema.ts +0 -2
- package/src/migrations/2026-04-06_initial-schema.ts +4 -5
- package/src/migrations/2026-07-14_query-indexes.ts +34 -0
- package/src/server/avatar.ts +32 -6
- package/src/server/cliPasskeyPage.ts +109 -11
- package/src/server/errors.ts +7 -0
- package/src/server/file.ts +34 -13
- package/src/server/index.ts +494 -139
- package/src/server/passkey.ts +531 -31
- package/src/server/passkeyDevices.ts +1 -0
- package/src/server/password.ts +96 -0
- package/src/server/permissions.ts +20 -2
- package/src/server/rateLimit.ts +47 -4
- package/src/server/serverIcon.ts +199 -0
- package/src/server/user.ts +44 -9
- package/src/types/express.ts +3 -4
- package/src/utils/authJwt.ts +34 -0
- package/src/utils/loadEnv.ts +4 -0
- package/src/utils/preKeySignature.ts +12 -15
- package/dist/migrations/2026-04-14_argon2id-password-hashing.js +0 -17
- package/dist/migrations/2026-04-14_argon2id-password-hashing.js.map +0 -1
- package/src/migrations/2026-04-14_argon2id-password-hashing.ts +0 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"2026-04-06_initial-schema.js","sourceRoot":"","sources":["../../src/migrations/2026-04-06_initial-schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAe,GAAG,EAAE,MAAM,QAAQ,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,EAAmB;IAC1C,MAAM,MAAM,GAAG;QACX,iBAAiB;QACjB,SAAS;QACT,QAAQ;QACR,OAAO;QACP,aAAa;QACb,UAAU;QACV,SAAS;QACT,aAAa;QACb,SAAS;QACT,MAAM;QACN,SAAS;QACT,OAAO;KACD,CAAC;IAEX,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,EAAmB;IACxC,MAAM,EAAE,CAAC,MAAM;SACV,WAAW,CAAC,OAAO,CAAC;SACpB,WAAW,EAAE;SACb,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;
|
|
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/migrations/{2026-04-14_argon2id-password-hashing.d.ts → 2026-07-14_query-indexes.d.ts}
RENAMED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* Licensed under AGPL-3.0. See LICENSE for details.
|
|
4
4
|
* Commercial licenses available at vex.wtf
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import type { Kysely } from "kysely";
|
|
7
7
|
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
8
8
|
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-2026 Vex Heavy Industries LLC
|
|
3
|
+
* Licensed under AGPL-3.0. See LICENSE for details.
|
|
4
|
+
* Commercial licenses available at vex.wtf
|
|
5
|
+
*/
|
|
6
|
+
export async function down(db) {
|
|
7
|
+
await db.schema.dropIndex("channels_serverID_idx").ifExists().execute();
|
|
8
|
+
await db.schema.dropIndex("devices_owner_deleted_idx").ifExists().execute();
|
|
9
|
+
await db.schema.dropIndex("permissions_user_type_idx").ifExists().execute();
|
|
10
|
+
}
|
|
11
|
+
export async function up(db) {
|
|
12
|
+
await db.schema
|
|
13
|
+
.createIndex("devices_owner_deleted_idx")
|
|
14
|
+
.ifNotExists()
|
|
15
|
+
.on("devices")
|
|
16
|
+
.columns(["owner", "deleted"])
|
|
17
|
+
.execute();
|
|
18
|
+
await db.schema
|
|
19
|
+
.createIndex("channels_serverID_idx")
|
|
20
|
+
.ifNotExists()
|
|
21
|
+
.on("channels")
|
|
22
|
+
.column("serverID")
|
|
23
|
+
.execute();
|
|
24
|
+
await db.schema
|
|
25
|
+
.createIndex("permissions_user_type_idx")
|
|
26
|
+
.ifNotExists()
|
|
27
|
+
.on("permissions")
|
|
28
|
+
.columns(["userID", "resourceType"])
|
|
29
|
+
.execute();
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=2026-07-14_query-indexes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"2026-07-14_query-indexes.js","sourceRoot":"","sources":["../../src/migrations/2026-07-14_query-indexes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,EAAmB;IAC1C,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;IACxE,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;IAC5E,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;AAChF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,EAAmB;IACxC,MAAM,EAAE,CAAC,MAAM;SACV,WAAW,CAAC,2BAA2B,CAAC;SACxC,WAAW,EAAE;SACb,EAAE,CAAC,SAAS,CAAC;SACb,OAAO,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;SAC7B,OAAO,EAAE,CAAC;IACf,MAAM,EAAE,CAAC,MAAM;SACV,WAAW,CAAC,uBAAuB,CAAC;SACpC,WAAW,EAAE;SACb,EAAE,CAAC,UAAU,CAAC;SACd,MAAM,CAAC,UAAU,CAAC;SAClB,OAAO,EAAE,CAAC;IACf,MAAM,EAAE,CAAC,MAAM;SACV,WAAW,CAAC,2BAA2B,CAAC;SACxC,WAAW,EAAE;SACb,EAAE,CAAC,aAAa,CAAC;SACjB,OAAO,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;SACnC,OAAO,EAAE,CAAC;AACnB,CAAC"}
|
package/dist/server/avatar.js
CHANGED
|
@@ -14,12 +14,19 @@ import { uploadLimiter } from "./rateLimit.js";
|
|
|
14
14
|
import { getParam, getUser } from "./utils.js";
|
|
15
15
|
import { ALLOWED_IMAGE_TYPES, protect } from "./index.js";
|
|
16
16
|
const safePathParam = z.string().regex(/^[a-zA-Z0-9._-]+$/);
|
|
17
|
+
const MAX_AVATAR_BYTES = 5 * 1024 * 1024;
|
|
18
|
+
const avatarUpload = multer({
|
|
19
|
+
limits: { fields: 1, files: 1, fileSize: MAX_AVATAR_BYTES, parts: 2 },
|
|
20
|
+
});
|
|
17
21
|
// Avatars are public, unencrypted images. The body for the JSON path is just a
|
|
18
22
|
// base64-encoded image; nothing else. Do NOT reuse FilePayloadSchema here —
|
|
19
23
|
// that schema is for encrypted user-file uploads and requires nonce/owner/signed,
|
|
20
24
|
// which the avatar client never sends (and shouldn't).
|
|
21
25
|
const avatarJsonPayload = z.object({
|
|
22
|
-
file: z
|
|
26
|
+
file: z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(Math.ceil((MAX_AVATAR_BYTES * 4) / 3) + 4),
|
|
23
30
|
});
|
|
24
31
|
export const getAvatarRouter = () => {
|
|
25
32
|
const router = express.Router();
|
|
@@ -37,6 +44,7 @@ export const getAvatarRouter = () => {
|
|
|
37
44
|
}
|
|
38
45
|
res.set("Content-type", typeDetails.mime);
|
|
39
46
|
res.set("Cache-control", "public, max-age=31536000");
|
|
47
|
+
res.set("Cross-Origin-Resource-Policy", "cross-origin");
|
|
40
48
|
const stream = fs.createReadStream(filePath);
|
|
41
49
|
stream.on("error", (_err) => {
|
|
42
50
|
// debugger: avatar stream read error
|
|
@@ -44,7 +52,7 @@ export const getAvatarRouter = () => {
|
|
|
44
52
|
});
|
|
45
53
|
stream.pipe(res);
|
|
46
54
|
});
|
|
47
|
-
router.post("/:userID/json", protect, async (req, res) => {
|
|
55
|
+
router.post("/:userID/json", uploadLimiter, protect, async (req, res) => {
|
|
48
56
|
const parsed = avatarJsonPayload.safeParse(req.body);
|
|
49
57
|
if (!parsed.success) {
|
|
50
58
|
res.status(400).json({
|
|
@@ -60,11 +68,26 @@ export const getAvatarRouter = () => {
|
|
|
60
68
|
res.sendStatus(401);
|
|
61
69
|
return;
|
|
62
70
|
}
|
|
63
|
-
|
|
71
|
+
if (getParam(req, "userID") !== userDetails.userID) {
|
|
72
|
+
res.sendStatus(403);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
let buf;
|
|
76
|
+
try {
|
|
77
|
+
buf = Buffer.from(XUtils.decodeBase64(payload.file));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
res.status(400).send({ error: "Avatar must be valid base64." });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (buf.byteLength > MAX_AVATAR_BYTES) {
|
|
84
|
+
res.sendStatus(413);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
64
87
|
const mimeType = await fileTypeFromBuffer(buf);
|
|
65
88
|
if (!ALLOWED_IMAGE_TYPES.includes(mimeType?.mime || "no/type")) {
|
|
66
89
|
res.status(400).send({
|
|
67
|
-
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or
|
|
90
|
+
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or webp but received " +
|
|
68
91
|
String(mimeType?.ext),
|
|
69
92
|
});
|
|
70
93
|
return;
|
|
@@ -79,13 +102,17 @@ export const getAvatarRouter = () => {
|
|
|
79
102
|
res.sendStatus(500);
|
|
80
103
|
}
|
|
81
104
|
});
|
|
82
|
-
router.post("/:userID", uploadLimiter, protect,
|
|
105
|
+
router.post("/:userID", uploadLimiter, protect, avatarUpload.single("avatar"), async (req, res) => {
|
|
83
106
|
const userDetails = getUser(req);
|
|
84
107
|
const deviceDetails = req.device;
|
|
85
108
|
if (!deviceDetails) {
|
|
86
109
|
res.sendStatus(401);
|
|
87
110
|
return;
|
|
88
111
|
}
|
|
112
|
+
if (getParam(req, "userID") !== userDetails.userID) {
|
|
113
|
+
res.sendStatus(403);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
89
116
|
if (!req.file) {
|
|
90
117
|
res.sendStatus(400);
|
|
91
118
|
return;
|
|
@@ -93,7 +120,7 @@ export const getAvatarRouter = () => {
|
|
|
93
120
|
const mimeType = await fileTypeFromBuffer(req.file.buffer);
|
|
94
121
|
if (!ALLOWED_IMAGE_TYPES.includes(mimeType?.mime || "no/type")) {
|
|
95
122
|
res.status(400).send({
|
|
96
|
-
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or
|
|
123
|
+
error: "Unsupported file type. Expected jpeg, png, gif, apng, avif, or webp but received " +
|
|
97
124
|
String(mimeType?.ext),
|
|
98
125
|
});
|
|
99
126
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.js","sourceRoot":"","sources":["../../src/server/avatar.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"avatar.js","sourceRoot":"","sources":["../../src/server/avatar.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;AAC5D,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,MAAM,YAAY,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE;CACxE,CAAC,CAAC;AAEH,+EAA+E;AAC/E,4EAA4E;AAC5E,kFAAkF;AAClF,uDAAuD;AACvD,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC;SACF,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;CACtD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAClB,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC;QACrD,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,qCAAqC;YACrC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACpE,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACjB,KAAK,EAAE,wBAAwB;gBAC/B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;aAC9B,CAAC,CAAC;YACH,OAAO;QACX,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC;QAEjC,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;YACjD,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QAED,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACD,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACL,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;YAChE,OAAO;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,GAAG,gBAAgB,EAAE,CAAC;YACpC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACjB,KAAK,EACD,mFAAmF;oBACnF,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC;aAC5B,CAAC,CAAC;YACH,OAAO;QACX,CAAC;QAED,IAAI,CAAC;YACD,yBAAyB;YACzB,MAAM,GAAG,CAAC,SAAS,CAAC,UAAU,GAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC1D,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,IAAa,EAAE,CAAC;YACrB,gCAAgC;YAChC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CACP,UAAU,EACV,aAAa,EACb,OAAO,EACP,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC7B,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACf,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC;QAEjC,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;YACjD,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACZ,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACjB,KAAK,EACD,mFAAmF;oBACnF,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC;aAC5B,CAAC,CAAC;YACH,OAAO;QACX,CAAC;QAED,IAAI,CAAC;YACD,yBAAyB;YACzB,MAAM,GAAG,CAAC,SAAS,CACf,UAAU,GAAG,WAAW,CAAC,MAAM,EAC/B,GAAG,CAAC,IAAI,CAAC,MAAM,CAClB,CAAC;YACF,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,IAAa,EAAE,CAAC;YACrB,gCAAgC;YAChC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACL,CAAC,CACJ,CAAC;IAEF,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC"}
|
|
@@ -147,6 +147,13 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
147
147
|
"use strict";
|
|
148
148
|
|
|
149
149
|
var params = new URLSearchParams(window.location.hash.slice(1));
|
|
150
|
+
if (window.location.hash) {
|
|
151
|
+
window.history.replaceState(
|
|
152
|
+
null,
|
|
153
|
+
"",
|
|
154
|
+
window.location.pathname + window.location.search,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
150
157
|
var action = document.getElementById("action");
|
|
151
158
|
var statusEl = document.getElementById("status");
|
|
152
159
|
var titleEl = document.getElementById("title");
|
|
@@ -155,6 +162,7 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
155
162
|
var startupError = null;
|
|
156
163
|
var apiBase = window.location.origin;
|
|
157
164
|
var busy = false;
|
|
165
|
+
var completed = false;
|
|
158
166
|
|
|
159
167
|
try {
|
|
160
168
|
apiBase = resolveTrustedApiBase(params.get("api"));
|
|
@@ -162,11 +170,16 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
162
170
|
startupError = err;
|
|
163
171
|
}
|
|
164
172
|
|
|
165
|
-
if (mode === "register") {
|
|
173
|
+
if (mode === "register" || mode === "register-handoff") {
|
|
166
174
|
titleEl.textContent = "Create a passkey for Vex.";
|
|
167
175
|
copyEl.textContent = "This adds a passkey to your Vex account.";
|
|
168
176
|
action.textContent = "Create passkey";
|
|
169
177
|
setStatus("Ready to create passkey.");
|
|
178
|
+
} else if (mode === "authenticate-handoff") {
|
|
179
|
+
titleEl.textContent = "Continue signing in to Vex.";
|
|
180
|
+
copyEl.textContent =
|
|
181
|
+
"Use your passkey here, then return to the Vex desktop app.";
|
|
182
|
+
setStatus("Ready to verify passkey.");
|
|
170
183
|
} else {
|
|
171
184
|
setStatus("Ready to verify passkey.");
|
|
172
185
|
}
|
|
@@ -187,7 +200,7 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
187
200
|
|
|
188
201
|
function setBusy(nextBusy) {
|
|
189
202
|
busy = nextBusy;
|
|
190
|
-
action.disabled = nextBusy;
|
|
203
|
+
action.disabled = nextBusy || completed;
|
|
191
204
|
}
|
|
192
205
|
|
|
193
206
|
function apiUrl(path) {
|
|
@@ -268,12 +281,19 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
268
281
|
}
|
|
269
282
|
if (mode === "register") {
|
|
270
283
|
await registerPasskey();
|
|
284
|
+
} else if (mode === "register-handoff") {
|
|
285
|
+
await registerPasskeyWithHandoff();
|
|
286
|
+
} else if (mode === "authenticate-handoff") {
|
|
287
|
+
await authenticatePasskeyWithHandoff();
|
|
271
288
|
} else {
|
|
272
289
|
await recoverWithPasskey();
|
|
273
290
|
}
|
|
274
291
|
} catch (err) {
|
|
275
292
|
setStatus(errorMessage(err), "error");
|
|
276
|
-
action.textContent =
|
|
293
|
+
action.textContent =
|
|
294
|
+
mode === "register" || mode === "register-handoff"
|
|
295
|
+
? "Try again"
|
|
296
|
+
: "Retry passkey";
|
|
277
297
|
} finally {
|
|
278
298
|
setBusy(false);
|
|
279
299
|
}
|
|
@@ -294,15 +314,8 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
294
314
|
body: { name: name },
|
|
295
315
|
token: token,
|
|
296
316
|
});
|
|
297
|
-
var credentialOptions = makeCreationOptions(begin.options);
|
|
298
|
-
|
|
299
317
|
setStatus("Waiting for browser passkey prompt...");
|
|
300
|
-
var credential = await
|
|
301
|
-
publicKey: credentialOptions,
|
|
302
|
-
});
|
|
303
|
-
if (!credential) {
|
|
304
|
-
throw new Error("No passkey was created.");
|
|
305
|
-
}
|
|
318
|
+
var credential = await createPasskeyCredential(begin.options);
|
|
306
319
|
|
|
307
320
|
setStatus("Saving passkey...");
|
|
308
321
|
await apiRequest("/user/" + encodeURIComponent(userID) + "/passkeys/register/finish", {
|
|
@@ -316,6 +329,90 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
316
329
|
setStatus("Passkey saved. Return to the Vex CLI.", "success");
|
|
317
330
|
titleEl.textContent = "Passkey saved.";
|
|
318
331
|
copyEl.textContent = "The CLI can finish connecting now.";
|
|
332
|
+
completed = true;
|
|
333
|
+
action.textContent = "Done";
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async function registerPasskeyWithHandoff() {
|
|
337
|
+
var token = requiredParam("token");
|
|
338
|
+
var requestID = requiredParam("request");
|
|
339
|
+
|
|
340
|
+
setStatus("Requesting a one-time passkey challenge...");
|
|
341
|
+
var begin = await apiRequest(
|
|
342
|
+
"/auth/passkey/browser-registration/" +
|
|
343
|
+
encodeURIComponent(requestID) +
|
|
344
|
+
"/begin",
|
|
345
|
+
{ body: { token: token } },
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
setStatus("Waiting for browser passkey prompt...");
|
|
349
|
+
var credential = await createPasskeyCredential(begin.options);
|
|
350
|
+
|
|
351
|
+
setStatus("Saving passkey...");
|
|
352
|
+
await apiRequest(
|
|
353
|
+
"/auth/passkey/browser-registration/" +
|
|
354
|
+
encodeURIComponent(requestID) +
|
|
355
|
+
"/finish",
|
|
356
|
+
{
|
|
357
|
+
body: {
|
|
358
|
+
response: registrationResponseJSON(credential),
|
|
359
|
+
token: token,
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
);
|
|
363
|
+
setStatus("Passkey saved. You can close this page.", "success");
|
|
364
|
+
titleEl.textContent = "Passkey saved.";
|
|
365
|
+
copyEl.textContent = "Vex has updated your account.";
|
|
366
|
+
completed = true;
|
|
367
|
+
action.textContent = "Done";
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function createPasskeyCredential(options) {
|
|
371
|
+
var credential = await navigator.credentials.create({
|
|
372
|
+
publicKey: makeCreationOptions(options),
|
|
373
|
+
});
|
|
374
|
+
if (!credential) {
|
|
375
|
+
throw new Error("No passkey was created.");
|
|
376
|
+
}
|
|
377
|
+
return credential;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function authenticatePasskeyWithHandoff() {
|
|
381
|
+
var token = requiredParam("token");
|
|
382
|
+
var requestID = requiredParam("request");
|
|
383
|
+
|
|
384
|
+
setStatus("Requesting a one-time passkey challenge...");
|
|
385
|
+
var begin = await apiRequest(
|
|
386
|
+
"/auth/passkey/browser-authentication/" +
|
|
387
|
+
encodeURIComponent(requestID) +
|
|
388
|
+
"/begin",
|
|
389
|
+
{ body: { token: token } },
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
setStatus("Waiting for browser passkey prompt...");
|
|
393
|
+
var credential = await navigator.credentials.get({
|
|
394
|
+
publicKey: makeRequestOptions(begin.options),
|
|
395
|
+
});
|
|
396
|
+
if (!credential) {
|
|
397
|
+
throw new Error("No passkey was returned.");
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
setStatus("Returning verification to Vex...");
|
|
401
|
+
await apiRequest(
|
|
402
|
+
"/auth/passkey/browser-authentication/" +
|
|
403
|
+
encodeURIComponent(requestID) +
|
|
404
|
+
"/finish",
|
|
405
|
+
{
|
|
406
|
+
body: {
|
|
407
|
+
response: authenticationResponseJSON(credential),
|
|
408
|
+
token: token,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
);
|
|
412
|
+
setStatus("Passkey verified. You can close this page.", "success");
|
|
413
|
+
titleEl.textContent = "Passkey verified.";
|
|
414
|
+
copyEl.textContent = "Return to Vex to finish signing in.";
|
|
415
|
+
completed = true;
|
|
319
416
|
action.textContent = "Done";
|
|
320
417
|
}
|
|
321
418
|
|
|
@@ -368,6 +465,7 @@ const CLI_PASSKEY_PAGE = `<!doctype html>
|
|
|
368
465
|
setStatus("CLI device recovered. Return to the Vex CLI.", "success");
|
|
369
466
|
titleEl.textContent = "Device signed in.";
|
|
370
467
|
copyEl.textContent = "The CLI can finish connecting now.";
|
|
468
|
+
completed = true;
|
|
371
469
|
action.textContent = "Done";
|
|
372
470
|
}
|
|
373
471
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliPasskeyPage.js","sourceRoot":"","sources":["../../src/server/cliPasskeyPage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,MAAM,GAAG,GAAG;IACR,oBAAoB;IACpB,iBAAiB;IACjB,0DAA0D;IAC1D,oBAAoB;IACpB,wBAAwB;IACxB,gBAAgB;IAChB,4BAA4B;IAC5B,2BAA2B;CAC9B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,gBAAgB,GAAG
|
|
1
|
+
{"version":3,"file":"cliPasskeyPage.js","sourceRoot":"","sources":["../../src/server/cliPasskeyPage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,MAAM,GAAG,GAAG;IACR,oBAAoB;IACpB,iBAAiB;IACjB,0DAA0D;IAC1D,oBAAoB;IACpB,wBAAwB;IACxB,gBAAgB;IAChB,4BAA4B;IAC5B,2BAA2B;CAC9B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyjBjB,CAAC;AAET,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAmB,EAAE;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACrC,GAAG,CAAC,GAAG,CAAC;YACJ,eAAe,EAAE,UAAU;YAC3B,yBAAyB,EAAE,GAAG;YAC9B,cAAc,EAAE,0BAA0B;YAC1C,oBAAoB,EAChB,uEAAuE;YAC3E,iBAAiB,EAAE,aAAa;YAChC,wBAAwB,EAAE,SAAS;SACtC,CAAC,CAAC;QACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC"}
|
package/dist/server/errors.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Commercial licenses available at vex.wtf
|
|
5
5
|
*/
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
|
+
import multer from "multer";
|
|
7
8
|
import { ZodError } from "zod/v4";
|
|
8
9
|
/**
|
|
9
10
|
* Operational HTTP errors that are safe to surface to the client.
|
|
@@ -55,6 +56,13 @@ export const errorHandler = () => (err, _req, res, _next) => {
|
|
|
55
56
|
clientMessage = "Validation failed";
|
|
56
57
|
details = err.issues;
|
|
57
58
|
}
|
|
59
|
+
else if (err instanceof multer.MulterError) {
|
|
60
|
+
status = err.code === "LIMIT_FILE_SIZE" ? 413 : 400;
|
|
61
|
+
clientMessage =
|
|
62
|
+
err.code === "LIMIT_FILE_SIZE"
|
|
63
|
+
? "Uploaded file is too large"
|
|
64
|
+
: "Invalid multipart upload";
|
|
65
|
+
}
|
|
58
66
|
else if (err instanceof AppError) {
|
|
59
67
|
status = err.status;
|
|
60
68
|
clientMessage = err.message;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/server/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA+BH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;;;;;;;;;;;GAYG;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,GAAwB,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;IACjD,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,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"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/server/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA+BH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;;;;;;;;;;;GAYG;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,GAAwB,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;IACjD,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,MAAM,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACpD,aAAa;YACT,GAAG,CAAC,IAAI,KAAK,iBAAiB;gBAC1B,CAAC,CAAC,4BAA4B;gBAC9B,CAAC,CAAC,0BAA0B,CAAC;IACzC,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,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.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as fsp from "node:fs/promises";
|
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import express from "express";
|
|
10
10
|
import { XUtils } from "@vex-chat/crypto";
|
|
11
|
-
import { FilePayloadSchema } from "@vex-chat/types";
|
|
11
|
+
import { FilePayloadSchema, MAX_FILE_UPLOAD_BYTES } from "@vex-chat/types";
|
|
12
12
|
import multer from "multer";
|
|
13
13
|
import { z } from "zod/v4";
|
|
14
14
|
import { msgpack } from "../utils/msgpack.js";
|
|
@@ -16,6 +16,14 @@ import { uploadLimiter } from "./rateLimit.js";
|
|
|
16
16
|
import { getParam } from "./utils.js";
|
|
17
17
|
import { protect } from "./index.js";
|
|
18
18
|
const safePathParam = z.string().regex(/^[a-zA-Z0-9._-]+$/);
|
|
19
|
+
const fileUpload = multer({
|
|
20
|
+
limits: {
|
|
21
|
+
fields: 4,
|
|
22
|
+
files: 1,
|
|
23
|
+
fileSize: MAX_FILE_UPLOAD_BYTES,
|
|
24
|
+
parts: 5,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
19
27
|
export const getFileRouter = (db) => {
|
|
20
28
|
const router = express.Router();
|
|
21
29
|
router.get("/:id", protect, async (req, res) => {
|
|
@@ -62,7 +70,7 @@ export const getFileRouter = (db) => {
|
|
|
62
70
|
});
|
|
63
71
|
}
|
|
64
72
|
});
|
|
65
|
-
router.post("/json", protect, async (req, res) => {
|
|
73
|
+
router.post("/json", uploadLimiter, protect, async (req, res) => {
|
|
66
74
|
const deviceDetails = req.device;
|
|
67
75
|
if (!deviceDetails) {
|
|
68
76
|
res.sendStatus(401);
|
|
@@ -77,15 +85,28 @@ export const getFileRouter = (db) => {
|
|
|
77
85
|
return;
|
|
78
86
|
}
|
|
79
87
|
const payload = parsed.data;
|
|
80
|
-
if (payload.
|
|
88
|
+
if (!payload.file) {
|
|
81
89
|
res.sendStatus(400);
|
|
82
90
|
return;
|
|
83
91
|
}
|
|
84
|
-
if (
|
|
85
|
-
res.
|
|
92
|
+
if (payload.owner !== deviceDetails.deviceID) {
|
|
93
|
+
res.status(400).send({
|
|
94
|
+
error: "File owner must match this device.",
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let buf;
|
|
99
|
+
try {
|
|
100
|
+
buf = Buffer.from(XUtils.decodeBase64(payload.file));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
res.status(400).send({ error: "File must be valid base64." });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (buf.byteLength > MAX_FILE_UPLOAD_BYTES) {
|
|
107
|
+
res.sendStatus(413);
|
|
86
108
|
return;
|
|
87
109
|
}
|
|
88
|
-
const buf = Buffer.from(XUtils.decodeBase64(payload.file));
|
|
89
110
|
const newFile = {
|
|
90
111
|
fileID: crypto.randomUUID(),
|
|
91
112
|
nonce: payload.nonce,
|
|
@@ -97,13 +118,13 @@ export const getFileRouter = (db) => {
|
|
|
97
118
|
});
|
|
98
119
|
// Multipart file upload — form fields are strings from multer, not full FilePayload
|
|
99
120
|
const multipartFields = z.object({
|
|
100
|
-
nonce: z.string().
|
|
101
|
-
owner: z.string().min(1),
|
|
121
|
+
nonce: z.string().regex(/^[0-9a-fA-F]{48}$/),
|
|
122
|
+
owner: z.string().min(1).max(128),
|
|
102
123
|
});
|
|
103
|
-
router.post("/", uploadLimiter, protect,
|
|
124
|
+
router.post("/", uploadLimiter, protect, fileUpload.single("file"), async (req, res) => {
|
|
104
125
|
const deviceDetails = req.device;
|
|
105
126
|
if (!deviceDetails) {
|
|
106
|
-
res.sendStatus(
|
|
127
|
+
res.sendStatus(401);
|
|
107
128
|
return;
|
|
108
129
|
}
|
|
109
130
|
const parsed = multipartFields.safeParse(req.body);
|
|
@@ -119,8 +140,10 @@ export const getFileRouter = (db) => {
|
|
|
119
140
|
res.sendStatus(400);
|
|
120
141
|
return;
|
|
121
142
|
}
|
|
122
|
-
if (payload.
|
|
123
|
-
res.
|
|
143
|
+
if (payload.owner !== deviceDetails.deviceID) {
|
|
144
|
+
res.status(400).send({
|
|
145
|
+
error: "File owner must match this device.",
|
|
146
|
+
});
|
|
124
147
|
return;
|
|
125
148
|
}
|
|
126
149
|
const newFile = {
|
package/dist/server/file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -10,7 +10,15 @@ import { TokenScopes } from "@vex-chat/types";
|
|
|
10
10
|
export declare const EXPIRY_TIME: number;
|
|
11
11
|
export declare const ALLOWED_IMAGE_TYPES: string[];
|
|
12
12
|
export declare function createCheckDevice(db: Pick<Database, "retrieveDevice">): express.RequestHandler;
|
|
13
|
+
/**
|
|
14
|
+
* Revalidate the credential behind a passkey-scoped bearer on every request.
|
|
15
|
+
* Passkey JWTs are short-lived, but removing a credential must revoke its
|
|
16
|
+
* recovery and account-administration access immediately.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createCheckPasskey(db: Pick<Database, "retrievePasskeyInternal">): express.RequestHandler;
|
|
13
19
|
export declare const protect: express.RequestHandler;
|
|
20
|
+
/** Require either an approved device or a fresh passkey session. */
|
|
21
|
+
export declare const protectAnyAuth: express.RequestHandler;
|
|
14
22
|
/**
|
|
15
23
|
* Restrict a route to passkey-scoped JWTs (used by the parallel
|
|
16
24
|
* `/user/:id/passkey/devices/...` admin/recovery routes). A
|