refactor(api): ♻️ Improve authentication checker API

This commit is contained in:
Jesse Wierzbinski 2024-12-30 19:18:31 +01:00
parent 621dd7e9d9
commit dc12b269f5
No known key found for this signature in database
76 changed files with 687 additions and 169 deletions

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/block", path: "/api/v1/accounts/{id}/block",
summary: "Block user", summary: "Block user",
description: "Block a user", description: "Block a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:blocks"],
permissions: [
RolePermissions.ManageOwnBlocks,
RolePermissions.ViewAccounts,
],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Updated relationship", description: "Updated relationship",

View file

@ -46,7 +46,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/follow", path: "/api/v1/accounts/{id}/follow",
summary: "Follow user", summary: "Follow user",
description: "Follow a user", description: "Follow a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:follows"],
permissions: [
RolePermissions.ManageOwnFollows,
RolePermissions.ViewAccounts,
],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Updated relationship", description: "Updated relationship",

View file

@ -43,7 +43,16 @@ const route = createRoute({
summary: "Get account followers", summary: "Get account followers",
description: description:
"Gets an paginated list of accounts that follow the specified account", "Gets an paginated list of accounts that follow the specified account",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
scopes: ["read:accounts"],
permissions: [
RolePermissions.ViewAccountFollows,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
query: schemas.query, query: schemas.query,

View file

@ -43,7 +43,16 @@ const route = createRoute({
summary: "Get account following", summary: "Get account following",
description: description:
"Gets an paginated list of accounts that the specified account follows", "Gets an paginated list of accounts that the specified account follows",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
scopes: ["read:accounts"],
permissions: [
RolePermissions.ViewAccountFollows,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
query: schemas.query, query: schemas.query,

View file

@ -32,7 +32,12 @@ const route = createRoute({
path: "/api/v1/accounts/{id}", path: "/api/v1/accounts/{id}",
summary: "Get account data", summary: "Get account data",
description: "Gets the specified account data", description: "Gets the specified account data",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.ViewAccounts],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -44,7 +44,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/mute", path: "/api/v1/accounts/{id}/mute",
summary: "Mute user", summary: "Mute user",
description: "Mute a user", description: "Mute a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:mutes"],
permissions: [
RolePermissions.ManageOwnMutes,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {
@ -90,10 +99,6 @@ export default apiRoute((app) =>
// TODO: Add duration support // TODO: Add duration support
const { notifications } = context.req.valid("json"); const { notifications } = context.req.valid("json");
if (!user) {
throw new ApiError(401, "Unauthorized");
}
const otherUser = await User.fromId(id); const otherUser = await User.fromId(id);
if (!otherUser) { if (!otherUser) {

View file

@ -38,7 +38,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/note", path: "/api/v1/accounts/{id}/note",
summary: "Set note", summary: "Set note",
description: "Set a note on a user's profile, visible only to you", description: "Set a note on a user's profile, visible only to you",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:accounts"],
permissions: [
RolePermissions.ManageOwnAccount,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/pin", path: "/api/v1/accounts/{id}/pin",
summary: "Pin user", summary: "Pin user",
description: "Pin a user to your profile", description: "Pin a user to your profile",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:accounts"],
permissions: [
RolePermissions.ManageOwnAccount,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -32,7 +32,13 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/refetch", path: "/api/v1/accounts/{id}/refetch",
summary: "Refetch user", summary: "Refetch user",
description: "Refetch a user's profile from the remote server", description: "Refetch a user's profile from the remote server",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:accounts"],
permissions: [RolePermissions.ViewAccounts],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/remove_from_followers", path: "/api/v1/accounts/{id}/remove_from_followers",
summary: "Remove user from followers", summary: "Remove user from followers",
description: "Remove a user from your followers", description: "Remove a user from your followers",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:follows"],
permissions: [
RolePermissions.ManageOwnFollows,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -35,7 +35,12 @@ const routePost = createRoute({
method: "post", method: "post",
path: "/api/v1/accounts/{id}/roles/{role_id}", path: "/api/v1/accounts/{id}/roles/{role_id}",
summary: "Assign role to user", summary: "Assign role to user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageRoles],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -74,7 +79,12 @@ const routeDelete = createRoute({
method: "delete", method: "delete",
path: "/api/v1/accounts/{id}/roles/{role_id}", path: "/api/v1/accounts/{id}/roles/{role_id}",
summary: "Remove role from user", summary: "Remove role from user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageRoles],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -29,7 +29,11 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/accounts/{id}/roles", path: "/api/v1/accounts/{id}/roles",
summary: "List user roles", summary: "List user roles",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -59,7 +59,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/statuses", path: "/api/v1/accounts/{id}/statuses",
summary: "Get account statuses", summary: "Get account statuses",
description: "Gets an paginated list of statuses by the specified account", description: "Gets an paginated list of statuses by the specified account",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [
RolePermissions.ViewNotes,
RolePermissions.ViewAccounts,
],
scopes: ["read:statuses"],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
query: schemas.query, query: schemas.query,

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/unblock", path: "/api/v1/accounts/{id}/unblock",
summary: "Unblock user", summary: "Unblock user",
description: "Unblock a user", description: "Unblock a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:blocks"],
permissions: [
RolePermissions.ManageOwnBlocks,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/unfollow", path: "/api/v1/accounts/{id}/unfollow",
summary: "Unfollow user", summary: "Unfollow user",
description: "Unfollow a user", description: "Unfollow a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:follows"],
permissions: [
RolePermissions.ManageOwnFollows,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/unmute", path: "/api/v1/accounts/{id}/unmute",
summary: "Unmute user", summary: "Unmute user",
description: "Unmute a user", description: "Unmute a user",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:mutes"],
permissions: [
RolePermissions.ManageOwnMutes,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -35,7 +35,16 @@ const route = createRoute({
path: "/api/v1/accounts/{id}/unpin", path: "/api/v1/accounts/{id}/unpin",
summary: "Unpin user", summary: "Unpin user",
description: "Unpin a user from your profile", description: "Unpin a user from your profile",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:accounts"],
permissions: [
RolePermissions.ManageOwnAccount,
RolePermissions.ViewAccounts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -39,7 +39,14 @@ const route = createRoute({
summary: "Get familiar followers", summary: "Get familiar followers",
description: description:
"Obtain a list of all accounts that follow a given account, filtered for accounts you follow.", "Obtain a list of all accounts that follow a given account, filtered for accounts you follow.",
middleware: [auth(meta.auth, meta.permissions), qsQuery()] as const, middleware: [
auth({
auth: true,
scopes: ["read:follows"],
permissions: [RolePermissions.ManageOwnFollows],
}),
qsQuery(),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -33,7 +33,12 @@ const route = createRoute({
path: "/api/v1/accounts/id", path: "/api/v1/accounts/id",
summary: "Get account by username", summary: "Get account by username",
description: "Get an account by username", description: "Get an account by username",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.Search],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -44,7 +44,11 @@ const route = createRoute({
summary: "Create account", summary: "Create account",
description: "Register a new account", description: "Register a new account",
middleware: [ middleware: [
auth(meta.auth, meta.permissions, meta.challenge), auth({
auth: false,
scopes: ["write:accounts"],
challenge: true,
}),
jsonOrForm(), jsonOrForm(),
], ],
request: { request: {

View file

@ -34,7 +34,12 @@ const route = createRoute({
path: "/api/v1/accounts/lookup", path: "/api/v1/accounts/lookup",
summary: "Lookup account", summary: "Lookup account",
description: "Lookup an account by acct", description: "Lookup an account by acct",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.Search],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -32,7 +32,14 @@ const route = createRoute({
path: "/api/v1/accounts/relationships", path: "/api/v1/accounts/relationships",
summary: "Get relationships", summary: "Get relationships",
description: "Get relationships by account ID", description: "Get relationships by account ID",
middleware: [auth(meta.auth, meta.permissions), qsQuery()] as const, middleware: [
auth({
auth: true,
scopes: ["read:follows"],
permissions: [RolePermissions.ManageOwnFollows],
}),
qsQuery(),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -50,7 +50,13 @@ export const route = createRoute({
path: "/api/v1/accounts/search", path: "/api/v1/accounts/search",
summary: "Search accounts", summary: "Search accounts",
description: "Search for accounts", description: "Search for accounts",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.Search, RolePermissions.ViewAccounts],
scopes: ["read:accounts"],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -151,7 +151,14 @@ const route = createRoute({
path: "/api/v1/accounts/update_credentials", path: "/api/v1/accounts/update_credentials",
summary: "Update credentials", summary: "Update credentials",
description: "Update user credentials", description: "Update user credentials",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnAccount],
scopes: ["write:accounts"],
}),
jsonOrForm(),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -21,7 +21,12 @@ const route = createRoute({
path: "/api/v1/accounts/verify_credentials", path: "/api/v1/accounts/verify_credentials",
summary: "Verify credentials", summary: "Verify credentials",
description: "Get your own account information", description: "Get your own account information",
middleware: [auth(meta.auth)] as const, middleware: [
auth({
auth: true,
scopes: ["read:accounts"],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Account", description: "Account",

View file

@ -24,7 +24,12 @@ const route = createRoute({
path: "/api/v1/apps/verify_credentials", path: "/api/v1/apps/verify_credentials",
summary: "Verify credentials", summary: "Verify credentials",
description: "Get your own application information", description: "Get your own application information",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnApps],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Application", description: "Application",

View file

@ -36,7 +36,13 @@ const route = createRoute({
path: "/api/v1/blocks", path: "/api/v1/blocks",
summary: "Get blocks", summary: "Get blocks",
description: "Get users you have blocked", description: "Get users you have blocked",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["read:blocks"],
permissions: [RolePermissions.ManageOwnBlocks],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -24,7 +24,11 @@ const route = createRoute({
path: "/api/v1/challenges", path: "/api/v1/challenges",
summary: "Generate a challenge", summary: "Generate a challenge",
description: "Generate a challenge to solve", description: "Generate a challenge to solve",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Challenge", description: "Challenge",

View file

@ -23,7 +23,12 @@ const route = createRoute({
path: "/api/v1/custom_emojis", path: "/api/v1/custom_emojis",
summary: "Get custom emojis", summary: "Get custom emojis",
description: "Get custom emojis", description: "Get custom emojis",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.ViewEmojis],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Emojis", description: "Emojis",

View file

@ -71,7 +71,12 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/emojis/{id}", path: "/api/v1/emojis/{id}",
summary: "Get emoji data", summary: "Get emoji data",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ViewEmojis],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -92,14 +97,6 @@ const routeGet = createRoute({
}, },
}, },
}, },
403: {
description: "Insufficient credentials",
content: {
"application/json": {
schema: ErrorSchema,
},
},
},
404: { 404: {
description: "Emoji not found", description: "Emoji not found",
content: { content: {
@ -115,7 +112,16 @@ const routePatch = createRoute({
method: "patch", method: "patch",
path: "/api/v1/emojis/{id}", path: "/api/v1/emojis/{id}",
summary: "Modify emoji", summary: "Modify emoji",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnEmojis,
RolePermissions.ViewEmojis,
],
}),
jsonOrForm(),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {
@ -180,7 +186,15 @@ const routeDelete = createRoute({
method: "delete", method: "delete",
path: "/api/v1/emojis/{id}", path: "/api/v1/emojis/{id}",
summary: "Delete emoji", summary: "Delete emoji",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnEmojis,
RolePermissions.ViewEmojis,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -222,16 +236,12 @@ export default apiRoute((app) => {
throw new ApiError(404, "Emoji not found"); throw new ApiError(404, "Emoji not found");
} }
// Check if user is admin // Don't leak non-global emojis to non-admins
if ( if (
!user.hasPermission(RolePermissions.ManageEmojis) && !user.hasPermission(RolePermissions.ManageEmojis) &&
emoji.data.ownerId !== user.data.id emoji.data.ownerId !== user.data.id
) { ) {
throw new ApiError( throw new ApiError(404, "Emoji not found");
403,
"Cannot modify emoji not owned by you",
`This emoji is either global (and you do not have the '${RolePermissions.ManageEmojis}' permission) or not owned by you`,
);
} }
return context.json(emoji.toApi(), 200); return context.json(emoji.toApi(), 200);

View file

@ -67,7 +67,16 @@ const route = createRoute({
path: "/api/v1/emojis", path: "/api/v1/emojis",
summary: "Upload emoji", summary: "Upload emoji",
description: "Upload an emoji", description: "Upload an emoji",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnEmojis,
RolePermissions.ViewEmojis,
],
}),
jsonOrForm(),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -34,7 +34,12 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/favourites", path: "/api/v1/favourites",
summary: "Get favourites", summary: "Get favourites",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnLikes],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -30,7 +30,12 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/follow_requests/{account_id}/authorize", path: "/api/v1/follow_requests/{account_id}/authorize",
summary: "Authorize follow request", summary: "Authorize follow request",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFollows],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -30,7 +30,12 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/follow_requests/{account_id}/reject", path: "/api/v1/follow_requests/{account_id}/reject",
summary: "Reject follow request", summary: "Reject follow request",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFollows],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -34,7 +34,12 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/follow_requests", path: "/api/v1/follow_requests",
summary: "Get follow requests", summary: "Get follow requests",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFollows],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -22,7 +22,11 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/instance", path: "/api/v1/instance",
summary: "Get instance information", summary: "Get instance information",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: false,
}),
],
responses: { responses: {
200: { 200: {
description: "Instance information", description: "Instance information",

View file

@ -18,7 +18,11 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/instance/privacy_policy", path: "/api/v1/instance/privacy_policy",
summary: "Get instance privacy policy", summary: "Get instance privacy policy",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: false,
}),
],
responses: { responses: {
200: { 200: {
description: "Instance privacy policy", description: "Instance privacy policy",

View file

@ -17,7 +17,11 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/instance/rules", path: "/api/v1/instance/rules",
summary: "Get instance rules", summary: "Get instance rules",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: false,
}),
],
responses: { responses: {
200: { 200: {
description: "Instance rules", description: "Instance rules",

View file

@ -18,7 +18,11 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/instance/tos", path: "/api/v1/instance/tos",
summary: "Get instance terms of service", summary: "Get instance terms of service",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: false,
}),
],
responses: { responses: {
200: { 200: {
description: "Instance terms of service", description: "Instance terms of service",

View file

@ -48,7 +48,12 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/markers", path: "/api/v1/markers",
summary: "Get markers", summary: "Get markers",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnAccount],
}),
] as const,
request: { request: {
query: z.object({ query: z.object({
"timeline[]": z "timeline[]": z
@ -82,7 +87,12 @@ const routePost = createRoute({
method: "post", method: "post",
path: "/api/v1/markers", path: "/api/v1/markers",
summary: "Update markers", summary: "Update markers",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnAccount],
}),
] as const,
request: { request: {
query: z.object({ query: z.object({
"home[last_read_id]": z.string().regex(idValidator).optional(), "home[last_read_id]": z.string().regex(idValidator).optional(),

View file

@ -41,7 +41,13 @@ const routePut = createRoute({
method: "put", method: "put",
path: "/api/v1/media/{id}", path: "/api/v1/media/{id}",
summary: "Update media", summary: "Update media",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:media"],
permissions: [RolePermissions.ManageOwnMedia],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {
@ -84,7 +90,12 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/media/{id}", path: "/api/v1/media/{id}",
summary: "Get media", summary: "Get media",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnMedia],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -40,7 +40,13 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/media", path: "/api/v1/media",
summary: "Upload media", summary: "Upload media",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:media"],
permissions: [RolePermissions.ManageOwnMedia],
}),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -35,7 +35,13 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/mutes", path: "/api/v1/mutes",
summary: "Get muted users", summary: "Get muted users",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["read:mutes"],
permissions: [RolePermissions.ManageOwnMutes],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -31,7 +31,13 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/notifications/{id}/dismiss", path: "/api/v1/notifications/{id}/dismiss",
summary: "Dismiss notification", summary: "Dismiss notification",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:notifications"],
permissions: [RolePermissions.ManageOwnNotifications],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -31,15 +31,25 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/notifications/{id}", path: "/api/v1/notifications/{id}",
summary: "Get notification", summary: "Get notification",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnNotifications],
scopes: ["read:notifications"],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
responses: { responses: {
200: { 200: {
description: "Notification", description: "Notification",
content: {
"application/json": {
schema: Notification.schema, schema: Notification.schema,
}, },
},
},
401: { 401: {
description: "Unauthorized", description: "Unauthorized",
content: { content: {

View file

@ -23,7 +23,13 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/notifications/clear", path: "/api/v1/notifications/clear",
summary: "Clear notifications", summary: "Clear notifications",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnNotifications],
scopes: ["write:notifications"],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "Notifications cleared", description: "Notifications cleared",

View file

@ -30,7 +30,13 @@ const route = createRoute({
method: "delete", method: "delete",
path: "/api/v1/notifications/destroy_multiple", path: "/api/v1/notifications/destroy_multiple",
summary: "Dismiss multiple notifications", summary: "Dismiss multiple notifications",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnNotifications],
scopes: ["write:notifications"],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -20,7 +20,7 @@ export const meta = applyConfig({
permissions: { permissions: {
required: [ required: [
RolePermissions.ManageOwnNotifications, RolePermissions.ManageOwnNotifications,
RolePermissions.ViewPrimateTimelines, RolePermissions.ViewPrivateTimelines,
], ],
}, },
}); });
@ -94,7 +94,15 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/notifications", path: "/api/v1/notifications",
summary: "Get notifications", summary: "Get notifications",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotifications,
RolePermissions.ViewPrivateTimelines,
],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -23,7 +23,13 @@ const route = createRoute({
method: "delete", method: "delete",
path: "/api/v1/profile/avatar", path: "/api/v1/profile/avatar",
summary: "Delete avatar", summary: "Delete avatar",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnAccount],
scopes: ["write:account"],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "User", description: "User",

View file

@ -23,7 +23,13 @@ const route = createRoute({
method: "delete", method: "delete",
path: "/api/v1/profile/header", path: "/api/v1/profile/header",
summary: "Delete header", summary: "Delete header",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnAccount],
scopes: ["write:account"],
}),
] as const,
responses: { responses: {
200: { 200: {
description: "User", description: "User",

View file

@ -34,7 +34,11 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/roles/{id}", path: "/api/v1/roles/{id}",
summary: "Get role data", summary: "Get role data",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: true,
}),
],
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -70,7 +74,12 @@ const routePatch = createRoute({
method: "patch", method: "patch",
path: "/api/v1/roles/{id}", path: "/api/v1/roles/{id}",
summary: "Update role data", summary: "Update role data",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageRoles],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {
@ -116,7 +125,12 @@ const routeDelete = createRoute({
method: "delete", method: "delete",
path: "/api/v1/roles/{id}", path: "/api/v1/roles/{id}",
summary: "Delete role", summary: "Delete role",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageRoles],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -29,7 +29,11 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/roles", path: "/api/v1/roles",
summary: "Get all roles", summary: "Get all roles",
middleware: [auth(meta.auth)], middleware: [
auth({
auth: true,
}),
] as const,
responses: { responses: {
200: { 200: {
description: "List of all roles", description: "List of all roles",
@ -54,7 +58,12 @@ const routePost = createRoute({
method: "post", method: "post",
path: "/api/v1/roles", path: "/api/v1/roles",
summary: "Create a new role", summary: "Create a new role",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageRoles],
}),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -29,7 +29,12 @@ export const schemas = {
const route = createRoute({ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/statuses/{id}/context", path: "/api/v1/statuses/{id}/context",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.ViewNotes],
}),
] as const,
summary: "Get status context", summary: "Get status context",
request: { request: {
params: schemas.param, params: schemas.param,

View file

@ -30,7 +30,15 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/favourite", path: "/api/v1/statuses/{id}/favourite",
summary: "Favourite a status", summary: "Favourite a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnLikes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -37,7 +37,15 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/statuses/{id}/favourited_by", path: "/api/v1/statuses/{id}/favourited_by",
summary: "Get users who favourited a status", summary: "Get users who favourited a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ViewNotes,
RolePermissions.ViewNoteLikes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
query: schemas.query, query: schemas.query,

View file

@ -92,7 +92,12 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v1/statuses/{id}", path: "/api/v1/statuses/{id}",
summary: "Get status", summary: "Get status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [RolePermissions.ViewNotes],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -120,7 +125,15 @@ const routeDelete = createRoute({
method: "delete", method: "delete",
path: "/api/v1/statuses/{id}", path: "/api/v1/statuses/{id}",
summary: "Delete a status", summary: "Delete a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -156,7 +169,16 @@ const routePut = createRoute({
method: "put", method: "put",
path: "/api/v1/statuses/{id}", path: "/api/v1/statuses/{id}",
summary: "Update a status", summary: "Update a status",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
jsonOrForm(),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {

View file

@ -31,7 +31,15 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/pin", path: "/api/v1/statuses/{id}/pin",
summary: "Pin a status", summary: "Pin a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -34,7 +34,16 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/reblog", path: "/api/v1/statuses/{id}/reblog",
summary: "Reblog a status", summary: "Reblog a status",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnBoosts,
RolePermissions.ViewNotes,
],
}),
jsonOrForm(),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {

View file

@ -37,7 +37,15 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/statuses/{id}/reblogged_by", path: "/api/v1/statuses/{id}/reblogged_by",
summary: "Get users who reblogged a status", summary: "Get users who reblogged a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ViewNotes,
RolePermissions.ViewNoteBoosts,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
query: schemas.query, query: schemas.query,

View file

@ -31,7 +31,15 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/statuses/{id}/source", path: "/api/v1/statuses/{id}/source",
summary: "Get status source", summary: "Get status source",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -30,7 +30,15 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/unfavourite", path: "/api/v1/statuses/{id}/unfavourite",
summary: "Unfavourite a status", summary: "Unfavourite a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -30,7 +30,15 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/unpin", path: "/api/v1/statuses/{id}/unpin",
summary: "Unpin a status", summary: "Unpin a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -31,7 +31,15 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses/{id}/unreblog", path: "/api/v1/statuses/{id}/unreblog",
summary: "Unreblog a status", summary: "Unreblog a status",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -103,7 +103,13 @@ export const schemas = {
const route = createRoute({ const route = createRoute({
method: "post", method: "post",
path: "/api/v1/statuses", path: "/api/v1/statuses",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnNotes],
}),
jsonOrForm(),
] as const,
summary: "Post a new status", summary: "Post a new status",
request: { request: {
body: { body: {

View file

@ -21,7 +21,7 @@ export const meta = applyConfig({
RolePermissions.ManageOwnNotes, RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes, RolePermissions.ViewNotes,
RolePermissions.ViewAccounts, RolePermissions.ViewAccounts,
RolePermissions.ViewPrimateTimelines, RolePermissions.ViewPrivateTimelines,
], ],
}, },
}); });
@ -39,7 +39,17 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/timelines/home", path: "/api/v1/timelines/home",
summary: "Get home timeline", summary: "Get home timeline",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [
RolePermissions.ManageOwnNotes,
RolePermissions.ViewNotes,
RolePermissions.ViewAccounts,
RolePermissions.ViewPrivateTimelines,
],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -49,7 +49,16 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v1/timelines/public", path: "/api/v1/timelines/public",
summary: "Get public timeline", summary: "Get public timeline",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
permissions: [
RolePermissions.ViewNotes,
RolePermissions.ViewAccounts,
RolePermissions.ViewPublicTimelines,
],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -89,7 +89,12 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v2/filters/{id}", path: "/api/v2/filters/{id}",
summary: "Get filter", summary: "Get filter",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFilters],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },
@ -125,7 +130,13 @@ const routePut = createRoute({
method: "put", method: "put",
path: "/api/v2/filters/{id}", path: "/api/v2/filters/{id}",
summary: "Update filter", summary: "Update filter",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFilters],
}),
jsonOrForm(),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
body: { body: {
@ -168,7 +179,12 @@ const routeDelete = createRoute({
method: "delete", method: "delete",
path: "/api/v2/filters/{id}", path: "/api/v2/filters/{id}",
summary: "Delete filter", summary: "Delete filter",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFilters],
}),
] as const,
request: { request: {
params: schemas.param, params: schemas.param,
}, },

View file

@ -77,7 +77,13 @@ const routeGet = createRoute({
method: "get", method: "get",
path: "/api/v2/filters", path: "/api/v2/filters",
summary: "Get filters", summary: "Get filters",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFilters],
}),
jsonOrForm(),
] as const,
responses: { responses: {
200: { 200: {
description: "Filters", description: "Filters",
@ -102,7 +108,13 @@ const routePost = createRoute({
method: "post", method: "post",
path: "/api/v2/filters", path: "/api/v2/filters",
summary: "Create filter", summary: "Create filter",
middleware: [auth(meta.auth, meta.permissions), jsonOrForm()] as const, middleware: [
auth({
auth: true,
permissions: [RolePermissions.ManageOwnFilters],
}),
jsonOrForm(),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -40,7 +40,13 @@ const route = createRoute({
method: "post", method: "post",
path: "/api/v2/media", path: "/api/v2/media",
summary: "Upload media", summary: "Upload media",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: true,
scopes: ["write:media"],
permissions: [RolePermissions.ManageOwnMedia],
}),
] as const,
request: { request: {
body: { body: {
content: { content: {

View file

@ -52,7 +52,17 @@ const route = createRoute({
method: "get", method: "get",
path: "/api/v2/search", path: "/api/v2/search",
summary: "Instance database search", summary: "Instance database search",
middleware: [auth(meta.auth, meta.permissions)] as const, middleware: [
auth({
auth: false,
scopes: ["read:search"],
permissions: [
RolePermissions.Search,
RolePermissions.ViewAccounts,
RolePermissions.ViewNotes,
],
}),
] as const,
request: { request: {
query: schemas.query, query: schemas.query,
}, },

View file

@ -549,7 +549,7 @@ export enum RolePermissions {
ManageOwnApps = "owner:app", ManageOwnApps = "owner:app",
Search = "search", Search = "search",
ViewPublicTimelines = "public_timelines", ViewPublicTimelines = "public_timelines",
ViewPrimateTimelines = "private_timelines", ViewPrivateTimelines = "private_timelines",
IgnoreRateLimits = "ignore_rate_limits", IgnoreRateLimits = "ignore_rate_limits",
Impersonate = "impersonate", Impersonate = "impersonate",
ManageInstance = "instance", ManageInstance = "instance",
@ -584,7 +584,7 @@ export const DEFAULT_ROLES = [
RolePermissions.ManageOwnApps, RolePermissions.ManageOwnApps,
RolePermissions.Search, RolePermissions.Search,
RolePermissions.ViewPublicTimelines, RolePermissions.ViewPublicTimelines,
RolePermissions.ViewPrimateTimelines, RolePermissions.ViewPrivateTimelines,
RolePermissions.OAuth, RolePermissions.OAuth,
]; ];

View file

@ -71,7 +71,7 @@ export default (plugin: PluginType): void =>
path: "/oauth/authorize", path: "/oauth/authorize",
middleware: [ middleware: [
auth({ auth({
required: false, auth: false,
}), }),
jsonOrForm(), jsonOrForm(),
plugin.middleware, plugin.middleware,

View file

@ -34,7 +34,7 @@ export default (plugin: PluginType): void => {
}, },
middleware: [ middleware: [
auth({ auth({
required: false, auth: false,
}), }),
plugin.middleware, plugin.middleware,
] as const, ] as const,

View file

@ -16,14 +16,10 @@ export default (plugin: PluginType): void => {
path: "/api/v1/sso/{id}", path: "/api/v1/sso/{id}",
summary: "Get linked account", summary: "Get linked account",
middleware: [ middleware: [
auth( auth({
{ auth: true,
required: true, permissions: [RolePermissions.OAuth],
}, }),
{
required: [RolePermissions.OAuth],
},
),
plugin.middleware, plugin.middleware,
] as const, ] as const,
request: { request: {
@ -115,14 +111,10 @@ export default (plugin: PluginType): void => {
path: "/api/v1/sso/{id}", path: "/api/v1/sso/{id}",
summary: "Unlink account", summary: "Unlink account",
middleware: [ middleware: [
auth( auth({
{ auth: true,
required: true, permissions: [RolePermissions.OAuth],
}, }),
{
required: [RolePermissions.OAuth],
},
),
plugin.middleware, plugin.middleware,
] as const, ] as const,
request: { request: {

View file

@ -19,14 +19,10 @@ export default (plugin: PluginType): void => {
path: "/api/v1/sso", path: "/api/v1/sso",
summary: "Get linked accounts", summary: "Get linked accounts",
middleware: [ middleware: [
auth( auth({
{ auth: true,
required: true, permissions: [RolePermissions.OAuth],
}, }),
{
required: [RolePermissions.OAuth],
},
),
plugin.middleware, plugin.middleware,
] as const, ] as const,
responses: { responses: {
@ -82,14 +78,10 @@ export default (plugin: PluginType): void => {
path: "/api/v1/sso", path: "/api/v1/sso",
summary: "Link account", summary: "Link account",
middleware: [ middleware: [
auth( auth({
{ auth: true,
required: true, permissions: [RolePermissions.OAuth],
}, }),
{
required: [RolePermissions.OAuth],
},
),
plugin.middleware, plugin.middleware,
] as const, ] as const,
request: { request: {

View file

@ -1,7 +1,7 @@
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 { Application, Token, db } from "@versia/kit/db"; import { Application, Token, db } from "@versia/kit/db";
import { Challenges } from "@versia/kit/tables"; import { Challenges, type RolePermissions } from "@versia/kit/tables";
import { extractParams, verifySolution } from "altcha-lib"; import { extractParams, verifySolution } from "altcha-lib";
import chalk from "chalk"; import chalk from "chalk";
import { type SQL, eq } from "drizzle-orm"; import { type SQL, eq } from "drizzle-orm";
@ -27,7 +27,7 @@ import { fromZodError } from "zod-validation-error";
import { ApiError } from "~/classes/errors/api-error"; import { ApiError } from "~/classes/errors/api-error";
import type { AuthData } from "~/classes/functions/user"; import type { AuthData } from "~/classes/functions/user";
import { config } from "~/packages/config-manager/index.ts"; import { config } from "~/packages/config-manager/index.ts";
import type { ApiRouteMetadata, HonoEnv, HttpVerb } from "~/types/api"; import type { ApiRouteMetadata, HonoEnv } from "~/types/api";
export const applyConfig = (routeMeta: ApiRouteMetadata): ApiRouteMetadata => { export const applyConfig = (routeMeta: ApiRouteMetadata): ApiRouteMetadata => {
const newMeta = routeMeta; const newMeta = routeMeta;
@ -161,19 +161,14 @@ export const handleZodError = (
const checkPermissions = ( const checkPermissions = (
auth: AuthData | null, auth: AuthData | null,
permissionData: ApiRouteMetadata["permissions"], required: RolePermissions[],
context: Context,
): void => { ): void => {
const userPerms = auth?.user const userPerms = auth?.user
? auth.user.getAllPermissions() ? auth.user.getAllPermissions()
: config.permissions.anonymous; : config.permissions.anonymous;
const requiredPerms =
permissionData?.methodOverrides?.[context.req.method as HttpVerb] ??
permissionData?.required ??
[];
if (!requiredPerms.every((perm) => userPerms.includes(perm))) { if (!required.every((perm) => userPerms.includes(perm))) {
const missingPerms = requiredPerms.filter( const missingPerms = required.filter(
(perm) => !userPerms.includes(perm), (perm) => !userPerms.includes(perm),
); );
throw new ApiError( throw new ApiError(
@ -186,8 +181,7 @@ const checkPermissions = (
const checkRouteNeedsAuth = ( const checkRouteNeedsAuth = (
auth: AuthData | null, auth: AuthData | null,
authData: ApiRouteMetadata["auth"], required: boolean,
context: Context,
): AuthData => { ): AuthData => {
if (auth?.user && auth?.token) { if (auth?.user && auth?.token) {
return { return {
@ -196,10 +190,7 @@ const checkRouteNeedsAuth = (
application: auth.application, application: auth.application,
}; };
} }
if ( if (required) {
authData.required ||
authData.methodOverrides?.[context.req.method as HttpVerb]
) {
throw new ApiError(401, "This route requires authentication"); throw new ApiError(401, "This route requires authentication");
} }
@ -211,10 +202,10 @@ const checkRouteNeedsAuth = (
}; };
export const checkRouteNeedsChallenge = async ( export const checkRouteNeedsChallenge = async (
challengeData: ApiRouteMetadata["challenge"], required: boolean,
context: Context, context: Context,
): Promise<void> => { ): Promise<void> => {
if (!challengeData) { if (!required) {
return; return;
} }
@ -265,12 +256,22 @@ export const checkRouteNeedsChallenge = async (
.where(eq(Challenges.id, challenge_id)); .where(eq(Challenges.id, challenge_id));
}; };
export const auth = ( type HonoEnvWithAuth = HonoEnv & {
authData: ApiRouteMetadata["auth"], Variables: {
permissionData?: ApiRouteMetadata["permissions"], auth: AuthData & { user: NonNullable<AuthData["user"]> };
challengeData?: ApiRouteMetadata["challenge"], };
): MiddlewareHandler<HonoEnv, string> => };
createMiddleware<HonoEnv>(async (context, next) => {
export const auth = <AuthRequired extends boolean>(options: {
auth: AuthRequired;
permissions?: RolePermissions[];
challenge?: boolean;
scopes?: string[];
// If authRequired is true, HonoEnv.Variables.auth.user will never be null
}): MiddlewareHandler<
AuthRequired extends true ? HonoEnvWithAuth : HonoEnv
> => {
return createMiddleware(async (context, next) => {
const header = context.req.header("Authorization"); const header = context.req.header("Authorization");
const tokenString = header?.split(" ")[1]; const tokenString = header?.split(" ")[1];
@ -287,22 +288,23 @@ export const auth = (
}; };
// Authentication check // Authentication check
const authCheck = checkRouteNeedsAuth(auth, authData, context); const authCheck = checkRouteNeedsAuth(auth, options.auth);
context.set("auth", authCheck); context.set("auth", authCheck);
// Permissions check // Permissions check
if (permissionData) { if (options.permissions) {
checkPermissions(auth, permissionData, context); checkPermissions(auth, options.permissions);
} }
// Challenge check // Challenge check
if (challengeData && config.validation.challenges.enabled) { if (options.challenge && config.validation.challenges.enabled) {
await checkRouteNeedsChallenge(challengeData, context); await checkRouteNeedsChallenge(options.challenge, context);
} }
await next(); await next();
}); });
};
// Helper function to parse form data // Helper function to parse form data
async function parseFormData(context: Context): Promise<{ async function parseFormData(context: Context): Promise<{