@nmshd/typescript-rest
Version:
A Library to create RESTFul APIs with Typescript
50 lines • 2.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.routeRequiresAuthorization = routeRequiresAuthorization;
const debug = require("debug");
const Errors = require("../server/model/errors");
const debuggerInstance = debug('typescript-rest:middlewares:routeRequiresAuthorization');
function routeRequiresAuthorization(authenticator, ...permittedRoles) {
if (permittedRoles.length === 0)
throw new Error('At least one permitted role must be specified.');
const roleRegex = /^[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+){0,}$/;
const nonMatchingRoles = permittedRoles.filter((role) => !roleRegex.test(role));
if (nonMatchingRoles.length > 0) {
throw new Error(`Invalid permitted role(s) specified: ${nonMatchingRoles.join(', ')}. Roles must match the pattern: ${roleRegex}.`);
}
return (req, res, next) => {
const rawUserRoles = authenticator.getRoles(req, res);
if (debuggerInstance.enabled)
debuggerInstance('Validating authentication roles: <%j>.', rawUserRoles);
const userRoles = rawUserRoles.map(Role.from);
const isAuthorized = permittedRoles.some((r) => isRoleMatched(r, userRoles));
if (!isAuthorized) {
next(new Errors.ForbiddenError('You are not allowed to access this endpoint.'));
return;
}
next();
};
}
function isRoleMatched(permittedRole, userRoles) {
return userRoles.some((userRole) => userRole.matches(permittedRole));
}
class Role {
constructor(role) {
this.roleRegex = this.transformUserRole(role);
}
static from(role) {
return new Role(role);
}
transformUserRole(userRole) {
if (!userRole.includes('*'))
return new RegExp(`^${userRole}$`);
const regexString = userRole
.replaceAll('**', '[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+){0,}')
.replaceAll('*', '[a-zA-Z0-9_-]+');
return new RegExp(`^${regexString}$`);
}
matches(permittedRole) {
return this.roleRegex.test(permittedRole);
}
}
//# sourceMappingURL=routeRequiresAuthorization.js.map