42 lines
1.6 KiB
Go
42 lines
1.6 KiB
Go
package snapshot
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
)
|
|
|
|
// remoteKeyPrefix is mixed into the snapshot ID hash so the resulting
|
|
// hex digest is domain-separated from any other "double SHA256 of a
|
|
// string" identifier the user might also use. Keeping this stable is a
|
|
// hard compatibility requirement: changing it invalidates every
|
|
// existing snapshot's remote storage path.
|
|
const remoteKeyPrefix = "vaultik|"
|
|
|
|
// RemoteSnapshotKey returns the storage-side identifier for a snapshot
|
|
// given its human snapshot ID. It is hex(SHA256(SHA256(prefix + id))).
|
|
// The two SHA256 rounds match Bitcoin's "hash256" convention so the
|
|
// output looks like a 64-character hex blob with no exploitable
|
|
// structure visible to a remote observer.
|
|
//
|
|
// We use this in three places:
|
|
//
|
|
// - the "metadata/<remote-key>/..." subdirectory on the storage
|
|
// backend so a directory listing of the bucket / file:// dest
|
|
// doesn't reveal hostnames, configured snapshot names, or backup
|
|
// timestamps;
|
|
// - the `snapshot_id` field of the unencrypted manifest.json.zst
|
|
// for the same reason;
|
|
// - any code path that needs to translate a known local snapshot ID
|
|
// into the path it would occupy on remote storage.
|
|
//
|
|
// The human ID stays the user-visible handle everywhere else — local
|
|
// database joins, CLI arguments, summary lines, log fields — because
|
|
// it's never written to the public bytes once this function gates
|
|
// every storage-path construction.
|
|
func RemoteSnapshotKey(snapshotID string) string {
|
|
first := sha256.Sum256([]byte(remoteKeyPrefix + snapshotID))
|
|
second := sha256.Sum256(first[:])
|
|
|
|
return hex.EncodeToString(second[:])
|
|
}
|