Разделены экраны «Входы» и «Изменения»; логин пишет IP/UA и last_login_ip; SSO handoff и revoke refresh-сессий; улучшены audit-карточки. Co-authored-by: Cursor <cursoragent@cursor.com>
44 lines
1.1 KiB
TypeScript
44 lines
1.1 KiB
TypeScript
import type { AuditSourceApp } from '@authportal/shared'
|
|
|
|
/** Resolve SSO target app from return_to URL host/path. */
|
|
export function targetAppFromReturnTo(
|
|
returnTo: string | undefined | null,
|
|
): AuditSourceApp {
|
|
if (!returnTo) return 'portal'
|
|
let host = ''
|
|
let path = ''
|
|
try {
|
|
const u = new URL(returnTo)
|
|
host = u.hostname.toLowerCase()
|
|
path = u.pathname.toLowerCase()
|
|
} catch {
|
|
return 'portal'
|
|
}
|
|
const hay = `${host} ${path}`
|
|
if (/\bvps\b/.test(hay) || host.includes('vps')) return 'vps'
|
|
if (
|
|
/\bcfdm\b/.test(hay) ||
|
|
host.includes('cfdm') ||
|
|
host.includes('domain')
|
|
) {
|
|
return 'cfdm'
|
|
}
|
|
if (/\bbgp\b/.test(hay) || host.includes('bgp')) return 'bgp'
|
|
if (
|
|
/\bfw\b/.test(hay) ||
|
|
host.includes('firewall') ||
|
|
host.includes('evofw')
|
|
) {
|
|
return 'fw'
|
|
}
|
|
return 'portal'
|
|
}
|
|
|
|
export function clientUserAgent(
|
|
headers: Record<string, string | string[] | undefined>,
|
|
): string | null {
|
|
const ua = headers['user-agent']
|
|
if (typeof ua === 'string' && ua.trim()) return ua.trim().slice(0, 512)
|
|
return null
|
|
}
|