Fixed 267U.pre2

This commit is contained in:
2026-07-26 18:25:37 +09:00
parent 50bfaeafdf
commit 317d00a284
1286 changed files with 80222 additions and 1 deletions
@@ -0,0 +1,51 @@
import { MastoApiError } from "./catch-errors.js";
import { OAuthTokens } from "../../../../models/index.js";
import authenticate from "../../authenticate.js";
import { AuthHelpers } from "../helpers/auth.js";
export async function AuthMiddleware(ctx, next) {
const token = await getTokenFromOAuth(ctx.headers.authorization);
ctx.appId = token?.appId;
ctx.user = token?.user ?? null;
ctx.scopes = token?.scopes ?? [];
await next();
}
export async function getTokenFromOAuth(authorization) {
if (authorization == null) return null;
if (authorization.substring(0, 7).toLowerCase() === "bearer ") authorization = authorization.substring(7);
return OAuthTokens.findOne({
where: {
token: authorization,
active: true
},
relations: [
'user'
]
}).then((token)=>{
if (!token) return null;
return {
...token,
scopes: AuthHelpers.expandScopes(token.scopes)
};
});
}
export function auth(required, scopes = []) {
return async function auth(ctx, next) {
if (required && !ctx.user) throw new MastoApiError(401, "This method requires an authenticated user");
if (!scopes.every((p)=>ctx.scopes.includes(p))) {
if (required) throw new MastoApiError(403, "This action is outside the authorized scopes");
ctx.user = null;
ctx.scopes = [];
}
await next();
};
}
export function MiAuth(required) {
return async function MiAuth(ctx, next) {
ctx.miauth = await authenticate(ctx.headers.authorization, null, true).catch((_)=>[
null,
null
]);
if (required && !ctx.miauth[0]) throw new MastoApiError(401, "Unauthorized");
await next();
};
}
@@ -0,0 +1,5 @@
import { UserHelpers } from "../helpers/user.js";
export async function CacheMiddleware(ctx, next) {
ctx.cache = UserHelpers.getFreshAccountCache();
await next();
}
@@ -0,0 +1,54 @@
import { logger } from "../index.js";
import { IdentifiableError } from "../../../../misc/identifiable-error.js";
import { ApiError } from "../../error.js";
export class MastoApiError extends Error {
statusCode;
errorDescription;
constructor(statusCode, message, description){
if (message == null) {
switch(statusCode){
case 404:
message = 'Record not found';
break;
default:
message = 'Unknown error occurred';
break;
}
}
super(message);
this.errorDescription = description;
this.statusCode = statusCode;
}
}
export async function CatchErrorsMiddleware(ctx, next) {
try {
await next();
} catch (e) {
if (e instanceof MastoApiError) {
ctx.status = e.statusCode;
ctx.body = {
error: e.message,
error_description: e.errorDescription
};
return;
} else if (e instanceof IdentifiableError) {
if (e.message.length < 1) e.message = e.id;
ctx.status = 400;
} else if (e instanceof ApiError) {
ctx.status = e.httpStatusCode ?? 500;
} else {
logger.error(`Error occured in ${ctx.method} ${ctx.path}:`);
if (e instanceof Error) {
if (e.stack) logger.error(e.stack);
else logger.error(`${e.name}: ${e.message}`);
} else {
logger.error(e);
}
ctx.status = 500;
}
ctx.body = {
error: e.message ?? e
};
return;
}
}
@@ -0,0 +1,6 @@
export function filterContext(context) {
return async function filterContext(ctx, next) {
ctx.filterContext = context;
await next();
};
}
@@ -0,0 +1,14 @@
import { HttpMethodEnum, koaBody } from "koa-body";
export function KoaBodyMiddleware() {
const options = {
multipart: true,
urlencoded: true,
parsedMethods: [
HttpMethodEnum.POST,
HttpMethodEnum.PUT,
HttpMethodEnum.PATCH,
HttpMethodEnum.DELETE
] // dear god mastodon why
};
return koaBody(options);
}
@@ -0,0 +1,13 @@
export async function NormalizeQueryMiddleware(ctx, next) {
if (ctx.request.query) {
if (!ctx.request.body || Object.keys(ctx.request.body).length === 0) {
ctx.request.body = ctx.request.query;
} else {
ctx.request.body = {
...ctx.request.body,
...ctx.request.query
};
}
}
await next();
}
@@ -0,0 +1,26 @@
import config from "../../../../config/index.js";
export async function PaginationMiddleware(ctx, next) {
await next();
if (!ctx.pagination) return;
const link = [];
const limit = ctx.pagination.limit;
if (ctx.pagination.maxId) {
const l = `<${config.url}/api${ctx.path}?limit=${limit}&max_id=${ctx.pagination.maxId}>; rel="next"`;
link.push(l);
}
if (ctx.pagination.minId) {
const l = `<${config.url}/api${ctx.path}?limit=${limit}&min_id=${ctx.pagination.minId}>; rel="prev"`;
link.push(l);
}
if (link.length > 0) {
ctx.response.append('Link', link.join(', '));
}
}
export function generatePaginationData(ids, limit) {
if (ids.length < 1) return undefined;
return {
limit: limit,
maxId: ids.length < limit ? undefined : ids.at(-1),
minId: ids.at(0)
};
}
@@ -0,0 +1,7 @@
const headers = {
"Access-Control-Expose-Headers": "Link,Connection,Sec-Websocket-Accept,Upgrade"
};
export async function SetHeadersMiddleware(ctx, next) {
ctx.set(headers);
await next();
}