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 }