You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
6.7 KiB

  1. package censusmanager
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "strconv"
  8. "time"
  9. signature "github.com/vocdoni/go-dvote/crypto/signature_ecdsa"
  10. tree "github.com/vocdoni/go-dvote/tree"
  11. )
  12. // Time window (seconds) in which TimeStamp will be accepted if auth enabled
  13. const authTimeWindow = 10
  14. // MkTrees map of merkle trees indexed by censusId
  15. var MkTrees map[string]*tree.Tree
  16. // Signatures map of management pubKeys indexed by censusId
  17. var Signatures map[string]string
  18. var currentSignature signature.SignKeys
  19. // Claim type represents a JSON object with all possible fields
  20. type Claim struct {
  21. Method string `json:"method"` // method to call
  22. CensusID string `json:"censusId"` // References to MerkleTree namespace
  23. RootHash string `json:"rootHash"` // References to MerkleTree rootHash
  24. ClaimData string `json:"claimData"` // Data to add to the MerkleTree
  25. ProofData string `json:"proofData"` // MerkleProof to check
  26. TimeStamp string `json:"timeStamp"` // Unix TimeStamp in seconds
  27. Signature string `json:"signature"` // Signature as Hexadecimal String
  28. }
  29. // Result type represents a JSON object with the result of the method executed
  30. type Result struct {
  31. Error bool `json:"error"`
  32. Response string `json:"response"`
  33. }
  34. // AddNamespace adds a new merkletree identified by a censusId (name)
  35. func AddNamespace(name, pubKey string) {
  36. if len(MkTrees) == 0 {
  37. MkTrees = make(map[string]*tree.Tree)
  38. }
  39. if len(Signatures) == 0 {
  40. Signatures = make(map[string]string)
  41. }
  42. mkTree := tree.Tree{}
  43. mkTree.Init(name)
  44. MkTrees[name] = &mkTree
  45. Signatures[name] = pubKey
  46. }
  47. func reply(resp *Result, w http.ResponseWriter) {
  48. err := json.NewEncoder(w).Encode(resp)
  49. if err != nil {
  50. http.Error(w, err.Error(), 500)
  51. } else {
  52. w.Header().Set("content-type", "application/json")
  53. }
  54. }
  55. func checkRequest(w http.ResponseWriter, req *http.Request) bool {
  56. if req.Body == nil {
  57. http.Error(w, "Please send a request body", 400)
  58. return false
  59. }
  60. return true
  61. }
  62. func checkAuth(timestamp, signed, pubKey, message string) bool {
  63. if len(pubKey) < 1 {
  64. return true
  65. }
  66. currentTime := int64(time.Now().Unix())
  67. timeStampRemote, err := strconv.ParseInt(timestamp, 10, 32)
  68. if err != nil {
  69. log.Printf("Cannot parse timestamp data %s\n", err)
  70. return false
  71. }
  72. if timeStampRemote < currentTime+authTimeWindow &&
  73. timeStampRemote > currentTime-authTimeWindow {
  74. v, err := currentSignature.Verify(message, signed, pubKey)
  75. if err != nil {
  76. log.Printf("Verification error: %s\n", err)
  77. }
  78. return v
  79. }
  80. return false
  81. }
  82. func httpHandler(w http.ResponseWriter, req *http.Request) {
  83. var c Claim
  84. if ok := checkRequest(w, req); !ok {
  85. return
  86. }
  87. // Decode JSON
  88. err := json.NewDecoder(req.Body).Decode(&c)
  89. if err != nil {
  90. http.Error(w, err.Error(), 400)
  91. return
  92. }
  93. if len(c.Method) < 1 {
  94. http.Error(w, "method must be specified", 400)
  95. return
  96. }
  97. resp := opHandler(&c)
  98. reply(resp, w)
  99. }
  100. func opHandler(c *Claim) *Result {
  101. var resp Result
  102. op := c.Method
  103. var err error
  104. // Process data
  105. log.Printf("censusId:{%s} method:{%s} rootHash:{%s} claimData:{%s} proofData:{%s} timeStamp:{%s} signature:{%s}\n",
  106. c.CensusID, c.Method, c.RootHash, c.ClaimData, c.ProofData, c.TimeStamp, c.Signature)
  107. authString := fmt.Sprintf("%s%s%s%s%s", c.Method, c.CensusID, c.RootHash, c.ClaimData, c.TimeStamp)
  108. resp.Error = false
  109. resp.Response = ""
  110. censusFound := false
  111. if len(c.CensusID) > 0 {
  112. _, censusFound = MkTrees[c.CensusID]
  113. }
  114. if !censusFound {
  115. resp.Error = true
  116. resp.Response = "censusId not valid or not found"
  117. return &resp
  118. }
  119. //Methods without rootHash
  120. if op == "getRoot" {
  121. resp.Response = MkTrees[c.CensusID].GetRoot()
  122. return &resp
  123. }
  124. if op == "addClaim" {
  125. if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); auth {
  126. err = MkTrees[c.CensusID].AddClaim([]byte(c.ClaimData))
  127. } else {
  128. resp.Error = true
  129. resp.Response = "invalid authentication"
  130. }
  131. return &resp
  132. }
  133. //Methods with rootHash, if rootHash specified snapshot the tree
  134. var t *tree.Tree
  135. if len(c.RootHash) > 1 { //if rootHash specified
  136. t, err = MkTrees[c.CensusID].Snapshot(c.RootHash)
  137. if err != nil {
  138. log.Printf("Snapshot error: %s", err.Error())
  139. resp.Error = true
  140. resp.Response = "invalid root hash"
  141. return &resp
  142. }
  143. } else { //if rootHash not specified use current tree
  144. t = MkTrees[c.CensusID]
  145. }
  146. if op == "genProof" {
  147. resp.Response, err = t.GenProof([]byte(c.ClaimData))
  148. if err != nil {
  149. resp.Error = true
  150. resp.Response = err.Error()
  151. }
  152. return &resp
  153. }
  154. if op == "getIdx" {
  155. resp.Response, err = t.GetIndex([]byte(c.ClaimData))
  156. return &resp
  157. }
  158. if op == "dump" {
  159. if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); !auth {
  160. resp.Error = true
  161. resp.Response = "invalid authentication"
  162. return &resp
  163. }
  164. //dump the claim data and return it
  165. values, err := t.Dump()
  166. if err != nil {
  167. resp.Error = true
  168. resp.Response = err.Error()
  169. } else {
  170. jValues, err := json.Marshal(values)
  171. if err != nil {
  172. resp.Error = true
  173. resp.Response = err.Error()
  174. } else {
  175. resp.Response = fmt.Sprintf("%s", jValues)
  176. }
  177. }
  178. return &resp
  179. }
  180. if op == "checkProof" {
  181. if len(c.ProofData) < 1 {
  182. resp.Error = true
  183. resp.Response = "proofData not provided"
  184. return &resp
  185. }
  186. // Generate proof and return it
  187. validProof, err := t.CheckProof([]byte(c.ClaimData), c.ProofData)
  188. if err != nil {
  189. resp.Error = true
  190. resp.Response = err.Error()
  191. return &resp
  192. }
  193. if validProof {
  194. resp.Response = "valid"
  195. } else {
  196. resp.Response = "invalid"
  197. }
  198. return &resp
  199. }
  200. return &resp
  201. }
  202. func addCorsHeaders(w *http.ResponseWriter, req *http.Request) {
  203. (*w).Header().Set("Access-Control-Allow-Origin", "*")
  204. (*w).Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
  205. (*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
  206. }
  207. // Listen starts a census service defined of type "proto"
  208. func Listen(port int, proto string) {
  209. srv := &http.Server{
  210. Addr: fmt.Sprintf(":%d", port),
  211. ReadHeaderTimeout: 4 * time.Second,
  212. ReadTimeout: 4 * time.Second,
  213. WriteTimeout: 4 * time.Second,
  214. IdleTimeout: 3 * time.Second,
  215. }
  216. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  217. addCorsHeaders(&w, r)
  218. if r.Method == http.MethodPost {
  219. httpHandler(w, r)
  220. } else if r.Method != http.MethodOptions {
  221. http.Error(w, "Not found", http.StatusNotFound)
  222. }
  223. })
  224. if proto == "https" {
  225. log.Print("Starting server in https mode")
  226. if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil {
  227. panic(err)
  228. }
  229. }
  230. if proto == "http" {
  231. log.Print("Starting server in http mode")
  232. srv.SetKeepAlivesEnabled(false)
  233. if err := srv.ListenAndServe(); err != nil {
  234. panic(err)
  235. }
  236. }
  237. }