Read the text form with blank lines in front, as age does (closes #77)
check / check (push) Waiting to run

age decrypt took the text form only when the file began exactly with
-----BEGIN AGE ENCRYPTED FILE-----, so a blank line in front made it
read the file as the binary form and refuse it. It now looks for that
line past up to 1024 bytes of whitespace, as the age tool does, and
the text form reader skips the blank lines. A test puts a blank line
and a line of two spaces in front of a text-form file. The README's
age decrypt section says so.

Judgement call: that first line with spaces in front of it on the same
line is still refused, as age refuses it.

Model: opus-5-5
This commit is contained in:
2026-10-14 19:49:07 +00:00
committed by sneak
parent 44cb5215b0
commit bb41583356
3 changed files with 35 additions and 4 deletions
+10 -3
View File
@@ -4,6 +4,7 @@ package agekey
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
@@ -187,12 +188,18 @@ func (k *Key) Decrypt(dst io.Writer, src io.Reader) error {
}
// unarmored strips the text form when the input begins with the line
// that starts one, and leaves binary input alone.
// that starts one, and leaves binary input alone. Like age, it looks
// past up to 1024 bytes of whitespace for that line, and the text form
// reader skips blank lines in front of it.
func unarmored(src io.Reader) io.Reader {
const maxWhitespace = 1024
buffered := bufio.NewReader(src)
start, err := buffered.Peek(len(armor.Header))
if err == nil && string(start) == armor.Header {
// A shorter input gives an error along with all of it, which is
// enough to look at.
start, _ := buffered.Peek(maxWhitespace + len(armor.Header))
if bytes.HasPrefix(bytes.TrimSpace(start), []byte(armor.Header)) {
return armor.NewReader(buffered)
}
+22
View File
@@ -2,6 +2,7 @@ package agekey_test
import (
"bytes"
"io"
"strings"
"testing"
@@ -99,6 +100,27 @@ func TestTheArmoredFormIsText(t *testing.T) {
))
}
func TestTheTextFormIsReadWithWhitespaceInFront(t *testing.T) {
t.Parallel()
key := forIndex(t, 0)
var sealed bytes.Buffer
err := key.Encrypt(&sealed, strings.NewReader("hello"), nil, true)
require.NoError(t, err)
// A blank line and a line of two spaces, as pasting can leave. age
// refuses spaces on the first line of the text form itself, and so
// does this.
pasted := io.MultiReader(strings.NewReader("\n \n"), &sealed)
var opened bytes.Buffer
require.NoError(t, key.Decrypt(&opened, pasted))
require.Equal(t, "hello", opened.String())
}
func TestAFileForSomebodyElseIsRefused(t *testing.T) {
t.Parallel()