github.com/grailbio/base@v0.0.11/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/grailbio/base/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  }