michangarrito/apps/backend/dist/modules/auth/auth.service.js
rckrdmrd 48dea7a5d0 feat: Initial commit - michangarrito
Marketplace móvil para negocios locales mexicanos.

Estructura inicial:
- apps/backend (NestJS API)
- apps/frontend (React Web)
- apps/mobile (Expo/React Native)
- apps/mcp-server (Claude MCP Server)
- apps/whatsapp-service (WhatsApp Business API)
- database/ (PostgreSQL DDL)
- docs/ (Documentación)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 04:41:02 -06:00

192 lines
7.7 KiB
JavaScript

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const jwt_1 = require("@nestjs/jwt");
const config_1 = require("@nestjs/config");
const bcrypt = require("bcrypt");
const tenant_entity_1 = require("./entities/tenant.entity");
const user_entity_1 = require("./entities/user.entity");
let AuthService = class AuthService {
constructor(tenantRepository, userRepository, jwtService, configService) {
this.tenantRepository = tenantRepository;
this.userRepository = userRepository;
this.jwtService = jwtService;
this.configService = configService;
}
generateSlug(name) {
return name
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/[^a-z0-9]+/g, '-')
.replace(/(^-|-$)/g, '')
.substring(0, 45) + '-' + Date.now().toString(36).slice(-4);
}
async register(dto) {
const existingTenant = await this.tenantRepository.findOne({
where: { phone: dto.phone },
});
if (existingTenant) {
throw new common_1.ConflictException('Este teléfono ya está registrado');
}
const pinHash = await bcrypt.hash(dto.pin, 10);
const slug = this.generateSlug(dto.name);
const tenant = this.tenantRepository.create({
name: dto.name,
slug,
businessType: dto.businessType,
phone: dto.phone,
email: dto.email,
address: dto.address,
city: dto.city,
whatsappNumber: dto.whatsapp || dto.phone,
subscriptionStatus: 'trial',
status: 'active',
});
const savedTenant = await this.tenantRepository.save(tenant);
const user = this.userRepository.create({
tenantId: savedTenant.id,
phone: dto.phone,
name: dto.ownerName,
pinHash,
role: 'owner',
status: 'active',
});
const savedUser = await this.userRepository.save(user);
return this.generateTokens(savedUser, savedTenant);
}
async login(dto) {
const user = await this.userRepository.findOne({
where: { phone: dto.phone },
});
if (!user) {
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
}
const tenant = await this.tenantRepository.findOne({
where: { id: user.tenantId },
});
if (!tenant) {
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
}
if (tenant.subscriptionStatus === 'cancelled') {
throw new common_1.UnauthorizedException('Tu suscripción ha sido cancelada');
}
if (tenant.subscriptionStatus === 'suspended' || tenant.status === 'suspended') {
throw new common_1.UnauthorizedException('Tu cuenta está suspendida. Contacta soporte.');
}
if (user.status !== 'active') {
throw new common_1.UnauthorizedException('Tu cuenta está inactiva');
}
if (user.lockedUntil && user.lockedUntil > new Date()) {
throw new common_1.UnauthorizedException('Cuenta bloqueada temporalmente. Intenta más tarde.');
}
const isValidPin = await bcrypt.compare(dto.pin, user.pinHash);
if (!isValidPin) {
user.failedAttempts = (user.failedAttempts || 0) + 1;
if (user.failedAttempts >= 5) {
user.lockedUntil = new Date(Date.now() + 15 * 60 * 1000);
}
await this.userRepository.save(user);
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
}
user.failedAttempts = 0;
user.lockedUntil = null;
user.lastLoginAt = new Date();
await this.userRepository.save(user);
return this.generateTokens(user, tenant);
}
async refreshToken(refreshToken) {
try {
const payload = this.jwtService.verify(refreshToken, {
secret: this.configService.get('JWT_SECRET'),
});
const user = await this.userRepository.findOne({
where: { id: payload.sub },
});
if (!user) {
throw new common_1.UnauthorizedException('Token inválido');
}
const tenant = await this.tenantRepository.findOne({
where: { id: user.tenantId },
});
if (!tenant) {
throw new common_1.UnauthorizedException('Token inválido');
}
return this.generateTokens(user, tenant);
}
catch {
throw new common_1.UnauthorizedException('Token inválido o expirado');
}
}
async changePin(userId, currentPin, newPin) {
const user = await this.userRepository.findOne({
where: { id: userId },
});
if (!user) {
throw new common_1.BadRequestException('Usuario no encontrado');
}
const isValidPin = await bcrypt.compare(currentPin, user.pinHash);
if (!isValidPin) {
throw new common_1.UnauthorizedException('PIN actual incorrecto');
}
user.pinHash = await bcrypt.hash(newPin, 10);
await this.userRepository.save(user);
}
generateTokens(user, tenant) {
const payload = {
sub: user.id,
tenantId: tenant.id,
phone: user.phone,
role: user.role,
};
const accessToken = this.jwtService.sign(payload, {
expiresIn: this.configService.get('JWT_EXPIRES_IN', '24h'),
});
const refreshToken = this.jwtService.sign(payload, {
expiresIn: this.configService.get('JWT_REFRESH_EXPIRES_IN', '7d'),
});
return {
accessToken,
refreshToken,
user: {
id: user.id,
name: user.name,
role: user.role,
phone: user.phone,
},
tenant: {
id: tenant.id,
name: tenant.name,
slug: tenant.slug,
businessType: tenant.businessType,
subscriptionStatus: tenant.subscriptionStatus,
},
};
}
};
exports.AuthService = AuthService;
exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)),
__param(1, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
__metadata("design:paramtypes", [typeorm_2.Repository,
typeorm_2.Repository,
jwt_1.JwtService,
config_1.ConfigService])
], AuthService);
//# sourceMappingURL=auth.service.js.map