Files
vaultik/internal/blobgen/reader.go
sneak 7ae470e530 Remediate all lint findings under the canonical golangci-lint config
Fix every finding surfaced by the canonical .golangci.yml with
golangci-lint v2.12.2 (refs #61), behavior-preserving throughout:

- err113: dynamic errors replaced with package-level sentinels and %w
  wrapping; direct comparisons converted to errors.Is
- goprintffuncname: printf-style helpers renamed with an f suffix
  (ui.Writer message methods, cli.ReportErrorf, database.Fatalf,
  vaultik stdoutf) and all call sites updated
- revive: stuttering type names renamed (blob.Handler, blob.WithReader,
  blob.ChunkPosition, storage.URL, storage.Info), doc comments added,
  unused parameters blanked, package comments added
- contextcheck/noctx: ctx threaded through blob.Packer
  (AddChunk/Flush/FinalizeBlob/PackChunks) and scanner call sites;
  context-aware exec and sql variants used
- funlen/cyclop/gocognit/nestif/dupl: oversized or duplicated
  functions split into focused helpers across production and test code
- paralleltest/tparallel/thelper/usetesting/testpackage: tests
  parallelized where safe (global log.Initialize kept in the serial
  phase), helpers marked, t.TempDir adopted, external test packages
  where only exported API is used
- gosec: integer conversions clamped or justified, header timeouts
  added, remaining findings suppressed with per-site justifications
- mnd/goconst/lll/wsl_v5/nlreturn/noinlineerr/errcheck and other
  mechanical findings fixed directly

Remove the deprecated log.LogOptions alias (callers migrated to
log.Options). make check is green.
2026-08-07 18:51:21 +00:00

76 lines
1.6 KiB
Go

package blobgen
import (
"crypto/sha256"
"fmt"
"hash"
"io"
"filippo.io/age"
"github.com/klauspost/compress/zstd"
)
// Reader wraps decompression and decryption with SHA256 verification
type Reader struct {
reader io.Reader
decompressor *zstd.Decoder
decryptor io.Reader
hasher hash.Hash
teeReader io.Reader
bytesRead int64
}
// NewReader creates a new Reader that decrypts, decompresses, and verifies data
func NewReader(r io.Reader, identity age.Identity) (*Reader, error) {
// Create decryption reader
decReader, err := age.Decrypt(r, identity)
if err != nil {
return nil, fmt.Errorf("creating decryption reader: %w", err)
}
// Create decompression reader
decompressor, err := zstd.NewReader(decReader)
if err != nil {
return nil, fmt.Errorf("creating decompression reader: %w", err)
}
// Create SHA256 hasher
hasher := sha256.New()
// Create tee reader that reads from decompressor and writes to hasher
teeReader := io.TeeReader(decompressor, hasher)
return &Reader{
reader: r,
decompressor: decompressor,
decryptor: decReader,
hasher: hasher,
teeReader: teeReader,
}, nil
}
// Read implements io.Reader
func (r *Reader) Read(p []byte) (int, error) {
n, err := r.teeReader.Read(p)
r.bytesRead += int64(n)
return n, err
}
// Close closes the decompressor
func (r *Reader) Close() error {
r.decompressor.Close()
return nil
}
// Sum256 returns the SHA256 hash of all data read
func (r *Reader) Sum256() []byte {
return r.hasher.Sum(nil)
}
// BytesRead returns the number of uncompressed bytes read
func (r *Reader) BytesRead() int64 {
return r.bytesRead
}