mirror of
https://github.com/detleph/server.git
synced 2026-09-05 07:56:21 +02:00
patched review suggestions and discovered bugs
This commit is contained in:
+105
-105
@@ -18,42 +18,82 @@ export const getBearerToken = (authorization: string) => authorization.slice(7);
|
||||
|
||||
const _requireAdminAuthentication =
|
||||
(config: { optional?: Boolean; controlled?: Boolean } = { optional: false, controlled: false }) =>
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
if (!JWT_SECRET) {
|
||||
throw new Error("JWT_SECRET not set");
|
||||
}
|
||||
|
||||
const { authorization } = req.headers;
|
||||
|
||||
if (!authorization) {
|
||||
if (config.optional) {
|
||||
return false;
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
if (!JWT_SECRET) {
|
||||
throw new Error("JWT_SECRET not set");
|
||||
}
|
||||
|
||||
return res.status(403).send({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "The requeset did not include the Authorization header",
|
||||
},
|
||||
});
|
||||
}
|
||||
const { authorization } = req.headers;
|
||||
|
||||
if (!verifyAuthorizationFormat(authorization)) {
|
||||
return res.status(400).send({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "Malformed Authorization header",
|
||||
format: "Bearer <token>",
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!authorization) {
|
||||
if (config.optional) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let token_payload_: string | JwtPayload;
|
||||
return res.status(403).send({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "The requeset did not include the Authorization header",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
token_payload_ = jwt.verify(getBearerToken(authorization), JWT_SECRET);
|
||||
} catch (e) {
|
||||
if (e instanceof JsonWebTokenError) {
|
||||
if (!verifyAuthorizationFormat(authorization)) {
|
||||
return res.status(400).send({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "Malformed Authorization header",
|
||||
format: "Bearer <token>",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let token_payload_: string | JwtPayload;
|
||||
|
||||
try {
|
||||
token_payload_ = jwt.verify(getBearerToken(authorization), JWT_SECRET);
|
||||
} catch (e) {
|
||||
if (e instanceof JsonWebTokenError) {
|
||||
return res.status(403).json({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "Token could not be verified; It might be expired",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
const token_payload = token_payload_ as AuthJWTPayload;
|
||||
|
||||
if (!token_payload.permission_level || !token_payload.pid || !token_payload.revision) {
|
||||
if (typeof (token_payload as unknown as TeamleaderJWTPayload).team === "string") {
|
||||
if (config.controlled) {
|
||||
return false;
|
||||
}
|
||||
throw new AuthError("Teamleader authentication is not supported for this operation!");
|
||||
}
|
||||
|
||||
throw new AuthError("The token did not include the required information!");
|
||||
}
|
||||
|
||||
const { pid, revision } = token_payload;
|
||||
|
||||
let db_revision = await authClient.get(pid);
|
||||
|
||||
if (db_revision === null) {
|
||||
// Load the revision ID from the main DB and cache it in redis
|
||||
const user = await prisma.admin.findUnique({ where: { pid }, select: { revision: true } });
|
||||
|
||||
if (user) {
|
||||
db_revision = user.revision.toISOString();
|
||||
|
||||
await authClient.set(pid, db_revision);
|
||||
}
|
||||
}
|
||||
|
||||
if (revision !== db_revision || !revision || !db_revision) {
|
||||
return res.status(403).json({
|
||||
type: "error",
|
||||
payload: {
|
||||
@@ -62,62 +102,22 @@ const _requireAdminAuthentication =
|
||||
});
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
req.auth = {
|
||||
isAuthenticated: true,
|
||||
pid: token_payload.pid,
|
||||
name: token_payload.name,
|
||||
permission_level: token_payload.permission_level,
|
||||
groups: token_payload.groups,
|
||||
revision: token_payload.revision,
|
||||
};
|
||||
|
||||
const token_payload = token_payload_ as AuthJWTPayload;
|
||||
|
||||
if (!token_payload.permission_level || !token_payload.pid || !token_payload.revision) {
|
||||
if (typeof (token_payload as unknown as TeamleaderJWTPayload).team === "string") {
|
||||
if (config.controlled) {
|
||||
return false;
|
||||
}
|
||||
throw new AuthError("Teamleader authentication is not supported for this operation!");
|
||||
if (!config.controlled) {
|
||||
next();
|
||||
}
|
||||
|
||||
throw new AuthError("The token did not include the required information!");
|
||||
}
|
||||
|
||||
const { pid, revision } = token_payload;
|
||||
|
||||
let db_revision = await authClient.get(pid);
|
||||
|
||||
if (db_revision === null) {
|
||||
// Load the revision ID from the main DB and cache it in redis
|
||||
const user = await prisma.admin.findUnique({ where: { pid }, select: { revision: true } });
|
||||
|
||||
if (user) {
|
||||
db_revision = user.revision.toISOString();
|
||||
|
||||
await authClient.set(pid, db_revision);
|
||||
}
|
||||
}
|
||||
|
||||
if (revision !== db_revision || !revision || !db_revision) {
|
||||
return res.status(403).json({
|
||||
type: "error",
|
||||
payload: {
|
||||
message: "Token could not be verified; It might be expired",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
req.auth = {
|
||||
isAuthenticated: true,
|
||||
pid: token_payload.pid,
|
||||
name: token_payload.name,
|
||||
permission_level: token_payload.permission_level,
|
||||
groups: token_payload.groups,
|
||||
revision: token_payload.revision,
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!config.controlled) {
|
||||
next();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const requireAuthentication = _requireAdminAuthentication({ optional: false, controlled: false });
|
||||
|
||||
type AuthType = "admin" | "teamleader";
|
||||
@@ -144,37 +144,37 @@ function getAuthTypes(type: AuthType | AuthTypeConfig): AuthType[] {
|
||||
|
||||
export const requireConfiguredAuthentication =
|
||||
(config: AuthConfiguration = { optional: false, type: "admin" }) =>
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const types = getAuthTypes(config.type);
|
||||
const optional = config.optional;
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const types = getAuthTypes(config.type);
|
||||
const optional = config.optional;
|
||||
|
||||
let adminFinished = false;
|
||||
let teamleaderFinished = false;
|
||||
let adminFinished = false;
|
||||
let teamleaderFinished = false;
|
||||
|
||||
if (types.includes("admin")) {
|
||||
adminFinished = Boolean(await _requireAdminAuthentication({ optional: true, controlled: true })(req, res, next));
|
||||
if (types.includes("admin")) {
|
||||
adminFinished = Boolean(await _requireAdminAuthentication({ optional: true, controlled: true })(req, res, next));
|
||||
|
||||
if (adminFinished) {
|
||||
return next();
|
||||
if (adminFinished) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (types.includes("teamleader")) {
|
||||
teamleaderFinished = Boolean(
|
||||
_requireTeamleaderAuthentication({ optional: true, controlled: true })(req, res, next)
|
||||
);
|
||||
if (types.includes("teamleader")) {
|
||||
teamleaderFinished = Boolean(
|
||||
_requireTeamleaderAuthentication({ optional: true, controlled: true })(req, res, next)
|
||||
);
|
||||
|
||||
if (teamleaderFinished) {
|
||||
return next();
|
||||
if (teamleaderFinished) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.optional) {
|
||||
throw new AuthError("No sufficient authorization was provided for this operation");
|
||||
}
|
||||
if (!config.optional) {
|
||||
throw new AuthError("No sufficient authorization was provided for this operation");
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
next();
|
||||
};
|
||||
|
||||
export function requireResponsibleForGroups(auth: AuthJWTPayload | undefined, groupPids: string[] | string) {
|
||||
if (auth?.permission_level === "ELEVATED") {
|
||||
@@ -190,7 +190,7 @@ export function requireResponsibleForGroups(auth: AuthJWTPayload | undefined, gr
|
||||
throw new AuthError("The provided authorization is not valid for the requested operation!");
|
||||
});
|
||||
} else {
|
||||
if (auth?.groups.includes(groupPids)) {
|
||||
if (!auth?.groups.includes(groupPids)) {
|
||||
throw new AuthError("The provided authorization is not valid for the requested operation!");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user