diff --git a/web/src/lib/tinode/connection.ts b/web/src/lib/tinode/connection.ts index 04dbb057..5b076958 100644 --- a/web/src/lib/tinode/connection.ts +++ b/web/src/lib/tinode/connection.ts @@ -136,13 +136,21 @@ export function clearKickedInfo() { } /** - * The server extends the stock {hi} packet with a `tenant` field the vendored JS SDK has no API for - * (resolved via POST /v1/im/tenants/resolve; see server/datamodel.go). The packet builder is private, - * so the only usable hook is wrapping the connection's raw sendText and injecting the field into the - * already-serialized JSON. Ported as-is from the old app's tnSetup/installTenantHiPatch -- this is a - * real backend protocol extension, not an old-codebase-specific workaround. + * Two backend protocol extensions the vendored JS SDK has no API for -- both fields the packet + * builders (#initPacket/login(), both private) never write, so the only usable hook for either is + * wrapping the connection's raw sendText and injecting the field into the already-serialized JSON: + * - {hi}.tenant (resolved via POST /v1/im/tenants/resolve; see server/datamodel.go). Ported as-is + * from the old app's tnSetup/installTenantHiPatch. + * - {login}.login_type: confirmed live (server/user.go validateLoginTenant, called from every + * session.login()) that scheme:"basic" logins now hard-require this field -- 0 enterprise / + * 1 personal -- and fail with a 422 LOGIN_TYPE_REQUIRED without it (Zentao bug #33). tenant_code + * is deliberately left unset: validateLoginTenant falls back to the session's own tenant (already + * established by the {hi} patch above) when {login} omits it, for both the personal and + * enterprise branches, so login_type is the only field this client needs to add. token-scheme + * logins (restoreSession/reconnect re-auth) are untouched -- validateLoginTenant only requires + * login_type when scheme is "basic". */ -function installTenantHiPatch(t: Tinode) { +function installOutgoingPacketPatches(t: Tinode) { const conn = t._connection; if (!conn || conn.__tenantPatched) return; const original = conn.sendText.bind(conn); @@ -160,6 +168,17 @@ function installTenantHiPatch(t: Tinode) { } catch { // Not valid JSON -- send as is. } + } else if (typeof msg === 'string' && msg.indexOf('"login":') >= 0) { + try { + const parsed = JSON.parse(msg); + if (parsed.login && parsed.login.scheme === 'basic') { + const tenantCode = useSessionStore.getState().tenant?.code || 'default'; + parsed.login.login_type = tenantCode.toLowerCase() === 'default' ? 1 : 0; + msg = JSON.stringify(parsed); + } + } catch { + // Not valid JSON -- send as is. + } } return original(msg as string); }; @@ -173,7 +192,7 @@ function createTinode(): Tinode { const t = new Tinode({ appName: APP_NAME, host, apiKey: API_KEY, transport: 'ws', secure, persist: false }); t.setHumanLanguage('zh'); t.enableLogging(LOGGING_ENABLED, true); - installTenantHiPatch(t); + installOutgoingPacketPatches(t); t.onConnect = () => { const wasReconnecting = reconnectState.retryInSeconds > 0 || reconnectState.attemptInFlight;