From dad369ebff6b79c4a2de01b13348c96188321502 Mon Sep 17 00:00:00 2001 From: p4u Date: Fri, 1 Feb 2019 20:20:34 +0100 Subject: [PATCH] Keep adapting the code to new merkletree implementation Use different database storages and merkletree for each censusID Signed-off-by: p4u --- cmd/censushttp/README.md | 10 +++-- cmd/censushttp/censushttp.go | 23 +++++++---- service/README.md | 15 -------- service/censusmanager.go | 74 ++++++++++++++++++------------------ tree/tree.go | 22 ++++++++--- 5 files changed, 74 insertions(+), 70 deletions(-) delete mode 100644 service/README.md diff --git a/cmd/censushttp/README.md b/cmd/censushttp/README.md index f00433d..b52242e 100644 --- a/cmd/censushttp/README.md +++ b/cmd/censushttp/README.md @@ -13,14 +13,14 @@ go build -o censusHttpService github.com/vocdoni/dvote-census/cmd/censushttp #### Usage -`./censusHttpService [publicKey]` +`./censusHttpService [:pubKey] [[:pubKey] ...]` Example: ``` -./censusHttpService 1500 -2018/12/17 09:54:20 Starting process HTTP service on port 1500 -2018/12/17 09:54:20 Starting server in http mode +./censusHttpService 1500 Got_Favorite +2019/02/01 20:01:15 Starting process HTTP service on port 1500 for namespace GoT_Favorite +2019/02/01 20:01:15 Starting server in http mode ``` #### add claims @@ -35,6 +35,8 @@ If public key authentication enabled, `signature` field is required using Nancl The signed message is expected to be a concatenation of the following fields: `censusID, claimData, timeStamp` +There is a time window of 10 seconds while the signature is considered valid. + ``` curl -d '{"censusID":"GoT_Favorite", "claimData":"Jon Snow", diff --git a/cmd/censushttp/censushttp.go b/cmd/censushttp/censushttp.go index 68d545a..b80c64c 100644 --- a/cmd/censushttp/censushttp.go +++ b/cmd/censushttp/censushttp.go @@ -4,13 +4,15 @@ import ( "log" "os" "strconv" + "strings" censusmanager "github.com/vocdoni/dvote-census/service" ) func main() { if len(os.Args) < 2 { - log.Fatal("Usage: " + os.Args[0] + " [pubKey]") + log.Fatal("Usage: " + os.Args[0] + + " [:pubKey] [[:pubKey]]...") os.Exit(2) } port, err := strconv.Atoi(os.Args[1]) @@ -18,13 +20,18 @@ func main() { log.Fatal(err) os.Exit(2) } - pubK := "" - if len(os.Args) > 2 { - log.Print("Public key authentication enabled") - pubK = os.Args[2] + for i := 2; i < len(os.Args); i++ { + s := strings.Split(os.Args[i], ":") + ns := s[0] + pubK := "" + if len(s) > 1 { + pubK = s[1] + log.Printf("Public Key authentication enabled on namespace %s\n", ns) + } + censusmanager.AddNamespace(ns, pubK) + log.Printf("Starting process HTTP service on port %d for namespace %s\n", + port, ns) } - log.Print("Starting process HTTP service on port " + os.Args[1]) - censusmanager.T.Init() - censusmanager.Listen(port, "http", pubK) + censusmanager.Listen(port, "http") } diff --git a/service/README.md b/service/README.md deleted file mode 100644 index 8263538..0000000 --- a/service/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## dvot-census http service library - -#### How to use it - -``` -processHttp.T.Init() -processHttp.Listen(1500, "http", "") -``` - -To enable authentication (using pubKey signature): - -``` -pubK := "39f54ce5293520b689f6658ea7f3401f4ff931fa3d90dea21ff901cdf82bb8aa" -processHttp.Listen(1500, "http", pubK) -``` diff --git a/service/censusmanager.go b/service/censusmanager.go index 6b56b85..4bb6da1 100644 --- a/service/censusmanager.go +++ b/service/censusmanager.go @@ -9,16 +9,14 @@ import ( "strings" "time" - "github.com/vocdoni/dvote-census/tree" - "github.com/vocdoni/dvote-relay/crypto/signature" + tree "github.com/vocdoni/dvote-census/tree" + signature "github.com/vocdoni/dvote-relay/crypto/signature" ) -const authTimeWindow = 10 // Time window (seconds) in which TimeStamp will be accepted if auth enabled - -var authPubKey string - -var T tree.Tree // MerkleTree dvote-census library -var S signature.SignKeys // Signature dvote-relay library +const authTimeWindow = 10 // Time window (seconds) in which TimeStamp will be accepted if auth enabled +var MkTrees map[string]*tree.Tree // MerkleTree dvote-census library +var Signatures map[string]string +var Signature signature.SignKeys // Signature dvote-relay library type Claim struct { CensusID string `json:"censusID"` // References to MerkleTree namespace @@ -33,6 +31,20 @@ type Result struct { Response string `json:"response"` } +func AddNamespace(name, pubKey string) { + if len(MkTrees) == 0 { + MkTrees = make(map[string]*tree.Tree) + } + if len(Signatures) == 0 { + Signatures = make(map[string]string) + } + + mkTree := tree.Tree{} + mkTree.Init(name) + MkTrees[name] = &mkTree + Signatures[name] = pubKey +} + func reply(resp *Result, w http.ResponseWriter) { err := json.NewEncoder(w).Encode(resp) if err != nil { @@ -50,8 +62,8 @@ func checkRequest(w http.ResponseWriter, req *http.Request) bool { return true } -func checkAuth(timestamp, signature, message string) bool { - if len(authPubKey) < 1 { +func checkAuth(timestamp, signature, pubKey, message string) bool { + if len(pubKey) < 1 { return true } currentTime := int64(time.Now().Unix()) @@ -62,7 +74,7 @@ func checkAuth(timestamp, signature, message string) bool { } if timeStampRemote < currentTime+authTimeWindow && timeStampRemote > currentTime-authTimeWindow { - v, err := S.Verify(message, signature, authPubKey) + v, err := Signature.Verify(message, signature, pubKey) if err != nil { log.Printf("Verification error: %s\n", err) } @@ -74,6 +86,7 @@ func checkAuth(timestamp, signature, message string) bool { func claimHandler(w http.ResponseWriter, req *http.Request, op string) { var c Claim var resp Result + if ok := checkRequest(w, req); !ok { return } @@ -89,31 +102,25 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { c.CensusID, c.ClaimData, c.ProofData, c.TimeStamp, c.Signature) resp.Error = false resp.Response = "" - + censusFound := false if len(c.CensusID) > 0 { - T.Namespace = c.CensusID - } else { - resp.Error = true - resp.Response = "censusID is not valid" - reply(&resp, w) - return + _, censusFound = MkTrees[c.CensusID] } - - if len(c.ClaimData) < 0 { + if !censusFound { resp.Error = true - resp.Response = "data not valid" + resp.Response = "censusID not valid or not found" reply(&resp, w) return } if op == "add" { msg := fmt.Sprintf("%s%s%s", c.CensusID, c.ClaimData, c.TimeStamp) - if auth := checkAuth(c.TimeStamp, c.Signature, msg); auth { + if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], msg); auth { if strings.HasPrefix(c.CensusID, "0x") { resp.Error = true resp.Response = "add claim to snapshot is not allowed" } else { - err = T.AddClaim([]byte(c.ClaimData)) + err = MkTrees[c.CensusID].AddClaim([]byte(c.ClaimData)) } } else { resp.Error = true @@ -122,15 +129,15 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { } if op == "gen" { - resp.Response, err = T.GenProof([]byte(c.ClaimData)) + resp.Response, err = MkTrees[c.CensusID].GenProof([]byte(c.ClaimData)) } if op == "root" { - resp.Response = T.GetRoot() + resp.Response = MkTrees[c.CensusID].GetRoot() } if op == "dump" { - values, err := T.Dump() + values, err := MkTrees[c.CensusID].Dump() if err != nil { resp.Error = true resp.Response = fmt.Sprint(err) @@ -147,12 +154,12 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { if op == "snapshot" { msg := fmt.Sprintf("%s%s%s", c.CensusID, c.ClaimData, c.TimeStamp) - if auth := checkAuth(c.TimeStamp, c.Signature, msg); auth { + if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], msg); auth { if strings.HasPrefix(c.CensusID, "0x") { resp.Error = true resp.Response = "snapshot an snapshot makes no sense" } else { - snapshotNamespace, err := T.Snapshot() + snapshotNamespace, err := MkTrees[c.CensusID].Snapshot() if err != nil { resp.Error = true resp.Response = fmt.Sprint(err) @@ -171,7 +178,7 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { resp.Error = true resp.Response = "proofData not provided" } else { - validProof, _ := T.CheckProof([]byte(c.ClaimData), c.ProofData) + validProof, _ := MkTrees[c.CensusID].CheckProof([]byte(c.ClaimData), c.ProofData) if validProof { resp.Response = "valid" } else { @@ -183,7 +190,7 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { reply(&resp, w) } -func Listen(port int, proto string, pubKey string) { +func Listen(port int, proto string) { srv := &http.Server{ Addr: fmt.Sprintf(":%d", port), ReadHeaderTimeout: 4 * time.Second, @@ -211,13 +218,6 @@ func Listen(port int, proto string, pubKey string) { claimHandler(w, r, "dump") }) - if len(pubKey) > 1 { - log.Printf("Enabling signature authentication with %s\n", pubKey) - authPubKey = pubKey - } else { - authPubKey = "" - } - if proto == "https" { log.Print("Starting server in https mode") if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil { diff --git a/tree/tree.go b/tree/tree.go index ae1d5fa..4ebeac6 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -12,19 +12,21 @@ import ( ) type Tree struct { - Namespace string Storage string Tree *merkletree.MerkleTree DbStorage *db.LevelDbStorage } -func (t *Tree) Init() error { +func (t *Tree) Init(namespace string) error { if len(t.Storage) < 1 { + if len(namespace) < 1 { + return errors.New("namespace not valid") + } usr, err := user.Current() if err == nil { - t.Storage = usr.HomeDir + "/.dvote/Tree" + t.Storage = usr.HomeDir + "/.dvote/census/" + namespace } else { - t.Storage = "./dvoteTree" + t.Storage = "./dvoteTree/" + namespace } } mtdb, err := db.NewLevelDbStorage(t.Storage, false) @@ -49,7 +51,7 @@ func (t *Tree) GetClaim(data []byte) (*mkcore.ClaimBasic, error) { return nil, errors.New("claim data too large") } for i := len(data); i <= 496/8; i++ { - data = append(data, byte('0')) + data = append(data, byte('.')) } var indexSlot [400 / 8]byte var dataSlot [496 / 8]byte @@ -106,7 +108,15 @@ func (t *Tree) Dump() ([]string, error) { err := t.Tree.Walk(t.Tree.RootKey(), func(n *merkletree.Node) { if n.Type == merkletree.NodeTypeLeaf { - response = append(response, fmt.Sprintf("|%s", n.Entry.Data)) + rawValue := n.Value() + var cleanValue []byte + for i := 0; i < len(rawValue); i++ { + if rawValue[i] == byte('.') { + break + } + cleanValue = append(cleanValue, rawValue[i]) + } + response = append(response, fmt.Sprintf("%s", cleanValue)) } }) return response, err