// Package backup dumps and restores a whole Vantage MongoDB database. // // The archive never contains KEY_ENCRYPTION_KEY. It contains a fingerprint of // it, which is enough to answer "will this archive restore into this // deployment" and is not a hint at the value. package backup import ( "crypto/sha256" "encoding/hex" "errors" "fmt" "gitea.hostxtra.co.uk/vantage/vantage-shared/cryptobox" ) // ErrNoKey is returned when no key was supplied at all. It is distinct from // ErrBadKey because the operator remedies are different: one is "set the // variable", the other is "the value you set is wrong". var ErrNoKey = errors.New("KEY_ENCRYPTION_KEY is not set") // ErrBadKey is returned when a key was supplied but is not 64 hex characters. var ErrBadKey = errors.New("KEY_ENCRYPTION_KEY must be a 64-character hex string (32 bytes)") // ParseKey decodes the hex form used by KEY_ENCRYPTION_KEY. func ParseKey(hexKey string) ([]byte, error) { if hexKey == "" { return nil, ErrNoKey } key, err := hex.DecodeString(hexKey) if err != nil { return nil, fmt.Errorf("%w: not hexadecimal", ErrBadKey) } if len(key) != cryptobox.KeySize { return nil, fmt.Errorf("%w: decoded to %d bytes", ErrBadKey, len(key)) } return key, nil } // Fingerprint is the SHA-256 of the raw key bytes, hex encoded. // // Of the raw bytes rather than of the hex string, so an operator who writes the // key in uppercase in one deployment and lowercase in another still gets one // fingerprint for one key. func Fingerprint(key []byte) string { sum := sha256.Sum256(key) return hex.EncodeToString(sum[:]) } // FingerprintHex parses and fingerprints in one step. func FingerprintHex(hexKey string) (string, error) { key, err := ParseKey(hexKey) if err != nil { return "", err } return Fingerprint(key), nil }