ccm,ocm: check credential file writability before token refresh
Refuse to refresh tokens when the credential file is not writable, preventing server-side invalidation of the old refresh token that would make the credential permanently unusable after restart.
This commit is contained in:
@@ -108,6 +108,14 @@ func readCredentialsFromFile(path string) (*oauthCredentials, error) {
|
||||
return credentialsContainer.ClaudeAIAuth, nil
|
||||
}
|
||||
|
||||
func checkCredentialFileWritable(path string) error {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func writeCredentialsToFile(oauthCredentials *oauthCredentials, path string) error {
|
||||
data, err := json.MarshalIndent(map[string]any{
|
||||
"claudeAiOauth": oauthCredentials,
|
||||
|
||||
@@ -69,6 +69,13 @@ func platformReadCredentials(customPath string) (*oauthCredentials, error) {
|
||||
return readCredentialsFromFile(defaultPath)
|
||||
}
|
||||
|
||||
func platformCanWriteCredentials(customPath string) error {
|
||||
if customPath == "" {
|
||||
return nil
|
||||
}
|
||||
return checkCredentialFileWritable(customPath)
|
||||
}
|
||||
|
||||
func platformWriteCredentials(oauthCredentials *oauthCredentials, customPath string) error {
|
||||
if customPath != "" {
|
||||
return writeCredentialsToFile(oauthCredentials, customPath)
|
||||
|
||||
@@ -13,6 +13,17 @@ func platformReadCredentials(customPath string) (*oauthCredentials, error) {
|
||||
return readCredentialsFromFile(customPath)
|
||||
}
|
||||
|
||||
func platformCanWriteCredentials(customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
customPath, err = getDefaultCredentialsPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return checkCredentialFileWritable(customPath)
|
||||
}
|
||||
|
||||
func platformWriteCredentials(oauthCredentials *oauthCredentials, customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
|
||||
@@ -225,6 +225,11 @@ func (c *defaultCredential) getAccessToken() (string, error) {
|
||||
return c.credentials.AccessToken, nil
|
||||
}
|
||||
|
||||
err = platformCanWriteCredentials(c.credentialPath)
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "credential file not writable, refusing refresh to avoid invalidation")
|
||||
}
|
||||
|
||||
baseCredentials := cloneCredentials(c.credentials)
|
||||
newCredentials, err := refreshToken(c.httpClient, c.credentials)
|
||||
if err != nil {
|
||||
@@ -258,7 +263,7 @@ func (c *defaultCredential) getAccessToken() (string, error) {
|
||||
|
||||
err = platformWriteCredentials(newCredentials, c.credentialPath)
|
||||
if err != nil {
|
||||
c.logger.Warn("persist refreshed token for ", c.tag, ": ", err)
|
||||
c.logger.Error("persist refreshed token for ", c.tag, ": ", err)
|
||||
}
|
||||
|
||||
return newCredentials.AccessToken, nil
|
||||
|
||||
@@ -55,6 +55,14 @@ func readCredentialsFromFile(path string) (*oauthCredentials, error) {
|
||||
return &credentials, nil
|
||||
}
|
||||
|
||||
func checkCredentialFileWritable(path string) error {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func writeCredentialsToFile(credentials *oauthCredentials, path string) error {
|
||||
data, err := json.MarshalIndent(credentials, "", " ")
|
||||
if err != nil {
|
||||
|
||||
@@ -13,6 +13,17 @@ func platformReadCredentials(customPath string) (*oauthCredentials, error) {
|
||||
return readCredentialsFromFile(customPath)
|
||||
}
|
||||
|
||||
func platformCanWriteCredentials(customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
customPath, err = getDefaultCredentialsPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return checkCredentialFileWritable(customPath)
|
||||
}
|
||||
|
||||
func platformWriteCredentials(credentials *oauthCredentials, customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
|
||||
@@ -13,6 +13,17 @@ func platformReadCredentials(customPath string) (*oauthCredentials, error) {
|
||||
return readCredentialsFromFile(customPath)
|
||||
}
|
||||
|
||||
func platformCanWriteCredentials(customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
customPath, err = getDefaultCredentialsPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return checkCredentialFileWritable(customPath)
|
||||
}
|
||||
|
||||
func platformWriteCredentials(credentials *oauthCredentials, customPath string) error {
|
||||
if customPath == "" {
|
||||
var err error
|
||||
|
||||
@@ -234,6 +234,11 @@ func (c *defaultCredential) getAccessToken() (string, error) {
|
||||
return c.credentials.getAccessToken(), nil
|
||||
}
|
||||
|
||||
err = platformCanWriteCredentials(c.credentialPath)
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "credential file not writable, refusing refresh to avoid invalidation")
|
||||
}
|
||||
|
||||
baseCredentials := cloneCredentials(c.credentials)
|
||||
newCredentials, err := refreshToken(c.httpClient, c.credentials)
|
||||
if err != nil {
|
||||
@@ -265,7 +270,7 @@ func (c *defaultCredential) getAccessToken() (string, error) {
|
||||
|
||||
err = platformWriteCredentials(newCredentials, c.credentialPath)
|
||||
if err != nil {
|
||||
c.logger.Warn("persist refreshed token for ", c.tag, ": ", err)
|
||||
c.logger.Error("persist refreshed token for ", c.tag, ": ", err)
|
||||
}
|
||||
|
||||
return newCredentials.getAccessToken(), nil
|
||||
|
||||
Reference in New Issue
Block a user