github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/security/keycrypt/file/file.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  // Package file implements a file-based keycrypt.
     6  package file
     7  
     8  import (
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"github.com/Schaudge/grailbase/security/keycrypt"
    14  )
    15  
    16  func init() {
    17  	keycrypt.RegisterFunc("file", func(h string) keycrypt.Keycrypt {
    18  		return &crypt{"/"}
    19  	})
    20  	keycrypt.RegisterFunc("localfile", func(h string) keycrypt.Keycrypt {
    21  		// h is taken to be a namespace
    22  		return &crypt{filepath.Join(os.Getenv("HOME"), ".keycrypt", h)}
    23  	})
    24  }
    25  
    26  type crypt struct{ path string }
    27  
    28  func (c *crypt) Lookup(name string) keycrypt.Secret {
    29  	return fileSecret(filepath.Join(c.path, name))
    30  }
    31  
    32  type fileSecret string
    33  
    34  func (f fileSecret) Get() ([]byte, error) {
    35  	if _, err := os.Stat(string(f)); os.IsNotExist(err) {
    36  		return nil, nil
    37  	}
    38  	return ioutil.ReadFile(string(f))
    39  }
    40  
    41  func (f fileSecret) Put(b []byte) error {
    42  	dir := filepath.Dir(string(f))
    43  	os.MkdirAll(dir, 0777) // best effort
    44  	tmpfile, err := ioutil.TempFile(dir, "")
    45  	if err != nil {
    46  		return err
    47  	}
    48  	// Best effort because it's not vital and it doesn't work on Windows.
    49  	tmpfile.Chmod(0644)
    50  	if _, err := tmpfile.Write(b); err != nil {
    51  		return err
    52  	}
    53  	if err := tmpfile.Close(); err != nil {
    54  		return err
    55  	}
    56  	return os.Rename(tmpfile.Name(), string(f))
    57  }