Files
url_tracker_tool/apps/api/dist/services/auth.service.js
Andrei 58f8093689 Rebrand from 'Redirect Intelligence v2' to 'URL Tracker Tool V2' throughout UI
- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
2025-08-19 19:12:23 +00:00

229 lines
7.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.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 || `${name}'s 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',
},
}
});
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