github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/golang.org/x/crypto/acme/autocert/cache.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package autocert
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  )
    14  
    15  // ErrCacheMiss is returned when a certificate is not found in cache.
    16  var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
    17  
    18  // Cache is used by Manager to store and retrieve previously obtained certificates
    19  // as opaque data.
    20  //
    21  // The key argument of the methods refers to a domain name but need not be an FQDN.
    22  // Cache implementations should not rely on the key naming pattern.
    23  type Cache interface {
    24  	// Get returns a certificate data for the specified key.
    25  	// If there's no such key, Get returns ErrCacheMiss.
    26  	Get(ctx context.Context, key string) ([]byte, error)
    27  
    28  	// Put stores the data in the cache under the specified key.
    29  	// Underlying implementations may use any data storage format,
    30  	// as long as the reverse operation, Get, results in the original data.
    31  	Put(ctx context.Context, key string, data []byte) error
    32  
    33  	// Delete removes a certificate data from the cache under the specified key.
    34  	// If there's no such key in the cache, Delete returns nil.
    35  	Delete(ctx context.Context, key string) error
    36  }
    37  
    38  // DirCache implements Cache using a directory on the local filesystem.
    39  // If the directory does not exist, it will be created with 0700 permissions.
    40  type DirCache string
    41  
    42  // Get reads a certificate data from the specified file name.
    43  func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
    44  	name = filepath.Join(string(d), name)
    45  	var (
    46  		data []byte
    47  		err  error
    48  		done = make(chan struct{})
    49  	)
    50  	go func() {
    51  		data, err = ioutil.ReadFile(name)
    52  		close(done)
    53  	}()
    54  	select {
    55  	case <-ctx.Done():
    56  		return nil, ctx.Err()
    57  	case <-done:
    58  	}
    59  	if os.IsNotExist(err) {
    60  		return nil, ErrCacheMiss
    61  	}
    62  	return data, err
    63  }
    64  
    65  // Put writes the certificate data to the specified file name.
    66  // The file will be created with 0600 permissions.
    67  func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
    68  	if err := os.MkdirAll(string(d), 0700); err != nil {
    69  		return err
    70  	}
    71  
    72  	done := make(chan struct{})
    73  	var err error
    74  	go func() {
    75  		defer close(done)
    76  		var tmp string
    77  		if tmp, err = d.writeTempFile(name, data); err != nil {
    78  			return
    79  		}
    80  		select {
    81  		case <-ctx.Done():
    82  			// Don't overwrite the file if the context was canceled.
    83  		default:
    84  			newName := filepath.Join(string(d), name)
    85  			err = os.Rename(tmp, newName)
    86  		}
    87  	}()
    88  	select {
    89  	case <-ctx.Done():
    90  		return ctx.Err()
    91  	case <-done:
    92  	}
    93  	return err
    94  }
    95  
    96  // Delete removes the specified file name.
    97  func (d DirCache) Delete(ctx context.Context, name string) error {
    98  	name = filepath.Join(string(d), name)
    99  	var (
   100  		err  error
   101  		done = make(chan struct{})
   102  	)
   103  	go func() {
   104  		err = os.Remove(name)
   105  		close(done)
   106  	}()
   107  	select {
   108  	case <-ctx.Done():
   109  		return ctx.Err()
   110  	case <-done:
   111  	}
   112  	if err != nil && !os.IsNotExist(err) {
   113  		return err
   114  	}
   115  	return nil
   116  }
   117  
   118  // writeTempFile writes b to a temporary file, closes the file and returns its path.
   119  func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
   120  	// TempFile uses 0600 permissions
   121  	f, err := ioutil.TempFile(string(d), prefix)
   122  	if err != nil {
   123  		return "", err
   124  	}
   125  	if _, err := f.Write(b); err != nil {
   126  		f.Close()
   127  		return "", err
   128  	}
   129  	return f.Name(), f.Close()
   130  }