fix(auth): update credential filename logic to include account hash

- Modified `CredentialFileName` to incorporate `hashAccountID` for better disambiguation when available.
- Updated fallback behavior to maintain compatibility with legacy email-based filenames.
- Refined test suite to validate scenarios with and without account hash and plan type.

Closes: #4425
This commit is contained in:
Luis Pater
2026-07-19 02:19:38 +08:00
parent 58ef846ff0
commit 0b2ce80fcb
2 changed files with 36 additions and 13 deletions

View File

@@ -7,9 +7,8 @@ import (
)
// CredentialFileName returns the filename used to persist Codex OAuth credentials.
// When planType is available (e.g. "plus", "team"), it is appended after the email
// as a suffix to disambiguate subscriptions. Team-scoped plans include the account
// hash to avoid overwriting credentials for the same email across multiple teams.
// The account hash is included when available to keep accounts with the same email
// and plan distinct. The legacy email-based format remains the fallback.
func CredentialFileName(email, planType, hashAccountID string, includeProviderPrefix bool) string {
email = strings.TrimSpace(email)
plan := normalizePlanTypeForFilename(planType)
@@ -20,18 +19,18 @@ func CredentialFileName(email, planType, hashAccountID string, includeProviderPr
prefix = "codex"
}
if plan == "" {
return fmt.Sprintf("%s-%s.json", prefix, email)
} else if isTeamScopedPlan(plan) && hashAccountID != "" {
if hashAccountID != "" {
if plan == "" {
return fmt.Sprintf("%s-%s-%s.json", prefix, hashAccountID, email)
}
return fmt.Sprintf("%s-%s-%s-%s.json", prefix, hashAccountID, email, plan)
}
if plan == "" {
return fmt.Sprintf("%s-%s.json", prefix, email)
}
return fmt.Sprintf("%s-%s-%s.json", prefix, email, plan)
}
func isTeamScopedPlan(plan string) bool {
return plan == "team" || plan == "k12"
}
func normalizePlanTypeForFilename(planType string) string {
planType = strings.TrimSpace(planType)
if planType == "" {

View File

@@ -36,10 +36,18 @@ func TestCredentialFileName(t *testing.T) {
want: "codex-user@example.com-k12.json",
},
{
name: "plus ignores account hash",
name: "plus includes account hash",
email: " user@example.com ",
planType: "Plus",
hashAccountID: "abc12345",
hashAccountID: " abc12345 ",
includeProviderPrefix: true,
want: "codex-abc12345-user@example.com-plus.json",
},
{
name: "plus without account hash falls back to email and plan",
email: "user@example.com",
planType: "plus",
hashAccountID: "",
includeProviderPrefix: true,
want: "codex-user@example.com-plus.json",
},
@@ -49,7 +57,23 @@ func TestCredentialFileName(t *testing.T) {
planType: " Team Plan ",
hashAccountID: "abc12345",
includeProviderPrefix: true,
want: "codex-user@example.com-team-plan.json",
want: "codex-abc12345-user@example.com-team-plan.json",
},
{
name: "account hash is used without plan",
email: "user@example.com",
planType: "",
hashAccountID: "abc12345",
includeProviderPrefix: true,
want: "codex-abc12345-user@example.com.json",
},
{
name: "missing plan and account hash falls back to email",
email: "user@example.com",
planType: "",
hashAccountID: "",
includeProviderPrefix: true,
want: "codex-user@example.com.json",
},
}