aboutsummaryrefslogtreecommitdiff
path: root/pkg/client/api
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus@mullvad.net>2022-03-02 23:16:43 +0100
committerRasmus Dahlberg <rasmus@mullvad.net>2022-03-02 23:17:48 +0100
commit8da382069f42f6d88d3abf914dd38d7e40a845bc (patch)
tree780e8297ee3905ab662c6c88cb8bf33f0717c90c /pkg/client/api
initial commit
Diffstat (limited to 'pkg/client/api')
-rw-r--r--pkg/client/api/api.go22
-rw-r--r--pkg/client/api/network_client.go133
2 files changed, 155 insertions, 0 deletions
diff --git a/pkg/client/api/api.go b/pkg/client/api/api.go
new file mode 100644
index 0000000..d773bcc
--- /dev/null
+++ b/pkg/client/api/api.go
@@ -0,0 +1,22 @@
+// package api implements the Sigsum v0 API. See
+//
+// https://git.sigsum.org/sigsum/tree/doc/api.md
+//
+// for further details. No verification, retries, etc., is done here.
+package api
+
+import (
+ "git.sigsum.org/sigsum-lib-go/pkg/requests"
+ "git.sigsum.org/sigsum-lib-go/pkg/types"
+)
+
+type API interface {
+ GetToCosignTreeHead() (*types.SignedTreeHead, error)
+ GetCosignedTreeHead() (*types.CosignedTreeHead, error)
+ GetInclusionProof(treeSize uint64, leafHash *types.Hash) (*types.InclusionProof, error)
+ GetConsistencyProof(oldSize, newSize uint64) (*types.ConsistencyProof, error)
+ GetLeaves(startSize, endSize uint64) (*types.Leaves, error)
+
+ AddLeaf(*requests.Leaf) error
+ AddCosignature(*requests.Cosignature) error
+}
diff --git a/pkg/client/api/network_client.go b/pkg/client/api/network_client.go
new file mode 100644
index 0000000..f7baf76
--- /dev/null
+++ b/pkg/client/api/network_client.go
@@ -0,0 +1,133 @@
+package api
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+
+ "git.sigsum.org/sigsum-lib-go/pkg/requests"
+ "git.sigsum.org/sigsum-lib-go/pkg/types"
+)
+
+type NetworkClient struct {
+ http.Client
+ LogURL string
+}
+
+func NewNetworkClient(httpClient http.Client, logURL string) *NetworkClient {
+ return &NetworkClient{
+ Client: httpClient,
+ LogURL: logURL,
+ }
+}
+
+func (c *NetworkClient) GetToCosignTreeHead() (*types.SignedTreeHead, error) {
+ return nil, fmt.Errorf("TODO")
+}
+
+func (c *NetworkClient) GetCosignedTreeHead() (*types.CosignedTreeHead, error) {
+ rsp, err := c.get(types.EndpointGetTreeHeadCosigned.Path(c.LogURL))
+ if err != nil {
+ return nil, fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+
+ defer rsp.Body.Close()
+ if rsp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+
+ var cth types.CosignedTreeHead
+ if err := cth.FromASCII(rsp.Body); err != nil {
+ return nil, fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+ return &cth, nil
+}
+
+func (c *NetworkClient) GetInclusionProof(treeSize uint64, leafHash *types.Hash) (*types.InclusionProof, error) {
+ data := requests.InclusionProof{
+ TreeSize: treeSize,
+ LeafHash: *leafHash,
+ }
+ buf := bytes.NewBuffer(nil)
+ if err := data.ToASCII(buf); err != nil {
+ return nil, fmt.Errorf("client: invalid request data: %v", err)
+ }
+
+ rsp, err := c.post(types.EndpointGetInclusionProof.Path(c.LogURL), buf)
+ if err != nil {
+ return nil, fmt.Errorf("client: invalid proof request: %v", err)
+ }
+
+ defer rsp.Body.Close()
+ if rsp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+ var proof types.InclusionProof
+ if err := proof.FromASCII(rsp.Body, treeSize); err != nil {
+ return nil, fmt.Errorf("client: failed parsing response: %v", err)
+ }
+
+ return &proof, nil
+}
+
+func (c *NetworkClient) GetConsistencyProof(oldSize, newSize uint64) (*types.ConsistencyProof, error) {
+ return nil, fmt.Errorf("TODO")
+}
+
+func (c *NetworkClient) GetLeaves(startSize, endSize uint64) (*types.Leaves, error) {
+ return nil, fmt.Errorf("TODO")
+}
+
+func (c *NetworkClient) AddLeaf(leaf *requests.Leaf) error {
+ buf := bytes.NewBuffer(nil)
+ if err := leaf.ToASCII(buf); err != nil {
+ return fmt.Errorf("client: invalid request data: %v", err)
+ }
+
+ rsp, err := c.post(types.EndpointAddLeaf.Path(c.LogURL), buf)
+ if err != nil {
+ return fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+
+ defer rsp.Body.Close()
+ if rsp.StatusCode != http.StatusOK {
+ return fmt.Errorf("client: HTTP %d: %s", rsp.StatusCode, errorMessage(rsp.Body))
+ }
+ return nil
+}
+
+func (c *NetworkClient) AddCosignature(*requests.Cosignature) error {
+ return fmt.Errorf("TODO")
+}
+
+func (c *NetworkClient) get(url string) (*http.Response, error) {
+ log.Printf("GET %s", url)
+ return c.Get(url)
+}
+
+func (c *NetworkClient) post(url string, buf *bytes.Buffer) (*http.Response, error) {
+ req, err := http.NewRequest("POST", url, buf)
+ if err != nil {
+ return nil, fmt.Errorf("client: invalid leaf request: %v", err)
+ }
+
+ log.Printf("POST %s", url)
+ return c.Do(req)
+}
+
+func errorMessage(r io.Reader) string {
+ b, _ := ioutil.ReadAll(r)
+ return string(b)
+
+ // TODO: the below doesn't work because log error messages are malformed
+ //msg := struct {
+ // Message string `ascii:"Error"`
+ //}{}
+ //if err := ascii.StdEncoding.Deserialize(r, &msg); err != nil {
+ // return fmt.Sprintf("malformed error message: %v", err)
+ //}
+ //return msg.Message
+}