diff --git a/cmd/censushttp/README.md b/cmd/censushttp/README.md index 2a06617..f00433d 100644 --- a/cmd/censushttp/README.md +++ b/cmd/censushttp/README.md @@ -1,23 +1,106 @@ -# censusService -Reference implementation of a voting census service running on the Vocdoni platform - ## Census HTTP service +Reference implementation of a voting census service running on the Vocdoni platform + #### Compile +In a GO ready environment: + ``` -go get github.com/vocdoni/censusService -go build -o httpService http_census_service.go +go get -u github.com/vocdoni/dvote-census +go build -o censusHttpService github.com/vocdoni/dvote-census/cmd/censushttp ``` #### Usage +`./censusHttpService [publicKey]` + +Example: + ``` -./httpService 1500 +./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 ``` +#### add claims + +``` +curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/addClaim + +{"error":false,"response":""} +``` + +If public key authentication enabled, `signature` field is required using Nancl signature. + +The signed message is expected to be a concatenation of the following fields: `censusID, claimData, timeStamp` + +``` +curl -d '{"censusID":"GoT_Favorite", +"claimData":"Jon Snow", +"timeStamp":"1547814675", +"signature":"a117c4ce12b29090884112ffe57e664f007e7ef142a1679996e2d34fd2b852fe76966e47932f1e9d3a54610d0f361383afe2d9aab096e15d136c236abb0a0d0e"}' http://localhost:1500/addClaim + +{"error":false,"response":""} +``` + + +#### generate proof + +``` +curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/genProof + +{"error":false,"response":"0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"} +``` + +#### check proof + +``` +curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x0000000000000000000000000000000000000000000000000000000000000000000123"}' http://localhost:1500/checkProof + +{"error":false,"response":"invalid"} +``` + +``` +curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"}' http://localhost:1500/checkProof + +{"error":false,"response":"valid"} +``` + +#### make snapshot + +Snapshots are static and unmutable copies of a specific census + +``` +curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/snapshot + +{"error":false,"response":"0x8647692e073a10980d821764c65ca3fddbc606bb936f9812a7a806bfa97df152"} +``` + +The name for the snapshot is "0x8647692e073a10980d821764c65ca3fddbc606bb936f9812a7a806bfa97df152" which represents the Root Hash. + +Now you can use it as censusID for checkProof, getRoot, genProof and dump. But addClaim is not longer allowed. + +#### dump + +Dump contents of a specific censusID (values) + +``` +curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/dump +{"error":false,"response":"[\"Tyrion\",\"Jon Snow\"]"} +``` + + + + + + + + + + + + ##### add claims ``` @@ -33,19 +116,19 @@ curl -d '{"processID":"GoT_Favorite","claimData":"Tyrion"}' http://localhost:150 ##### generate proof ``` -curl -d '{"processID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/genProof +curl -d '{"censusID":"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 +curl -d '{"censusID":"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 +curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"}' http://localhost:1500/checkProof {"error":false,"response":"valid"} ``` diff --git a/service/README.md b/service/README.md index b8def01..8263538 100644 --- a/service/README.md +++ b/service/README.md @@ -1,6 +1,6 @@ -## dvot-process http service +## dvot-census http service library -#### start http server +#### How to use it ``` processHttp.T.Init() @@ -13,74 +13,3 @@ To enable authentication (using pubKey signature): pubK := "39f54ce5293520b689f6658ea7f3401f4ff931fa3d90dea21ff901cdf82bb8aa" processHttp.Listen(1500, "http", pubK) ``` - - -#### add claims - -``` -curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/addClaim - -{"error":false,"response":""} -``` - -``` -curl -d '{"censusID":"GoT_Favorite", -"claimData":"Jon Snow", -"timeStamp":"1547814675", -"signature":"a117c4ce12b29090884112ffe57e664f007e7ef142a1679996e2d34fd2b852fe76966e47932f1e9d3a54610d0f361383afe2d9aab096e15d136c236abb0a0d0e"}' http://localhost:1500/addClaim - -{"error":false,"response":""} -``` - -The signature message is a concatenation of the following strings: `censusID, claimData, timeStamp` - -``` -curl -d '{"censusID":"GoT_Favorite","claimData":"Tyrion"}' http://localhost:1500/addClaim - -{"error":false,"response":""} -``` - -#### generate proof - -``` -curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/genProof - -{"error":false,"response":"0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"} -``` - -#### check proof - -``` -curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x0000000000000000000000000000000000000000000000000000000000000000000123"}' http://localhost:1500/checkProof - -{"error":false,"response":"invalid"} -``` - -``` -curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow", "proofData": "0x000000000000000000000000000000000000000000000000000000000000000352f3ca2aaf635ec2ae4452f6a65be7bca72678287a8bb08ad4babfcccd76c2fef1aac7675261bf6d12c746fb7907beea6d1f1635af93ba931eec0c6a747ecc37"}' http://localhost:1500/checkProof - -{"error":false,"response":"valid"} -``` - -#### make snapshot - -Snapshots are static and unmutable copies of a specific census - -``` -curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/snapshot - -{"error":false,"response":"snaphost.GoT_Favorite.1548169813"} -``` - -The name for the snapshot is "snaphost.GoT_Favorite.1548169813" - -Now you can use it as censusID for checkProof, genProof and dump. But addClaim is not longer allowed. - -#### dump - -Dump contents of a specific censusID (values) - -``` -curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/dump -{"error":false,"response":"[\"Tyrion\",\"Jon Snow\"]"} -``` \ No newline at end of file diff --git a/service/censusmanager.go b/service/censusmanager.go index 911dae4..6b56b85 100644 --- a/service/censusmanager.go +++ b/service/censusmanager.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "strconv" + "strings" "time" "github.com/vocdoni/dvote-census/tree" @@ -84,8 +85,8 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { } // Process data - log.Printf("Received: %s,%s,%s,%s,%s", c.CensusID, c.ClaimData, c.ProofData, - c.TimeStamp, c.Signature) + log.Printf("Received censusID:{%s} claimData:{%s} proofData:{%s} timeStamp:{%s} signature:{%s}\n", + c.CensusID, c.ClaimData, c.ProofData, c.TimeStamp, c.Signature) resp.Error = false resp.Response = "" @@ -108,7 +109,12 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) { if op == "add" { msg := fmt.Sprintf("%s%s%s", c.CensusID, c.ClaimData, c.TimeStamp) if auth := checkAuth(c.TimeStamp, c.Signature, msg); auth { - err = T.AddClaim([]byte(c.ClaimData)) + 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)) + } } else { resp.Error = true resp.Response = "invalid authentication" @@ -142,12 +148,17 @@ 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 { - snapshotNamespace, err := T.Snapshot() - if err != nil { + if strings.HasPrefix(c.CensusID, "0x") { resp.Error = true - resp.Response = fmt.Sprint(err) + resp.Response = "snapshot an snapshot makes no sense" } else { - resp.Response = snapshotNamespace + snapshotNamespace, err := T.Snapshot() + if err != nil { + resp.Error = true + resp.Response = fmt.Sprint(err) + } else { + resp.Response = snapshotNamespace + } } } else { resp.Error = true diff --git a/tree/tree.go b/tree/tree.go index 618f86e..88de057 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -5,7 +5,6 @@ import ( "fmt" "os/user" "strings" - "time" common3 "github.com/vocdoni/go-iden3/common" mkcore "github.com/vocdoni/go-iden3/core" @@ -47,7 +46,7 @@ func (t *Tree) Close() { } func (t *Tree) AddClaim(data []byte) error { - isSnapshot := strings.Contains(t.Namespace, "snapshot.") + isSnapshot := strings.HasPrefix(t.Namespace, "0x") if isSnapshot { return errors.New("No new claims can be added to a Snapshot") } @@ -100,15 +99,16 @@ func (t *Tree) Dump() ([]string, error) { func (t *Tree) Snapshot() (string, error) { substorage := t.DbStorage.WithPrefix([]byte(t.Namespace)) nsHash := merkletree.HashBytes([]byte(t.Namespace)) - currentTime := int64(time.Now().Unix()) - snapshotNamespace := fmt.Sprintf("snapshot.%s.%d", t.Namespace, currentTime) + snapshotNamespace := t.GetRoot() + fmt.Printf("Snapshoting %s\n", snapshotNamespace) + t.Namespace = snapshotNamespace substorage.Iterate(func(key, value []byte) { nsValue := value[5:37] if fmt.Sprint(nsHash) == fmt.Sprint(nsValue) { + fmt.Printf("%x\n", value) data := value[69:] - //fmt.Printf(" Adding value: %s\n", data) - claim := mkcore.NewGenericClaim(snapshotNamespace, "default", data, nil) - err := t.Tree.Add(claim) + //claim := mkcore.NewGenericClaim(snapshotNamespace, "default", data, nil) + err := t.AddClaim(data) if err != nil { fmt.Println(err) }