aboutsummaryrefslogtreecommitdiff
path: root/pkg/client/submitter.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/client/submitter.go')
-rw-r--r--pkg/client/submitter.go129
1 files changed, 129 insertions, 0 deletions
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")
+}