From da2191789a4db9a68ed5f078aca2ac49d55e7740 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 26 Dec 2025 21:35:42 +0100 Subject: [PATCH] age: add ExampleDecryptReaderAt with zip.NewReader --- age.go | 4 ++-- age_test.go | 36 ++++++++++++++++++++++++++++++++++++ testdata/example.zip.age | Bin 0 -> 391 bytes 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 testdata/example.zip.age diff --git a/age.go b/age.go index 16d9bf6..13a2802 100644 --- a/age.go +++ b/age.go @@ -284,8 +284,8 @@ func Decrypt(src io.Reader, identities ...Identity) (io.Reader, error) { // DecryptReaderAt takes an underlying [io.ReaderAt] and its total encrypted // size, and returns a ReaderAt of the decrypted plaintext and the plaintext // size. These can be used for example to instantiate an [io.SectionReader], -// which implements [io.Reader] and [io.Seeker]. Note that ReaderAt by -// definition disregards the seek position of src. +// which implements [io.Reader] and [io.Seeker], or for [zip.NewReader]. +// Note that ReaderAt by definition disregards the seek position of src. // // The ReadAt method of the returned ReaderAt can be called concurrently. // The ReaderAt will internally cache the most recently decrypted chunk. diff --git a/age_test.go b/age_test.go index bbe9e26..7cded16 100644 --- a/age_test.go +++ b/age_test.go @@ -5,10 +5,12 @@ package age_test import ( + "archive/zip" "bytes" "errors" "fmt" "io" + "io/fs" "log" "os" "slices" @@ -191,6 +193,40 @@ func TestEncryptDecryptScrypt(t *testing.T) { } } +func ExampleDecryptReaderAt() { + identity, err := age.ParseX25519Identity(privateKey) + if err != nil { + log.Fatalf("Failed to parse private key: %v", err) + } + + f, err := os.Open("testdata/example.zip.age") + if err != nil { + log.Fatalf("Failed to open file: %v", err) + } + stat, err := f.Stat() + if err != nil { + log.Fatalf("Failed to stat file: %v", err) + } + + r, size, err := age.DecryptReaderAt(f, stat.Size(), identity) + if err != nil { + log.Fatalf("Failed to open encrypted file: %v", err) + } + + z, err := zip.NewReader(r, size) + if err != nil { + log.Fatalf("Failed to open zip: %v", err) + } + contents, err := fs.ReadFile(z, "example.txt") + if err != nil { + log.Fatalf("Failed to read file from zip: %v", err) + } + + fmt.Printf("File contents: %q\n", contents) + // Output: + // File contents: "Black lives matter." +} + func TestParseIdentities(t *testing.T) { tests := []struct { name string diff --git a/testdata/example.zip.age b/testdata/example.zip.age new file mode 100644 index 0000000000000000000000000000000000000000..7a798ce6eb680fc8906fb10569e3fec930d291fb GIT binary patch literal 391 zcmV;20eJplXJsvAZewzJaCB*JZZ2S!r%lO*MLPRY?jhEiE82ba_rkLt#*FR5n#^bx(OWb5TlWF=be8 zG;m@!dNOruQ)g5}NqBNfcvT8l3LWpEf@B7CRbseQptHF!u;a%l;CV{~K~REZaxsTZ z929={sLW895fgCyWNyDSX`N8fwxgqlYEiNe8jYvs%;ed0NoRIbIu z-m$J|Owf<#*;j)tQe>)_{L7<<_tHqeQ)E>T;ESM;teBF8#F__2bHj-2z%qFSD=Fsm zT?iZ!FYw+hYdyv|C|Hb??NY}<*4HpGQp4+6u8O;Zw~ovpm1{Ikr-nAu+H|XStmnXD lt%2%e3xo^aUq&!w>UP?Ai|zpp*W1q|SOOCG6(4>e4KL@Kr;z{v literal 0 HcmV?d00001