gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

cache.go (3551B)


      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 	"os"
     11 	"path/filepath"
     12 )
     13 
     14 // ErrCacheMiss is returned when a certificate is not found in cache.
     15 var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
     16 
     17 // Cache is used by Manager to store and retrieve previously obtained certificates
     18 // and other account data as opaque blobs.
     19 //
     20 // Cache implementations should not rely on the key naming pattern. Keys can
     21 // include any printable ASCII characters, except the following: \/:*?"<>|
     22 type Cache interface {
     23 	// Get returns a certificate data for the specified key.
     24 	// If there's no such key, Get returns ErrCacheMiss.
     25 	Get(ctx context.Context, key string) ([]byte, error)
     26 
     27 	// Put stores the data in the cache under the specified key.
     28 	// Underlying implementations may use any data storage format,
     29 	// as long as the reverse operation, Get, results in the original data.
     30 	Put(ctx context.Context, key string, data []byte) error
     31 
     32 	// Delete removes a certificate data from the cache under the specified key.
     33 	// If there's no such key in the cache, Delete returns nil.
     34 	Delete(ctx context.Context, key string) error
     35 }
     36 
     37 // DirCache implements Cache using a directory on the local filesystem.
     38 // If the directory does not exist, it will be created with 0700 permissions.
     39 type DirCache string
     40 
     41 // Get reads a certificate data from the specified file name.
     42 func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
     43 	name = filepath.Join(string(d), filepath.Clean("/"+name))
     44 	var (
     45 		data []byte
     46 		err  error
     47 		done = make(chan struct{})
     48 	)
     49 	go func() {
     50 		data, err = os.ReadFile(name)
     51 		close(done)
     52 	}()
     53 	select {
     54 	case <-ctx.Done():
     55 		return nil, ctx.Err()
     56 	case <-done:
     57 	}
     58 	if os.IsNotExist(err) {
     59 		return nil, ErrCacheMiss
     60 	}
     61 	return data, err
     62 }
     63 
     64 // Put writes the certificate data to the specified file name.
     65 // The file will be created with 0600 permissions.
     66 func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
     67 	if err := os.MkdirAll(string(d), 0700); err != nil {
     68 		return err
     69 	}
     70 
     71 	done := make(chan struct{})
     72 	var err error
     73 	go func() {
     74 		defer close(done)
     75 		var tmp string
     76 		if tmp, err = d.writeTempFile(name, data); err != nil {
     77 			return
     78 		}
     79 		defer os.Remove(tmp)
     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), filepath.Clean("/"+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), filepath.Clean("/"+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) (name string, reterr error) {
    120 	// TempFile uses 0600 permissions
    121 	f, err := os.CreateTemp(string(d), prefix)
    122 	if err != nil {
    123 		return "", err
    124 	}
    125 	defer func() {
    126 		if reterr != nil {
    127 			os.Remove(f.Name())
    128 		}
    129 	}()
    130 	if _, err := f.Write(b); err != nil {
    131 		f.Close()
    132 		return "", err
    133 	}
    134 	return f.Name(), f.Close()
    135 }