feat: remove OTP gate from transactions, fix categories auth, add implementation plan

- Remove OtpGateGuard from transactions controller (OTP verified at login)
- Fix categories controller to use authenticated user instead of TEMP_USER_ID
- Add comprehensive implementation plan document
- Update .env.example with WEB_APP_URL
- Prepare for admin dashboard development
This commit is contained in:
dwindown
2025-10-11 14:00:11 +07:00
parent 0da6071eb3
commit 249f3a9d7d
159 changed files with 13748 additions and 3369 deletions

83
apps/api/dist/auth/auth.controller.d.ts vendored Normal file
View File

@@ -0,0 +1,83 @@
import { AuthService } from './auth.service';
import type { Response } from 'express';
interface RequestWithUser {
user: {
userId: string;
email: string;
};
}
export declare class AuthController {
private authService;
constructor(authService: AuthService);
register(body: {
email: string;
password: string;
name?: string;
}): Promise<{
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
}>;
login(body: {
email: string;
password: string;
}): Promise<{
requiresOtp: boolean;
availableMethods: {
email: boolean;
whatsapp: boolean;
totp: boolean;
};
tempToken: string;
user?: undefined;
token?: undefined;
} | {
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
requiresOtp?: undefined;
availableMethods?: undefined;
tempToken?: undefined;
}>;
verifyOtp(body: {
tempToken: string;
otpCode: string;
method: 'email' | 'totp';
}): Promise<{
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
}>;
googleAuth(): Promise<void>;
googleAuthCallback(req: any, res: Response): Promise<void>;
getProfile(req: RequestWithUser): Promise<{
id: string;
email: string;
emailVerified: boolean;
name: string | null;
avatarUrl: string | null;
}>;
changePassword(req: RequestWithUser, body: {
currentPassword: string;
newPassword: string;
isSettingPassword?: boolean;
}): Promise<{
message: string;
}>;
}
export {};

112
apps/api/dist/auth/auth.controller.js vendored Normal file
View File

@@ -0,0 +1,112 @@
"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.AuthController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("./auth.guard");
const passport_1 = require("@nestjs/passport");
const auth_service_1 = require("./auth.service");
let AuthController = class AuthController {
authService;
constructor(authService) {
this.authService = authService;
}
async register(body) {
return this.authService.register(body.email, body.password, body.name);
}
async login(body) {
return this.authService.login(body.email, body.password);
}
async verifyOtp(body) {
return this.authService.verifyOtpAndLogin(body.tempToken, body.otpCode, body.method);
}
async googleAuth() {
}
async googleAuthCallback(req, res) {
const result = await this.authService.googleLogin(req.user);
const frontendUrl = process.env.WEB_APP_URL || 'http://localhost:5174';
if (result.requiresOtp) {
res.redirect(`${frontendUrl}/auth/otp?token=${result.tempToken}&methods=${JSON.stringify(result.availableMethods)}`);
}
else {
res.redirect(`${frontendUrl}/auth/callback?token=${result.token}`);
}
}
async getProfile(req) {
return this.authService.getUserProfile(req.user.userId);
}
async changePassword(req, body) {
return this.authService.changePassword(req.user.userId, body.currentPassword, body.newPassword, body.isSettingPassword);
}
};
exports.AuthController = AuthController;
__decorate([
(0, common_1.Post)('register'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "register", null);
__decorate([
(0, common_1.Post)('login'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "login", null);
__decorate([
(0, common_1.Post)('verify-otp'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "verifyOtp", null);
__decorate([
(0, common_1.Get)('google'),
(0, common_1.UseGuards)((0, passport_1.AuthGuard)('google')),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AuthController.prototype, "googleAuth", null);
__decorate([
(0, common_1.Get)('google/callback'),
(0, common_1.UseGuards)((0, passport_1.AuthGuard)('google')),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "googleAuthCallback", null);
__decorate([
(0, common_1.Get)('me'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "getProfile", null);
__decorate([
(0, common_1.Post)('change-password'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "changePassword", null);
exports.AuthController = AuthController = __decorate([
(0, common_1.Controller)('auth'),
__metadata("design:paramtypes", [auth_service_1.AuthService])
], AuthController);
//# sourceMappingURL=auth.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":"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"}

View File

@@ -1,8 +1,9 @@
import { CanActivate, ExecutionContext } from '@nestjs/common';
import { FirebaseService } from './firebase.service';
export declare class AuthGuard implements CanActivate {
private firebaseService;
constructor(firebaseService: FirebaseService);
canActivate(context: ExecutionContext): Promise<boolean>;
private extractTokenFromHeader;
import { ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
declare const AuthGuard_base: import("@nestjs/passport").Type<import("@nestjs/passport").IAuthGuard>;
export declare class AuthGuard extends AuthGuard_base {
private reflector;
constructor(reflector: Reflector);
canActivate(context: ExecutionContext): boolean | Promise<boolean> | import("rxjs").Observable<boolean>;
}
export {};

View File

@@ -11,39 +11,28 @@ var __metadata = (this && this.__metadata) || function (k, v) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthGuard = void 0;
const common_1 = require("@nestjs/common");
const firebase_service_1 = require("./firebase.service");
let AuthGuard = class AuthGuard {
firebaseService;
constructor(firebaseService) {
this.firebaseService = firebaseService;
const core_1 = require("@nestjs/core");
const passport_1 = require("@nestjs/passport");
let AuthGuard = class AuthGuard extends (0, passport_1.AuthGuard)('jwt') {
reflector;
constructor(reflector) {
super();
this.reflector = reflector;
}
async canActivate(context) {
const request = context.switchToHttp().getRequest();
if (!this.firebaseService.isFirebaseConfigured()) {
console.warn('⚠️ Firebase not configured - allowing request without auth');
canActivate(context) {
const isPublic = this.reflector.getAllAndOverride('isPublic', [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new common_1.UnauthorizedException('No token provided');
}
try {
const decodedToken = await this.firebaseService.verifyIdToken(token);
request.user = decodedToken;
return true;
}
catch (error) {
throw new common_1.UnauthorizedException('Invalid token');
}
}
extractTokenFromHeader(request) {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
return super.canActivate(context);
}
};
exports.AuthGuard = AuthGuard;
exports.AuthGuard = AuthGuard = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [firebase_service_1.FirebaseService])
__metadata("design:paramtypes", [core_1.Reflector])
], AuthGuard);
//# sourceMappingURL=auth.guard.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/auth/auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAkG;AAClG,yDAAqD;AAG9C,IAAM,SAAS,GAAf,MAAM,SAAS;IACA;IAApB,YAAoB,eAAgC;QAAhC,oBAAe,GAAf,eAAe,CAAiB;IAAG,CAAC;IAExD,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAGpD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,EAAE,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC,mBAAmB,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,OAAY;QACzC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;CACF,CAAA;AA/BY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;qCAE0B,kCAAe;GADzC,SAAS,CA+BrB"}
{"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/auth/auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA8D;AAC9D,uCAAyC;AACzC,+CAAkE;AAG3D,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,IAAA,oBAAiB,EAAC,KAAK,CAAC;IACjC;IAApB,YAAoB,SAAoB;QACtC,KAAK,EAAE,CAAC;QADU,cAAS,GAAT,SAAS,CAAW;IAExC,CAAC;IAED,WAAW,CAAC,OAAyB;QAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAU,UAAU,EAAE;YACrE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QAEH,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;CACF,CAAA;AAlBY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;qCAEoB,gBAAS;GAD7B,SAAS,CAkBrB"}

View File

@@ -8,15 +8,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthModule = void 0;
const common_1 = require("@nestjs/common");
const firebase_service_1 = require("./firebase.service");
const auth_guard_1 = require("./auth.guard");
const jwt_1 = require("@nestjs/jwt");
const passport_1 = require("@nestjs/passport");
const auth_controller_1 = require("./auth.controller");
const auth_service_1 = require("./auth.service");
const jwt_strategy_1 = require("./jwt.strategy");
const google_strategy_1 = require("./google.strategy");
const prisma_module_1 = require("../prisma/prisma.module");
const otp_module_1 = require("../otp/otp.module");
let AuthModule = class AuthModule {
};
exports.AuthModule = AuthModule;
exports.AuthModule = AuthModule = __decorate([
(0, common_1.Module)({
providers: [firebase_service_1.FirebaseService, auth_guard_1.AuthGuard],
exports: [firebase_service_1.FirebaseService, auth_guard_1.AuthGuard],
imports: [
prisma_module_1.PrismaModule,
passport_1.PassportModule,
(0, common_1.forwardRef)(() => otp_module_1.OtpModule),
jwt_1.JwtModule.register({
secret: process.env.JWT_SECRET || 'your-secret-key',
signOptions: { expiresIn: '7d' },
}),
],
controllers: [auth_controller_1.AuthController],
providers: [auth_service_1.AuthService, jwt_strategy_1.JwtStrategy, google_strategy_1.GoogleStrategy],
exports: [auth_service_1.AuthService],
})
], AuthModule);
//# sourceMappingURL=auth.module.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,yDAAqD;AACrD,6CAAyC;AAMlC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAJtB,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;QACvC,OAAO,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;KACtC,CAAC;GACW,UAAU,CAAG"}
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAoD;AACpD,qCAAwC;AACxC,+CAAkD;AAClD,uDAAmD;AACnD,iDAA6C;AAC7C,iDAA6C;AAC7C,uDAAmD;AACnD,2DAAuD;AACvD,kDAA8C;AAgBvC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAdtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,4BAAY;YACZ,yBAAc;YACd,IAAA,mBAAU,EAAC,GAAG,EAAE,CAAC,sBAAS,CAAC;YAC3B,eAAS,CAAC,QAAQ,CAAC;gBACjB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,iBAAiB;gBACnD,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aACjC,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,EAAE,0BAAW,EAAE,gCAAc,CAAC;QACrD,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAAG"}

93
apps/api/dist/auth/auth.service.d.ts vendored Normal file
View File

@@ -0,0 +1,93 @@
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
import { OtpService } from '../otp/otp.service';
export declare class AuthService {
private readonly prisma;
private readonly jwtService;
private readonly otpService;
constructor(prisma: PrismaService, jwtService: JwtService, otpService: OtpService);
register(email: string, password: string, name?: string): Promise<{
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
}>;
login(email: string, password: string): Promise<{
requiresOtp: boolean;
availableMethods: {
email: boolean;
whatsapp: boolean;
totp: boolean;
};
tempToken: string;
user?: undefined;
token?: undefined;
} | {
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
requiresOtp?: undefined;
availableMethods?: undefined;
tempToken?: undefined;
}>;
googleLogin(googleProfile: {
googleId: string;
email: string;
name: string;
avatarUrl?: string;
}): Promise<{
requiresOtp: boolean;
availableMethods: {
email: boolean;
whatsapp: boolean;
totp: boolean;
};
tempToken: string;
user?: undefined;
token?: undefined;
} | {
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
requiresOtp?: undefined;
availableMethods?: undefined;
tempToken?: undefined;
}>;
verifyOtpAndLogin(tempToken: string, otpCode: string, method: 'email' | 'whatsapp' | 'totp'): Promise<{
user: {
id: string;
email: string;
name: string | null;
avatarUrl: string | null;
emailVerified: boolean;
};
token: string;
}>;
private generateToken;
private generateTempToken;
getUserProfile(userId: string): Promise<{
id: string;
email: string;
emailVerified: boolean;
name: string | null;
avatarUrl: string | null;
}>;
changePassword(userId: string, currentPassword: string, newPassword: string, isSettingPassword?: boolean): Promise<{
message: string;
}>;
private downloadAndStoreAvatar;
}

404
apps/api/dist/auth/auth.service.js vendored Normal file
View File

@@ -0,0 +1,404 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
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 __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
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); }
};
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 common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
const prisma_service_1 = require("../prisma/prisma.service");
const otp_service_1 = require("../otp/otp.service");
const bcrypt = __importStar(require("bcrypt"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const axios_1 = __importDefault(require("axios"));
let AuthService = class AuthService {
prisma;
jwtService;
otpService;
constructor(prisma, jwtService, otpService) {
this.prisma = prisma;
this.jwtService = jwtService;
this.otpService = otpService;
}
async register(email, password, name) {
const existing = await this.prisma.user.findUnique({ where: { email } });
if (existing) {
throw new common_1.ConflictException('Email already registered');
}
const passwordHash = await bcrypt.hash(password, 10);
const user = await this.prisma.user.create({
data: {
email,
passwordHash,
name,
emailVerified: false,
},
});
const token = this.generateToken(user.id, user.email);
return {
user: {
id: user.id,
email: user.email,
name: user.name,
avatarUrl: user.avatarUrl,
emailVerified: user.emailVerified,
},
token,
};
}
async login(email, password) {
const user = await this.prisma.user.findUnique({
where: { email },
select: {
id: true,
email: true,
passwordHash: true,
name: true,
avatarUrl: true,
emailVerified: true,
otpEmailEnabled: true,
otpWhatsappEnabled: true,
otpTotpEnabled: true,
},
});
if (!user || !user.passwordHash) {
throw new common_1.UnauthorizedException('Invalid credentials');
}
const isValid = await bcrypt.compare(password, user.passwordHash);
if (!isValid) {
throw new common_1.UnauthorizedException('Invalid credentials');
}
const requiresOtp = user.otpEmailEnabled || user.otpWhatsappEnabled || user.otpTotpEnabled;
if (requiresOtp) {
if (user.otpEmailEnabled) {
try {
await this.otpService.sendEmailOtp(user.id);
}
catch (error) {
console.error('Failed to send email OTP during login:', error);
}
}
if (user.otpWhatsappEnabled) {
try {
await this.otpService.sendWhatsappOtp(user.id, 'live');
}
catch (error) {
console.error('Failed to send WhatsApp OTP during login:', error);
}
}
return {
requiresOtp: true,
availableMethods: {
email: user.otpEmailEnabled,
whatsapp: user.otpWhatsappEnabled,
totp: user.otpTotpEnabled,
},
tempToken: this.generateTempToken(user.id, user.email),
};
}
const token = this.generateToken(user.id, user.email);
return {
user: {
id: user.id,
email: user.email,
name: user.name,
avatarUrl: user.avatarUrl,
emailVerified: user.emailVerified,
},
token,
};
}
async googleLogin(googleProfile) {
let user = await this.prisma.user.findUnique({
where: { email: googleProfile.email },
});
if (!user) {
user = await this.prisma.user.create({
data: {
email: googleProfile.email,
name: googleProfile.name,
avatarUrl: googleProfile.avatarUrl,
emailVerified: true,
authAccounts: {
create: {
provider: 'google',
issuer: 'google.com',
subject: googleProfile.googleId,
},
},
},
});
}
else {
const existingAuth = await this.prisma.authAccount.findUnique({
where: {
issuer_subject: {
issuer: 'google.com',
subject: googleProfile.googleId,
},
},
});
if (!existingAuth) {
await this.prisma.authAccount.create({
data: {
userId: user.id,
provider: 'google',
issuer: 'google.com',
subject: googleProfile.googleId,
},
});
}
console.log('Updating user with Google profile:', {
name: googleProfile.name,
avatarUrl: googleProfile.avatarUrl,
});
let avatarUrl = user.avatarUrl;
if (googleProfile.avatarUrl) {
try {
avatarUrl = await this.downloadAndStoreAvatar(googleProfile.avatarUrl, user.id);
}
catch (error) {
console.error('Failed to download avatar:', error);
avatarUrl = googleProfile.avatarUrl;
}
}
user = await this.prisma.user.update({
where: { id: user.id },
data: {
name: googleProfile.name || user.name,
avatarUrl: avatarUrl || user.avatarUrl,
emailVerified: true,
},
});
console.log('User updated, avatar:', user.avatarUrl);
}
const requiresOtp = user.otpEmailEnabled || user.otpWhatsappEnabled || user.otpTotpEnabled;
if (requiresOtp) {
if (user.otpEmailEnabled) {
try {
await this.otpService.sendEmailOtp(user.id);
}
catch (error) {
console.error('Failed to send email OTP during Google login:', error);
}
}
if (user.otpWhatsappEnabled) {
try {
await this.otpService.sendWhatsappOtp(user.id, 'live');
}
catch (error) {
console.error('Failed to send WhatsApp OTP during Google login:', error);
}
}
return {
requiresOtp: true,
availableMethods: {
email: user.otpEmailEnabled,
whatsapp: user.otpWhatsappEnabled,
totp: user.otpTotpEnabled,
},
tempToken: this.generateTempToken(user.id, user.email),
};
}
const token = this.generateToken(user.id, user.email);
return {
user: {
id: user.id,
email: user.email,
name: user.name,
avatarUrl: user.avatarUrl,
emailVerified: user.emailVerified,
},
token,
};
}
async verifyOtpAndLogin(tempToken, otpCode, method) {
let payload;
try {
payload = this.jwtService.verify(tempToken);
}
catch {
throw new common_1.UnauthorizedException('Invalid or expired token');
}
if (!payload.temp) {
throw new common_1.UnauthorizedException('Invalid token type');
}
const userId = payload.userId || payload.sub;
const email = payload.email;
if (!userId || !email) {
throw new common_1.UnauthorizedException('Invalid token payload');
}
const user = await this.prisma.user.findUnique({
where: { id: userId },
});
if (!user) {
throw new common_1.UnauthorizedException('User not found');
}
if (method === 'email') {
const isValid = this.otpService.verifyEmailOtpForLogin(userId, otpCode);
if (!isValid) {
throw new common_1.UnauthorizedException('Invalid or expired email OTP code');
}
}
else if (method === 'whatsapp') {
const isValid = this.otpService.verifyWhatsappOtpForLogin(userId, otpCode);
if (!isValid) {
throw new common_1.UnauthorizedException('Invalid or expired WhatsApp OTP code');
}
}
else if (method === 'totp') {
if (!user.otpTotpSecret) {
throw new common_1.UnauthorizedException('TOTP not set up');
}
const { authenticator } = await import('otplib');
const isValid = authenticator.verify({
token: otpCode,
secret: user.otpTotpSecret,
});
if (!isValid) {
throw new common_1.UnauthorizedException('Invalid TOTP code');
}
}
const token = this.generateToken(userId, email);
return {
user: {
id: user.id,
email: user.email,
name: user.name,
avatarUrl: user.avatarUrl,
emailVerified: user.emailVerified,
},
token,
};
}
generateToken(userId, email) {
return this.jwtService.sign({
sub: userId,
email,
});
}
generateTempToken(userId, email) {
return this.jwtService.sign({ userId, email, temp: true }, { expiresIn: '5m' });
}
async getUserProfile(userId) {
const user = await this.prisma.user.findUnique({
where: { id: userId },
select: {
id: true,
email: true,
name: true,
avatarUrl: true,
emailVerified: true,
},
});
if (!user) {
throw new common_1.UnauthorizedException('User not found');
}
return user;
}
async changePassword(userId, currentPassword, newPassword, isSettingPassword) {
const user = await this.prisma.user.findUnique({
where: { id: userId },
select: { passwordHash: true },
});
if (!user) {
throw new common_1.BadRequestException('User not found');
}
if (isSettingPassword && !user.passwordHash) {
const newPasswordHash = await bcrypt.hash(newPassword, 10);
await this.prisma.user.update({
where: { id: userId },
data: { passwordHash: newPasswordHash },
});
return { message: 'Password set successfully' };
}
if (!user.passwordHash) {
throw new common_1.BadRequestException('Cannot change password for this account');
}
const isValid = await bcrypt.compare(currentPassword, user.passwordHash);
if (!isValid) {
throw new common_1.UnauthorizedException('Current password is incorrect');
}
const newPasswordHash = await bcrypt.hash(newPassword, 10);
await this.prisma.user.update({
where: { id: userId },
data: { passwordHash: newPasswordHash },
});
return { message: 'Password changed successfully' };
}
async downloadAndStoreAvatar(avatarUrl, userId) {
try {
const uploadsDir = path.join(process.cwd(), 'public', 'avatars');
if (!fs.existsSync(uploadsDir)) {
fs.mkdirSync(uploadsDir, { recursive: true });
}
const response = await axios_1.default.get(avatarUrl, {
responseType: 'arraybuffer',
});
const ext = 'jpg';
const filename = `${userId}.${ext}`;
const filepath = path.join(uploadsDir, filename);
fs.writeFileSync(filepath, response.data);
return `/avatars/${filename}`;
}
catch (error) {
console.error('Error downloading avatar:', error);
throw error;
}
}
};
exports.AuthService = AuthService;
exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => otp_service_1.OtpService))),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
jwt_1.JwtService,
otp_service_1.OtpService])
], AuthService);
//# sourceMappingURL=auth.service.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
import * as admin from 'firebase-admin';
export declare class FirebaseService {
private app;
private isConfigured;
constructor();
verifyIdToken(idToken: string): Promise<admin.auth.DecodedIdToken>;
getUser(uid: string): Promise<admin.auth.UserRecord>;
isFirebaseConfigured(): boolean;
}

View File

@@ -1,113 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
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 __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirebaseService = void 0;
const common_1 = require("@nestjs/common");
const admin = __importStar(require("firebase-admin"));
let FirebaseService = class FirebaseService {
app = null;
isConfigured = false;
constructor() {
const projectId = process.env.FIREBASE_PROJECT_ID;
const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;
const privateKey = process.env.FIREBASE_PRIVATE_KEY;
if (projectId && clientEmail && privateKey) {
try {
if (!admin.apps.length) {
this.app = admin.initializeApp({
credential: admin.credential.cert({
projectId,
clientEmail,
privateKey: privateKey.replace(/\\n/g, '\n'),
}),
});
}
else {
this.app = admin.app();
}
this.isConfigured = true;
console.log('✅ Firebase Admin initialized successfully');
}
catch (error) {
console.warn('⚠️ Firebase Admin initialization failed:', error.message);
this.isConfigured = false;
}
}
else {
console.warn('⚠️ Firebase credentials not found. Auth will use fallback mode.');
this.isConfigured = false;
}
}
async verifyIdToken(idToken) {
if (!this.isConfigured || !this.app) {
throw new Error('Firebase not configured');
}
try {
return await admin.auth().verifyIdToken(idToken);
}
catch (error) {
throw new Error('Invalid token');
}
}
async getUser(uid) {
if (!this.isConfigured || !this.app) {
throw new Error('Firebase not configured');
}
try {
return await admin.auth().getUser(uid);
}
catch (error) {
throw new Error('User not found');
}
}
isFirebaseConfigured() {
return this.isConfigured;
}
};
exports.FirebaseService = FirebaseService;
exports.FirebaseService = FirebaseService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], FirebaseService);
//# sourceMappingURL=firebase.service.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"firebase.service.js","sourceRoot":"","sources":["../../src/auth/firebase.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,sDAAwC;AAGjC,IAAM,eAAe,GAArB,MAAM,eAAe;IAClB,GAAG,GAAyB,IAAI,CAAC;IACjC,YAAY,GAAY,KAAK,CAAC;IAEtC;QAEE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAClD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QACtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAEpD,IAAI,SAAS,IAAI,WAAW,IAAI,UAAU,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACvB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,aAAa,CAAC;wBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;4BAChC,SAAS;4BACT,WAAW;4BACX,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;yBAC7C,CAAC;qBACH,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACzB,CAAC;gBACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YAC3D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;YAC5B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;YAChF,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAe;QACjC,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;CACF,CAAA;AA5DY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;;GACA,eAAe,CA4D3B"}

View File

@@ -0,0 +1,9 @@
import { Strategy, VerifyCallback } from 'passport-google-oauth20';
declare const GoogleStrategy_base: new (...args: [options: import("passport-google-oauth20").StrategyOptionsWithRequest] | [options: import("passport-google-oauth20").StrategyOptions] | [options: import("passport-google-oauth20").StrategyOptions] | [options: import("passport-google-oauth20").StrategyOptionsWithRequest]) => Strategy & {
validate(...args: any[]): unknown;
};
export declare class GoogleStrategy extends GoogleStrategy_base {
constructor();
validate(accessToken: string, refreshToken: string, profile: any, done: VerifyCallback): Promise<any>;
}
export {};

42
apps/api/dist/auth/google.strategy.js vendored Normal file
View File

@@ -0,0 +1,42 @@
"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GoogleStrategy = void 0;
const common_1 = require("@nestjs/common");
const passport_1 = require("@nestjs/passport");
const passport_google_oauth20_1 = require("passport-google-oauth20");
let GoogleStrategy = class GoogleStrategy extends (0, passport_1.PassportStrategy)(passport_google_oauth20_1.Strategy, 'google') {
constructor() {
super({
clientID: process.env.GOOGLE_CLIENT_ID || '',
clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
callbackURL: process.env.GOOGLE_CALLBACK_URL ||
'http://localhost:3001/api/auth/google/callback',
scope: ['email', 'profile'],
});
}
async validate(accessToken, refreshToken, profile, done) {
const { id, name, emails, photos } = profile;
const user = {
googleId: id,
email: emails[0].value,
name: name.givenName + ' ' + name.familyName,
avatarUrl: photos[0]?.value,
};
done(null, user);
}
};
exports.GoogleStrategy = GoogleStrategy;
exports.GoogleStrategy = GoogleStrategy = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], GoogleStrategy);
//# sourceMappingURL=google.strategy.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"google.strategy.js","sourceRoot":"","sources":["../../src/auth/google.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,+CAAoD;AACpD,qEAAmE;AAG5D,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,IAAA,2BAAgB,EAAC,kCAAQ,EAAE,QAAQ,CAAC;IACtE;QACE,KAAK,CAAC;YACJ,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE;YAC5C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE;YACpD,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,mBAAmB;gBAC/B,gDAAgD;YAClD,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,WAAmB,EACnB,YAAoB,EACpB,OAAY,EACZ,IAAoB;QAEpB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAE7C,MAAM,IAAI,GAAG;YACX,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;YACtB,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU;YAC5C,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK;SAC5B,CAAC;QAEF,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnB,CAAC;CACF,CAAA;AA7BY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;;GACA,cAAc,CA6B1B"}

18
apps/api/dist/auth/jwt.strategy.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
import { Strategy } from 'passport-jwt';
export interface JwtPayload {
sub: string;
email: string;
iat?: number;
exp?: number;
}
declare const JwtStrategy_base: new (...args: [opt: import("passport-jwt").StrategyOptionsWithRequest] | [opt: import("passport-jwt").StrategyOptionsWithoutRequest]) => Strategy & {
validate(...args: any[]): unknown;
};
export declare class JwtStrategy extends JwtStrategy_base {
constructor();
validate(payload: JwtPayload): Promise<{
userId: string;
email: string;
}>;
}
export {};

33
apps/api/dist/auth/jwt.strategy.js vendored Normal file
View File

@@ -0,0 +1,33 @@
"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JwtStrategy = void 0;
const common_1 = require("@nestjs/common");
const passport_1 = require("@nestjs/passport");
const passport_jwt_1 = require("passport-jwt");
let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(passport_jwt_1.Strategy) {
constructor() {
super({
jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET || 'your-secret-key-change-this',
});
}
async validate(payload) {
return { userId: payload.sub, email: payload.email };
}
};
exports.JwtStrategy = JwtStrategy;
exports.JwtStrategy = JwtStrategy = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], JwtStrategy);
//# sourceMappingURL=jwt.strategy.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../src/auth/jwt.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,+CAAoD;AACpD,+CAAoD;AAU7C,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;IACzD;QACE,KAAK,CAAC;YACJ,cAAc,EAAE,yBAAU,CAAC,2BAA2B,EAAE;YACxD,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,6BAA6B;SACrE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAmB;QAChC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC;CACF,CAAA;AAZY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;;GACA,WAAW,CAYvB"}