You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys-App/scripts/locator-go-verdicts.go

175 lines
5.3 KiB

//go:build ignore
// Opens with Go what the locator of datekeys-ts writes, and prints
// src/lib/dkc/testing/locator-interop.json: each recipe of
// src/lib/dkc/testing/locator-interop.ts, written by
// scripts/locator-ts-samples.mjs, with the SHA-256 of each of its files and
// the verdict of Go:
//
// - locator.Open of the sealed locator with Quicknet, its round and the
// published release of the round, from the fixtures;
// - Marshal of the locator that Open gives, which must be the plaintext
// that TypeScript sealed, and Usable, which must keep every address;
// - OpenEnvelope of the rest, which must give the .dkc;
// - RestIn of the rest hidden after a host with Hide, at its offset,
// which must give the rest again.
//
// A verdict is "ok" or the text of the first thing that failed.
//
// It imports only public packages of the reference implementation, and runs
// in a module of it without changing anything there: an export of the tag
// spec-v0.12, so that no change in progress in datekeys-go is read.
//
// node scripts/locator-ts-samples.mjs /tmp/samples
// git -C ../datekeys-go archive spec-v0.12 | tar -x -C /tmp/dkgo
// (cd /tmp/dkgo && go run .../datekeys-ts/scripts/locator-go-verdicts.go \
// -source spec-v0.12 -testdata .../datekeys-ts/testdata -samples /tmp/samples > .../locator-interop.json)
package main
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"g.activething.com/go/DateKeys/locator"
"g.activething.com/go/DateKeys/profile"
"g.activething.com/go/DateKeys/provider"
)
type obj = map[string]any
func h(b []byte) string { return hex.EncodeToString(b) }
func check(err error) {
if err != nil {
_, file, line, _ := runtime.Caller(1)
log.Fatalf("%s:%d: %v", filepath.Base(file), line, err)
}
}
func pattern(n int) []byte {
b := make([]byte, n)
for i := range b {
b[i] = byte(31*i + 7)
}
return b
}
func releases(testdata string) map[uint64]provider.Release {
out := map[uint64]provider.Release{}
files, err := filepath.Glob(filepath.Join(testdata, "fixtures", "*.json"))
check(err)
sort.Strings(files)
for _, f := range files {
raw, err := os.ReadFile(f)
check(err)
var v struct {
Release *struct {
Round uint64 `json:"round"`
Signature string `json:"signature"`
} `json:"release"`
}
if err := json.Unmarshal(raw, &v); err != nil || v.Release == nil {
continue
}
sig, err := hex.DecodeString(v.Release.Signature)
check(err)
out[v.Release.Round] = provider.Release{Round: v.Release.Round, Signature: sig}
}
return out
}
func verdict(r obj, files map[string][]byte, rel map[uint64]provider.Release) error {
round := uint64(r["round"].(float64))
release, ok := rel[round]
if !ok {
return fmt.Errorf("no release of round %d", round)
}
loc, err := locator.Open(profile.Quicknet(), round, release, files["sealed"])
if err != nil {
return err
}
pt, err := loc.Marshal()
if err != nil {
return err
}
if !bytes.Equal(pt, files["plaintext"]) {
return errors.New("another plaintext")
}
if len(loc.Usable()) != len(r["addresses"].([]any)) || len(loc.Addresses) != len(loc.Usable()) {
return errors.New("an address that a reader does not use")
}
dkc, err := loc.OpenEnvelope(files["rest"])
if err != nil {
return err
}
if !bytes.Equal(dkc, files["dkc"]) || !bytes.Equal(dkc, pattern(int(r["dkc_length"].(float64)))) {
return errors.New("another .dkc")
}
file, offset := locator.Hide([]byte("GIF89a, a host of some kind"), files["rest"])
rest, err := loc.RestIn(append(file, "and more"...), offset)
if err != nil {
return err
}
if !bytes.Equal(rest, files["rest"]) {
return errors.New("another rest in the host")
}
return nil
}
func main() {
samples := flag.String("samples", "", "the directory of the samples")
src := flag.String("source", "", "the commit of datekeys-go")
testdata := flag.String("testdata", "", "the testdata of this repository")
flag.Parse()
if *samples == "" || *src == "" || *testdata == "" {
log.Fatal("usage: -source <commit> -testdata <dir> -samples <dir>")
}
rel := releases(*testdata)
raw, err := os.ReadFile(filepath.Join(*samples, "samples.json"))
check(err)
var doc struct {
Samples []obj `json:"samples"`
}
check(json.Unmarshal(raw, &doc))
result := []obj{}
for i, r := range doc.Samples {
names, err := filepath.Glob(filepath.Join(*samples, fmt.Sprintf("%d.*", i)))
check(err)
files := map[string][]byte{}
digests := obj{}
for _, n := range names {
b, err := os.ReadFile(n)
check(err)
suffix := strings.TrimPrefix(filepath.Ext(n), ".")
files[suffix] = b
s := sha256.Sum256(b)
digests[suffix] = h(s[:])
}
v := "ok"
if err := verdict(r, files, rel); err != nil {
v = err.Error()
log.Printf("%s: %s", r["name"], v)
}
r["files"] = digests
r["verdict"] = v
result = append(result, r)
}
var buf bytes.Buffer
e := json.NewEncoder(&buf)
e.SetEscapeHTML(false)
e.SetIndent("", " ")
check(e.Encode(obj{"source": *src, "go": runtime.Version(), "description": "What Go makes of the sealed locators and envelopes that datekeys-ts writes from a seed, from the recipes of src/lib/dkc/testing/locator-interop.ts, by scripts/locator-go-verdicts.go: the SHA-256 of each file and the verdict of Go, ok or the text of what failed.", "samples": result}))
os.Stdout.Write(buf.Bytes())
}

Powered by TurnKey Linux.