"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthService = void 0; const argon2_1 = __importDefault(require("argon2")); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const zod_1 = require("zod"); const prisma_1 = require("../lib/prisma"); const logger_1 = require("../lib/logger"); const loginSchema = zod_1.z.object({ email: zod_1.z.string().email(), password: zod_1.z.string().min(8), }); const registerSchema = zod_1.z.object({ email: zod_1.z.string().email(), name: zod_1.z.string().min(2), password: zod_1.z.string().min(8), organizationName: zod_1.z.string().min(2).optional(), }); class AuthService { JWT_SECRET = process.env.JWT_SECRET || 'fallback-secret-change-in-production'; JWT_EXPIRES_IN = '7d'; async hashPassword(password) { try { return await argon2_1.default.hash(password, { type: argon2_1.default.argon2id, memoryCost: 2 ** 16, timeCost: 3, parallelism: 1, }); } catch (error) { logger_1.logger.error('Password hashing failed:', error); throw new Error('Password hashing failed'); } } async verifyPassword(hash, password) { try { return await argon2_1.default.verify(hash, password); } catch (error) { logger_1.logger.error('Password verification failed:', error); return false; } } generateToken(userId, email) { return jsonwebtoken_1.default.sign({ userId, email, iat: Math.floor(Date.now() / 1000), }, this.JWT_SECRET, { expiresIn: this.JWT_EXPIRES_IN }); } verifyToken(token) { try { const decoded = jsonwebtoken_1.default.verify(token, this.JWT_SECRET); return decoded; } catch (error) { logger_1.logger.error('Token verification failed:', error); throw new Error('Invalid token'); } } async login(data) { const { email, password } = loginSchema.parse(data); logger_1.logger.info(`Login attempt for email: ${email}`); const user = await prisma_1.prisma.user.findUnique({ where: { email }, include: { memberships: { include: { organization: { select: { name: true, plan: true, } } } } } }); if (!user) { logger_1.logger.warn(`Login failed: User not found for email ${email}`); throw new Error('Invalid credentials'); } const isValidPassword = await this.verifyPassword(user.passwordHash, password); if (!isValidPassword) { logger_1.logger.warn(`Login failed: Invalid password for email ${email}`); throw new Error('Invalid credentials'); } await prisma_1.prisma.user.update({ where: { id: user.id }, data: { lastLoginAt: new Date() } }); const token = this.generateToken(user.id, user.email); const authUser = { id: user.id, email: user.email, name: user.name, memberships: user.memberships.map(m => ({ orgId: m.orgId, role: m.role, organization: { name: m.organization.name, plan: m.organization.plan, } })) }; logger_1.logger.info(`Login successful for user: ${user.email}`); return { user: authUser, token }; } async register(data) { const { email, name, password, organizationName } = registerSchema.parse(data); logger_1.logger.info(`Registration attempt for email: ${email}`); const existingUser = await prisma_1.prisma.user.findUnique({ where: { email } }); if (existingUser) { logger_1.logger.warn(`Registration failed: User already exists for email ${email}`); throw new Error('User already exists'); } const passwordHash = await this.hashPassword(password); const result = await prisma_1.prisma.$transaction(async (tx) => { const user = await tx.user.create({ data: { email, name, passwordHash, } }); const organization = await tx.organization.create({ data: { name: organizationName || `Default Organization`, plan: 'free', } }); await tx.orgMembership.create({ data: { userId: user.id, orgId: organization.id, role: 'OWNER', } }); await tx.project.create({ data: { name: 'Default Project', orgId: organization.id, settingsJson: { description: 'Default project for redirect tracking', defaultMethod: 'GET', createdBy: user.id, }, } }); return { user, organization }; }); logger_1.logger.info(`Registration successful for user: ${email}`); return { id: result.user.id, email: result.user.email, name: result.user.name, memberships: [{ orgId: result.organization.id, role: 'OWNER', organization: { name: result.organization.name, plan: result.organization.plan, } }] }; } async getUserById(userId) { const user = await prisma_1.prisma.user.findUnique({ where: { id: userId }, include: { memberships: { include: { organization: { select: { name: true, plan: true, } } } } } }); if (!user) { return null; } return { id: user.id, email: user.email, name: user.name, memberships: user.memberships.map(m => ({ orgId: m.orgId, role: m.role, organization: { name: m.organization.name, plan: m.organization.plan, } })) }; } async hasOrgAccess(userId, orgId) { const membership = await prisma_1.prisma.orgMembership.findUnique({ where: { orgId_userId: { orgId, userId, } } }); return !!membership; } async getUserRole(userId, orgId) { const membership = await prisma_1.prisma.orgMembership.findUnique({ where: { orgId_userId: { orgId, userId, } } }); return membership?.role || null; } } exports.AuthService = AuthService; //# sourceMappingURL=auth.service.js.map