diff --git a/api/api/auth/login/index.ts b/api/api/auth/login/index.ts index 29ef11fe..3d90d84e 100644 --- a/api/api/auth/login/index.ts +++ b/api/api/auth/login/index.ts @@ -1,6 +1,6 @@ -import { apiRoute, applyConfig, handleZodError } from "@/api"; +import { apiRoute, applyConfig } from "@/api"; import { redirect } from "@/response"; -import { zValidator } from "@hono/zod-validator"; +import { createRoute } from "@hono/zod-openapi"; import { eq, or } from "drizzle-orm"; import { SignJWT } from "jose"; import { z } from "zod"; @@ -59,6 +59,34 @@ export const schemas = { }), }; +const route = createRoute({ + method: "post", + path: "/api/auth/login", + summary: "Login", + description: "Login to the application", + request: { + body: { + content: { + "multipart/form-data": { + schema: schemas.form, + }, + }, + }, + query: schemas.query, + }, + responses: { + 302: { + description: "Redirect to OAuth authorize, or error", + headers: { + "Set-Cookie": { + description: "JWT cookie", + required: false, + }, + }, + }, + }, +}); + const returnError = (query: object, error: string, description: string) => { const searchParams = new URLSearchParams(); @@ -81,116 +109,103 @@ const returnError = (query: object, error: string, description: string) => { }; export default apiRoute((app) => - app.on( - meta.allowedMethods, - meta.route, - zValidator("form", schemas.form, handleZodError), - zValidator("query", schemas.query, handleZodError), - async (context) => { - if (config.oidc.forced) { - return returnError( - context.req.query(), - "invalid_request", - "Logging in with a password is disabled by the administrator. Please use a valid OpenID Connect provider.", - ); - } - - const { identifier, password } = context.req.valid("form"); - const { client_id } = context.req.valid("query"); - - // Find user - const user = await User.fromSql( - or( - eq(Users.email, identifier.toLowerCase()), - eq(Users.username, identifier.toLowerCase()), - ), + app.openapi(route, async (context) => { + if (config.oidc.forced) { + return returnError( + context.req.query(), + "invalid_request", + "Logging in with a password is disabled by the administrator. Please use a valid OpenID Connect provider.", ); + } - if ( - !( - user && - (await Bun.password.verify( - password, - user.data.password || "", - )) - ) - ) { - return returnError( - context.req.query(), - "invalid_grant", - "Invalid identifier or password", - ); - } + const { identifier, password } = context.req.valid("form"); + const { client_id } = context.req.valid("query"); - if (user.data.passwordResetToken) { - return redirect( - `${ - config.frontend.routes.password_reset - }?${new URLSearchParams({ + // Find user + const user = await User.fromSql( + or( + eq(Users.email, identifier.toLowerCase()), + eq(Users.username, identifier.toLowerCase()), + ), + ); + + if ( + !( + user && + (await Bun.password.verify(password, user.data.password || "")) + ) + ) { + return returnError( + context.req.query(), + "invalid_grant", + "Invalid identifier or password", + ); + } + + if (user.data.passwordResetToken) { + return redirect( + `${config.frontend.routes.password_reset}?${new URLSearchParams( + { token: user.data.passwordResetToken ?? "", login_reset: "true", - }).toString()}`, - ); - } - - // Try and import the key - const privateKey = await crypto.subtle.importKey( - "pkcs8", - Buffer.from(config.oidc.jwt_key.split(";")[0], "base64"), - "Ed25519", - false, - ["sign"], + }, + ).toString()}`, ); + } - // Generate JWT - const jwt = await new SignJWT({ - sub: user.id, - iss: new URL(config.http.base_url).origin, - aud: client_id, - exp: Math.floor(Date.now() / 1000) + 60 * 60, - iat: Math.floor(Date.now() / 1000), - nbf: Math.floor(Date.now() / 1000), - }) - .setProtectedHeader({ alg: "EdDSA" }) - .sign(privateKey); + // Try and import the key + const privateKey = await crypto.subtle.importKey( + "pkcs8", + Buffer.from(config.oidc.jwt_key.split(";")[0], "base64"), + "Ed25519", + false, + ["sign"], + ); - const application = await db.query.Applications.findFirst({ - where: (app, { eq }) => eq(app.clientId, client_id), - }); + // Generate JWT + const jwt = await new SignJWT({ + sub: user.id, + iss: new URL(config.http.base_url).origin, + aud: client_id, + exp: Math.floor(Date.now() / 1000) + 60 * 60, + iat: Math.floor(Date.now() / 1000), + nbf: Math.floor(Date.now() / 1000), + }) + .setProtectedHeader({ alg: "EdDSA" }) + .sign(privateKey); - if (!application) { - return context.json({ error: "Invalid application" }, 400); + const application = await db.query.Applications.findFirst({ + where: (app, { eq }) => eq(app.clientId, client_id), + }); + + if (!application) { + return context.json({ error: "Invalid application" }, 400); + } + + const searchParams = new URLSearchParams({ + application: application.name, + }); + + if (application.website) { + searchParams.append("website", application.website); + } + + // Add all data that is not undefined except email and password + for (const [key, value] of Object.entries(context.req.query())) { + if (key !== "email" && key !== "password" && value !== undefined) { + searchParams.append(key, String(value)); } + } - const searchParams = new URLSearchParams({ - application: application.name, - }); - - if (application.website) { - searchParams.append("website", application.website); - } - - // Add all data that is not undefined except email and password - for (const [key, value] of Object.entries(context.req.query())) { - if ( - key !== "email" && - key !== "password" && - value !== undefined - ) { - searchParams.append(key, String(value)); - } - } - - // Redirect to OAuth authorize with JWT - return redirect( - `${config.frontend.routes.consent}?${searchParams.toString()}`, - 302, - { - "Set-Cookie": `jwt=${jwt}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=${ - 60 * 60 - }`, - }, - ); - }, - ), + // Redirect to OAuth authorize with JWT + return redirect( + `${config.frontend.routes.consent}?${searchParams.toString()}`, + 302, + { + "Set-Cookie": `jwt=${jwt}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=${ + 60 * 60 + }`, + }, + ); + }), ); diff --git a/api/api/auth/redirect/index.ts b/api/api/auth/redirect/index.ts index 135446c9..5d045bce 100644 --- a/api/api/auth/redirect/index.ts +++ b/api/api/auth/redirect/index.ts @@ -1,5 +1,5 @@ -import { apiRoute, applyConfig, handleZodError } from "@/api"; -import { zValidator } from "@hono/zod-validator"; +import { apiRoute, applyConfig } from "@/api"; +import { createRoute } from "@hono/zod-openapi"; import { and, eq } from "drizzle-orm"; import { z } from "zod"; import { db } from "~/drizzle/db"; @@ -26,48 +26,56 @@ export const schemas = { }), }; +const route = createRoute({ + method: "get", + path: "/api/auth/redirect", + summary: "OAuth Code flow", + description: + "Redirects to the application, or back to login if the code is invalid", + responses: { + 302: { + description: + "Redirects to the application, or back to login if the code is invalid", + }, + }, + request: { + query: schemas.query, + }, +}); + /** * OAuth Code flow */ export default apiRoute((app) => - app.on( - meta.allowedMethods, - meta.route, - zValidator("query", schemas.query, handleZodError), - async (context) => { - const { redirect_uri, client_id, code } = - context.req.valid("query"); + app.openapi(route, async (context) => { + const { redirect_uri, client_id, code } = context.req.valid("query"); - const redirectToLogin = (error: string) => - Response.redirect( - `${config.frontend.routes.login}?${new URLSearchParams({ - ...context.req.query, - error: encodeURIComponent(error), - }).toString()}`, - 302, - ); + const redirectToLogin = (error: string) => + Response.redirect( + `${config.frontend.routes.login}?${new URLSearchParams({ + ...context.req.query, + error: encodeURIComponent(error), + }).toString()}`, + 302, + ); - const foundToken = await db - .select() - .from(Tokens) - .leftJoin( - Applications, - eq(Tokens.applicationId, Applications.id), - ) - .where( - and( - eq(Tokens.code, code), - eq(Applications.clientId, client_id), - ), - ) - .limit(1); + const foundToken = await db + .select() + .from(Tokens) + .leftJoin(Applications, eq(Tokens.applicationId, Applications.id)) + .where( + and( + eq(Tokens.code, code), + eq(Applications.clientId, client_id), + ), + ) + .limit(1); - if (!foundToken || foundToken.length <= 0) { - return redirectToLogin("Invalid code"); - } + if (!foundToken || foundToken.length <= 0) { + return redirectToLogin("Invalid code"); + } - // Redirect back to application - return Response.redirect(`${redirect_uri}?code=${code}`, 302); - }, - ), + // Redirect back to application + return Response.redirect(`${redirect_uri}?code=${code}`, 302); + }), ); diff --git a/api/api/auth/reset/index.ts b/api/api/auth/reset/index.ts index 2478cb83..1146cd1b 100644 --- a/api/api/auth/reset/index.ts +++ b/api/api/auth/reset/index.ts @@ -1,6 +1,6 @@ -import { apiRoute, applyConfig, handleZodError } from "@/api"; +import { apiRoute, applyConfig } from "@/api"; import { response } from "@/response"; -import { zValidator } from "@hono/zod-validator"; +import { createRoute } from "@hono/zod-openapi"; import { eq } from "drizzle-orm"; import { z } from "zod"; import { Users } from "~/drizzle/schema"; @@ -26,6 +26,30 @@ export const schemas = { }), }; +const route = createRoute({ + method: "post", + path: "/api/auth/reset", + summary: "Reset password", + description: "Reset password", + responses: { + 302: { + description: "Redirect to the password reset page with a message", + }, + }, + request: { + body: { + content: { + "application/x-www-form-urlencoded": { + schema: schemas.form, + }, + "multipart/form-data": { + schema: schemas.form, + }, + }, + }, + }, +}); + const returnError = (token: string, error: string, description: string) => { const searchParams = new URLSearchParams(); @@ -44,29 +68,22 @@ const returnError = (token: string, error: string, description: string) => { }; export default apiRoute((app) => - app.on( - meta.allowedMethods, - meta.route, - zValidator("form", schemas.form, handleZodError), - async (context) => { - const { token, password } = context.req.valid("form"); + app.openapi(route, async (context) => { + const { token, password } = context.req.valid("form"); - const user = await User.fromSql( - eq(Users.passwordResetToken, token), - ); + const user = await User.fromSql(eq(Users.passwordResetToken, token)); - if (!user) { - return returnError(token, "invalid_token", "Invalid token"); - } + if (!user) { + return returnError(token, "invalid_token", "Invalid token"); + } - await user.update({ - password: await Bun.password.hash(password), - passwordResetToken: null, - }); + await user.update({ + password: await Bun.password.hash(password), + passwordResetToken: null, + }); - return response(null, 302, { - Location: `${config.frontend.routes.password_reset}?success=true`, - }); - }, - ), + return response(null, 302, { + Location: `${config.frontend.routes.password_reset}?success=true`, + }); + }), ); diff --git a/api/api/v1/accounts/:id/block.ts b/api/api/v1/accounts/:id/block.ts index 0efcd9fb..d7e34e94 100644 --- a/api/api/v1/accounts/:id/block.ts +++ b/api/api/v1/accounts/:id/block.ts @@ -1,9 +1,10 @@ -import { apiRoute, applyConfig, auth, handleZodError } from "@/api"; -import { zValidator } from "@hono/zod-validator"; +import { apiRoute, applyConfig, auth } from "@/api"; +import { createRoute } from "@hono/zod-openapi"; import { z } from "zod"; import { RolePermissions } from "~/drizzle/schema"; import { Relationship } from "~/packages/database-interface/relationship"; import { User } from "~/packages/database-interface/user"; +import { ErrorSchema } from "~/types/api"; export const meta = applyConfig({ allowedMethods: ["POST"], @@ -30,38 +31,69 @@ export const schemas = { }), }; -export default apiRoute((app) => - app.on( - meta.allowedMethods, - meta.route, - zValidator("param", schemas.param, handleZodError), - auth(meta.auth, meta.permissions), - async (context) => { - const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); - - if (!user) { - return context.json({ error: "Unauthorized" }, 401); - } - - const otherUser = await User.fromId(id); - - if (!otherUser) { - return context.json({ error: "User not found" }, 404); - } - - const foundRelationship = await Relationship.fromOwnerAndSubject( - user, - otherUser, - ); - - if (!foundRelationship.data.blocking) { - await foundRelationship.update({ - blocking: true, - }); - } - - return context.json(foundRelationship.toApi()); +const route = createRoute({ + method: "post", + path: "/api/v1/accounts/{id}/block", + summary: "Block user", + description: "Block a user", + middleware: [auth(meta.auth, meta.permissions)], + responses: { + 200: { + description: "User blocked", + content: { + "application/json": { + schema: Relationship.schema, + }, + }, }, - ), + 401: { + description: "Unauthorized", + content: { + "application/json": { + schema: ErrorSchema, + }, + }, + }, + 404: { + description: "User not found", + content: { + "application/json": { + schema: ErrorSchema, + }, + }, + }, + }, + request: { + params: schemas.param, + }, +}); + +export default apiRoute((app) => + app.openapi(route, async (context) => { + const { id } = context.req.valid("param"); + const { user } = context.get("auth"); + + if (!user) { + return context.json({ error: "Unauthorized" }, 401); + } + + const otherUser = await User.fromId(id); + + if (!otherUser) { + return context.json({ error: "User not found" }, 404); + } + + const foundRelationship = await Relationship.fromOwnerAndSubject( + user, + otherUser, + ); + + if (!foundRelationship.data.blocking) { + await foundRelationship.update({ + blocking: true, + }); + } + + return context.json(foundRelationship.toApi(), 200); + }), ); diff --git a/api/api/v1/accounts/:id/follow.ts b/api/api/v1/accounts/:id/follow.ts index 5e28e99e..0e0d6823 100644 --- a/api/api/v1/accounts/:id/follow.ts +++ b/api/api/v1/accounts/:id/follow.ts @@ -50,7 +50,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { reblogs, notify, languages } = context.req.valid("json"); if (!user) { diff --git a/api/api/v1/accounts/:id/index.ts b/api/api/v1/accounts/:id/index.ts index e217c35f..c48f9f58 100644 --- a/api/api/v1/accounts/:id/index.ts +++ b/api/api/v1/accounts/:id/index.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const foundUser = await User.fromId(id); diff --git a/api/api/v1/accounts/:id/mute.ts b/api/api/v1/accounts/:id/mute.ts index c2b96f9f..e9844c53 100644 --- a/api/api/v1/accounts/:id/mute.ts +++ b/api/api/v1/accounts/:id/mute.ts @@ -48,7 +48,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); // TODO: Add duration support const { notifications } = context.req.valid("json"); diff --git a/api/api/v1/accounts/:id/note.ts b/api/api/v1/accounts/:id/note.ts index fb1d0060..25d0be9d 100644 --- a/api/api/v1/accounts/:id/note.ts +++ b/api/api/v1/accounts/:id/note.ts @@ -42,7 +42,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { comment } = context.req.valid("json"); if (!user) { diff --git a/api/api/v1/accounts/:id/pin.ts b/api/api/v1/accounts/:id/pin.ts index 5a785dea..ee07fa89 100644 --- a/api/api/v1/accounts/:id/pin.ts +++ b/api/api/v1/accounts/:id/pin.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/refetch.ts b/api/api/v1/accounts/:id/refetch.ts index 6647e56a..997b4e84 100644 --- a/api/api/v1/accounts/:id/refetch.ts +++ b/api/api/v1/accounts/:id/refetch.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/remove_from_followers.ts b/api/api/v1/accounts/:id/remove_from_followers.ts index a5b24728..ae346a97 100644 --- a/api/api/v1/accounts/:id/remove_from_followers.ts +++ b/api/api/v1/accounts/:id/remove_from_followers.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/statuses.ts b/api/api/v1/accounts/:id/statuses.ts index e7e9f490..1a78f28a 100644 --- a/api/api/v1/accounts/:id/statuses.ts +++ b/api/api/v1/accounts/:id/statuses.ts @@ -69,7 +69,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const otherUser = await User.fromId(id); diff --git a/api/api/v1/accounts/:id/unblock.ts b/api/api/v1/accounts/:id/unblock.ts index c60bed77..fcfea7ad 100644 --- a/api/api/v1/accounts/:id/unblock.ts +++ b/api/api/v1/accounts/:id/unblock.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/unfollow.ts b/api/api/v1/accounts/:id/unfollow.ts index 2184fd6a..a366311b 100644 --- a/api/api/v1/accounts/:id/unfollow.ts +++ b/api/api/v1/accounts/:id/unfollow.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/unmute.ts b/api/api/v1/accounts/:id/unmute.ts index fcc50908..41d6e76d 100644 --- a/api/api/v1/accounts/:id/unmute.ts +++ b/api/api/v1/accounts/:id/unmute.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/:id/unpin.ts b/api/api/v1/accounts/:id/unpin.ts index 86beaf6a..5ad01ffe 100644 --- a/api/api/v1/accounts/:id/unpin.ts +++ b/api/api/v1/accounts/:id/unpin.ts @@ -38,7 +38,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/familiar_followers/index.ts b/api/api/v1/accounts/familiar_followers/index.ts index 44c08700..510ca003 100644 --- a/api/api/v1/accounts/familiar_followers/index.ts +++ b/api/api/v1/accounts/familiar_followers/index.ts @@ -36,7 +36,7 @@ export default apiRoute((app) => zValidator("query", schemas.query, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); const { id: ids } = context.req.valid("query"); if (!self) { diff --git a/api/api/v1/accounts/lookup/index.ts b/api/api/v1/accounts/lookup/index.ts index c8c68b9e..08d1051b 100644 --- a/api/api/v1/accounts/lookup/index.ts +++ b/api/api/v1/accounts/lookup/index.ts @@ -46,7 +46,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { acct } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!acct) { return context.json({ error: "Invalid acct parameter" }, 400); diff --git a/api/api/v1/accounts/relationships/index.ts b/api/api/v1/accounts/relationships/index.ts index d33c4d3f..0e39ab71 100644 --- a/api/api/v1/accounts/relationships/index.ts +++ b/api/api/v1/accounts/relationships/index.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => zValidator("query", schemas.query, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); const { id } = context.req.valid("query"); const ids = Array.isArray(id) ? id : [id]; diff --git a/api/api/v1/accounts/search/index.ts b/api/api/v1/accounts/search/index.ts index 9e23edd0..a6f3d22e 100644 --- a/api/api/v1/accounts/search/index.ts +++ b/api/api/v1/accounts/search/index.ts @@ -76,7 +76,7 @@ export default apiRoute((app) => async (context) => { const { q, limit, offset, resolve, following } = context.req.valid("query"); - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self && following) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/accounts/update_credentials/index.ts b/api/api/v1/accounts/update_credentials/index.ts index c99f2ffa..bcb1774f 100644 --- a/api/api/v1/accounts/update_credentials/index.ts +++ b/api/api/v1/accounts/update_credentials/index.ts @@ -133,7 +133,7 @@ export default apiRoute((app) => zValidator("json", schemas.json, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { display_name, username, diff --git a/api/api/v1/accounts/verify_credentials/index.ts b/api/api/v1/accounts/verify_credentials/index.ts index e0275a25..a3c67172 100644 --- a/api/api/v1/accounts/verify_credentials/index.ts +++ b/api/api/v1/accounts/verify_credentials/index.ts @@ -20,7 +20,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), (context) => { // TODO: Add checks for disabled/unverified accounts - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/apps/verify_credentials/index.ts b/api/api/v1/apps/verify_credentials/index.ts index bdcdf0a1..930d3186 100644 --- a/api/api/v1/apps/verify_credentials/index.ts +++ b/api/api/v1/apps/verify_credentials/index.ts @@ -23,7 +23,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user, token } = context.req.valid("header"); + const { user, token } = context.get("auth"); if (!token) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/blocks/index.ts b/api/api/v1/blocks/index.ts index 7965caeb..930055c1 100644 --- a/api/api/v1/blocks/index.ts +++ b/api/api/v1/blocks/index.ts @@ -46,7 +46,7 @@ export default apiRoute((app) => const { max_id, since_id, min_id, limit } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/custom_emojis/index.ts b/api/api/v1/custom_emojis/index.ts index ee1a8c60..1359e262 100644 --- a/api/api/v1/custom_emojis/index.ts +++ b/api/api/v1/custom_emojis/index.ts @@ -24,7 +24,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const emojis = await Emoji.manyFromSql( and( diff --git a/api/api/v1/emojis/:id/index.ts b/api/api/v1/emojis/:id/index.ts index ab5e2e99..5615410c 100644 --- a/api/api/v1/emojis/:id/index.ts +++ b/api/api/v1/emojis/:id/index.ts @@ -77,7 +77,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/emojis/index.ts b/api/api/v1/emojis/index.ts index a3b6efe3..13f6bfe9 100644 --- a/api/api/v1/emojis/index.ts +++ b/api/api/v1/emojis/index.ts @@ -69,7 +69,7 @@ export default apiRoute((app) => async (context) => { const { shortcode, element, alt, global, category } = context.req.valid("json"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/favourites/index.ts b/api/api/v1/favourites/index.ts index 2142ce37..86ffa5b8 100644 --- a/api/api/v1/favourites/index.ts +++ b/api/api/v1/favourites/index.ts @@ -45,7 +45,7 @@ export default apiRoute((app) => const { max_id, since_id, min_id, limit } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/follow_requests/:account_id/authorize.ts b/api/api/v1/follow_requests/:account_id/authorize.ts index b34230dd..6a89c5db 100644 --- a/api/api/v1/follow_requests/:account_id/authorize.ts +++ b/api/api/v1/follow_requests/:account_id/authorize.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => zValidator("param", schemas.param, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/follow_requests/:account_id/reject.ts b/api/api/v1/follow_requests/:account_id/reject.ts index cf484230..e675de4e 100644 --- a/api/api/v1/follow_requests/:account_id/reject.ts +++ b/api/api/v1/follow_requests/:account_id/reject.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => zValidator("param", schemas.param, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/follow_requests/index.ts b/api/api/v1/follow_requests/index.ts index d474d6ed..25d8ba49 100644 --- a/api/api/v1/follow_requests/index.ts +++ b/api/api/v1/follow_requests/index.ts @@ -45,7 +45,7 @@ export default apiRoute((app) => const { max_id, since_id, min_id, limit } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/markers/index.ts b/api/api/v1/markers/index.ts index 4c081aba..4791f3df 100644 --- a/api/api/v1/markers/index.ts +++ b/api/api/v1/markers/index.ts @@ -48,7 +48,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { "timeline[]": timelines } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const timeline = Array.isArray(timelines) ? timelines : []; diff --git a/api/api/v1/mutes/index.ts b/api/api/v1/mutes/index.ts index 0428e2ca..165d06c0 100644 --- a/api/api/v1/mutes/index.ts +++ b/api/api/v1/mutes/index.ts @@ -45,7 +45,7 @@ export default apiRoute((app) => async (context) => { const { max_id, since_id, limit, min_id } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/notifications/:id/dismiss.ts b/api/api/v1/notifications/:id/dismiss.ts index f422c6a3..ad2eb5fd 100644 --- a/api/api/v1/notifications/:id/dismiss.ts +++ b/api/api/v1/notifications/:id/dismiss.ts @@ -36,7 +36,7 @@ export default apiRoute((app) => async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); } diff --git a/api/api/v1/notifications/:id/index.ts b/api/api/v1/notifications/:id/index.ts index 59d60c7d..8a00d120 100644 --- a/api/api/v1/notifications/:id/index.ts +++ b/api/api/v1/notifications/:id/index.ts @@ -35,7 +35,7 @@ export default apiRoute((app) => async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); } diff --git a/api/api/v1/notifications/clear/index.ts b/api/api/v1/notifications/clear/index.ts index 8ea0b672..f61ca99c 100644 --- a/api/api/v1/notifications/clear/index.ts +++ b/api/api/v1/notifications/clear/index.ts @@ -25,7 +25,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); } diff --git a/api/api/v1/notifications/destroy_multiple/index.ts b/api/api/v1/notifications/destroy_multiple/index.ts index 50b666b1..8f6cc0e1 100644 --- a/api/api/v1/notifications/destroy_multiple/index.ts +++ b/api/api/v1/notifications/destroy_multiple/index.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => zValidator("query", schemas.query, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/notifications/index.ts b/api/api/v1/notifications/index.ts index d645bd4f..b9bf92ff 100644 --- a/api/api/v1/notifications/index.ts +++ b/api/api/v1/notifications/index.ts @@ -102,7 +102,7 @@ export default apiRoute((app) => zValidator("query", schemas.query, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); } diff --git a/api/api/v1/profile/avatar.ts b/api/api/v1/profile/avatar.ts index 6a4079c1..76e9b918 100644 --- a/api/api/v1/profile/avatar.ts +++ b/api/api/v1/profile/avatar.ts @@ -22,7 +22,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/profile/header.ts b/api/api/v1/profile/header.ts index ee51a91f..130d4f42 100644 --- a/api/api/v1/profile/header.ts +++ b/api/api/v1/profile/header.ts @@ -22,7 +22,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); if (!self) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/roles/:id/index.ts b/api/api/v1/roles/:id/index.ts index c09206ea..21cea149 100644 --- a/api/api/v1/roles/:id/index.ts +++ b/api/api/v1/roles/:id/index.ts @@ -36,7 +36,7 @@ export default apiRoute((app) => zValidator("param", schemas.param, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { id } = context.req.valid("param"); if (!user) { diff --git a/api/api/v1/roles/index.ts b/api/api/v1/roles/index.ts index 9ac88a73..87b7adad 100644 --- a/api/api/v1/roles/index.ts +++ b/api/api/v1/roles/index.ts @@ -19,7 +19,7 @@ export default apiRoute((app) => meta.route, auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/sso/:id/index.ts b/api/api/v1/sso/:id/index.ts index 51b9d031..304cedc9 100644 --- a/api/api/v1/sso/:id/index.ts +++ b/api/api/v1/sso/:id/index.ts @@ -41,7 +41,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id: issuerId } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/sso/index.ts b/api/api/v1/sso/index.ts index aad3e5f9..7b2a20c5 100644 --- a/api/api/v1/sso/index.ts +++ b/api/api/v1/sso/index.ts @@ -55,7 +55,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const form = context.req.valid("json"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/context.ts b/api/api/v1/statuses/:id/context.ts index f4ac9ca8..ed152c9c 100644 --- a/api/api/v1/statuses/:id/context.ts +++ b/api/api/v1/statuses/:id/context.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const foundStatus = await Note.fromId(id, user?.id); diff --git a/api/api/v1/statuses/:id/favourite.ts b/api/api/v1/statuses/:id/favourite.ts index 66b75678..4cec924d 100644 --- a/api/api/v1/statuses/:id/favourite.ts +++ b/api/api/v1/statuses/:id/favourite.ts @@ -36,7 +36,7 @@ export default apiRoute((app) => async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/favourited_by.ts b/api/api/v1/statuses/:id/favourited_by.ts index b53dd0ba..1dfb9abc 100644 --- a/api/api/v1/statuses/:id/favourited_by.ts +++ b/api/api/v1/statuses/:id/favourited_by.ts @@ -51,7 +51,7 @@ export default apiRoute((app) => context.req.valid("query"); const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/index.ts b/api/api/v1/statuses/:id/index.ts index baa6a551..4f55e443 100644 --- a/api/api/v1/statuses/:id/index.ts +++ b/api/api/v1/statuses/:id/index.ts @@ -105,7 +105,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); // TODO: Polls const { diff --git a/api/api/v1/statuses/:id/pin.ts b/api/api/v1/statuses/:id/pin.ts index dc817875..a5c31741 100644 --- a/api/api/v1/statuses/:id/pin.ts +++ b/api/api/v1/statuses/:id/pin.ts @@ -40,7 +40,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/reblog.ts b/api/api/v1/statuses/:id/reblog.ts index 5cfd6027..101459ea 100644 --- a/api/api/v1/statuses/:id/reblog.ts +++ b/api/api/v1/statuses/:id/reblog.ts @@ -41,7 +41,7 @@ export default apiRoute((app) => async (context) => { const { id } = context.req.valid("param"); const { visibility } = context.req.valid("json"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/reblogged_by.ts b/api/api/v1/statuses/:id/reblogged_by.ts index a837c5a2..b598af4e 100644 --- a/api/api/v1/statuses/:id/reblogged_by.ts +++ b/api/api/v1/statuses/:id/reblogged_by.ts @@ -44,7 +44,7 @@ export default apiRoute((app) => const { id } = context.req.valid("param"); const { max_id, min_id, since_id, limit } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/source.ts b/api/api/v1/statuses/:id/source.ts index 5c3a51d9..8a40ac74 100644 --- a/api/api/v1/statuses/:id/source.ts +++ b/api/api/v1/statuses/:id/source.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/unfavourite.ts b/api/api/v1/statuses/:id/unfavourite.ts index 21236fcf..5acc731b 100644 --- a/api/api/v1/statuses/:id/unfavourite.ts +++ b/api/api/v1/statuses/:id/unfavourite.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/unpin.ts b/api/api/v1/statuses/:id/unpin.ts index 252b8580..d62777c3 100644 --- a/api/api/v1/statuses/:id/unpin.ts +++ b/api/api/v1/statuses/:id/unpin.ts @@ -33,7 +33,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/:id/unreblog.ts b/api/api/v1/statuses/:id/unreblog.ts index 672518dc..d464392b 100644 --- a/api/api/v1/statuses/:id/unreblog.ts +++ b/api/api/v1/statuses/:id/unreblog.ts @@ -34,7 +34,7 @@ export default apiRoute((app) => auth(meta.auth, meta.permissions), async (context) => { const { id } = context.req.valid("param"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/statuses/index.ts b/api/api/v1/statuses/index.ts index 209479e2..af3eaa8c 100644 --- a/api/api/v1/statuses/index.ts +++ b/api/api/v1/statuses/index.ts @@ -108,7 +108,7 @@ export default apiRoute((app) => zValidator("json", schemas.json, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user, application } = context.req.valid("header"); + const { user, application } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/timelines/home.ts b/api/api/v1/timelines/home.ts index 32e0fcfb..661cd2a3 100644 --- a/api/api/v1/timelines/home.ts +++ b/api/api/v1/timelines/home.ts @@ -50,7 +50,7 @@ export default apiRoute((app) => const { max_id, since_id, min_id, limit } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v1/timelines/public.ts b/api/api/v1/timelines/public.ts index edfe49b5..f7de03aa 100644 --- a/api/api/v1/timelines/public.ts +++ b/api/api/v1/timelines/public.ts @@ -68,7 +68,7 @@ export default apiRoute((app) => only_media, } = context.req.valid("query"); - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { objects, link } = await Timeline.getNoteTimeline( and( diff --git a/api/api/v2/filters/:id/index.ts b/api/api/v2/filters/:id/index.ts index 4469f920..b68a2127 100644 --- a/api/api/v2/filters/:id/index.ts +++ b/api/api/v2/filters/:id/index.ts @@ -77,7 +77,7 @@ export default apiRoute((app) => zValidator("json", schemas.json, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); const { id } = context.req.valid("param"); if (!user) { diff --git a/api/api/v2/filters/index.ts b/api/api/v2/filters/index.ts index a51fa2a7..c062e988 100644 --- a/api/api/v2/filters/index.ts +++ b/api/api/v2/filters/index.ts @@ -65,7 +65,7 @@ export default apiRoute((app) => zValidator("json", schemas.json, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user } = context.req.valid("header"); + const { user } = context.get("auth"); if (!user) { return context.json({ error: "Unauthorized" }, 401); diff --git a/api/api/v2/search/index.ts b/api/api/v2/search/index.ts index e095b542..5e4329ca 100644 --- a/api/api/v2/search/index.ts +++ b/api/api/v2/search/index.ts @@ -57,7 +57,7 @@ export default apiRoute((app) => zValidator("query", schemas.query, handleZodError), auth(meta.auth, meta.permissions), async (context) => { - const { user: self } = context.req.valid("header"); + const { user: self } = context.get("auth"); const { q, type, resolve, following, account_id, limit, offset } = context.req.valid("query"); diff --git a/app.ts b/app.ts index f1d0696d..667fd9a1 100644 --- a/app.ts +++ b/app.ts @@ -12,12 +12,12 @@ import { boundaryCheck } from "./middlewares/boundary-check"; import { ipBans } from "./middlewares/ip-bans"; import { logger } from "./middlewares/logger"; import { routes } from "./routes"; -import type { ApiRouteExports } from "./types/api"; +import type { ApiRouteExports, HonoEnv } from "./types/api"; export const appFactory = async () => { const serverLogger = getLogger("server"); - const app = new OpenAPIHono({ + const app = new OpenAPIHono({ strict: false, }); diff --git a/packages/database-interface/relationship.ts b/packages/database-interface/relationship.ts index 6ec151c0..64bf9342 100644 --- a/packages/database-interface/relationship.ts +++ b/packages/database-interface/relationship.ts @@ -8,6 +8,7 @@ import { eq, inArray, } from "drizzle-orm"; +import { z } from "zod"; import { db } from "~/drizzle/db"; import { Relationships } from "~/drizzle/schema"; import { BaseInterface } from "./base"; @@ -25,6 +26,23 @@ export class Relationship extends BaseInterface< typeof Relationships, RelationshipWithOpposite > { + static schema = z.object({ + id: z.string(), + blocked_by: z.boolean(), + blocking: z.boolean(), + domain_blocking: z.boolean(), + endorsed: z.boolean(), + followed_by: z.boolean(), + following: z.boolean(), + muting_notifications: z.boolean(), + muting: z.boolean(), + note: z.string().nullable(), + notifying: z.boolean(), + requested_by: z.boolean(), + requested: z.boolean(), + showing_reblogs: z.boolean(), + }); + async reload(): Promise { const reloaded = await Relationship.fromId(this.data.id); diff --git a/types/api.ts b/types/api.ts index 04e49db2..1062a7c3 100644 --- a/types/api.ts +++ b/types/api.ts @@ -11,8 +11,10 @@ import type { Unfollow, User, } from "@versia/federation/types"; -import type { z } from "zod"; +import { z } from "zod"; +import type { Application } from "~/classes/functions/application"; import type { RolePermissions } from "~/drizzle/schema"; +import type { User as DatabaseUser } from "~/packages/database-interface/user"; export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS"; export interface ApiRouteMetadata { @@ -43,13 +45,27 @@ export interface ApiRouteMetadata { }; } +export const ErrorSchema = z.object({ + error: z.string(), +}); + +export type HonoEnv = { + Variables: { + auth: { + user: DatabaseUser | null; + token: string | null; + application: Application | null; + }; + }; +}; + export interface ApiRouteExports { meta: ApiRouteMetadata; schemas?: { query?: z.AnyZodObject; body?: z.AnyZodObject; }; - default: (app: OpenAPIHono) => RouterRoute; + default: (app: OpenAPIHono) => RouterRoute; } export type KnownEntity = diff --git a/utils/api.ts b/utils/api.ts index 0823603d..53491469 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -1,6 +1,5 @@ import type { Context } from "@hono/hono"; import { createMiddleware } from "@hono/hono/factory"; -import { validator } from "@hono/hono/validator"; import type { OpenAPIHono } from "@hono/zod-openapi"; import { getLogger } from "@logtape/logtape"; import { extractParams, verifySolution } from "altcha-lib"; @@ -29,7 +28,7 @@ import { db } from "~/drizzle/db"; import { Challenges } from "~/drizzle/schema"; import { config } from "~/packages/config-manager/index"; import type { User } from "~/packages/database-interface/user"; -import type { ApiRouteMetadata, HttpVerb } from "~/types/api"; +import type { ApiRouteMetadata, HonoEnv, HttpVerb } from "~/types/api"; export const applyConfig = (routeMeta: ApiRouteMetadata) => { const newMeta = routeMeta; @@ -45,13 +44,7 @@ export const applyConfig = (routeMeta: ApiRouteMetadata) => { return newMeta; }; -export const apiRoute = ( - fn: ( - app: OpenAPIHono /* <{ - Bindings: {}; - }> */, - ) => void, -) => fn; +export const apiRoute = (fn: (app: OpenAPIHono) => void) => fn; export const idValidator = createRegExp( anyOf(digit, charIn("ABCDEF")).times(8), @@ -151,12 +144,6 @@ export const handleZodError = ( } }; -const getAuth = async (value: Record) => { - return value.authorization - ? await getFromHeader(value.authorization) - : null; -}; - const checkPermissions = ( auth: AuthData | null, permissionData: ApiRouteMetadata["permissions"], @@ -300,8 +287,10 @@ export const auth = ( permissionData?: ApiRouteMetadata["permissions"], challengeData?: ApiRouteMetadata["challenge"], ) => - validator("header", async (value, context) => { - const auth = await getAuth(value); + createMiddleware(async (context, next) => { + const header = context.req.header("Authorization"); + + const auth = header ? await getFromHeader(header) : null; // Only exists for type casting, as otherwise weird errors happen with Hono const fakeResponse = context.json({}); @@ -328,13 +317,21 @@ export const auth = ( } } - return checkRouteNeedsAuth(auth, authData, context) as + const authCheck = checkRouteNeedsAuth(auth, authData, context) as | typeof fakeResponse | { user: User | null; token: string | null; application: Application | null; }; + + if (authCheck instanceof Response) { + return authCheck; + } + + context.set("auth", authCheck); + + await next(); }); // Helper function to parse form data diff --git a/utils/server.ts b/utils/server.ts index c6de74c2..6296f74f 100644 --- a/utils/server.ts +++ b/utils/server.ts @@ -1,7 +1,8 @@ import type { OpenAPIHono } from "@hono/zod-openapi"; import type { Config } from "~/packages/config-manager/config.type"; +import type { HonoEnv } from "~/types/api"; -export const createServer = (config: Config, app: OpenAPIHono) => +export const createServer = (config: Config, app: OpenAPIHono) => Bun.serve({ port: config.http.bind_port, reusePort: true,