From 38337c62d76ff56f1ed745317c068f400be5ae61 Mon Sep 17 00:00:00 2001 From: adonis Date: Wed, 9 Sep 2026 22:12:21 +0330 Subject: [PATCH] test: build HMAC tenant fixtures from domain, drop product URLs HMAC identity tests should not hardcode gholak/montzar hosts. Co-authored-by: Cursor --- src/auth/tenant-host.util.spec.ts | 103 +++++++++++++++--------------- src/auth/tenant-host.util.ts | 5 +- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/auth/tenant-host.util.spec.ts b/src/auth/tenant-host.util.spec.ts index af83c49..1d656b8 100644 --- a/src/auth/tenant-host.util.spec.ts +++ b/src/auth/tenant-host.util.spec.ts @@ -1,65 +1,66 @@ -import { findTenantForHost, scoreTenantHost } from './tenant-host.util'; +import { + findTenantForHost, + scoreTenantHost, + type TenantHostFields, +} from './tenant-host.util'; -const gholak = { - domain: 'app.gholaktala.ir', - domains: [], - appUrl: 'https://app.gholaktala.ir', - adminUrl: 'https://k.montzar.ir/admin', - nodeServer: 'https://new.gholaktala.ir/server', -}; - -const montzar = { - domain: 'k.montzar.ir', - domains: ['montzar.ir'], - appUrl: 'https://k.montzar.ir', - adminUrl: 'https://k.montzar.ir', - nodeServer: 'https://new.gholaktala.ir/server', -}; - -const otherOnSameBox = { - domain: 'examplegold.ir', - domains: [], - appUrl: 'https://examplegold.ir', - adminUrl: null, - nodeServer: 'https://new.gholaktala.ir/server', -}; +function fromDomain( + domain: string, + extra: Partial = {}, +): TenantHostFields { + return { + domain, + domains: [], + appUrl: `https://${domain}`, + adminUrl: null, + nodeServer: null, + ...extra, + }; +} describe('findTenantForHost', () => { - const tenants = [gholak, otherOnSameBox, montzar]; + it('hmac matches the tenant whose domain is the host', () => { + const host = 'shop.example.ir'; + const mine = fromDomain(host); + const other = fromDomain('other.example.ir', { + adminUrl: `https://${host}/admin`, + }); - it('hmac does not treat shared adminUrl as gholaktala', () => { - expect(scoreTenantHost(gholak, 'k.montzar.ir', 'hmac')).toBe(0); - expect(findTenantForHost(tenants, 'k.montzar.ir', 'hmac')?.domain).toBe( - 'k.montzar.ir', - ); + expect(scoreTenantHost(other, host, 'hmac')).toBe(0); + expect(findTenantForHost([other, mine], host, 'hmac')?.domain).toBe(host); }); - it('hmac without montzar tenant does not fall back to gholak adminUrl', () => { - expect( - findTenantForHost([gholak, otherOnSameBox], 'k.montzar.ir', 'hmac'), - ).toBeUndefined(); + it('hmac does not use another tenant adminUrl as identity', () => { + const host = 'panel.example.ir'; + const other = fromDomain('app.other.ir', { + adminUrl: `https://${host}/admin`, + }); + + expect(findTenantForHost([other], host, 'hmac')).toBeUndefined(); }); - it('full get_user still maps k.montzar.ir to montzar by primary domain', () => { - expect(findTenantForHost(tenants, 'k.montzar.ir')?.domain).toBe( - 'k.montzar.ir', - ); + it('full match uses primary domain when present', () => { + const host = 'shop.example.ir'; + expect(findTenantForHost([fromDomain(host)], host)?.domain).toBe(host); }); - it('maps new.gholaktala.ir to gholaktala via subdomain, not nodeServer', () => { - const gholakBare = { ...gholak, domain: 'gholaktala.ir' }; - expect( - findTenantForHost([montzar, otherOnSameBox, gholakBare], 'new.gholaktala.ir') - ?.domain, - ).toBe('gholaktala.ir'); - expect(scoreTenantHost(gholakBare, 'new.gholaktala.ir')).toBe(75); + it('subdomain of the tenant domain beats a shared nodeServer', () => { + const root = 'shop.example.ir'; + const api = `new.${root}`; + const mine = fromDomain(root, { nodeServer: `https://${api}/server` }); + const roommate = fromDomain('roommate.ir', { + nodeServer: `https://${api}/server`, + }); + + expect(findTenantForHost([roommate, mine], api)?.domain).toBe(root); + expect(scoreTenantHost(mine, api)).toBe(75); }); - it('does not pick a random tenant when only nodeServer matches several rows', () => { - const sharedOnly = [ - { ...montzar, domain: 'a.ir', domains: [] }, - { ...gholak, domain: 'b.ir', domains: [] }, - ]; - expect(findTenantForHost(sharedOnly, 'new.gholaktala.ir')).toBeUndefined(); + it('does not pick a tenant when only a shared nodeServer matches', () => { + const api = 'box.example.ir'; + const left = fromDomain('a.ir', { nodeServer: `https://${api}/server` }); + const right = fromDomain('b.ir', { nodeServer: `https://${api}/server` }); + + expect(findTenantForHost([left, right], api)).toBeUndefined(); }); }); diff --git a/src/auth/tenant-host.util.ts b/src/auth/tenant-host.util.ts index 1d2227e..18c448f 100644 --- a/src/auth/tenant-host.util.ts +++ b/src/auth/tenant-host.util.ts @@ -54,7 +54,7 @@ function hostsEqual(left: string, right: string): boolean { return left.replace(/^www\./, '') === right.replace(/^www\./, ''); } -/** new.gholaktala.ir belongs to tenant domain gholaktala.ir — not via shared nodeServer. */ +/** new.shop.ir belongs to tenant domain shop.ir — not via shared nodeServer. */ function isSubdomainOf(host: string, parent: string): boolean { const child = normalizeTenantHost(host); const root = normalizeTenantHost(parent).replace(/^www\./, ''); @@ -66,8 +66,7 @@ export type TenantHostMatchMode = 'full' | 'hmac'; /** * full: get_user — دامنه، alias، app/admin/node. - * hmac: فقط دامنهٔ اصلی نسخه (و ساب‌دامنهٔ همان). adminUrl مشترک - * (k.montzar.ir روی نسخهٔ app.gholaktala.ir) هویت نیست. + * hmac: فقط دامنهٔ اصلی نسخه (و ساب‌دامنهٔ همان). adminUrl هویت نیست. */ export function scoreTenantHost( tenant: TenantHostFields,