Exposes a HTTP API to manage merkle trees Signed-off-by: p4u <p4u@dabax.net>feature_chain_module
@ -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"} |
||||
|
``` |
@ -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) |
||||
|
} |
||||
|
} |
||||
|
} |