sonr/internal/db/options.go

85 lines
1.7 KiB
Go

package db
import (
"crypto/rand"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/gormlite"
"github.com/ncruces/go-sqlite3/vfs"
"golang.org/x/crypto/argon2"
"gorm.io/gorm"
"lukechampine.com/adiantum/hbsh"
"lukechampine.com/adiantum/hpolyc"
)
type DBOption func(config *DBConfig)
func WithDir(dir string) DBOption {
return func(config *DBConfig) {
config.Dir = dir
}
}
func WithInMemory() DBOption {
return func(config *DBConfig) {
config.InMemory = true
}
}
func WithSecretKey(secretKey string) DBOption {
return func(config *DBConfig) {
config.SecretKey = secretKey
}
}
func WithOpenFlag(flag vfs.OpenFlag) DBOption {
return func(config *DBConfig) {
config.OpenFlag = flag
}
}
type DBConfig struct {
Dir string
InMemory bool
SecretKey string
OpenFlag vfs.OpenFlag
fileName string
}
func (config *DBConfig) ConnectionString() string {
connStr := "file:"
if config.InMemory {
connStr += ":memory:"
} else {
connStr += config.Dir + "/" + config.fileName
}
return connStr
}
// GormDialector creates a gorm dialector for the database.
func (config *DBConfig) GormDialector() (*gorm.DB, error) {
return gorm.Open(gormlite.Open(config.ConnectionString()))
}
// HBSH creates an HBSH cipher given a key.
func (c *DBConfig) HBSH(key []byte) *hbsh.HBSH {
if len(key) != 32 {
// Key is not appropriate, return nil.
return nil
}
return hpolyc.New(key)
}
// KDF gets a key from a secret.
func (c *DBConfig) KDF(secret string) []byte {
if secret == "" {
// No secret is given, generate a random key.
key := make([]byte, 32)
n, _ := rand.Read(key)
return key[:n]
}
// Hash the secret with a KDF.
return argon2.IDKey([]byte(secret), []byte("hpolyc"), 3, 64*1024, 4, 32)
}