Feat build new

This commit is contained in:
mahmood
2026-10-07 21:26:54 +03:30
parent 5223de313a
commit 40a28d5605
257 changed files with 838 additions and 384 deletions
+461 -9
View File
@@ -83398,6 +83398,8 @@ var require_env = __commonJS({
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.envOr = envOr;
exports2.envOrNull = envOrNull;
exports2.envList = envList;
exports2.pickExactUri = pickExactUri;
function envOr(name, fallback) {
const raw = process.env[name];
const trimmed = typeof raw === "string" ? raw.trim() : "";
@@ -83408,6 +83410,18 @@ var require_env = __commonJS({
const trimmed = typeof raw === "string" ? raw.trim() : "";
return trimmed === "" ? null : trimmed;
}
function envList(name) {
const raw = envOrNull(name);
if (!raw)
return [];
return raw.split(",").map((item) => item.trim()).filter(Boolean);
}
function pickExactUri(requested, allowed) {
const unique = [...new Set(allowed.filter((item) => Boolean(item)))];
if (requested)
return unique.includes(requested) ? requested : null;
return unique[0] ?? null;
}
}
});
@@ -83492,6 +83506,9 @@ var require_iam_service = __commonJS({
body.tenant_slug = tenantSlug;
if (clientIp)
body.client_ip = clientIp;
const returnTo = (0, env_12.envOrNull)("IAM_ADMIN_BROWSER_RETURN_URL") || (0, env_12.envOrNull)("IAM_BROWSER_RETURN_URL");
if (returnTo)
body.return_to = returnTo;
const timeout = Number((0, env_12.envOr)("IAM_HTTP_TIMEOUT_MS", "8000"));
let response;
try {
@@ -83519,7 +83536,8 @@ var require_iam_service = __commonJS({
phoneNumber: user.phone_number ?? null,
firstName: user.first_name ?? null,
lastName: user.last_name ?? null,
sessionId: payload.session_id ?? null
sessionId: payload.session_id ?? null,
browserTicket: typeof payload.browser_ticket === "string" ? payload.browser_ticket : null
};
}
if ([401, 403, 422].includes(response.status)) {
@@ -83541,9 +83559,8 @@ var require_iam_service = __commonJS({
* and no way for a central sign-out to end it.
*
* The IAM only accepts this from a trusted confidential client carrying the
* explicit `passwordless_delegation_allowed` flag, and it never creates an
* account: an unknown user is reported as such so this app can carry on with
* its own local login.
* explicit `passwordless_delegation_allowed` flag. An unknown mobile is
* created there. A locked or inactive account is still refused.
*/
async attestOtpLogin(identifier, clientIp, factorReference) {
const body = {
@@ -83562,6 +83579,9 @@ var require_iam_service = __commonJS({
body.client_ip = clientIp;
if (factorReference)
body.factor_reference = factorReference;
const returnTo = (0, env_12.envOrNull)("IAM_BROWSER_RETURN_URL");
if (returnTo)
body.return_to = returnTo;
const timeout = Number((0, env_12.envOr)("IAM_HTTP_TIMEOUT_MS", "8000"));
let response;
try {
@@ -83586,7 +83606,8 @@ var require_iam_service = __commonJS({
phoneNumber: user.phone_number ?? null,
firstName: user.first_name ?? null,
lastName: user.last_name ?? null,
sessionId: payload.session_id ?? null
sessionId: payload.session_id ?? null,
browserTicket: typeof payload.browser_ticket === "string" ? payload.browser_ticket : null
};
}
const code = String(payload.error ?? "");
@@ -83599,11 +83620,63 @@ var require_iam_service = __commonJS({
this.logger.warn(`identity service returned ${response.status} for an OTP attestation`);
throw new IamUnavailableError(`identity service returned ${response.status}`);
}
browserBootstrapUrl(ticket) {
if (!ticket || !this.issuer)
return null;
return `${this.issuer}/auth/bootstrap?ticket=${encodeURIComponent(ticket)}`;
}
/** تبادل کد مجوز مرورگر. پاسخ از خود issuer و با راز کلاینت آمده است. */
async exchangeAuthorizationCode(code, codeVerifier, redirectUri) {
const timeout = Number((0, env_12.envOr)("IAM_HTTP_TIMEOUT_MS", "8000"));
const body = new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
code_verifier: codeVerifier,
client_id: this.clientId,
client_secret: (0, env_12.envOrNull)("IAM_CLIENT_SECRET")
});
let response;
try {
response = await fetch(`${this.issuer}/oauth/token`, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
body,
signal: AbortSignal.timeout(timeout)
});
} catch (error) {
throw new IamUnavailableError(`identity service unreachable: ${error.message}`);
}
const payload = await response.json().catch(() => ({}));
if (!response.ok || typeof payload.id_token !== "string") {
throw new IamUnavailableError(`identity service refused the authorization code (${response.status})`);
}
const claims = decodeIdToken(payload.id_token);
if (claims.iss !== this.issuer) {
throw new IamUnavailableError("identity token issuer does not match");
}
const aud = claims.aud;
const audiences = Array.isArray(aud) ? aud : [aud];
if (!audiences.includes(this.clientId)) {
throw new IamUnavailableError("identity token audience does not match");
}
return {
sub: String(claims.sub ?? ""),
phoneNumber: typeof claims.phone_number === "string" ? claims.phone_number : null,
sessionId: typeof claims.sid === "string" ? claims.sid : null
};
}
};
exports2.IamService = IamService;
exports2.IamService = IamService = IamService_1 = __decorate4([
(0, common_12.Injectable)()
], IamService);
function decodeIdToken(token) {
const part = token.split(".")[1];
if (!part)
throw new IamUnavailableError("identity token is malformed");
return JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
}
}
});
@@ -84291,6 +84364,7 @@ var require_customer_auth_service = __commonJS({
exports2.masterOtpCode = masterOtpCode;
exports2.masterOtpEnabled = masterOtpEnabled;
exports2.customerJwtSecret = customerJwtSecret;
var node_crypto_1 = require("node:crypto");
var common_12 = require_common();
var jwt_1 = (init_dist(), __toCommonJS(dist_exports));
var client_1 = require("@prisma/client");
@@ -84320,6 +84394,15 @@ var require_customer_auth_service = __commonJS({
function masterOtpEnabled() {
return masterOtpCode() !== null;
}
function mobileVariants(raw) {
const digits = raw.replace(/\D/g, "");
const variants = /* @__PURE__ */ new Set([raw.trim(), digits]);
if (digits.startsWith("98") && digits.length >= 12)
variants.add(`0${digits.slice(2)}`);
if (digits.startsWith("0") && digits.length === 11)
variants.add(`98${digits.slice(1)}`);
return [...variants].filter((value) => value !== "");
}
function maskMobile(mobile) {
return mobile.length < 7 ? null : `${mobile.slice(0, 4)}***${mobile.slice(-4)}`;
}
@@ -84561,15 +84644,15 @@ var require_customer_auth_service = __commonJS({
const identity = await this.attestToIam(mobile, ip);
const expert = await this.resolveExpertPrincipal(mobile);
if (expert) {
return {
return this.withBootstrap({
token: await this.issueExpertToken(expert.adminUserId, mobile, { identity, ip }),
customer: { id: expert.tradingCustomerId, mobile }
};
}, identity);
}
return {
return this.withBootstrap({
token: await this.issueToken(challenge.customer.id, challenge.customer.mobile, { identity, ip }),
customer: { id: challenge.customer.id, mobile: challenge.customer.mobile }
};
}, identity);
}
/**
* D21 — is this mobile an active sales expert with a usable trading account?
@@ -84639,6 +84722,129 @@ var require_customer_auth_service = __commonJS({
* Reference reused api_token forever once set (:60-62); a fresh token is
* issued on every verify here (T1).
*/
/**
* شروع بررسی بی‌صدای نشست IAM. کوکی امضاشده code_verifier را نگه می‌دارد
* تا در آدرس بازگشت دیده نشود.
*/
beginBrowserSso(requestedRedirect) {
if (!this.iam.enabled)
return null;
const redirectUri = (0, env_12.pickExactUri)(requestedRedirect, [
(0, env_12.envOrNull)("IAM_REDIRECT_URI"),
...(0, env_12.envList)("IAM_REDIRECT_URIS")
]);
const clientId = (0, env_12.envOrNull)("IAM_CLIENT_ID");
if (!redirectUri || !clientId)
return null;
const state = (0, node_crypto_1.randomBytes)(24).toString("base64url");
const nonce = (0, node_crypto_1.randomBytes)(24).toString("base64url");
const verifier = (0, node_crypto_1.randomBytes)(48).toString("base64url");
const challenge = (0, node_crypto_1.createHash)("sha256").update(verifier).digest("base64url");
const payload = Buffer.from(JSON.stringify({ state, nonce, verifier, redirectUri })).toString("base64url");
const sig = (0, node_crypto_1.createHmac)("sha256", this.ssoSecret()).update(payload).digest("base64url");
const secure = redirectUri.startsWith("https:");
const cookie = `gb_iam_sso=${payload}.${sig}; HttpOnly; Path=/; Max-Age=180; SameSite=Lax` + (secure ? "; Secure" : "");
const url = new URL(`${this.iam.issuer}/oauth/authorize`);
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", clientId);
url.searchParams.set("redirect_uri", redirectUri);
url.searchParams.set("scope", "openid profile email");
url.searchParams.set("state", state);
url.searchParams.set("nonce", nonce);
url.searchParams.set("code_challenge", challenge);
url.searchParams.set("code_challenge_method", "S256");
url.searchParams.set("prompt", "none");
return { authorizeUrl: url.toString(), cookie };
}
async completeBrowserSso(cookieValue, code, state, ip) {
const pending = this.readSsoCookie(cookieValue);
if (!pending || pending.state !== state) {
throw new common_12.UnauthorizedException("\u062F\u0631\u062E\u0648\u0627\u0633\u062A \u0648\u0631\u0648\u062F \u0645\u0634\u062A\u0631\u06A9 \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A");
}
const claims = await this.iam.exchangeAuthorizationCode(code, pending.verifier, pending.redirectUri);
if (!claims.phoneNumber || !claims.sub) {
throw new common_12.UnauthorizedException("\u0647\u0648\u06CC\u062A \u0645\u0634\u062A\u0631\u06A9 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0646\u062F\u0627\u0631\u062F");
}
const mobiles = mobileVariants(claims.phoneNumber);
let expert = null;
let expertMobile = claims.phoneNumber;
for (const candidate of mobiles) {
expert = await this.resolveExpertPrincipal(candidate);
if (expert) {
expertMobile = candidate;
break;
}
}
const identity = {
sub: claims.sub,
email: null,
phoneNumber: claims.phoneNumber,
firstName: null,
lastName: null,
sessionId: claims.sessionId,
browserTicket: null
};
if (expert) {
return {
token: await this.issueExpertToken(expert.adminUserId, expertMobile, { identity, ip }),
customer: { id: expert.tradingCustomerId, mobile: expertMobile }
};
}
const customer = await this.prisma.customer.findFirst({
where: { mobile: { in: mobiles }, isActive: true, isArchived: false },
select: { id: true, mobile: true }
});
if (!customer) {
throw new common_12.UnauthorizedException("\u062D\u0633\u0627\u0628\u06CC \u0628\u0627 \u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u062F\u0631 \u0627\u06CC\u0646 \u0633\u0627\u0645\u0627\u0646\u0647 \u0646\u06CC\u0633\u062A");
}
return {
token: await this.issueToken(customer.id, customer.mobile, { identity, ip }),
customer: { id: customer.id, mobile: customer.mobile }
};
}
centralLogoutUrl(requestedReturn) {
if (!this.iam.enabled)
return null;
const redirect = (0, env_12.pickExactUri)(requestedReturn, [
(0, env_12.envOrNull)("IAM_POST_LOGOUT_REDIRECT_URI"),
(0, env_12.envOrNull)("IAM_BROWSER_RETURN_URL"),
...(0, env_12.envList)("IAM_ALLOWED_RETURN_URLS")
]);
const clientId = (0, env_12.envOrNull)("IAM_CLIENT_ID");
if (!redirect || !clientId)
return null;
const url = new URL(`${this.iam.issuer}/oauth/logout`);
url.searchParams.set("client_id", clientId);
url.searchParams.set("post_logout_redirect_uri", redirect);
return url.toString();
}
withBootstrap(body, identity) {
const url = this.iam.browserBootstrapUrl(identity?.browserTicket);
return url ? { ...body, iamBootstrapUrl: url } : body;
}
ssoSecret() {
return (0, env_12.envOrNull)("JWT_CUSTOMER_SECRET") || (0, env_12.envOrNull)("JWT_SECRET") || (0, env_12.envOr)("IAM_CLIENT_SECRET", "iam-sso");
}
readSsoCookie(value) {
if (!value || !value.includes("."))
return null;
const split = value.lastIndexOf(".");
const payload = value.slice(0, split);
const sig = value.slice(split + 1);
const expected = (0, node_crypto_1.createHmac)("sha256", this.ssoSecret()).update(payload).digest("base64url");
if (expected.length !== sig.length)
return null;
let same = 0;
for (let i = 0; i < expected.length; i++)
same |= expected.charCodeAt(i) ^ sig.charCodeAt(i);
if (same !== 0)
return null;
try {
return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
} catch {
return null;
}
}
async issueToken(customerId, mobile, context = {}) {
const jti = this.sessions.newTokenId();
const payload = {
@@ -84880,6 +85086,21 @@ var require_customer_auth_controller = __commonJS({
verifyOtp(dto, ip) {
return this.auth.verifyOtp(dto.username, dto.password, ip);
}
/** اگر نشست IAM در مرورگر باشد، آدرس authorize با prompt=none برمی‌گردد. */
startSso(redirectUri, res) {
const started = this.auth.beginBrowserSso(redirectUri);
if (!started)
return { enabled: false, authorize_url: null };
res.setHeader("Set-Cookie", started.cookie);
return { enabled: true, authorize_url: started.authorizeUrl };
}
ssoCallback(body, cookieHeader, ip, res) {
res.setHeader("Set-Cookie", "gb_iam_sso=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax");
return this.auth.completeBrowserSso(readCookie(cookieHeader, "gb_iam_sso"), body.code ?? "", body.state ?? "", ip);
}
ssoLogoutUrl(returnUrl) {
return { logout_url: this.auth.centralLogoutUrl(returnUrl) };
}
me(me) {
return this.customers.getOrThrow(me.id);
}
@@ -84911,6 +85132,35 @@ var require_customer_auth_controller = __commonJS({
__metadata3("design:paramtypes", [verify_otp_dto_1.VerifyOtpDto, String]),
__metadata3("design:returntype", void 0)
], CustomerAuthController.prototype, "verifyOtp", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Get)("auth/sso/start"),
__param3(0, (0, common_12.Query)("redirect_uri")),
__param3(1, (0, common_12.Res)({ passthrough: true })),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [Object, Object]),
__metadata3("design:returntype", void 0)
], CustomerAuthController.prototype, "startSso", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Post)("auth/sso/callback"),
(0, common_12.HttpCode)(200),
__param3(0, (0, common_12.Body)()),
__param3(1, (0, common_12.Headers)("cookie")),
__param3(2, (0, common_12.Ip)()),
__param3(3, (0, common_12.Res)({ passthrough: true })),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [Object, Object, String, Object]),
__metadata3("design:returntype", void 0)
], CustomerAuthController.prototype, "ssoCallback", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Get)("auth/sso/logout-url"),
__param3(0, (0, common_12.Query)("return_url")),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [String]),
__metadata3("design:returntype", void 0)
], CustomerAuthController.prototype, "ssoLogoutUrl", null);
__decorate4([
(0, customer_guards_1.CustomerAuth)(),
(0, common_12.Get)("me"),
@@ -84942,6 +85192,16 @@ var require_customer_auth_controller = __commonJS({
customers_service_1.CustomersService
])
], CustomerAuthController);
function readCookie(header, name) {
if (!header)
return null;
for (const part of header.split(";")) {
const [key, ...rest] = part.trim().split("=");
if (key === name)
return decodeURIComponent(rest.join("="));
}
return null;
}
}
});
@@ -87469,12 +87729,14 @@ var require_auth_service = __commonJS({
var AuthService_1;
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.AuthService = void 0;
var node_crypto_1 = require("node:crypto");
var common_12 = require_common();
var jwt_1 = (init_dist(), __toCommonJS(dist_exports));
var bcrypt = __importStar2(require_umd());
var prisma_service_1 = require_prisma_service();
var iam_service_1 = require_iam_service();
var admin_session_service_1 = require_admin_session_service();
var env_12 = require_env();
var AuthService = AuthService_1 = class AuthService {
prisma;
jwt;
@@ -87529,6 +87791,110 @@ var require_auth_service = __commonJS({
userAgent: userAgent ?? null
});
}
const bootstrap2 = this.iam.browserBootstrapUrl(verified.identity?.browserTicket);
return {
id: user.id,
name: user.fullName,
fullName: user.fullName,
mobile: user.mobile,
role: user.role,
ut: user.userTypeId,
branch_id: user.branchId,
api_token: apiToken,
roles: (user.userType?.permissions ?? []).map((p) => ({ rid: p.rid })),
...bootstrap2 ? { iamBootstrapUrl: bootstrap2 } : {}
};
}
beginBrowserSso(requestedRedirect) {
if (!this.iam.enabled)
return null;
const redirectUri = (0, env_12.pickExactUri)(requestedRedirect, [
(0, env_12.envOrNull)("IAM_ADMIN_REDIRECT_URI"),
...(0, env_12.envList)("IAM_ADMIN_REDIRECT_URIS")
]);
const clientId = (0, env_12.envOrNull)("IAM_CLIENT_ID");
if (!redirectUri || !clientId)
return null;
const state = (0, node_crypto_1.randomBytes)(24).toString("base64url");
const nonce = (0, node_crypto_1.randomBytes)(24).toString("base64url");
const verifier = (0, node_crypto_1.randomBytes)(48).toString("base64url");
const challenge = (0, node_crypto_1.createHash)("sha256").update(verifier).digest("base64url");
const payload = Buffer.from(JSON.stringify({ state, nonce, verifier, redirectUri })).toString("base64url");
const sig = (0, node_crypto_1.createHmac)("sha256", this.ssoSecret()).update(payload).digest("base64url");
const secure = redirectUri.startsWith("https:");
const cookie = `gb_admin_iam_sso=${payload}.${sig}; HttpOnly; Path=/; Max-Age=180; SameSite=Lax` + (secure ? "; Secure" : "");
const url = new URL(`${this.iam.issuer}/oauth/authorize`);
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", clientId);
url.searchParams.set("redirect_uri", redirectUri);
url.searchParams.set("scope", "openid profile email");
url.searchParams.set("state", state);
url.searchParams.set("nonce", nonce);
url.searchParams.set("code_challenge", challenge);
url.searchParams.set("code_challenge_method", "S256");
url.searchParams.set("prompt", "none");
return { authorizeUrl: url.toString(), cookie };
}
async completeBrowserSso(cookieValue, code, state, ip, userAgent) {
const pending = this.readSsoCookie(cookieValue);
if (!pending || pending.state !== state) {
throw new common_12.UnauthorizedException("\u062F\u0631\u062E\u0648\u0627\u0633\u062A \u0648\u0631\u0648\u062F \u0645\u0634\u062A\u0631\u06A9 \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A");
}
const claims = await this.iam.exchangeAuthorizationCode(code, pending.verifier, pending.redirectUri);
if (!claims.phoneNumber) {
throw new common_12.UnauthorizedException("\u0647\u0648\u06CC\u062A \u0645\u0634\u062A\u0631\u06A9 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0646\u062F\u0627\u0631\u062F");
}
const user = await this.prisma.adminUser.findFirst({
where: { mobile: { in: mobileVariants(claims.phoneNumber) }, isActive: true },
include: { userType: { include: { permissions: true } } }
});
if (!user) {
throw new common_12.UnauthorizedException("\u062D\u0633\u0627\u0628 \u0645\u062F\u06CC\u0631\u06CC \u0628\u0627 \u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u062F\u0631 \u0627\u06CC\u0646 \u0633\u0627\u0645\u0627\u0646\u0647 \u0646\u06CC\u0633\u062A");
}
const identity = {
sub: claims.sub,
email: null,
phoneNumber: claims.phoneNumber,
firstName: null,
lastName: null,
sessionId: claims.sessionId,
browserTicket: null
};
return this.issueAdminToken(user, identity, ip, userAgent);
}
centralLogoutUrl(requestedReturn) {
if (!this.iam.enabled)
return null;
const redirect = (0, env_12.pickExactUri)(requestedReturn, [
(0, env_12.envOrNull)("IAM_ADMIN_POST_LOGOUT_REDIRECT_URI"),
(0, env_12.envOrNull)("IAM_ADMIN_BROWSER_RETURN_URL"),
...(0, env_12.envList)("IAM_ADMIN_ALLOWED_RETURN_URLS")
]);
const clientId = (0, env_12.envOrNull)("IAM_CLIENT_ID");
if (!redirect || !clientId)
return null;
const url = new URL(`${this.iam.issuer}/oauth/logout`);
url.searchParams.set("client_id", clientId);
url.searchParams.set("post_logout_redirect_uri", redirect);
return url.toString();
}
async issueAdminToken(user, identity, ip, userAgent) {
const jti = this.sessions.newTokenId();
const apiToken = await this.jwt.signAsync({
sub: user.id,
mobile: user.mobile,
...jti ? { jti } : {}
});
if (jti) {
await this.sessions.record({
jti,
adminUserId: user.id,
iamSessionId: identity?.sessionId ?? null,
iamSub: identity?.sub ?? null,
ipAddress: ip ?? null,
userAgent: userAgent ?? null
});
}
return {
id: user.id,
name: user.fullName,
@@ -87541,6 +87907,29 @@ var require_auth_service = __commonJS({
roles: (user.userType?.permissions ?? []).map((p) => ({ rid: p.rid }))
};
}
ssoSecret() {
return (0, env_12.envOrNull)("JWT_SECRET") || (0, env_12.envOr)("IAM_CLIENT_SECRET", "iam-sso");
}
readSsoCookie(value) {
if (!value || !value.includes("."))
return null;
const split = value.lastIndexOf(".");
const payload = value.slice(0, split);
const sig = value.slice(split + 1);
const expected = (0, node_crypto_1.createHmac)("sha256", this.ssoSecret()).update(payload).digest("base64url");
if (expected.length !== sig.length)
return null;
let same = 0;
for (let i = 0; i < expected.length; i++)
same |= expected.charCodeAt(i) ^ sig.charCodeAt(i);
if (same !== 0)
return null;
try {
return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
} catch {
return null;
}
}
/**
* Password check, optionally delegated to the central identity service.
*
@@ -87612,6 +88001,15 @@ var require_auth_service = __commonJS({
admin_session_service_1.AdminSessionService
])
], AuthService);
function mobileVariants(raw) {
const digits = raw.replace(/\D/g, "");
const variants = /* @__PURE__ */ new Set([raw.trim(), digits]);
if (digits.startsWith("98") && digits.length >= 12)
variants.add(`0${digits.slice(2)}`);
if (digits.startsWith("0") && digits.length === 11)
variants.add(`98${digits.slice(1)}`);
return [...variants].filter((value) => value !== "");
}
}
});
@@ -87681,6 +88079,20 @@ var require_auth_controller = __commonJS({
login(dto, ip, userAgent) {
return this.authService.login(dto, ip, userAgent);
}
startSso(redirectUri, res) {
const started = this.authService.beginBrowserSso(redirectUri);
if (!started)
return { enabled: false, authorize_url: null };
res.setHeader("Set-Cookie", started.cookie);
return { enabled: true, authorize_url: started.authorizeUrl };
}
ssoCallback(body, cookieHeader, ip, userAgent, res) {
res.setHeader("Set-Cookie", "gb_admin_iam_sso=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax");
return this.authService.completeBrowserSso(readCookie(cookieHeader, "gb_admin_iam_sso"), body.code ?? "", body.state ?? "", ip, userAgent);
}
ssoLogoutUrl(returnUrl) {
return { logout_url: this.authService.centralLogoutUrl(returnUrl) };
}
/** Legacy `users/show` — the router guard's permission refresh. */
me(admin) {
return this.authService.showData(admin.id);
@@ -87698,6 +88110,36 @@ var require_auth_controller = __commonJS({
__metadata3("design:paramtypes", [login_dto_1.LoginDto, String, String]),
__metadata3("design:returntype", void 0)
], AuthController.prototype, "login", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Get)("sso/start"),
__param3(0, (0, common_12.Query)("redirect_uri")),
__param3(1, (0, common_12.Res)({ passthrough: true })),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [Object, Object]),
__metadata3("design:returntype", void 0)
], AuthController.prototype, "startSso", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Post)("sso/callback"),
(0, common_12.HttpCode)(200),
__param3(0, (0, common_12.Body)()),
__param3(1, (0, common_12.Headers)("cookie")),
__param3(2, (0, common_12.Ip)()),
__param3(3, (0, common_12.Headers)("user-agent")),
__param3(4, (0, common_12.Res)({ passthrough: true })),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [Object, Object, String, Object, Object]),
__metadata3("design:returntype", void 0)
], AuthController.prototype, "ssoCallback", null);
__decorate4([
(0, guards_1.Public)(),
(0, common_12.Get)("sso/logout-url"),
__param3(0, (0, common_12.Query)("return_url")),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [String]),
__metadata3("design:returntype", void 0)
], AuthController.prototype, "ssoLogoutUrl", null);
__decorate4([
(0, common_12.Get)("me"),
__param3(0, (0, guards_1.CurrentAdmin)()),
@@ -87709,6 +88151,16 @@ var require_auth_controller = __commonJS({
(0, common_12.Controller)("admin/auth"),
__metadata3("design:paramtypes", [auth_service_1.AuthService])
], AuthController);
function readCookie(header, name) {
if (!header)
return null;
for (const part of header.split(";")) {
const [key, ...rest] = part.trim().split("=");
if (key === name)
return decodeURIComponent(rest.join("="));
}
return null;
}
}
});