mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
refactor(auth): centralize OAuth identity matching
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
OPENAI_CODEX_DEFAULT_PROFILE_ID,
|
||||
} from "./constants.js";
|
||||
import { log } from "./constants.js";
|
||||
import { isSafeToCopyOAuthIdentity } from "./oauth-identity.js";
|
||||
import {
|
||||
areOAuthCredentialsEquivalent,
|
||||
hasUsableOAuthCredential,
|
||||
@@ -61,15 +62,6 @@ type ExternalCliSyncProvider = {
|
||||
bootstrapOnly?: boolean;
|
||||
};
|
||||
|
||||
function normalizeAuthIdentityToken(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
function normalizeAuthEmailToken(value: string | undefined): string | undefined {
|
||||
return normalizeAuthIdentityToken(value)?.toLowerCase();
|
||||
}
|
||||
|
||||
// Keep this gate aligned with the canonical identity-copy rule in oauth.ts.
|
||||
/** Return true when imported CLI credentials match an existing profile identity. */
|
||||
export function isSafeToUseExternalCliCredential(
|
||||
@@ -82,24 +74,7 @@ export function isSafeToUseExternalCliCredential(
|
||||
if (existing.provider !== imported.provider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const existingAccountId = normalizeAuthIdentityToken(existing.accountId);
|
||||
const importedAccountId = normalizeAuthIdentityToken(imported.accountId);
|
||||
const existingEmail = normalizeAuthEmailToken(existing.email);
|
||||
const importedEmail = normalizeAuthEmailToken(imported.email);
|
||||
|
||||
if (existingAccountId !== undefined && importedAccountId !== undefined) {
|
||||
return existingAccountId === importedAccountId;
|
||||
}
|
||||
if (existingEmail !== undefined && importedEmail !== undefined) {
|
||||
return existingEmail === importedEmail;
|
||||
}
|
||||
|
||||
const existingHasIdentity = existingAccountId !== undefined || existingEmail !== undefined;
|
||||
if (existingHasIdentity) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return isSafeToCopyOAuthIdentity(existing, imported);
|
||||
}
|
||||
|
||||
const EXTERNAL_CLI_SYNC_PROVIDERS: ExternalCliSyncProvider[] = [
|
||||
|
||||
@@ -6,8 +6,15 @@
|
||||
import { asDateTimestampMs } from "../../shared/number-coercion.js";
|
||||
import { cloneAuthProfileStore } from "./clone.js";
|
||||
import { hasUsableOAuthCredential as hasUsableStoredOAuthCredential } from "./credential-state.js";
|
||||
import {
|
||||
isSafeToCopyOAuthIdentity,
|
||||
normalizeAuthEmailToken,
|
||||
normalizeAuthIdentityToken,
|
||||
} from "./oauth-identity.js";
|
||||
import type { AuthProfileStore, OAuthCredential } from "./types.js";
|
||||
|
||||
export { normalizeAuthEmailToken, normalizeAuthIdentityToken } from "./oauth-identity.js";
|
||||
|
||||
/** OAuth profile imported from a runtime external CLI source. */
|
||||
export type RuntimeExternalOAuthProfile = {
|
||||
profileId: string;
|
||||
@@ -74,17 +81,6 @@ export function hasUsableOAuthCredential(
|
||||
return hasUsableStoredOAuthCredential(credential, { now });
|
||||
}
|
||||
|
||||
/** Normalizes account identity tokens for equality checks. */
|
||||
export function normalizeAuthIdentityToken(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
/** Normalizes auth email identity tokens for equality checks. */
|
||||
export function normalizeAuthEmailToken(value: string | undefined): string | undefined {
|
||||
return normalizeAuthIdentityToken(value)?.toLowerCase();
|
||||
}
|
||||
|
||||
/** Returns true when an OAuth credential has account or email identity. */
|
||||
export function hasOAuthIdentity(
|
||||
credential: Pick<OAuthCredential, "accountId" | "email">,
|
||||
@@ -100,19 +96,7 @@ export function hasMatchingOAuthIdentity(
|
||||
existing: Pick<OAuthCredential, "accountId" | "email">,
|
||||
incoming: Pick<OAuthCredential, "accountId" | "email">,
|
||||
): boolean {
|
||||
const existingAccountId = normalizeAuthIdentityToken(existing.accountId);
|
||||
const incomingAccountId = normalizeAuthIdentityToken(incoming.accountId);
|
||||
if (existingAccountId !== undefined && incomingAccountId !== undefined) {
|
||||
return existingAccountId === incomingAccountId;
|
||||
}
|
||||
|
||||
const existingEmail = normalizeAuthEmailToken(existing.email);
|
||||
const incomingEmail = normalizeAuthEmailToken(incoming.email);
|
||||
if (existingEmail !== undefined && incomingEmail !== undefined) {
|
||||
return existingEmail === incomingEmail;
|
||||
}
|
||||
|
||||
return false;
|
||||
return hasOAuthIdentity(existing) && isSafeToCopyOAuthIdentity(existing, incoming);
|
||||
}
|
||||
|
||||
// Different adoption paths have different safety thresholds. Bootstrap can
|
||||
|
||||
Reference in New Issue
Block a user