diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5949147..15dc81e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,6 +23,10 @@ jobs: with: fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - run: make test - uses: paambaati/codeclimate-action@v3.0.0 @@ -34,10 +38,12 @@ jobs: coverageLocations: | ${{github.workspace}}/c.out:gocov - - uses: goreleaser/goreleaser-action@v3 + - if: ${{ !startsWith(github.ref, 'refs/tags/v') }} + run: echo "flags=--snapshot" >> $GITHUB_ENV + - uses: goreleaser/goreleaser-action@v6 if: matrix.os == 'ubuntu-latest' with: - args: release --rm-dist + args: release --clean ${{ env.flags }} env: GITHUB_TOKEN: ${{ secrets.GH_PAT }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 4a496c3..e6f9603 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,5 @@ +version: 2 + project_name: horcrux builds: @@ -29,7 +31,7 @@ archives: - CONTRIBUTING.md brews: - - tap: + - repository: owner: corvus-ch name: homebrew-tools diff --git a/README.md b/README.md index b704663..760fe7e 100644 --- a/README.md +++ b/README.md @@ -49,10 +49,52 @@ Restore a GPG key (builds on top of the above example): paperkey --pubring=public.gpg --secrets=paperkey.bin --input-type=raw --output=secret.gpg diff "${KEY_ID}.gpg" secret.gpg +Create PDF output using a template + +Contents of `text.tmpl` located in the current working directory. + +```go-tmpl +{{define "header" -}} += My document title +{{ printf "%03d" .Output.X }}, {docdate} +:version-label: Fragment +:doctype: book + +== File Information + +[horizontal] +Name:: {{ .Input.Name }} +Size:: {{ .Input.Size }} bytes +MD5:: {{ .Input.Checksums.Md5 }} +SHA1:: {{ .Input.Checksums.Sha1 }} +SHA256:: {{ .Input.Checksums.Sha256 }} +SHA512:: {{ .Input.Checksums.Sha512 }} + +== Text Data +.... +{{end}} + +{{define "footer" -}} +.... + +== QR Codes + +image::{{ .Input.Stem }}.{{ printf "%03d" .Output.X }}.1.png[align="center"] +{{end}} +``` + + horcrux create --encrypt -f text -f qr "/path/to/secret" + for f in test.txt.*; do asciidoctor-pdf -o "${f%.txt.*}-${f##*.}.pdf" "${f}"; done + +Print the PDFs. Write the corresponding password onto each of them by hand. + +IMPORTANT: This produces an incomplete result, should your secret does not fit in one single QR code. +Add more image lines as needed. + ## Known issues The QR code format provide a limited feature set and can not be used to recover -the data. A tool like `zbarimg` from the [zbar libary][zbar] can be used to +the data directly. A tool like `zbarimg` from the [zbar libary][zbar] can be used to scan the qr codes so it can be read by the zbase32 format. ## Milestones @@ -60,7 +102,8 @@ scan the qr codes so it can be read by the zbase32 format. * [x] Basic application * [x] Plain text format for print and easy scan/ocr * [x] QR Code format for easier scanning -* [ ] Template system for custom output +* [x] Template system for custom output +* [ ] Extend possibilities with templates ## Contributing and license diff --git a/format/text/text.go b/format/text/text.go index f8a9553..011a92f 100644 --- a/format/text/text.go +++ b/format/text/text.go @@ -30,12 +30,16 @@ func (f *Format) OutputFileName(x byte) string { // Writer creates a new text format writer for the part identified by x. func (f *Format) Writer(x byte) (io.Writer, []io.Closer, error) { - file, err := os.Create(f.OutputFileName(x)) + name := f.OutputFileName(x) + file, err := os.Create(name) if nil != err { return nil, nil, err } - w, err := NewWriter(file, f) + w, err := NewWriter(file, f, output{ + Name: name, + X: x, + }) if err != nil { return nil, []io.Closer{file}, err } diff --git a/format/text/writer.go b/format/text/writer.go index 90fd65d..9e73952 100644 --- a/format/text/writer.go +++ b/format/text/writer.go @@ -43,20 +43,27 @@ type line struct { CRC uint32 } +type output struct { + Name string + X byte +} + type templateData struct { - Input input.Input - Lines chan line + Input input.Input + Lines chan line + Output output } // NewWriter returns an text format writer instance. -func NewWriter(w io.Writer, f *Format) (io.WriteCloser, error) { +func NewWriter(w io.Writer, f *Format, o output) (io.WriteCloser, error) { tw := &writer{ w: w, buf: make([]byte, bufLen(f.LineLength)), crc: crc24.New(), data: templateData{ - Input: f.input, - Lines: make(chan line), + Input: f.input, + Lines: make(chan line), + Output: o, }, t: template.New("text"), } diff --git a/format/text/writer_test.go b/format/text/writer_test.go index 3c7a3fe..d8460c2 100644 --- a/format/text/writer_test.go +++ b/format/text/writer_test.go @@ -56,7 +56,7 @@ func TestWriterWrite(t *testing.T) { for _, test := range writeTests { t.Run(test.data, func(t *testing.T) { buf.Reset() - w, err := NewWriter(&buf, &Format{LineLength: 42}) + w, err := NewWriter(&buf, &Format{LineLength: 42}, output{"test", 7}) if err != nil { t.Fatal(err) } @@ -74,7 +74,7 @@ func TestWriter_Write_LineLength(t *testing.T) { for i := 14; i < len(data)+13; i++ { t.Run(fmt.Sprint(i), func(t *testing.T) { buf.Reset() - w, err := NewWriter(&buf, &Format{LineLength: uint8(i)}) + w, err := NewWriter(&buf, &Format{LineLength: uint8(i)}, output{"test", 13}) if err != nil { t.Fatal(err) }