mirror of
https://github.com/versia-pub/server.git
synced 2026-01-26 12:16:01 +01:00
refactor(api): 🚚 Refactor authentication middleware and implement some OpenAPI routes
This commit is contained in:
parent
edf5edca9f
commit
1ab1c68d36
|
|
@ -1,6 +1,6 @@
|
||||||
import { apiRoute, applyConfig, handleZodError } from "@/api";
|
import { apiRoute, applyConfig } from "@/api";
|
||||||
import { redirect } from "@/response";
|
import { redirect } from "@/response";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { createRoute } from "@hono/zod-openapi";
|
||||||
import { eq, or } from "drizzle-orm";
|
import { eq, or } from "drizzle-orm";
|
||||||
import { SignJWT } from "jose";
|
import { SignJWT } from "jose";
|
||||||
import { z } from "zod";
|
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 returnError = (query: object, error: string, description: string) => {
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
|
@ -81,116 +109,103 @@ const returnError = (query: object, error: string, description: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default apiRoute((app) =>
|
export default apiRoute((app) =>
|
||||||
app.on(
|
app.openapi(route, async (context) => {
|
||||||
meta.allowedMethods,
|
if (config.oidc.forced) {
|
||||||
meta.route,
|
return returnError(
|
||||||
zValidator("form", schemas.form, handleZodError),
|
context.req.query(),
|
||||||
zValidator("query", schemas.query, handleZodError),
|
"invalid_request",
|
||||||
async (context) => {
|
"Logging in with a password is disabled by the administrator. Please use a valid OpenID Connect provider.",
|
||||||
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()),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
const { identifier, password } = context.req.valid("form");
|
||||||
!(
|
const { client_id } = context.req.valid("query");
|
||||||
user &&
|
|
||||||
(await Bun.password.verify(
|
|
||||||
password,
|
|
||||||
user.data.password || "",
|
|
||||||
))
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return returnError(
|
|
||||||
context.req.query(),
|
|
||||||
"invalid_grant",
|
|
||||||
"Invalid identifier or password",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.data.passwordResetToken) {
|
// Find user
|
||||||
return redirect(
|
const user = await User.fromSql(
|
||||||
`${
|
or(
|
||||||
config.frontend.routes.password_reset
|
eq(Users.email, identifier.toLowerCase()),
|
||||||
}?${new URLSearchParams({
|
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 ?? "",
|
token: user.data.passwordResetToken ?? "",
|
||||||
login_reset: "true",
|
login_reset: "true",
|
||||||
}).toString()}`,
|
},
|
||||||
);
|
).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"],
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Generate JWT
|
// Try and import the key
|
||||||
const jwt = await new SignJWT({
|
const privateKey = await crypto.subtle.importKey(
|
||||||
sub: user.id,
|
"pkcs8",
|
||||||
iss: new URL(config.http.base_url).origin,
|
Buffer.from(config.oidc.jwt_key.split(";")[0], "base64"),
|
||||||
aud: client_id,
|
"Ed25519",
|
||||||
exp: Math.floor(Date.now() / 1000) + 60 * 60,
|
false,
|
||||||
iat: Math.floor(Date.now() / 1000),
|
["sign"],
|
||||||
nbf: Math.floor(Date.now() / 1000),
|
);
|
||||||
})
|
|
||||||
.setProtectedHeader({ alg: "EdDSA" })
|
|
||||||
.sign(privateKey);
|
|
||||||
|
|
||||||
const application = await db.query.Applications.findFirst({
|
// Generate JWT
|
||||||
where: (app, { eq }) => eq(app.clientId, client_id),
|
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) {
|
const application = await db.query.Applications.findFirst({
|
||||||
return context.json({ error: "Invalid application" }, 400);
|
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({
|
// Redirect to OAuth authorize with JWT
|
||||||
application: application.name,
|
return redirect(
|
||||||
});
|
`${config.frontend.routes.consent}?${searchParams.toString()}`,
|
||||||
|
302,
|
||||||
if (application.website) {
|
{
|
||||||
searchParams.append("website", application.website);
|
"Set-Cookie": `jwt=${jwt}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=${
|
||||||
}
|
60 * 60
|
||||||
|
}`,
|
||||||
// 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
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { apiRoute, applyConfig, handleZodError } from "@/api";
|
import { apiRoute, applyConfig } from "@/api";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { createRoute } from "@hono/zod-openapi";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "~/drizzle/db";
|
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
|
* OAuth Code flow
|
||||||
*/
|
*/
|
||||||
export default apiRoute((app) =>
|
export default apiRoute((app) =>
|
||||||
app.on(
|
app.openapi(route, async (context) => {
|
||||||
meta.allowedMethods,
|
const { redirect_uri, client_id, code } = context.req.valid("query");
|
||||||
meta.route,
|
|
||||||
zValidator("query", schemas.query, handleZodError),
|
|
||||||
async (context) => {
|
|
||||||
const { redirect_uri, client_id, code } =
|
|
||||||
context.req.valid("query");
|
|
||||||
|
|
||||||
const redirectToLogin = (error: string) =>
|
const redirectToLogin = (error: string) =>
|
||||||
Response.redirect(
|
Response.redirect(
|
||||||
`${config.frontend.routes.login}?${new URLSearchParams({
|
`${config.frontend.routes.login}?${new URLSearchParams({
|
||||||
...context.req.query,
|
...context.req.query,
|
||||||
error: encodeURIComponent(error),
|
error: encodeURIComponent(error),
|
||||||
}).toString()}`,
|
}).toString()}`,
|
||||||
302,
|
302,
|
||||||
);
|
);
|
||||||
|
|
||||||
const foundToken = await db
|
const foundToken = await db
|
||||||
.select()
|
.select()
|
||||||
.from(Tokens)
|
.from(Tokens)
|
||||||
.leftJoin(
|
.leftJoin(Applications, eq(Tokens.applicationId, Applications.id))
|
||||||
Applications,
|
.where(
|
||||||
eq(Tokens.applicationId, Applications.id),
|
and(
|
||||||
)
|
eq(Tokens.code, code),
|
||||||
.where(
|
eq(Applications.clientId, client_id),
|
||||||
and(
|
),
|
||||||
eq(Tokens.code, code),
|
)
|
||||||
eq(Applications.clientId, client_id),
|
.limit(1);
|
||||||
),
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!foundToken || foundToken.length <= 0) {
|
if (!foundToken || foundToken.length <= 0) {
|
||||||
return redirectToLogin("Invalid code");
|
return redirectToLogin("Invalid code");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect back to application
|
// Redirect back to application
|
||||||
return Response.redirect(`${redirect_uri}?code=${code}`, 302);
|
return Response.redirect(`${redirect_uri}?code=${code}`, 302);
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { apiRoute, applyConfig, handleZodError } from "@/api";
|
import { apiRoute, applyConfig } from "@/api";
|
||||||
import { response } from "@/response";
|
import { response } from "@/response";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { createRoute } from "@hono/zod-openapi";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Users } from "~/drizzle/schema";
|
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 returnError = (token: string, error: string, description: string) => {
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
|
@ -44,29 +68,22 @@ const returnError = (token: string, error: string, description: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default apiRoute((app) =>
|
export default apiRoute((app) =>
|
||||||
app.on(
|
app.openapi(route, async (context) => {
|
||||||
meta.allowedMethods,
|
const { token, password } = context.req.valid("form");
|
||||||
meta.route,
|
|
||||||
zValidator("form", schemas.form, handleZodError),
|
|
||||||
async (context) => {
|
|
||||||
const { token, password } = context.req.valid("form");
|
|
||||||
|
|
||||||
const user = await User.fromSql(
|
const user = await User.fromSql(eq(Users.passwordResetToken, token));
|
||||||
eq(Users.passwordResetToken, token),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return returnError(token, "invalid_token", "Invalid token");
|
return returnError(token, "invalid_token", "Invalid token");
|
||||||
}
|
}
|
||||||
|
|
||||||
await user.update({
|
await user.update({
|
||||||
password: await Bun.password.hash(password),
|
password: await Bun.password.hash(password),
|
||||||
passwordResetToken: null,
|
passwordResetToken: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
return response(null, 302, {
|
return response(null, 302, {
|
||||||
Location: `${config.frontend.routes.password_reset}?success=true`,
|
Location: `${config.frontend.routes.password_reset}?success=true`,
|
||||||
});
|
});
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { apiRoute, applyConfig, auth, handleZodError } from "@/api";
|
import { apiRoute, applyConfig, auth } from "@/api";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { createRoute } from "@hono/zod-openapi";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { RolePermissions } from "~/drizzle/schema";
|
import { RolePermissions } from "~/drizzle/schema";
|
||||||
import { Relationship } from "~/packages/database-interface/relationship";
|
import { Relationship } from "~/packages/database-interface/relationship";
|
||||||
import { User } from "~/packages/database-interface/user";
|
import { User } from "~/packages/database-interface/user";
|
||||||
|
import { ErrorSchema } from "~/types/api";
|
||||||
|
|
||||||
export const meta = applyConfig({
|
export const meta = applyConfig({
|
||||||
allowedMethods: ["POST"],
|
allowedMethods: ["POST"],
|
||||||
|
|
@ -30,38 +31,69 @@ export const schemas = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default apiRoute((app) =>
|
const route = createRoute({
|
||||||
app.on(
|
method: "post",
|
||||||
meta.allowedMethods,
|
path: "/api/v1/accounts/{id}/block",
|
||||||
meta.route,
|
summary: "Block user",
|
||||||
zValidator("param", schemas.param, handleZodError),
|
description: "Block a user",
|
||||||
auth(meta.auth, meta.permissions),
|
middleware: [auth(meta.auth, meta.permissions)],
|
||||||
async (context) => {
|
responses: {
|
||||||
const { id } = context.req.valid("param");
|
200: {
|
||||||
const { user } = context.req.valid("header");
|
description: "User blocked",
|
||||||
|
content: {
|
||||||
if (!user) {
|
"application/json": {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
schema: Relationship.schema,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
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());
|
|
||||||
},
|
},
|
||||||
),
|
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);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
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");
|
const { reblogs, notify, languages } = context.req.valid("json");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
const foundUser = await User.fromId(id);
|
const foundUser = await User.fromId(id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
// TODO: Add duration support
|
// TODO: Add duration support
|
||||||
const { notifications } = context.req.valid("json");
|
const { notifications } = context.req.valid("json");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
const { comment } = context.req.valid("json");
|
const { comment } = context.req.valid("json");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
const otherUser = await User.fromId(id);
|
const otherUser = await User.fromId(id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("query", schemas.query, handleZodError),
|
zValidator("query", schemas.query, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
const { id: ids } = context.req.valid("query");
|
const { id: ids } = context.req.valid("query");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { acct } = context.req.valid("query");
|
const { acct } = context.req.valid("query");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!acct) {
|
if (!acct) {
|
||||||
return context.json({ error: "Invalid acct parameter" }, 400);
|
return context.json({ error: "Invalid acct parameter" }, 400);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("query", schemas.query, handleZodError),
|
zValidator("query", schemas.query, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
const { id } = context.req.valid("query");
|
const { id } = context.req.valid("query");
|
||||||
|
|
||||||
const ids = Array.isArray(id) ? id : [id];
|
const ids = Array.isArray(id) ? id : [id];
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { q, limit, offset, resolve, following } =
|
const { q, limit, offset, resolve, following } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self && following) {
|
if (!self && following) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("json", schemas.json, handleZodError),
|
zValidator("json", schemas.json, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
const {
|
const {
|
||||||
display_name,
|
display_name,
|
||||||
username,
|
username,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
(context) => {
|
(context) => {
|
||||||
// TODO: Add checks for disabled/unverified accounts
|
// TODO: Add checks for disabled/unverified accounts
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user, token } = context.req.valid("header");
|
const { user, token } = context.get("auth");
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export default apiRoute((app) =>
|
||||||
const { max_id, since_id, min_id, limit } =
|
const { max_id, since_id, min_id, limit } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
const emojis = await Emoji.manyFromSql(
|
const emojis = await Emoji.manyFromSql(
|
||||||
and(
|
and(
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { shortcode, element, alt, global, category } =
|
const { shortcode, element, alt, global, category } =
|
||||||
context.req.valid("json");
|
context.req.valid("json");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ export default apiRoute((app) =>
|
||||||
const { max_id, since_id, min_id, limit } =
|
const { max_id, since_id, min_id, limit } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("param", schemas.param, handleZodError),
|
zValidator("param", schemas.param, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("param", schemas.param, handleZodError),
|
zValidator("param", schemas.param, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ export default apiRoute((app) =>
|
||||||
const { max_id, since_id, min_id, limit } =
|
const { max_id, since_id, min_id, limit } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { "timeline[]": timelines } = context.req.valid("query");
|
const { "timeline[]": timelines } = context.req.valid("query");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
const timeline = Array.isArray(timelines) ? timelines : [];
|
const timeline = Array.isArray(timelines) ? timelines : [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { max_id, since_id, limit, min_id } =
|
const { max_id, since_id, limit, min_id } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("query", schemas.query, handleZodError),
|
zValidator("query", schemas.query, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("query", schemas.query, handleZodError),
|
zValidator("query", schemas.query, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("param", schemas.param, handleZodError),
|
zValidator("param", schemas.param, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export default apiRoute((app) =>
|
||||||
meta.route,
|
meta.route,
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id: issuerId } = context.req.valid("param");
|
const { id: issuerId } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const form = context.req.valid("json");
|
const form = context.req.valid("json");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
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);
|
const foundStatus = await Note.fromId(id, user?.id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export default apiRoute((app) =>
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
// TODO: Polls
|
// TODO: Polls
|
||||||
const {
|
const {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { visibility } = context.req.valid("json");
|
const { visibility } = context.req.valid("json");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export default apiRoute((app) =>
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { max_id, min_id, since_id, limit } =
|
const { max_id, min_id, since_id, limit } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default apiRoute((app) =>
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("json", schemas.json, handleZodError),
|
zValidator("json", schemas.json, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user, application } = context.req.valid("header");
|
const { user, application } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export default apiRoute((app) =>
|
||||||
const { max_id, since_id, min_id, limit } =
|
const { max_id, since_id, min_id, limit } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export default apiRoute((app) =>
|
||||||
only_media,
|
only_media,
|
||||||
} = context.req.valid("query");
|
} = context.req.valid("query");
|
||||||
|
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
const { objects, link } = await Timeline.getNoteTimeline(
|
const { objects, link } = await Timeline.getNoteTimeline(
|
||||||
and(
|
and(
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("json", schemas.json, handleZodError),
|
zValidator("json", schemas.json, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
const { id } = context.req.valid("param");
|
const { id } = context.req.valid("param");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("json", schemas.json, handleZodError),
|
zValidator("json", schemas.json, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user } = context.req.valid("header");
|
const { user } = context.get("auth");
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default apiRoute((app) =>
|
||||||
zValidator("query", schemas.query, handleZodError),
|
zValidator("query", schemas.query, handleZodError),
|
||||||
auth(meta.auth, meta.permissions),
|
auth(meta.auth, meta.permissions),
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { user: self } = context.req.valid("header");
|
const { user: self } = context.get("auth");
|
||||||
const { q, type, resolve, following, account_id, limit, offset } =
|
const { q, type, resolve, following, account_id, limit, offset } =
|
||||||
context.req.valid("query");
|
context.req.valid("query");
|
||||||
|
|
||||||
|
|
|
||||||
4
app.ts
4
app.ts
|
|
@ -12,12 +12,12 @@ import { boundaryCheck } from "./middlewares/boundary-check";
|
||||||
import { ipBans } from "./middlewares/ip-bans";
|
import { ipBans } from "./middlewares/ip-bans";
|
||||||
import { logger } from "./middlewares/logger";
|
import { logger } from "./middlewares/logger";
|
||||||
import { routes } from "./routes";
|
import { routes } from "./routes";
|
||||||
import type { ApiRouteExports } from "./types/api";
|
import type { ApiRouteExports, HonoEnv } from "./types/api";
|
||||||
|
|
||||||
export const appFactory = async () => {
|
export const appFactory = async () => {
|
||||||
const serverLogger = getLogger("server");
|
const serverLogger = getLogger("server");
|
||||||
|
|
||||||
const app = new OpenAPIHono({
|
const app = new OpenAPIHono<HonoEnv>({
|
||||||
strict: false,
|
strict: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
eq,
|
eq,
|
||||||
inArray,
|
inArray,
|
||||||
} from "drizzle-orm";
|
} from "drizzle-orm";
|
||||||
|
import { z } from "zod";
|
||||||
import { db } from "~/drizzle/db";
|
import { db } from "~/drizzle/db";
|
||||||
import { Relationships } from "~/drizzle/schema";
|
import { Relationships } from "~/drizzle/schema";
|
||||||
import { BaseInterface } from "./base";
|
import { BaseInterface } from "./base";
|
||||||
|
|
@ -25,6 +26,23 @@ export class Relationship extends BaseInterface<
|
||||||
typeof Relationships,
|
typeof Relationships,
|
||||||
RelationshipWithOpposite
|
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<void> {
|
async reload(): Promise<void> {
|
||||||
const reloaded = await Relationship.fromId(this.data.id);
|
const reloaded = await Relationship.fromId(this.data.id);
|
||||||
|
|
||||||
|
|
|
||||||
20
types/api.ts
20
types/api.ts
|
|
@ -11,8 +11,10 @@ import type {
|
||||||
Unfollow,
|
Unfollow,
|
||||||
User,
|
User,
|
||||||
} from "@versia/federation/types";
|
} 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 { RolePermissions } from "~/drizzle/schema";
|
||||||
|
import type { User as DatabaseUser } from "~/packages/database-interface/user";
|
||||||
|
|
||||||
export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
||||||
export interface ApiRouteMetadata {
|
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 {
|
export interface ApiRouteExports {
|
||||||
meta: ApiRouteMetadata;
|
meta: ApiRouteMetadata;
|
||||||
schemas?: {
|
schemas?: {
|
||||||
query?: z.AnyZodObject;
|
query?: z.AnyZodObject;
|
||||||
body?: z.AnyZodObject;
|
body?: z.AnyZodObject;
|
||||||
};
|
};
|
||||||
default: (app: OpenAPIHono) => RouterRoute;
|
default: (app: OpenAPIHono<HonoEnv>) => RouterRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type KnownEntity =
|
export type KnownEntity =
|
||||||
|
|
|
||||||
33
utils/api.ts
33
utils/api.ts
|
|
@ -1,6 +1,5 @@
|
||||||
import type { Context } from "@hono/hono";
|
import type { Context } from "@hono/hono";
|
||||||
import { createMiddleware } from "@hono/hono/factory";
|
import { createMiddleware } from "@hono/hono/factory";
|
||||||
import { validator } from "@hono/hono/validator";
|
|
||||||
import type { OpenAPIHono } from "@hono/zod-openapi";
|
import type { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import { getLogger } from "@logtape/logtape";
|
import { getLogger } from "@logtape/logtape";
|
||||||
import { extractParams, verifySolution } from "altcha-lib";
|
import { extractParams, verifySolution } from "altcha-lib";
|
||||||
|
|
@ -29,7 +28,7 @@ import { db } from "~/drizzle/db";
|
||||||
import { Challenges } from "~/drizzle/schema";
|
import { Challenges } from "~/drizzle/schema";
|
||||||
import { config } from "~/packages/config-manager/index";
|
import { config } from "~/packages/config-manager/index";
|
||||||
import type { User } from "~/packages/database-interface/user";
|
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) => {
|
export const applyConfig = (routeMeta: ApiRouteMetadata) => {
|
||||||
const newMeta = routeMeta;
|
const newMeta = routeMeta;
|
||||||
|
|
@ -45,13 +44,7 @@ export const applyConfig = (routeMeta: ApiRouteMetadata) => {
|
||||||
return newMeta;
|
return newMeta;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiRoute = (
|
export const apiRoute = (fn: (app: OpenAPIHono<HonoEnv>) => void) => fn;
|
||||||
fn: (
|
|
||||||
app: OpenAPIHono /* <{
|
|
||||||
Bindings: {};
|
|
||||||
}> */,
|
|
||||||
) => void,
|
|
||||||
) => fn;
|
|
||||||
|
|
||||||
export const idValidator = createRegExp(
|
export const idValidator = createRegExp(
|
||||||
anyOf(digit, charIn("ABCDEF")).times(8),
|
anyOf(digit, charIn("ABCDEF")).times(8),
|
||||||
|
|
@ -151,12 +144,6 @@ export const handleZodError = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAuth = async (value: Record<string, string>) => {
|
|
||||||
return value.authorization
|
|
||||||
? await getFromHeader(value.authorization)
|
|
||||||
: null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkPermissions = (
|
const checkPermissions = (
|
||||||
auth: AuthData | null,
|
auth: AuthData | null,
|
||||||
permissionData: ApiRouteMetadata["permissions"],
|
permissionData: ApiRouteMetadata["permissions"],
|
||||||
|
|
@ -300,8 +287,10 @@ export const auth = (
|
||||||
permissionData?: ApiRouteMetadata["permissions"],
|
permissionData?: ApiRouteMetadata["permissions"],
|
||||||
challengeData?: ApiRouteMetadata["challenge"],
|
challengeData?: ApiRouteMetadata["challenge"],
|
||||||
) =>
|
) =>
|
||||||
validator("header", async (value, context) => {
|
createMiddleware<HonoEnv>(async (context, next) => {
|
||||||
const auth = await getAuth(value);
|
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
|
// Only exists for type casting, as otherwise weird errors happen with Hono
|
||||||
const fakeResponse = context.json({});
|
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
|
| typeof fakeResponse
|
||||||
| {
|
| {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
application: Application | null;
|
application: Application | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (authCheck instanceof Response) {
|
||||||
|
return authCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.set("auth", authCheck);
|
||||||
|
|
||||||
|
await next();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Helper function to parse form data
|
// Helper function to parse form data
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import type { OpenAPIHono } from "@hono/zod-openapi";
|
import type { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import type { Config } from "~/packages/config-manager/config.type";
|
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<HonoEnv>) =>
|
||||||
Bun.serve({
|
Bun.serve({
|
||||||
port: config.http.bind_port,
|
port: config.http.bind_port,
|
||||||
reusePort: true,
|
reusePort: true,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue