Fixed sync handshake

This commit is contained in:
2026-10-23 10:19:30 +02:00
parent 8f58e15f0f
commit 3316fc0275
8 changed files with 593 additions and 226 deletions
@@ -1,6 +1,7 @@
import { getTenant } from './api';
import { getTenant, getTenants } from './api';
import { ActivityStatus, Tenant } from '../types';
import { setActivationPending } from './userSyncService';
import { encodeHashIdSync, isAlreadyHashId } from './toolsService';
export interface TenantLockoutResult {
isActive: boolean;
@@ -58,30 +59,36 @@ export function getStatusLabel(status: any): string {
return 'Not Specified';
}
function isValidHashableOrHashedTenantId(val: unknown): val is number | string {
if (val === undefined || val === null || val === '') return false;
if (typeof val === 'number') {
return !isNaN(val) && isFinite(val) && val > 0;
}
if (typeof val === 'string') {
const trimmed = val.trim();
if (!trimmed) return false;
if (/^\d+$/.test(trimmed)) {
return parseInt(trimmed, 10) > 0;
}
return isAlreadyHashId(trimmed);
}
return false;
}
export async function verifyTenantLockout(
tenantId?: number | string | null,
tenantClaim?: string | null,
forceRefresh = false
): Promise<TenantLockoutResult> {
const primaryId =
tenantId !== undefined && tenantId !== null && tenantId !== ''
? tenantId
: tenantClaim !== undefined && tenantClaim !== null && tenantClaim !== ''
? tenantClaim
: null;
if (primaryId === null || primaryId === undefined || primaryId === '') {
const errorMsg =
'Tenant identification claims (tenant / tenant_id) not found in credentials. Access is restricted.';
setActivationPending(true, errorMsg);
return {
isActive: false,
tenant: null,
errorMessage: errorMsg,
};
// Resolve a valid numeric ID or HashId to avoid passing plain-text tenant names to /v1/api/governance/tenants/{id}
let candidateId: number | string | null = null;
if (isValidHashableOrHashedTenantId(tenantId)) {
candidateId = tenantId;
} else if (isValidHashableOrHashedTenantId(tenantClaim)) {
candidateId = tenantClaim;
}
const cacheKey = String(primaryId).trim().toLowerCase();
const cacheKey = String(candidateId ?? tenantClaim ?? 'default-1').trim().toLowerCase();
if (!forceRefresh && cachedTenantLockout && cachedTenantLockout.key === cacheKey) {
if (
cachedTenantLockout.result.isActive &&
@@ -94,23 +101,61 @@ export async function verifyTenantLockout(
let tenantRes: Tenant | null = null;
let lastError: any = null;
try {
tenantRes = await getTenant(primaryId);
} catch (err: any) {
lastError = err;
tenantRes = null;
}
if (!tenantRes && tenantClaim && String(tenantClaim) !== String(primaryId)) {
// 1. If we have a valid numeric tenantId or HashId, encode it via HashIds and call GET /v1/api/governance/tenants/{hashedId}
if (candidateId !== null) {
try {
tenantRes = await getTenant(tenantClaim);
lastError = null;
const hashedId = encodeHashIdSync(candidateId);
tenantRes = await getTenant(hashedId || candidateId);
} catch (err: any) {
lastError = err;
tenantRes = null;
}
}
// 2. If tenant lookup by ID wasn't possible or didn't resolve, resolve via getTenants() (matching tenantClaim name if provided)
if (!tenantRes) {
try {
const allTenants = await getTenants();
if (Array.isArray(allTenants) && allTenants.length > 0) {
const claimStr = tenantClaim ? String(tenantClaim).trim().toLowerCase() : '';
const matched = claimStr
? allTenants.find(
(t) =>
(t.name && t.name.trim().toLowerCase() === claimStr) ||
String(t.id).toLowerCase() === claimStr ||
encodeHashIdSync(t.id).toLowerCase() === claimStr
)
: null;
const targetTenant = matched || allTenants.find((t) => isStatusActive((t as any).status ?? (t as any).Status)) || allTenants[0];
if (targetTenant && targetTenant.id !== undefined && targetTenant.id !== null) {
try {
const hashedTargetId = encodeHashIdSync(targetTenant.id);
tenantRes = await getTenant(hashedTargetId || targetTenant.id);
lastError = null;
} catch {
tenantRes = targetTenant;
lastError = null;
}
}
}
} catch (err: any) {
if (!lastError) lastError = err;
}
}
// 3. Final fallback: query default primary tenant ID 1 encoded as a HashId (matching ConsoleUI)
if (!tenantRes && candidateId !== 1 && candidateId !== '1') {
try {
const hashedDefaultId = encodeHashIdSync(1);
tenantRes = await getTenant(hashedDefaultId);
lastError = null;
} catch (err: any) {
if (!lastError) lastError = err;
tenantRes = null;
}
}
if (!tenantRes || (typeof tenantRes === 'object' && Object.keys(tenantRes).length === 0)) {
const serverMsg =
lastError?.response?.data?.detail ||
@@ -140,7 +185,7 @@ export async function verifyTenantLockout(
if (!active) {
const statusLabel = getStatusLabel(rawStatus);
const tenantName = tenantObj?.name || String(primaryId);
const tenantName = tenantObj?.name || String(candidateId ?? tenantClaim ?? '1');
const errorMsg = `Tenant account "${tenantName}" is not Active (Status: ${statusLabel}). Account is locked out.`;
setActivationPending(true, errorMsg);
return {
@@ -150,6 +195,8 @@ export async function verifyTenantLockout(
};
}
setActivationPending(false);
const successResult: TenantLockoutResult = {
isActive: true,
tenant: tenantObj,
@@ -161,4 +208,3 @@ export async function verifyTenantLockout(
};
return successResult;
}