Use v.Stdout/v.Stdin instead of os.Stdout for all user-facing output (closes #26) #31
@ -479,53 +479,6 @@ func (v *Vaultik) restoreRegularFile(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlobFetchResult holds the result of fetching and decrypting a blob.
|
|
||||||
type BlobFetchResult struct {
|
|
||||||
Data []byte
|
|
||||||
CompressedSize int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchAndDecryptBlob downloads a blob from storage, decrypts and decompresses it.
|
|
||||||
func (v *Vaultik) FetchAndDecryptBlob(ctx context.Context, blobHash string, expectedSize int64, identity age.Identity) (*BlobFetchResult, error) {
|
|
||||||
// Construct blob path with sharding
|
|
||||||
blobPath := fmt.Sprintf("blobs/%s/%s/%s", blobHash[:2], blobHash[2:4], blobHash)
|
|
||||||
|
|
||||||
reader, err := v.Storage.Get(ctx, blobPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("downloading blob: %w", err)
|
|
||||||
}
|
|
||||||
defer func() { _ = reader.Close() }()
|
|
||||||
|
|
||||||
// Read encrypted data
|
|
||||||
encryptedData, err := io.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("reading blob data: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt and decompress
|
|
||||||
blobReader, err := blobgen.NewReader(bytes.NewReader(encryptedData), identity)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("creating decryption reader: %w", err)
|
|
||||||
}
|
|
||||||
defer func() { _ = blobReader.Close() }()
|
|
||||||
|
|
||||||
data, err := io.ReadAll(blobReader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("decrypting blob: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Downloaded and decrypted blob",
|
|
||||||
"hash", blobHash[:16],
|
|
||||||
"encrypted_size", humanize.Bytes(uint64(len(encryptedData))),
|
|
||||||
"decrypted_size", humanize.Bytes(uint64(len(data))),
|
|
||||||
)
|
|
||||||
|
|
||||||
return &BlobFetchResult{
|
|
||||||
Data: data,
|
|
||||||
CompressedSize: int64(len(encryptedData)),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// downloadBlob downloads and decrypts a blob
|
// downloadBlob downloads and decrypts a blob
|
||||||
func (v *Vaultik) downloadBlob(ctx context.Context, blobHash string, expectedSize int64, identity age.Identity) ([]byte, error) {
|
func (v *Vaultik) downloadBlob(ctx context.Context, blobHash string, expectedSize int64, identity age.Identity) ([]byte, error) {
|
||||||
result, err := v.FetchAndDecryptBlob(ctx, blobHash, expectedSize, identity)
|
result, err := v.FetchAndDecryptBlob(ctx, blobHash, expectedSize, identity)
|
||||||
|
|||||||
@ -545,7 +545,7 @@ func (v *Vaultik) PurgeSnapshots(keepLatest bool, olderThan string, force bool)
|
|||||||
if !force {
|
if !force {
|
||||||
v.printfStdout("\nDelete %d snapshot(s)? [y/N] ", len(toDelete))
|
v.printfStdout("\nDelete %d snapshot(s)? [y/N] ", len(toDelete))
|
||||||
var confirm string
|
var confirm string
|
||||||
if _, err := fmt.Scanln(&confirm); err != nil {
|
if _, err := v.scanStdin(&confirm); err != nil {
|
||||||
// Treat EOF or error as "no"
|
// Treat EOF or error as "no"
|
||||||
v.printlnStdout("Cancelled")
|
v.printlnStdout("Cancelled")
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -149,17 +149,6 @@ func (v *Vaultik) scanStdin(a ...any) (int, error) {
|
|||||||
return fmt.Fscanln(v.Stdin, a...)
|
return fmt.Fscanln(v.Stdin, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchBlob downloads a blob from storage and returns a reader for the encrypted data.
|
|
||||||
func (v *Vaultik) FetchBlob(ctx context.Context, blobHash string, expectedSize int64) (io.ReadCloser, int64, error) {
|
|
||||||
blobPath := fmt.Sprintf("blobs/%s/%s/%s", blobHash[:2], blobHash[2:4], blobHash)
|
|
||||||
|
|
||||||
reader, err := v.Storage.Get(ctx, blobPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("downloading blob: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader, expectedSize, nil
|
|
||||||
}
|
|
||||||
// TestVaultik wraps a Vaultik with captured stdout/stderr for testing
|
// TestVaultik wraps a Vaultik with captured stdout/stderr for testing
|
||||||
type TestVaultik struct {
|
type TestVaultik struct {
|
||||||
*Vaultik
|
*Vaultik
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user