github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/security/keycrypt/keychain/keychain_darwin.go (about) 1 // Copyright 2018 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 // +build darwin,cgo 6 7 // Secrets are stored directly into the macOS Keychain under the name 8 // com.grail.keycrypt.$namespace; Keycrypt names are stored into the 9 // account name. 10 package keychain 11 12 import ( 13 "github.com/Schaudge/grailbase/security/keycrypt" 14 keychain "github.com/keybase/go-keychain" 15 ) 16 17 const prefix = "com.grail.keycrypt." 18 19 func init() { 20 keycrypt.RegisterFunc("keychain", func(h string) keycrypt.Keycrypt { 21 return &Keychain{Namespace: h} 22 }) 23 } 24 25 var _ keycrypt.Keycrypt = (*Keychain)(nil) 26 27 type Keychain struct { 28 Namespace string 29 } 30 31 func (k *Keychain) Lookup(name string) keycrypt.Secret { 32 return &secret{k, name} 33 } 34 35 type secret struct { 36 kc *Keychain 37 name string 38 } 39 40 func (s *secret) Get() ([]byte, error) { 41 data, err := keychain.GetGenericPassword(prefix+s.kc.Namespace, s.name, "", "") 42 if err == keychain.ErrorItemNotFound { 43 return nil, keycrypt.ErrNoSuchSecret 44 } else if err != nil { 45 return nil, err 46 } 47 return data, nil 48 } 49 50 func (s *secret) Put(p []byte) error { 51 namespace := prefix + s.kc.Namespace 52 53 keychain.DeleteGenericPasswordItem(namespace, s.name) 54 55 item := keychain.NewGenericPassword(namespace, s.name, "", p, "") 56 item.SetSynchronizable(keychain.SynchronizableNo) 57 item.SetAccessible(keychain.AccessibleWhenUnlocked) 58 59 return keychain.AddItem(item) 60 }