fix remote HMAC: identify tenant by domain, not shared nodeServer

new.gholaktala.ir is the API host of many versions. Prefer subdomain of the product domain and refuse ambiguous nodeServer ties. 403 names the matched tenant.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-09 21:53:11 +03:30
co-authored by Cursor
parent 502b0c8b24
commit 3f0dfe448c
3 changed files with 87 additions and 10 deletions
+51
View File
@@ -0,0 +1,51 @@
import { findTenantForHost, scoreTenantHost } from './tenant-host.util';
const gholak = {
domain: 'gholaktala.ir',
domains: [],
appUrl: 'https://gholaktala.ir',
adminUrl: 'https://admin.gholaktala.ir',
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',
};
describe('findTenantForHost', () => {
const tenants = [montzar, otherOnSameBox, gholak];
it('maps new.gholaktala.ir to gholaktala, not the first shared nodeServer tenant', () => {
expect(findTenantForHost(tenants, 'new.gholaktala.ir')?.domain).toBe(
'gholaktala.ir',
);
expect(scoreTenantHost(gholak, 'new.gholaktala.ir')).toBe(75);
expect(scoreTenantHost(montzar, 'new.gholaktala.ir')).toBe(10);
});
it('maps k.montzar.ir to montzar by primary domain', () => {
expect(findTenantForHost(tenants, 'k.montzar.ir')?.domain).toBe(
'k.montzar.ir',
);
});
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();
});
});