Files
geo/apps/desktop-client/src/main/generic-ai-auth.ts
T
root f6e553dcc3 feat(monitoring): add DeepSeek monitoring end-to-end
- desktop: new DeepSeek page adapter and monitor registry
- desktop: extract generic AI auth helpers into shared module and
  skip binding when challenge signals are present
- admin-web: render DeepSeek HTML answers with inline citation anchors
  and surface reference-number badges on source cards
- server: fall back to inline_links/source_panel_links and read
  text/siteName fields when extracting DeepSeek citations

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:54:56 +08:00

114 lines
3.3 KiB
TypeScript

function normalizeText(value: unknown): string | null {
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim();
return trimmed ? trimmed : null;
}
function hashText(value: string): string {
let hash = 0;
for (let index = 0; index < value.length; index += 1) {
hash = ((hash << 5) - hash + value.charCodeAt(index)) | 0;
}
return Math.abs(hash).toString(16).padStart(8, "0");
}
function boundedIdentity(prefix: string, raw: string): string {
const normalizedPrefix = prefix.trim().replace(/:+$/, "");
const normalizedRaw = raw.trim();
if (!normalizedRaw) {
return `${normalizedPrefix}:${hashText(prefix)}`;
}
const candidate = `${normalizedPrefix}:${normalizedRaw}`;
if (candidate.length <= 120) {
return candidate;
}
return `${normalizedPrefix}:${hashText(normalizedRaw)}`;
}
function normalizeURLPath(pathname: string): string {
const normalized = pathname.replace(/\/+$/, "");
return normalized === "/" ? "" : normalized;
}
function safeParseURL(input: string): URL | null {
try {
return new URL(input);
} catch {
return null;
}
}
function genericAIConversationPath(pathname: string): boolean {
return /^\/(?:chat|c|conversation)(?:\/|$)/i.test(pathname);
}
export interface GenericAIPageState {
displayName: string | null;
avatarUrl: string | null;
fingerprint: string | null;
credentialFingerprint: string | null;
currentPath: string | null;
strongAuthSignalCount: number;
loginSignalCount: number;
loggedOutSignalCount: number;
challengeSignalCount: number;
}
export function genericAIPageLooksAuthenticated(
currentURL: string,
pageState: GenericAIPageState | null,
): boolean {
const current = safeParseURL(currentURL);
const currentPath = normalizeURLPath(current?.pathname ?? pageState?.currentPath ?? "");
const strongAuthSignalCount = pageState?.strongAuthSignalCount ?? 0;
const loginSignalCount = pageState?.loginSignalCount ?? 0;
const loggedOutSignalCount = pageState?.loggedOutSignalCount ?? 0;
const challengeSignalCount = pageState?.challengeSignalCount ?? 0;
const hasCredentialFingerprint = Boolean(normalizeText(pageState?.credentialFingerprint));
const onConversationPath = genericAIConversationPath(currentPath);
if (challengeSignalCount > 0) {
return false;
}
if (loggedOutSignalCount > 0) {
return false;
}
if (loginSignalCount > 0 && strongAuthSignalCount === 0 && !onConversationPath && !hasCredentialFingerprint) {
return false;
}
if (loginSignalCount > 0) {
return (strongAuthSignalCount >= 2 || hasCredentialFingerprint) && !onConversationPath;
}
return strongAuthSignalCount > 0 || onConversationPath || hasCredentialFingerprint;
}
export function buildGenericAIPageFingerprintFallback(
platformId: string,
pageState?: GenericAIPageState | null,
): string | null {
const credentialFingerprint = normalizeText(pageState?.credentialFingerprint);
if (credentialFingerprint) {
return boundedIdentity(`${platformId}-session`, credentialFingerprint);
}
const fallbackFingerprint = normalizeText(pageState?.fingerprint);
if (!fallbackFingerprint) {
return null;
}
const strongAuthSignalCount = pageState?.strongAuthSignalCount ?? 0;
if (strongAuthSignalCount <= 0) {
return null;
}
return boundedIdentity(`${platformId}-page`, fallbackFingerprint);
}