128 lines
4.0 KiB
JavaScript
128 lines
4.0 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.authenticate = authenticate;
|
|
exports.requireAdminRole = requireAdminRole;
|
|
exports.optionalAuth = optionalAuth;
|
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
const client_1 = require("@prisma/client");
|
|
const database_1 = require("../../../config/database");
|
|
const env_1 = require("../../../config/env");
|
|
/**
|
|
* Authenticate user via V2 JWT access token
|
|
* Verifies token and checks user status in Prisma database
|
|
*/
|
|
async function authenticate(request, reply) {
|
|
const authHeader = request.headers.authorization;
|
|
if (!authHeader?.startsWith('Bearer ')) {
|
|
return reply.status(401).send({
|
|
error: 'Authentication required',
|
|
code: 'AUTH_REQUIRED'
|
|
});
|
|
}
|
|
const token = authHeader.substring(7);
|
|
// Verify JWT with V2 access secret
|
|
let payload;
|
|
try {
|
|
payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET);
|
|
}
|
|
catch (error) {
|
|
return reply.status(401).send({
|
|
error: 'Invalid or expired token',
|
|
code: 'INVALID_TOKEN'
|
|
});
|
|
}
|
|
// Verify user still exists and is active
|
|
const user = await database_1.prisma.user.findUnique({
|
|
where: { id: payload.id },
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
status: true,
|
|
expiresAt: true,
|
|
},
|
|
});
|
|
if (!user) {
|
|
return reply.status(401).send({
|
|
error: 'User not found',
|
|
code: 'USER_NOT_FOUND'
|
|
});
|
|
}
|
|
if (user.status !== client_1.UserStatus.ACTIVE) {
|
|
return reply.status(403).send({
|
|
error: `Account is ${user.status.toLowerCase()}`,
|
|
code: 'ACCOUNT_INACTIVE'
|
|
});
|
|
}
|
|
// Check expiration if set
|
|
if (user.expiresAt && user.expiresAt < new Date()) {
|
|
return reply.status(403).send({
|
|
error: 'Account has expired',
|
|
code: 'ACCOUNT_EXPIRED'
|
|
});
|
|
}
|
|
// Attach user to request
|
|
request.user = {
|
|
id: user.id,
|
|
email: user.email,
|
|
role: user.role,
|
|
};
|
|
}
|
|
/**
|
|
* Require admin role (SUPER_ADMIN, INFLUENCE_ADMIN, or MAP_ADMIN)
|
|
* Also checks auth, so no need to use authenticate() separately
|
|
*/
|
|
async function requireAdminRole(request, reply) {
|
|
// First authenticate
|
|
await authenticate(request, reply);
|
|
// If authenticate sent a response, stop here
|
|
if (reply.sent) {
|
|
return;
|
|
}
|
|
// Check admin role (allow all admin roles)
|
|
const ADMIN_ROLES = ['SUPER_ADMIN', 'INFLUENCE_ADMIN', 'MAP_ADMIN'];
|
|
if (!request.user || !ADMIN_ROLES.includes(request.user.role)) {
|
|
return reply.status(403).send({
|
|
error: 'Admin access required',
|
|
code: 'ADMIN_REQUIRED'
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Optional authentication - attach user if token present, but don't require it
|
|
* Used for public endpoints that want to know if user is logged in
|
|
*/
|
|
async function optionalAuth(request, _reply) {
|
|
const authHeader = request.headers.authorization;
|
|
if (!authHeader?.startsWith('Bearer ')) {
|
|
return;
|
|
}
|
|
const token = authHeader.substring(7);
|
|
try {
|
|
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET);
|
|
// Verify user exists and is active
|
|
const user = await database_1.prisma.user.findUnique({
|
|
where: { id: payload.id },
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
status: true,
|
|
},
|
|
});
|
|
if (user && user.status === client_1.UserStatus.ACTIVE) {
|
|
request.user = {
|
|
id: user.id,
|
|
email: user.email,
|
|
role: user.role,
|
|
};
|
|
}
|
|
}
|
|
catch {
|
|
// Invalid token, just ignore and continue without user
|
|
}
|
|
}
|
|
//# sourceMappingURL=auth.js.map
|