@citrineos/util
Version:
The OCPP util module which supplies helpful utilities like cache and queue connectors, etc.
142 lines • 6.31 kB
JavaScript
;
/*
* // Copyright Contributors to the CitrineOS Project
*
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const tslog_1 = require("tslog");
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
const base_1 = require("@citrineos/base");
/**
* Authentication plugin for Fastify
* This plugin adds authentication and authorization capabilities to Fastify
* using the provided auth provider
*
* @param fastify Fastify instance
* @param provider Auth provider instance
* @param options Plugin options
*/
const apiAuthPlugin = (fastify_1, _a) => __awaiter(void 0, [fastify_1, _a], void 0, function* (fastify, { provider, options = {}, logger }) {
//TODO add logger instance ?
const _logger = logger
? logger.getSubLogger({ name: 'AuthPlugin' })
: new tslog_1.Logger({ name: 'AuthPlugin' });
// Register the auth provider
fastify.decorate('authProvider', provider);
// Helper to check if a route is excluded from authentication
function isExcludedRoute(url) {
var _a;
// Always exclude health check
if (url === '/health') {
return true;
}
const isExcluded = !!((_a = options.excludedRoutes) === null || _a === void 0 ? void 0 : _a.some((route) => url === route || url.startsWith(`${route}/`)));
if (isExcluded && options.debug) {
_logger.debug(`Skipping authentication for excluded route: ${url}`);
}
return isExcluded;
}
// Authentication decorator - validates token from Authorization header
fastify.decorate('authenticate', function (request, reply) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Extract token
const token = yield provider.extractToken(request);
if (!token) {
reply.code(base_1.HttpStatus.UNAUTHORIZED).send({
error: 'Unauthorized',
message: 'Missing or invalid authorization header',
});
return;
}
// Authenticate token
const authResult = yield provider.authenticateToken(token);
if (!authResult.isAuthenticated || !authResult.user) {
reply.code(base_1.HttpStatus.UNAUTHORIZED).send({
error: 'Unauthorized',
message: authResult.error || 'Invalid token',
});
return;
}
// Store user info in request
request.user = authResult.user;
if (options.debug) {
_logger.debug(`Authenticated user: ${authResult.user.id} (${authResult.user.name})`);
_logger.debug(`Roles: ${authResult.user.roles.join(', ')}`);
}
}
catch (error) {
_logger.error('Authentication error:', error);
reply.code(base_1.HttpStatus.UNAUTHORIZED).send({
error: 'Unauthorized',
message: 'Authentication failed',
});
}
});
});
// Authorization decorator - authorizes user for the requested resource
fastify.decorate('authorize', function (request, reply) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Check if user is authenticated
if (!request.user) {
reply.code(base_1.HttpStatus.UNAUTHORIZED).send({
error: 'Unauthorized',
message: 'Authentication required',
});
return;
}
// Authorize user for this request
const authzResult = yield provider.authorizeUser(request.user, request);
if (!authzResult.isAuthorized) {
reply.code(base_1.HttpStatus.FORBIDDEN).send({
error: 'Forbidden',
message: authzResult.error || 'Insufficient permissions',
});
return;
}
if (options.debug) {
_logger.debug(`Authorized user ${request.user.id} for ${request.method} ${request.url}`);
}
}
catch (error) {
_logger.error('Authorization error:', error);
reply.code(base_1.HttpStatus.FORBIDDEN).send({
error: 'Forbidden',
message: 'Authorization failed',
});
}
});
});
// Add global authentication hook for all routes
fastify.addHook('onRequest', (request, reply) => __awaiter(void 0, void 0, void 0, function* () {
// Skip authentication for excluded routes
if (isExcludedRoute(request.url)) {
if (options.debug) {
_logger.trace(`Skipping authentication for excluded route: ${request.url}`);
}
return;
}
// Authenticate and authorize the request
yield fastify.authenticate(request, reply);
yield fastify.authorize(request, reply);
}));
_logger.info('Authentication plugin registered');
});
exports.default = (0, fastify_plugin_1.default)(apiAuthPlugin, {
name: 'apiAuth',
fastify: '5.x',
});
//# sourceMappingURL=ApiAuthPlugin.js.map