mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-05-16 06:49:09 +02:00
Add user ban/activate feature
Add admin endpoints to ban and activate users, block banned users from all auth flows (OAuth, token login, bearer auth), and invalidate existing sessions on next request. Includes frontend translation and user detail page ban/activate buttons.
This commit is contained in:
@@ -38,7 +38,7 @@ export interface IUser {
|
||||
page: string | null;
|
||||
};
|
||||
};
|
||||
status?: "active" | "removed";
|
||||
status?: "active" | "removed" | "banned";
|
||||
dateOfEntry?: Date;
|
||||
lastUpdated?: Date;
|
||||
}
|
||||
|
||||
@@ -806,6 +806,42 @@ router.get(
|
||||
}
|
||||
}
|
||||
);
|
||||
router.post(
|
||||
"/users/:username/ban",
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const result = await UserModel.updateOne(
|
||||
{ username: req.params.username },
|
||||
{ $set: { status: "banned" } }
|
||||
);
|
||||
if (result.matchedCount === 0) {
|
||||
throw new AnonymousError("user_not_found", { httpStatus: 404 });
|
||||
}
|
||||
res.json({ ok: true });
|
||||
} catch (error) {
|
||||
handleError(error, res, req);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/users/:username/activate",
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const result = await UserModel.updateOne(
|
||||
{ username: req.params.username },
|
||||
{ $set: { status: "active" } }
|
||||
);
|
||||
if (result.matchedCount === 0) {
|
||||
throw new AnonymousError("user_not_found", { httpStatus: 404 });
|
||||
}
|
||||
res.json({ ok: true });
|
||||
} catch (error) {
|
||||
handleError(error, res, req);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get("/conferences", async (req, res) => {
|
||||
const page = parseInt(req.query.page as string) || 1;
|
||||
const limit = Math.min(parseInt(req.query.limit as string) || 10, 1000);
|
||||
|
||||
@@ -92,6 +92,14 @@ const verify = async (
|
||||
await user.save();
|
||||
}
|
||||
}
|
||||
if (user!.status === "banned") {
|
||||
done(
|
||||
new AnonymousError("user_banned", {
|
||||
httpStatus: 403,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
done(null, {
|
||||
username: profile.username,
|
||||
accessToken,
|
||||
@@ -197,6 +205,7 @@ router.all(
|
||||
"apiTokens.tokenHash": hashToken(token),
|
||||
});
|
||||
if (!model) return res.status(401).json({ error: "invalid_token" });
|
||||
if (model.status === "banned") return res.status(403).json({ error: "user_banned" });
|
||||
const synthUser = {
|
||||
username: model.username,
|
||||
accessToken: model.accessTokens?.github,
|
||||
|
||||
@@ -216,7 +216,9 @@ export function handleError(
|
||||
status = 401;
|
||||
}
|
||||
if (res && !res.headersSent) {
|
||||
res.status(status).json({ error: errorCode });
|
||||
const safeCode =
|
||||
error instanceof AnonymousError ? errorCode : "internal_error";
|
||||
res.status(status).json({ error: safeCode });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -244,5 +246,15 @@ export async function getUser(req: express.Request) {
|
||||
if (!model) {
|
||||
notConnected();
|
||||
}
|
||||
if (model.status === "banned") {
|
||||
req.logout((error) => {
|
||||
if (error) {
|
||||
logger.error("logout failed", serializeError(error));
|
||||
}
|
||||
});
|
||||
throw new AnonymousError("user_banned", {
|
||||
httpStatus: 403,
|
||||
});
|
||||
}
|
||||
return new User(model);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export async function bearerTokenAuth(
|
||||
try {
|
||||
const model = await UserModel.findOne({ "apiTokens.tokenHash": tokenHash });
|
||||
if (!model) return next();
|
||||
if (model.status === "banned") return next();
|
||||
|
||||
// Mirror the shape produced by passport's verify() in connection.ts
|
||||
// so existing getUser()/route code works unchanged.
|
||||
|
||||
Reference in New Issue
Block a user