Updating dependencies and switching to ESModules where possible
Some checks failed
CI / build (push) Has been cancelled

This commit is contained in:
Fabian Stamm
2025-09-15 22:04:57 +02:00
parent 8135190cd8
commit c6158fe2e2
66 changed files with 4540 additions and 3752 deletions

View File

@ -1,15 +1,15 @@
import Stacker from "../middlewares/stacker";
import { GetUserMiddleware } from "../middlewares/user";
import Stacker from "../middlewares/stacker.js";
import { GetUserMiddleware } from "../middlewares/user.js";
import { Request, Response } from "express";
import Client from "../../models/client";
import Client from "../../models/client.js";
import Logging from "@hibas123/nodelogging";
import Permission, { IPermission } from "../../models/permissions";
import ClientCode from "../../models/client_code";
import Permission, { IPermission } from "../../models/permissions.js";
import ClientCode from "../../models/client_code.js";
import moment = require("moment");
import { randomBytes } from "crypto";
// import { ObjectId } from "bson";
import Grant, { IGrant } from "../../models/grants";
import GetAuthPage from "../../views/authorize";
import Grant, { IGrant } from "../../models/grants.js";
import GetAuthPage from "../../views/authorize.js";
import { ObjectId } from "mongodb";
// const AuthRoute = Stacker(GetUserMiddleware(true), async (req: Request, res: Response) => {

View File

@ -1,73 +1,73 @@
import { Router } from "express";
import GetAuthRoute from "./auth";
import JWTRoute from "./jwt";
import Public from "./public";
import RefreshTokenRoute from "./refresh";
import ProfileRoute from "./profile";
const OAuthRoute: Router = Router();
/**
* @api {post} /oauth/auth
* @apiName OAuthAuth
*
* @apiGroup oauth
* @apiPermission user Special required
*
* @apiParam {String} response_type must be "code" others are not supported
* @apiParam {String} client_id ClientID
* @apiParam {String} redirect_uri The URI to redirect with code
* @apiParam {String} scope Scope that contains the requested permissions (comma seperated list of permissions)
* @apiParam {String} state State, that will be passed to redirect_uri for client
* @apiParam {String} nored Deactivates the Redirect response from server and instead returns the redirect URI in JSON response
*/
OAuthRoute.post("/auth", GetAuthRoute(false));
/**
* @api {get} /oauth/jwt
* @apiName OAuthJwt
*
* @apiGroup oauth
* @apiPermission none
*
* @apiParam {String} refreshtoken
*
* @apiSuccess {String} token The JWT that allowes the application to access the recources granted for refresh token
*/
OAuthRoute.get("/jwt", JWTRoute);
/**
* @api {get} /oauth/public
* @apiName OAuthPublic
*
* @apiGroup oauth
* @apiPermission none
*
* @apiSuccess {String} public_key The applications public_key. Used to verify JWT.
*/
OAuthRoute.get("/public", Public);
/**
* @api {get} /oauth/refresh
* @apiName OAuthRefreshGet
*
* @apiGroup oauth
*/
OAuthRoute.get("/refresh", RefreshTokenRoute);
/**
* @api {post} /oauth/refresh
* @apiName OAuthRefreshPost
*
* @apiGroup oauth
*/
OAuthRoute.post("/refresh", RefreshTokenRoute);
/**
* @api {get} /oauth/profile
* @apiName OAuthProfile
*
* @apiGroup oauth
*/
OAuthRoute.get("/profile", ProfileRoute);
export default OAuthRoute;
import { Router } from "express";
import GetAuthRoute from "./auth.js";
import JWTRoute from "./jwt.js";
import Public from "./public.js";
import RefreshTokenRoute from "./refresh.js";
import ProfileRoute from "./profile.js";
const OAuthRoute: Router = Router();
/**
* @api {post} /oauth/auth
* @apiName OAuthAuth
*
* @apiGroup oauth
* @apiPermission user Special required
*
* @apiParam {String} response_type must be "code" others are not supported
* @apiParam {String} client_id ClientID
* @apiParam {String} redirect_uri The URI to redirect with code
* @apiParam {String} scope Scope that contains the requested permissions (comma seperated list of permissions)
* @apiParam {String} state State, that will be passed to redirect_uri for client
* @apiParam {String} nored Deactivates the Redirect response from server and instead returns the redirect URI in JSON response
*/
OAuthRoute.post("/auth", GetAuthRoute(false));
/**
* @api {get} /oauth/jwt
* @apiName OAuthJwt
*
* @apiGroup oauth
* @apiPermission none
*
* @apiParam {String} refreshtoken
*
* @apiSuccess {String} token The JWT that allowes the application to access the recources granted for refresh token
*/
OAuthRoute.get("/jwt", JWTRoute);
/**
* @api {get} /oauth/public
* @apiName OAuthPublic
*
* @apiGroup oauth
* @apiPermission none
*
* @apiSuccess {String} public_key The applications public_key. Used to verify JWT.
*/
OAuthRoute.get("/public", Public);
/**
* @api {get} /oauth/refresh
* @apiName OAuthRefreshGet
*
* @apiGroup oauth
*/
OAuthRoute.get("/refresh", RefreshTokenRoute);
/**
* @api {post} /oauth/refresh
* @apiName OAuthRefreshPost
*
* @apiGroup oauth
*/
OAuthRoute.post("/refresh", RefreshTokenRoute);
/**
* @api {get} /oauth/profile
* @apiName OAuthProfile
*
* @apiGroup oauth
*/
OAuthRoute.get("/profile", ProfileRoute);
export default OAuthRoute;

View File

@ -1,43 +1,43 @@
import { Request, Response } from "express";
import promiseMiddleware from "../../helper/promiseMiddleware";
import RequestError, { HttpStatusCode } from "../../helper/request_error";
import RefreshToken from "../../models/refresh_token";
import User from "../../models/user";
import Client from "../../models/client";
import { getAccessTokenJWT } from "../../helper/jwt";
const JWTRoute = promiseMiddleware(async (req: Request, res: Response) => {
let { refreshtoken } = req.query as { [key: string]: string };
if (!refreshtoken)
throw new RequestError(
req.__("Refresh token not set"),
HttpStatusCode.BAD_REQUEST
);
let token = await RefreshToken.findOne({ token: refreshtoken });
if (!token)
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
let user = await User.findById(token.user);
if (!user) {
token.valid = false;
await RefreshToken.save(token);
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
}
let client = await Client.findById(token.client);
let jwt = await getAccessTokenJWT({
user,
permissions: token.permissions,
client,
});
res.json({ token: jwt });
});
export default JWTRoute;
import { Request, Response } from "express";
import promiseMiddleware from "../../helper/promiseMiddleware.js";
import RequestError, { HttpStatusCode } from "../../helper/request_error.js";
import RefreshToken from "../../models/refresh_token.js";
import User from "../../models/user.js";
import Client from "../../models/client.js";
import { getAccessTokenJWT } from "../../helper/jwt.js";
const JWTRoute = promiseMiddleware(async (req: Request, res: Response) => {
let { refreshtoken } = req.query as { [key: string]: string };
if (!refreshtoken)
throw new RequestError(
req.__("Refresh token not set"),
HttpStatusCode.BAD_REQUEST
);
let token = await RefreshToken.findOne({ token: refreshtoken });
if (!token)
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
let user = await User.findById(token.user);
if (!user) {
token.valid = false;
await RefreshToken.save(token);
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
}
let client = await Client.findById(token.client);
let jwt = await getAccessTokenJWT({
user,
permissions: token.permissions,
client,
});
res.json({ token: jwt });
});
export default JWTRoute;

View File

@ -1,6 +1,6 @@
import Mail from "../../models/mail";
import { GetClientApiAuthMiddleware } from "../middlewares/client";
import Stacker from "../middlewares/stacker";
import Mail from "../../models/mail.js";
import { GetClientApiAuthMiddleware } from "../middlewares/client.js";
import Stacker from "../middlewares/stacker.js";
import { Request, Response } from "express";
import Logging from "@hibas123/nodelogging";

View File

@ -1,6 +1,6 @@
import { Request, Response } from "express";
import { public_key } from "../../keys";
export default function Public(req: Request, res: Response) {
res.json({ public_key: public_key });
}
import { Request, Response } from "express";
import { public_key } from "../../keys.js";
export default function Public(req: Request, res: Response) {
res.json({ public_key: public_key });
}

View File

@ -1,122 +1,122 @@
import { Request, Response } from "express";
import RequestError, { HttpStatusCode } from "../../helper/request_error";
import User from "../../models/user";
import Client from "../../models/client";
import {
getAccessTokenJWT,
getIDToken,
AccessTokenJWTExp,
} from "../../helper/jwt";
import Stacker from "../middlewares/stacker";
import { GetClientAuthMiddleware } from "../middlewares/client";
import ClientCode from "../../models/client_code";
import Mail from "../../models/mail";
import { randomBytes } from "crypto";
import moment = require("moment");
// import { JWTExpDur } from "../../keys";
import RefreshToken from "../../models/refresh_token";
import { getEncryptionKey } from "../../helper/user_key";
import { refreshTokenValidTime } from "../../config";
// TODO:
/*
For example, the authorization server could employ refresh token
rotation in which a new refresh token is issued with every access
token refresh response. The previous refresh token is invalidated but retained by the authorization server. If a refresh token is
compromised and subsequently used by both the attacker and the
legitimate client, one of them will present an invalidated refresh
token, which will inform the authorization server of the breach.
*/
const RefreshTokenRoute = Stacker(
GetClientAuthMiddleware(false, false, true),
async (req: Request, res: Response) => {
let grant_type = req.query.grant_type || req.body.grant_type;
if (!grant_type || grant_type === "authorization_code") {
let code = req.query.code || req.body.code;
let nonce = req.query.nonce || req.body.nonce;
let c = await ClientCode.findOne({ code: code });
if (!c || moment(c.validTill).isBefore()) {
throw new RequestError(
req.__("Invalid code"),
HttpStatusCode.BAD_REQUEST
);
}
let client = await Client.findById(c.client);
let user = await User.findById(c.user);
let mails = await Promise.all(user.mails.map((m) => Mail.findOne(m)));
let token = RefreshToken.new({
user: c.user,
client: c.client,
permissions: c.permissions,
token: randomBytes(16).toString("hex"),
valid: true,
validTill: moment().add(refreshTokenValidTime).toDate(),
});
await RefreshToken.save(token);
await ClientCode.delete(c);
let mail = mails.find((e) => e.primary);
if (!mail) mail = mails[0];
res.json({
refresh_token: token.token,
token: token.token,
access_token: await getAccessTokenJWT({
client: client,
user: user,
permissions: c.permissions,
}),
token_type: "bearer",
expires_in: AccessTokenJWTExp.asSeconds(),
profile: {
uid: user.uid,
email: mail ? mail.mail : "",
name: user.name,
enc_key: getEncryptionKey(user, client),
},
id_token: getIDToken(user, client.client_id, nonce),
});
} else if (grant_type === "refresh_token") {
let refresh_token = req.query.refresh_token || req.body.refresh_token;
if (!refresh_token)
throw new RequestError(
req.__("refresh_token not set"),
HttpStatusCode.BAD_REQUEST
);
let token = await RefreshToken.findOne({ token: refresh_token });
if (!token || !token.valid || moment(token.validTill).isBefore())
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
token.validTill = moment().add(refreshTokenValidTime).toDate();
await RefreshToken.save(token);
let user = await User.findById(token.user);
let client = await Client.findById(token.client);
let jwt = await getAccessTokenJWT({
user,
client,
permissions: token.permissions,
});
res.json({
access_token: jwt,
expires_in: AccessTokenJWTExp.asSeconds(),
});
} else {
throw new RequestError(
"invalid grant_type",
HttpStatusCode.BAD_REQUEST
);
}
}
);
export default RefreshTokenRoute;
import { Request, Response } from "express";
import RequestError, { HttpStatusCode } from "../../helper/request_error.js";
import User from "../../models/user.js";
import Client from "../../models/client.js";
import {
getAccessTokenJWT,
getIDToken,
AccessTokenJWTExp,
} from "../../helper/jwt.js";
import Stacker from "../middlewares/stacker.js";
import { GetClientAuthMiddleware } from "../middlewares/client.js";
import ClientCode from "../../models/client_code.js";
import Mail from "../../models/mail.js";
import { randomBytes } from "crypto";
import moment = require("moment");
// import { JWTExpDur } from "../../keys";
import RefreshToken from "../../models/refresh_token.js";
import { getEncryptionKey } from "../../helper/user_key.js";
import { refreshTokenValidTime } from "../../config.js";
// TODO:
/*
For example, the authorization server could employ refresh token
rotation in which a new refresh token is issued with every access
token refresh response. The previous refresh token is invalidated but retained by the authorization server. If a refresh token is
compromised and subsequently used by both the attacker and the
legitimate client, one of them will present an invalidated refresh
token, which will inform the authorization server of the breach.
*/
const RefreshTokenRoute = Stacker(
GetClientAuthMiddleware(false, false, true),
async (req: Request, res: Response) => {
let grant_type = req.query.grant_type || req.body.grant_type;
if (!grant_type || grant_type === "authorization_code") {
let code = req.query.code || req.body.code;
let nonce = req.query.nonce || req.body.nonce;
let c = await ClientCode.findOne({ code: code });
if (!c || moment(c.validTill).isBefore()) {
throw new RequestError(
req.__("Invalid code"),
HttpStatusCode.BAD_REQUEST
);
}
let client = await Client.findById(c.client);
let user = await User.findById(c.user);
let mails = await Promise.all(user.mails.map((m) => Mail.findOne(m)));
let token = RefreshToken.new({
user: c.user,
client: c.client,
permissions: c.permissions,
token: randomBytes(16).toString("hex"),
valid: true,
validTill: moment().add(refreshTokenValidTime).toDate(),
});
await RefreshToken.save(token);
await ClientCode.delete(c);
let mail = mails.find((e) => e.primary);
if (!mail) mail = mails[0];
res.json({
refresh_token: token.token,
token: token.token,
access_token: await getAccessTokenJWT({
client: client,
user: user,
permissions: c.permissions,
}),
token_type: "bearer",
expires_in: AccessTokenJWTExp.asSeconds(),
profile: {
uid: user.uid,
email: mail ? mail.mail : "",
name: user.name,
enc_key: getEncryptionKey(user, client),
},
id_token: getIDToken(user, client.client_id, nonce),
});
} else if (grant_type === "refresh_token") {
let refresh_token = req.query.refresh_token || req.body.refresh_token;
if (!refresh_token)
throw new RequestError(
req.__("refresh_token not set"),
HttpStatusCode.BAD_REQUEST
);
let token = await RefreshToken.findOne({ token: refresh_token });
if (!token || !token.valid || moment(token.validTill).isBefore())
throw new RequestError(
req.__("Invalid token"),
HttpStatusCode.BAD_REQUEST
);
token.validTill = moment().add(refreshTokenValidTime).toDate();
await RefreshToken.save(token);
let user = await User.findById(token.user);
let client = await Client.findById(token.client);
let jwt = await getAccessTokenJWT({
user,
client,
permissions: token.permissions,
});
res.json({
access_token: jwt,
expires_in: AccessTokenJWTExp.asSeconds(),
});
} else {
throw new RequestError(
"invalid grant_type",
HttpStatusCode.BAD_REQUEST
);
}
}
);
export default RefreshTokenRoute;