From 5fd182549f6dcb4a3ad4c717673766bb48cc8807 Mon Sep 17 00:00:00 2001 From: p4u Date: Fri, 14 Dec 2018 14:11:28 +0100 Subject: [PATCH] Add processHttp implementation Exposes a HTTP API to manage merkle trees Signed-off-by: p4u --- service/README.md | 40 ++++++++++++ service/processHttp.go | 138 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 service/README.md create mode 100644 service/processHttp.go diff --git a/service/README.md b/service/README.md new file mode 100644 index 0000000..15d0bf0 --- /dev/null +++ b/service/README.md @@ -0,0 +1,40 @@ +## dvot-process http service + +#### start http server + +``` +processHttp.T.namespace = "vocdoni" +T.Init() +processHttp.Listen(1500, "http") +``` + +#### add claims + +``` +curl -d '{"processID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/addClaim +{"error":false,"response":""} +``` + +``` +curl -d '{"processID":"GoT_Favorite","claimData":"Tyrion"}' http://localhost:1500/addClaim +{"error":false,"response":""} +``` + +#### generate proof + +``` +curl -d '{"processID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/genProof +{"error":false,"response":"0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"} +``` + +#### check proof + +``` +curl -d '{"processID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x0000000000000000000000000000000000000000000000000000000000000000000123"}' http://localhost:1500/checkProof +{"error":false,"response":"invalid"} +``` + +``` +curl -d '{"processID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"}' http://localhost:1500/checkProof +{"error":false,"response":"valid"} +``` diff --git a/service/processHttp.go b/service/processHttp.go new file mode 100644 index 0000000..7e4c6d1 --- /dev/null +++ b/service/processHttp.go @@ -0,0 +1,138 @@ +package processHttp + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + "log" + "github.com/vocdoni/dvote-process/tree" +) + +var T tree.Tree + +type Claim struct { + ProcessID string `json:"processID"` + ClaimData string `json:"claimData"` + ProofData string `json:"proofData"` +} + +type Result struct { + Error bool `json:"error"` + Response string `json:"response"` +} + +func reply(resp *Result, w http.ResponseWriter) { + err := json.NewEncoder(w).Encode(resp) + if err != nil { + http.Error(w, err.Error(), 500) + } else { + w.Header().Set("content-type", "application/json") + } +} + +func checkRequest(w http.ResponseWriter,req *http.Request) bool { + if req.Body == nil { + http.Error(w, "Please send a request body", 400) + return false + } + return true +} + +func claimHandler(w http.ResponseWriter, req *http.Request, op string) { + var c Claim + var resp Result + if ok := checkRequest(w, req); !ok { return } + // Decode JSON + err := json.NewDecoder(req.Body).Decode(&c) + if err != nil { + http.Error(w, err.Error(), 400) + return + } + + // Process data + log.Printf("Received: %s,%s,%s ", c.ProcessID, c.ClaimData, c.ProofData) + resp.Error = false + resp.Response = "" + + if len(c.ProcessID) > 0 { + T.Namespace = c.ProcessID + } else { + resp.Error = true + resp.Response = "processID is not valid" + reply(&resp, w) + return + } + + if len(c.ClaimData) < 0 { + resp.Error = true + resp.Response = "data not valid" + reply(&resp, w) + return + } + + if op == "add" { + err = T.AddClaim([]byte(c.ClaimData)) + } + + if op == "gen" { + resp.Response, err = T.GenProof([]byte(c.ClaimData)) + } + + if op == "check" { + if len(c.ProofData) < 1 { + resp.Error = true + resp.Response = "proofData not provided" + reply(&resp, w) + return + } + var validProof bool + validProof, err = T.CheckProof([]byte(c.ClaimData), c.ProofData) + if validProof { + resp.Response = "valid" + } else { + resp.Response = "invalid" + } + } + + if err != nil { + resp.Error = true + resp.Response = fmt.Sprint(err) + log.Print(err) + reply(&resp, w) + return + } + + reply(&resp, w) +} + +func Listen(port int, proto string) { + srv := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + ReadHeaderTimeout: 4 * time.Second, + ReadTimeout: 4 * time.Second, + WriteTimeout: 4 * time.Second, + IdleTimeout: 3 * time.Second, + } + + http.HandleFunc("/addClaim", func(w http.ResponseWriter, r *http.Request) { + claimHandler(w, r, "add")}) + http.HandleFunc("/genProof", func(w http.ResponseWriter, r *http.Request) { + claimHandler(w, r, "gen")}) + http.HandleFunc("/checkProof", func(w http.ResponseWriter, r *http.Request) { + claimHandler(w, r, "check")}) + + if proto == "https" { + log.Print("Starting server in https mode") + if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil { + panic(err) + } + } + if proto == "http" { + log.Print("Starting server in http mode") + srv.SetKeepAlivesEnabled(false) + if err := srv.ListenAndServe(); err != nil { + panic(err) + } + } +}