| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- //go:build darwin && cgo
- package ccm
- import (
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "os"
- "path/filepath"
- E "github.com/sagernet/sing/common/exceptions"
- "github.com/keybase/go-keychain"
- )
- func getKeychainServiceName() string {
- configDirectory := os.Getenv("CLAUDE_CONFIG_DIR")
- if configDirectory == "" {
- return "Claude Code-credentials"
- }
- userInfo, err := getRealUser()
- if err != nil {
- return "Claude Code-credentials"
- }
- defaultConfigDirectory := filepath.Join(userInfo.HomeDir, ".claude")
- if configDirectory == defaultConfigDirectory {
- return "Claude Code-credentials"
- }
- hash := sha256.Sum256([]byte(configDirectory))
- return "Claude Code-credentials-" + hex.EncodeToString(hash[:])[:8]
- }
- func platformReadCredentials(customPath string) (*oauthCredentials, error) {
- if customPath != "" {
- return readCredentialsFromFile(customPath)
- }
- userInfo, err := getRealUser()
- if err == nil {
- query := keychain.NewItem()
- query.SetSecClass(keychain.SecClassGenericPassword)
- query.SetService(getKeychainServiceName())
- query.SetAccount(userInfo.Username)
- query.SetMatchLimit(keychain.MatchLimitOne)
- query.SetReturnData(true)
- results, err := keychain.QueryItem(query)
- if err == nil && len(results) == 1 {
- var container struct {
- ClaudeAIAuth *oauthCredentials `json:"claudeAiOauth,omitempty"`
- }
- unmarshalErr := json.Unmarshal(results[0].Data, &container)
- if unmarshalErr == nil && container.ClaudeAIAuth != nil {
- return container.ClaudeAIAuth, nil
- }
- }
- if err != nil && err != keychain.ErrorItemNotFound {
- return nil, E.Cause(err, "query keychain")
- }
- }
- defaultPath, err := getDefaultCredentialsPath()
- if err != nil {
- return nil, err
- }
- return readCredentialsFromFile(defaultPath)
- }
- func platformWriteCredentials(oauthCredentials *oauthCredentials, customPath string) error {
- if customPath != "" {
- return writeCredentialsToFile(oauthCredentials, customPath)
- }
- userInfo, err := getRealUser()
- if err == nil {
- data, err := json.Marshal(map[string]any{"claudeAiOauth": oauthCredentials})
- if err == nil {
- serviceName := getKeychainServiceName()
- item := keychain.NewItem()
- item.SetSecClass(keychain.SecClassGenericPassword)
- item.SetService(serviceName)
- item.SetAccount(userInfo.Username)
- item.SetData(data)
- item.SetAccessible(keychain.AccessibleWhenUnlocked)
- err = keychain.AddItem(item)
- if err == nil {
- return nil
- }
- if err == keychain.ErrorDuplicateItem {
- query := keychain.NewItem()
- query.SetSecClass(keychain.SecClassGenericPassword)
- query.SetService(serviceName)
- query.SetAccount(userInfo.Username)
- updateItem := keychain.NewItem()
- updateItem.SetData(data)
- updateErr := keychain.UpdateItem(query, updateItem)
- if updateErr == nil {
- return nil
- }
- }
- }
- }
- defaultPath, err := getDefaultCredentialsPath()
- if err != nil {
- return err
- }
- return writeCredentialsToFile(oauthCredentials, defaultPath)
- }
|