git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/httpx/autocertpg/autocertpg.go (about) 1 package autocertpg 2 3 import ( 4 "context" 5 "database/sql" 6 "fmt" 7 8 "git.sr.ht/~pingoo/stdx/crypto" 9 "git.sr.ht/~pingoo/stdx/db" 10 "git.sr.ht/~pingoo/stdx/log/slogx" 11 "golang.org/x/crypto/acme/autocert" 12 ) 13 14 type Cache struct { 15 key []byte 16 db db.DB 17 } 18 19 type cert struct { 20 Key string `db:"key"` 21 EncryptedData []byte `db:"encrypted_data"` 22 } 23 24 func NewCache(db db.DB, key []byte) *Cache { 25 return &Cache{ 26 db: db, 27 key: key, 28 } 29 } 30 31 func (cache *Cache) Get(ctx context.Context, key string) (data []byte, err error) { 32 var cert cert 33 query := "SELECT * FROM certs WHERE key = $1" 34 logger := slogx.FromCtx(ctx) 35 36 err = cache.db.Get(ctx, &cert, query, key) 37 if err != nil { 38 logger.Warn("autocertpg.Get: getting cert from db", slogx.Err(err)) 39 if err == sql.ErrNoRows { 40 err = autocert.ErrCacheMiss 41 } 42 return 43 } 44 45 data, err = crypto.Decrypt(cache.key, cert.EncryptedData, []byte(cert.Key)) 46 if err != nil { 47 logger.Warn("autocertpg.Get: decrypting data", slogx.Err(err)) 48 err = fmt.Errorf("autocertpg: decrypting data: %w", err) 49 return 50 } 51 52 return 53 } 54 55 func (cache *Cache) Put(ctx context.Context, key string, data []byte) (err error) { 56 query := ` 57 INSERT INTO certs (key, encrypted_data) 58 VALUES ($1, $2) 59 ON CONFLICT (key) 60 DO UPDATE SET encrypted_data = $2 61 ` 62 logger := slogx.FromCtx(ctx) 63 64 encryptedData, err := crypto.Encrypt(cache.key, data, []byte(key)) 65 if err != nil { 66 logger.Warn("autocertpg.Put: encrypting data", slogx.Err(err)) 67 err = fmt.Errorf("autocertpg: encrypting data: %w", err) 68 return 69 } 70 71 _, err = cache.db.Exec(ctx, query, key, encryptedData) 72 if err != nil { 73 logger.Warn("autocertpg.Put: inserting cert in DB", slogx.Err(err)) 74 return 75 } 76 77 return 78 } 79 80 func (cache *Cache) Delete(ctx context.Context, key string) (err error) { 81 logger := slogx.FromCtx(ctx) 82 query := "DELETE FROM certs WHERE key = $1" 83 84 _, err = cache.db.Exec(ctx, query, key) 85 if err != nil { 86 logger.Warn("autocertpg.Delete: deleting cert", slogx.Err(err)) 87 return 88 } 89 90 return 91 }