diff options
author | Rasmus Dahlberg <rasmus@mullvad.net> | 2022-03-02 23:16:43 +0100 |
---|---|---|
committer | Rasmus Dahlberg <rasmus@mullvad.net> | 2022-03-02 23:17:48 +0100 |
commit | 8da382069f42f6d88d3abf914dd38d7e40a845bc (patch) | |
tree | 780e8297ee3905ab662c6c88cb8bf33f0717c90c /pkg/client/api |
initial commit
Diffstat (limited to 'pkg/client/api')
-rw-r--r-- | pkg/client/api/api.go | 22 | ||||
-rw-r--r-- | pkg/client/api/network_client.go | 133 |
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 +} |