From 2fd1c7efe81d843b8828916ff692364cca2cc1c1 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Tue, 20 Oct 2020 17:36:49 +0200 Subject: added basic structure An STFE server instance that dials the Trillian gRPC back-end, and which listens on six different HTTP endpoints but without any actual processing. --- doc.go | 3 +++ handler.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ instance.go | 50 ++++++++++++++++++++++++++++++++++++ server/main.go | 52 ++++++++++++++++++++++++++++++++++++++ server/server | Bin 0 -> 14361514 bytes type.go | 3 +++ 6 files changed, 186 insertions(+) create mode 100644 doc.go create mode 100644 handler.go create mode 100644 instance.go create mode 100644 server/main.go create mode 100755 server/server create mode 100644 type.go diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..4e86552 --- /dev/null +++ b/doc.go @@ -0,0 +1,3 @@ +// Package stfe implements a System Transparency Front-End (STFE) personality +// for the Trillian log server gRPC API. +package stfe diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..90dbc27 --- /dev/null +++ b/handler.go @@ -0,0 +1,78 @@ +package stfe + +import ( + "context" + "fmt" + + "net/http" + + "github.com/golang/glog" +) + +// appHandler implements the http.Handler interface, and contains a reference +// to an STFE server instance as well as a function that uses it. +type appHandler struct { + instance *instance // STFE server instance + endpoint string // e.g., add-entry + method string // e.g., GET + handler func(context.Context, *instance, http.ResponseWriter, *http.Request) (int, error) +} + +// ServeHTTP docdoc +func (a appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithDeadline(r.Context(), a.instance.timesource.Now().Add(a.instance.deadline)) + defer cancel() + + if r.Method != a.method { + glog.Warningf("%s: got HTTP %s, wanted HTTP %s", a.instance.prefix+a.endpoint, r.Method, a.method) + a.sendHTTPError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed: %s", r.Method)) + return + } + + statusCode, err := a.handler(ctx, a.instance, w, r) + if err != nil { + glog.Warningf("handler error %s: %v", a.instance.prefix+a.endpoint, err) + a.sendHTTPError(w, statusCode, err) + } +} + +// sendHTTPError replies to a request with an error message and a status code. +func (a appHandler) sendHTTPError(w http.ResponseWriter, statusCode int, err error) { + http.Error(w, http.StatusText(statusCode), statusCode) +} + +// addEntry adds an entry to the Trillian backend +func addEntry(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in addEntry") + return http.StatusOK, nil // TODO +} + +// getEntries provides with a list of entries from the Trillian backend +func getEntries(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in getEntries") + return http.StatusOK, nil // TODO +} + +// getAnchors provides a list of configured trust anchors +func getAnchors(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in getAnchors") + return http.StatusOK, nil // TODO +} + +// getProofByHash provides an inclusion proof based on a given leaf hash +func getProofByHash(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in getProofByHash") + return http.StatusOK, nil // TODO +} + +// getConsistencyProof provides a consistency proof between two STHs +func getConsistencyProof(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in getConsistencyProof") + return http.StatusOK, nil // TODO +} + +// getSth provides the most recent STH +func getSth(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { + glog.Info("in getSth") + return http.StatusOK, nil // TODO +} diff --git a/instance.go b/instance.go new file mode 100644 index 0000000..5fa1b6c --- /dev/null +++ b/instance.go @@ -0,0 +1,50 @@ +package stfe + +import ( + "time" + + "net/http" + + "github.com/golang/glog" + "github.com/google/trillian" + + ctutil "github.com/google/certificate-transparency-go/trillian/util" +) + +// instance groups information about a specific STFE instance. +type instance struct { + prefix string + logID int64 + client trillian.TrillianLogClient + deadline time.Duration + timesource ctutil.TimeSource +} + +// NewInstance returns a new STFE instance +func NewInstance(prefix string, id int64, client trillian.TrillianLogClient, deadline time.Duration, timesource ctutil.TimeSource) *instance { + return &instance{ + prefix: prefix, + logID: id, + client: client, + deadline: deadline, + timesource: timesource, + } +} + +// addEndpoints registers STFE handler functions for the respective HTTP paths +func (i *instance) AddEndpoints(mux *http.ServeMux) { + for _, endpoint := range []struct { + path string + handler appHandler + }{ + {i.prefix + "/add-entry", appHandler{instance: i, handler: addEntry, endpoint: "add-entry", method: http.MethodPost}}, + {i.prefix + "/get-entries", appHandler{instance: i, handler: getEntries, endpoint: "get-entries", method: http.MethodGet}}, + {i.prefix + "/get-anchors", appHandler{instance: i, handler: getAnchors, endpoint: "get-anchors", method: http.MethodGet}}, + {i.prefix + "/get-proof-by-hash", appHandler{instance: i, handler: getProofByHash, endpoint: "get-proof-by-hash", method: http.MethodGet}}, + {i.prefix + "/get-consistency-proof", appHandler{instance: i, handler: getConsistencyProof, endpoint: "get-consistency-proof", method: http.MethodGet}}, + {i.prefix + "/get-sth", appHandler{instance: i, handler: getSth, endpoint: "get-sth", method: http.MethodGet}}, + } { + glog.Infof("adding handler for %v", endpoint.path) + mux.Handle(endpoint.path, endpoint.handler) + } +} diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..53ac8e6 --- /dev/null +++ b/server/main.go @@ -0,0 +1,52 @@ +// Package main provides an STFE binary +package main + +import ( + "flag" + "time" + + "net/http" + + "github.com/golang/glog" + "github.com/google/trillian" + "github.com/system-transparency/stfe" + "google.golang.org/grpc" + + ctutil "github.com/google/certificate-transparency-go/trillian/util" +) + +var ( + httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") + rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") + prefix = flag.String("prefix", "/st/v1", "a prefix that proceeds each endpoint path") + trillianID = flag.Int64("trillianID", 5991359069696313945, "log identifier in the Trillian database") + rpcDeadline = flag.Duration("rpc_deadline", time.Second*10, "deadline for backend RPC requests") +) + +func main() { + flag.Parse() + + glog.Info("Dialling Trillian gRPC log server") + dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(*rpcDeadline)} + conn, err := grpc.Dial(*rpcBackend, dialOpts...) + if err != nil { + glog.Fatal(err) + } + + glog.Info("Creating HTTP request multiplexer") + mux := http.NewServeMux() + http.Handle("/", mux) + + glog.Info("Creating STFE server instance") + stfe_server := stfe.NewInstance(*prefix, *trillianID, trillian.NewTrillianLogClient(conn), *rpcDeadline, new(ctutil.SystemTimeSource)) + stfe_server.AddEndpoints(mux) + + glog.Infof("Serving on %v%v", *httpEndpoint, *prefix) + srv := http.Server{Addr: *httpEndpoint} + err = srv.ListenAndServe() + if err != http.ErrServerClosed { + glog.Warningf("Server exited: %v", err) + } + + glog.Flush() +} diff --git a/server/server b/server/server new file mode 100755 index 0000000..466879e Binary files /dev/null and b/server/server differ diff --git a/type.go b/type.go new file mode 100644 index 0000000..140a698 --- /dev/null +++ b/type.go @@ -0,0 +1,3 @@ +package stfe + +// Leaf definition and such goes here -- cgit v1.2.3