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.
175 lines
5.3 KiB
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())
|
|
}
|