From 8da382069f42f6d88d3abf914dd38d7e40a845bc Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Wed, 2 Mar 2022 23:16:43 +0100 Subject: initial commit --- pkg/client/submitter.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 pkg/client/submitter.go (limited to 'pkg/client/submitter.go') diff --git a/pkg/client/submitter.go b/pkg/client/submitter.go new file mode 100644 index 0000000..f03e66a --- /dev/null +++ b/pkg/client/submitter.go @@ -0,0 +1,129 @@ +package client + +import ( + "context" + "fmt" + "io" + "log" + "net/http" + "time" + + "git.sigsum.org/sigsum-lib-go/pkg/requests" + "git.sigsum.org/sigsum-lib-go/pkg/types" + "git.sigsum.org/sigsum-tool-go/pkg/client/api" + "git.sigsum.org/sigsum-tool-go/pkg/policy" +) + +type Submitter interface { + AddLeaves(context.Context, []requests.Leaf) ([]Bundle, error) +} + +type SubmitClient struct { + api api.API + policy policy.Policy +} + +// TODO: should signature+key_hash (not) be in bundle? +type Bundle struct { + ShardHint uint64 + Signature types.Signature + KeyHash types.Hash + InclusionProof types.InclusionProof + CosignedTreeHead types.CosignedTreeHead +} + +func NewSubmitClient(policy policy.Policy) *SubmitClient { + return &SubmitClient{ + policy: policy, + } +} + +// TODO: feedback on the below sketch; improve it; implement properly. +// 0. Select one log in policy, setup API network client. +// 1. Loop over all leaves that have yet to received 200 OK. Move on to +// the next leaf on a non-200 status code, trying again next itteration. +// 3. Try to fetch an inclusion proof for the latest HTTP 200 OK +// response every time a new cosigned tree head becomes available. +// Output warning if more than two cosigned tree heads pass. +// 4. Loop over all leaves and fetch inclusion proofs for X. +// [Exit with error if any inclusion proof is not available / invalid] +// 5. Return bundles in the same order as leaves were passed. +func (sc *SubmitClient) AddLeaves(_ context.Context, leaves []requests.Leaf) ([]Bundle, error) { + if err := sc.newAPI(); err != nil { + return nil, fmt.Errorf("client: %v", err) + } + + for _, leaf := range leaves { + err := sc.api.AddLeaf(&leaf) + if err != nil { + return nil, fmt.Errorf("client: %v", err) + } + } + + start := time.Now().Unix() + var bundles []Bundle + for { + cth, err := sc.api.GetCosignedTreeHead() + if err != nil { + return nil, fmt.Errorf("client: %v", err) + } + // TODO: verify that cth is valid for policy + + ok := true + bundles = nil + for _, leaf := range leaves { + l := types.Leaf{ + Statement: types.Statement{ + ShardHint: leaf.ShardHint, + Checksum: leaf.Checksum, + }, + Signature: leaf.Signature, + KeyHash: *types.HashFn(leaf.VerificationKey[:]), + } + lh := types.HashFn(append([]byte{0x00}, l.ToBinary()...)) + log.Printf("leaf hash is: %x", lh[:]) + + proof, err := sc.api.GetInclusionProof(cth.TreeSize, lh) + if err != nil { + log.Printf("no inclusion proof for tree size %d yet, please wait.\n", cth.TreeSize) + ok = false + break + } + + // TODO: verify that inclusion proof is valid + bundles = append(bundles, Bundle{ + ShardHint: l.ShardHint, + Signature: l.Signature, + KeyHash: l.KeyHash, + InclusionProof: *proof, + CosignedTreeHead: *cth, + }) + } + if ok { + break + } + + time.Sleep(15 * time.Second) + log.Printf("waited %d seconds...\n", time.Now().Unix()-start) + } + + return bundles, nil +} + +func (sc *SubmitClient) newAPI() error { + // TODO: select a log properly. + sc.api = api.NewNetworkClient(http.Client{}, sc.policy.Logs()[0].LogURL) + return nil +} + +func (b *Bundle) ToASCII(w io.Writer) error { + return fmt.Errorf("TODO") +} + +func (b *Bundle) FromASCII(r io.Reader) error { + return fmt.Errorf("TODO") +} + +func (b *Bundle) Verify(k *types.PublicKey, p *policy.Policy, r io.Reader) error { + return fmt.Errorf("TODO") +} -- cgit v1.2.3