aboutsummaryrefslogtreecommitdiff
path: root/endpoint.go
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-02-25 14:36:35 +0100
committerRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-02-25 14:36:35 +0100
commitc05c22ddbc771e7713849cae40f9d91bfafa0503 (patch)
treeb97d11ab2a914806e6f671f9aff1cab9767b2eab /endpoint.go
parentc9b4b43654f0ff26207cc63449f13298cd3c56e8 (diff)
major refactor based on README.md and TODOs
Updated types, improved units tests, isolated most test data to have it in one place, renamed and created new files to improve readability, and fixed a bunch of minor TODOs.
Diffstat (limited to 'endpoint.go')
-rw-r--r--endpoint.go185
1 files changed, 185 insertions, 0 deletions
diff --git a/endpoint.go b/endpoint.go
new file mode 100644
index 0000000..d3da95e
--- /dev/null
+++ b/endpoint.go
@@ -0,0 +1,185 @@
+package stfe
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "net/http"
+
+ "github.com/golang/glog"
+ "github.com/google/trillian"
+ "github.com/system-transparency/stfe/types"
+)
+
+// Endpoint is a named HTTP API endpoint
+type Endpoint string
+
+const (
+ EndpointAddEntry = Endpoint("add-entry")
+ EndpointAddCosignature = Endpoint("add-cosignature")
+ EndpointGetLatestSth = Endpoint("get-latest-sth")
+ EndpointGetStableSth = Endpoint("get-stable-sth")
+ EndpointGetCosignedSth = Endpoint("get-cosigned-sth")
+ EndpointGetProofByHash = Endpoint("get-proof-by-hash")
+ EndpointGetConsistencyProof = Endpoint("get-consistency-proof")
+ EndpointGetEntries = Endpoint("get-entries")
+)
+
+// Path joins a number of components to form a full endpoint path, e.g., base
+// ("example.com"), prefix ("st/v1"), and the endpoint itself ("get-sth").
+func (e Endpoint) Path(components ...string) string {
+ return strings.Join(append(components, string(e)), "/")
+}
+
+func addEntry(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling add-entry request")
+ item, err := i.LogParameters.parseAddEntryV1Request(r)
+ if err != nil {
+ return http.StatusBadRequest, fmt.Errorf("parseAddEntryV1Request: %v", err)
+ }
+ leaf, err := types.Marshal(*item)
+ if err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("Marshal: %v", err) // should never happen
+ }
+ trsp, err := i.Client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
+ LogId: i.LogParameters.TreeId,
+ Leaf: &trillian.LogLeaf{
+ LeafValue: leaf,
+ ExtraData: nil,
+ },
+ })
+ if errInner := checkQueueLeaf(trsp, err); errInner != nil {
+ return http.StatusInternalServerError, fmt.Errorf("bad QueueLeafResponse: %v", errInner)
+ }
+ return http.StatusOK, nil
+}
+
+func addCosignature(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling add-cosignature request")
+ costh, err := i.LogParameters.parseAddCosignatureV1Request(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+ if err := i.SthSource.AddCosignature(ctx, costh); err != nil {
+ return http.StatusBadRequest, err
+ }
+ return http.StatusOK, nil
+}
+
+func getLatestSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-latest-sth request")
+ sth, err := i.SthSource.Latest(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("Latest: %v", err)
+ }
+ if err := writeOctetResponse(w, *sth); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func getStableSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-stable-sth request")
+ sth, err := i.SthSource.Stable(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("Latest: %v", err)
+ }
+ if err := writeOctetResponse(w, *sth); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func getCosignedSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-cosigned-sth request")
+ costh, err := i.SthSource.Cosigned(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("Cosigned: %v", err)
+ }
+ if err := writeOctetResponse(w, *costh); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func getConsistencyProof(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-consistency-proof request")
+ req, err := i.LogParameters.parseGetConsistencyProofV1Request(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ trsp, err := i.Client.GetConsistencyProof(ctx, &trillian.GetConsistencyProofRequest{
+ LogId: i.LogParameters.TreeId,
+ FirstTreeSize: int64(req.First),
+ SecondTreeSize: int64(req.Second),
+ })
+ if errInner := checkGetConsistencyProof(i.LogParameters, trsp, err); errInner != nil {
+ return http.StatusInternalServerError, fmt.Errorf("bad GetConsistencyProofResponse: %v", errInner)
+ }
+
+ if err := writeOctetResponse(w, *types.NewConsistencyProofV1(i.LogParameters.LogId, req.First, req.Second, NewNodePathFromHashPath(trsp.Proof.Hashes))); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func getProofByHash(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-proof-by-hash request")
+ req, err := i.LogParameters.parseGetProofByHashV1Request(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ trsp, err := i.Client.GetInclusionProofByHash(ctx, &trillian.GetInclusionProofByHashRequest{
+ LogId: i.LogParameters.TreeId,
+ LeafHash: req.Hash[:],
+ TreeSize: int64(req.TreeSize),
+ OrderBySequence: true,
+ })
+ if errInner := checkGetInclusionProofByHash(i.LogParameters, trsp, err); errInner != nil {
+ return http.StatusInternalServerError, fmt.Errorf("bad GetInclusionProofByHashResponse: %v", errInner)
+ }
+
+ if err := writeOctetResponse(w, *types.NewInclusionProofV1(i.LogParameters.LogId, req.TreeSize, uint64(trsp.Proof[0].LeafIndex), NewNodePathFromHashPath(trsp.Proof[0].Hashes))); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func getEntries(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-entries request")
+ req, err := i.LogParameters.parseGetEntriesV1Request(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ trsp, err := i.Client.GetLeavesByRange(ctx, &trillian.GetLeavesByRangeRequest{
+ LogId: i.LogParameters.TreeId,
+ StartIndex: int64(req.Start),
+ Count: int64(req.End-req.Start) + 1,
+ })
+ if errInner := checkGetLeavesByRange(req, trsp, err); errInner != nil {
+ return http.StatusInternalServerError, fmt.Errorf("checkGetLeavesByRangeResponse: %v", errInner) // there is one StatusBadRequest in here tho..
+ }
+
+ if rsp, err := NewStItemListFromLeaves(trsp.Leaves); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("NewStItemListFromLeaves: %v", err) // should never happen
+ } else if err := writeOctetResponse(w, *rsp); err != nil {
+ return http.StatusInternalServerError, fmt.Errorf("writeOctetResponse: %v", err)
+ }
+ return http.StatusOK, nil
+}
+
+func writeOctetResponse(w http.ResponseWriter, i interface{}) error {
+ b, err := types.Marshal(i)
+ if err != nil {
+ return fmt.Errorf("Marshal: %v", err)
+ }
+ w.Header().Set("Content-Type", "application/octet-stream")
+ if _, err := w.Write(b); err != nil {
+ return fmt.Errorf("Write: %v", err)
+ }
+ return nil
+}