149 lines
4.7 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");
const roles_1 = require("../../../utils/roles");
/**
* 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;
const queryToken = request.query?.token;
// Support both Authorization header and ?token= query param (for <img>/<video> src)
let token = null;
if (authHeader?.startsWith('Bearer ')) {
token = authHeader.substring(7);
}
else if (queryToken) {
token = queryToken;
}
if (!token) {
return reply.status(401).send({
error: 'Authentication required',
code: 'AUTH_REQUIRED'
});
}
// Verify JWT with V2 access secret
let payload;
try {
payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET, { algorithms: ['HS256'] });
}
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,
roles: 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
const userRoles = (0, roles_1.getUserRoles)(user);
request.user = {
id: user.id,
email: user.email,
role: user.role,
roles: userRoles,
};
}
/**
* 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 using multi-role utility
if (!request.user || !(0, roles_1.hasAnyRole)(request.user, roles_1.MEDIA_ROLES)) {
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;
const queryToken = request.query?.token;
let token = null;
if (authHeader?.startsWith('Bearer ')) {
token = authHeader.substring(7);
}
else if (queryToken) {
token = queryToken;
}
if (!token) {
return;
}
try {
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET, { algorithms: ['HS256'] });
// 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,
roles: true,
status: true,
},
});
if (user && user.status === client_1.UserStatus.ACTIVE) {
const userRoles = (0, roles_1.getUserRoles)(user);
request.user = {
id: user.id,
email: user.email,
role: user.role,
roles: userRoles,
};
}
}
catch {
// Invalid token, just ignore and continue without user
}
}
//# sourceMappingURL=auth.js.map