github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libpages/cert_store_backed_by_kvstore.go (about)

     1  // Copyright 2020 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package libpages
     6  
     7  import (
     8  	"context"
     9  	"encoding/base64"
    10  
    11  	"github.com/keybase/client/go/kbfs/libkbfs"
    12  	"github.com/keybase/client/go/protocol/keybase1"
    13  	"github.com/pkg/errors"
    14  	"golang.org/x/crypto/acme/autocert"
    15  )
    16  
    17  type keybaseServiceOwner interface {
    18  	KeybaseService() libkbfs.KeybaseService
    19  }
    20  
    21  // certStoreBackedByKVStore is a wrapper around the KVStore in Keybase. No
    22  // caching is done here since acme/autocert has an in-memory cache already.
    23  type certStoreBackedByKVStore struct {
    24  	serviceOwner keybaseServiceOwner
    25  }
    26  
    27  var _ autocert.Cache = (*certStoreBackedByKVStore)(nil)
    28  
    29  func newCertStoreBackedByKVStore(serviceOwner keybaseServiceOwner) autocert.Cache {
    30  	return &certStoreBackedByKVStore{
    31  		serviceOwner: serviceOwner,
    32  	}
    33  }
    34  
    35  func encodeData(data []byte) string {
    36  	return base64.URLEncoding.EncodeToString(data)
    37  }
    38  
    39  func decodeData(str string) ([]byte, error) {
    40  	return base64.URLEncoding.DecodeString(str)
    41  }
    42  
    43  const certKVStoreNamespace = "cert-store-v1"
    44  
    45  // Get implements the autocert.Cache interface.
    46  func (s *certStoreBackedByKVStore) Get(ctx context.Context, key string) ([]byte, error) {
    47  	res, err := s.serviceOwner.KeybaseService().GetKVStoreClient().GetKVEntry(ctx,
    48  		keybase1.GetKVEntryArg{
    49  			Namespace: certKVStoreNamespace,
    50  			EntryKey:  key,
    51  		})
    52  	if err != nil {
    53  		return nil, errors.WithMessage(err, "kvstore get error")
    54  	}
    55  	if res.EntryValue == nil {
    56  		return nil, errors.New("kvstore get error: empty result")
    57  	}
    58  	data, err := decodeData(*res.EntryValue)
    59  	if err != nil {
    60  		return nil, errors.WithMessage(err, "decodeData error")
    61  	}
    62  	return data, nil
    63  }
    64  
    65  // Put implements the autocert.Cache interface.
    66  func (s *certStoreBackedByKVStore) Put(ctx context.Context, key string, data []byte) error {
    67  	_, err := s.serviceOwner.KeybaseService().GetKVStoreClient().PutKVEntry(ctx,
    68  		keybase1.PutKVEntryArg{
    69  			Namespace:  certKVStoreNamespace,
    70  			EntryKey:   key,
    71  			EntryValue: encodeData(data),
    72  		})
    73  	if err != nil {
    74  		return errors.WithMessage(err, "kvstore put error")
    75  	}
    76  	return nil
    77  }
    78  
    79  // Delete implements the autocert.Cache interface.
    80  func (s *certStoreBackedByKVStore) Delete(ctx context.Context, key string) error {
    81  	_, err := s.serviceOwner.KeybaseService().GetKVStoreClient().DelKVEntry(ctx, keybase1.DelKVEntryArg{
    82  		Namespace: certKVStoreNamespace,
    83  		EntryKey:  key,
    84  	})
    85  	if err != nil {
    86  		return errors.WithMessage(err, "kvstore del error")
    87  	}
    88  	return nil
    89  }