mirror of
https://github.com/arnaucube/go-dvote.git
synced 2026-02-28 05:26:46 +01:00
Census Service refactory
- Add new JSON field `method`, so method is now specified in the JSON object (not in URL anymore) - Use Ethereum ECDSA signing library - Refactor censusmanager code to allow other than HTTP transport layers - Update documentation Signed-off-by: p4u <p4u@dabax.net>
This commit is contained in:
@@ -25,7 +25,7 @@ Example
|
|||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
A HTTP jSON endpoint is available with the following possible fields: `censusId`, `claimData`, `rootHash` and `proofData`.
|
A HTTP jSON endpoint is available with the following possible fields: `method` `censusId`, `claimData`, `rootHash` and `proofData`.
|
||||||
|
|
||||||
If `pubKey` has been configured for a specific `censusId`, then two more methods are available (`timeStamp` and `signature`) to provide authentication.
|
If `pubKey` has been configured for a specific `censusId`, then two more methods are available (`timeStamp` and `signature`) to provide authentication.
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ The next table shows the available methods and its relation with the fields.
|
|||||||
|
|
||||||
| method | censusId | claimData | rootHash | proofData | protected? | description |
|
| method | censusId | claimData | rootHash | proofData | protected? | description |
|
||||||
|------------|-----------|-----------|----------|-----------|------------|------------|
|
|------------|-----------|-----------|----------|-----------|------------|------------|
|
||||||
| `addCLaim` | mandatory | mandatory | none | none | yes | adds a new claim to the merkle tree |
|
| `addClaim` | mandatory | mandatory | none | none | yes | adds a new claim to the merkle tree |
|
||||||
| `getRoot` | mandatory | none | none | none | no | get the current merkletree root hash
|
| `getRoot` | mandatory | none | none | none | no | get the current merkletree root hash
|
||||||
| `genProof` | mandatory | mandatory | optional | none | no | generate the merkle proof for a given claim
|
| `genProof` | mandatory | mandatory | optional | none | no | generate the merkle proof for a given claim
|
||||||
| `checkProof` | mandatory | mandatory | optional | mandatory | no | check a claim and its merkle proof
|
| `checkProof` | mandatory | mandatory | optional | mandatory | no | check a claim and its merkle proof
|
||||||
@@ -53,13 +53,13 @@ The `timeStamp` when received on the server side must not differ more than 10 se
|
|||||||
|
|
||||||
Add two new claims, one for `Jon Snow` and another for `Tyrion`.
|
Add two new claims, one for `Jon Snow` and another for `Tyrion`.
|
||||||
```
|
```
|
||||||
curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/addClaim
|
curl -d '{"method":"addClaim","censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":""}
|
{"error":false,"response":""}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{"censusID":"GoT_Favorite","claimData":"Tyrion"}' http://localhost:1500/addClaim
|
curl -d '{"method":"addClaim","censusID":"GoT_Favorite","claimData":"Tyrion"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":""}
|
{"error":false,"response":""}
|
||||||
```
|
```
|
||||||
@@ -68,10 +68,11 @@ In case signature is enabled:
|
|||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{
|
curl -d '{
|
||||||
|
"method":"addClaim",
|
||||||
"censusID":"GoT_Favorite",
|
"censusID":"GoT_Favorite",
|
||||||
"claimData":"Jon Snow",
|
"claimData":"Jon Snow",
|
||||||
"timeStamp":"1547814675",
|
"timeStamp":"1547814675",
|
||||||
"signature":"a117c4ce12b29090884112ffe57e664f007e7ef142a1679996e2d34fd2b852fe76966e47932f1e9d3a54610d0f361383afe2d9aab096e15d136c236abb0a0d0e" }' http://localhost:1500/addClaim
|
"signature":"a117c4ce12b29090884112ffe57e664f007e7ef142a1679996e2d34fd2b852fe76966e47932f1e9d3a54610d0f361383afe2d9aab096e15d136c236abb0a0d0e" }' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":""}
|
{"error":false,"response":""}
|
||||||
```
|
```
|
||||||
@@ -82,7 +83,7 @@ curl -d '{
|
|||||||
Generate a merkle proof for the claim `Jon Snow`
|
Generate a merkle proof for the claim `Jon Snow`
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{"censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500/genProof
|
curl -d '{"method":"genProof","censusID":"GoT_Favorite","claimData":"Jon Snow"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":"0x000200000000000000000000000000000000000000000000000000000000000212f8134039730791388a9bd0460f9fbd0757327212a64b3a2b0f0841ce561ee3"}
|
{"error":false,"response":"0x000200000000000000000000000000000000000000000000000000000000000212f8134039730791388a9bd0460f9fbd0757327212a64b3a2b0f0841ce561ee3"}
|
||||||
```
|
```
|
||||||
@@ -94,7 +95,7 @@ If `rootHash` is specified, the proof will be calculated for the given root hash
|
|||||||
The previous merkle proof is valid only for the current root hash. Let's get it
|
The previous merkle proof is valid only for the current root hash. Let's get it
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/getRoot
|
curl -d '{"method":"getRoot","censusID":"GoT_Favorite"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":"0x2f0ddde5cb995eae23dc3b75a5c0333f1cc89b73f3a00b0fe71996fb90fef04b"}
|
{"error":false,"response":"0x2f0ddde5cb995eae23dc3b75a5c0333f1cc89b73f3a00b0fe71996fb90fef04b"}
|
||||||
```
|
```
|
||||||
@@ -106,9 +107,10 @@ Now let's check if the proof is valid
|
|||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{
|
curl -d '{
|
||||||
|
"method":"checkProof",
|
||||||
"censusID":"GoT_Favorite","claimData":"Jon Snow",
|
"censusID":"GoT_Favorite","claimData":"Jon Snow",
|
||||||
"rootHash":"0x2f0ddde5cb995eae23dc3b75a5c0333f1cc89b73f3a00b0fe71996fb90fef04b",
|
"rootHash":"0x2f0ddde5cb995eae23dc3b75a5c0333f1cc89b73f3a00b0fe71996fb90fef04b",
|
||||||
"proofData":"0x000200000000000000000000000000000000000000000000000000000000000212f8134039730791388a9bd0460f9fbd0757327212a64b3a2b0f0841ce561ee3"}' http://localhost:1500/checkProof
|
"proofData":"0x000200000000000000000000000000000000000000000000000000000000000212f8134039730791388a9bd0460f9fbd0757327212a64b3a2b0f0841ce561ee3"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":"valid"}
|
{"error":false,"response":"valid"}
|
||||||
```
|
```
|
||||||
@@ -120,7 +122,7 @@ If `rootHash` is not specified, the current root hash is used.
|
|||||||
Dump contents of a specific censusId (values)
|
Dump contents of a specific censusId (values)
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -d '{"censusID":"GoT_Favorite"}' http://localhost:1500/dump
|
curl -d '{"method":"dump","censusID":"GoT_Favorite"}' http://localhost:1500
|
||||||
|
|
||||||
{"error":false,"response":"[\"Tyrion\",\"Jon Snow\"]"}
|
{"error":false,"response":"[\"Tyrion\",\"Jon Snow\"]"}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,17 +8,24 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
signature "github.com/vocdoni/go-dvote/crypto/signature_ecdsa"
|
||||||
tree "github.com/vocdoni/go-dvote/tree"
|
tree "github.com/vocdoni/go-dvote/tree"
|
||||||
signature "github.com/vocdoni/go-dvote/crypto/signature"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const hashSize = 32
|
// Time window (seconds) in which TimeStamp will be accepted if auth enabled
|
||||||
const authTimeWindow = 10 // Time window (seconds) in which TimeStamp will be accepted if auth enabled
|
const authTimeWindow = 10
|
||||||
var MkTrees map[string]*tree.Tree // MerkleTree dvote-census library
|
|
||||||
var Signatures map[string]string
|
|
||||||
var Signature signature.SignKeys // Signature go-dvote library
|
|
||||||
|
|
||||||
|
// MkTrees map of merkle trees indexed by censusId
|
||||||
|
var MkTrees map[string]*tree.Tree
|
||||||
|
|
||||||
|
// Signatures map of management pubKeys indexed by censusId
|
||||||
|
var Signatures map[string]string
|
||||||
|
|
||||||
|
var currentSignature signature.SignKeys
|
||||||
|
|
||||||
|
// Claim type represents a JSON object with all possible fields
|
||||||
type Claim struct {
|
type Claim struct {
|
||||||
|
Method string `json:"method"` // method to call
|
||||||
CensusID string `json:"censusId"` // References to MerkleTree namespace
|
CensusID string `json:"censusId"` // References to MerkleTree namespace
|
||||||
RootHash string `json:"rootHash"` // References to MerkleTree rootHash
|
RootHash string `json:"rootHash"` // References to MerkleTree rootHash
|
||||||
ClaimData string `json:"claimData"` // Data to add to the MerkleTree
|
ClaimData string `json:"claimData"` // Data to add to the MerkleTree
|
||||||
@@ -27,11 +34,13 @@ type Claim struct {
|
|||||||
Signature string `json:"signature"` // Signature as Hexadecimal String
|
Signature string `json:"signature"` // Signature as Hexadecimal String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Result type represents a JSON object with the result of the method executed
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Error bool `json:"error"`
|
Error bool `json:"error"`
|
||||||
Response string `json:"response"`
|
Response string `json:"response"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddNamespace adds a new merkletree identified by a censusId (name)
|
||||||
func AddNamespace(name, pubKey string) {
|
func AddNamespace(name, pubKey string) {
|
||||||
if len(MkTrees) == 0 {
|
if len(MkTrees) == 0 {
|
||||||
MkTrees = make(map[string]*tree.Tree)
|
MkTrees = make(map[string]*tree.Tree)
|
||||||
@@ -63,7 +72,7 @@ func checkRequest(w http.ResponseWriter, req *http.Request) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAuth(timestamp, signature, pubKey, message string) bool {
|
func checkAuth(timestamp, signed, pubKey, message string) bool {
|
||||||
if len(pubKey) < 1 {
|
if len(pubKey) < 1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -75,7 +84,7 @@ func checkAuth(timestamp, signature, pubKey, message string) bool {
|
|||||||
}
|
}
|
||||||
if timeStampRemote < currentTime+authTimeWindow &&
|
if timeStampRemote < currentTime+authTimeWindow &&
|
||||||
timeStampRemote > currentTime-authTimeWindow {
|
timeStampRemote > currentTime-authTimeWindow {
|
||||||
v, err := Signature.Verify(message, signature, pubKey)
|
v, err := currentSignature.Verify(message, signed, pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Verification error: %s\n", err)
|
log.Printf("Verification error: %s\n", err)
|
||||||
}
|
}
|
||||||
@@ -84,10 +93,8 @@ func checkAuth(timestamp, signature, pubKey, message string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func claimHandler(w http.ResponseWriter, req *http.Request, op string) {
|
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
var c Claim
|
var c Claim
|
||||||
var resp Result
|
|
||||||
|
|
||||||
if ok := checkRequest(w, req); !ok {
|
if ok := checkRequest(w, req); !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -97,6 +104,18 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) {
|
|||||||
http.Error(w, err.Error(), 400)
|
http.Error(w, err.Error(), 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(c.Method) < 1 {
|
||||||
|
http.Error(w, "method must be specified", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp := opHandler(&c)
|
||||||
|
reply(resp, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opHandler(c *Claim) *Result {
|
||||||
|
var resp Result
|
||||||
|
op := c.Method
|
||||||
|
var err error
|
||||||
|
|
||||||
// Process data
|
// Process data
|
||||||
log.Printf("censusId:{%s} rootHash:{%s} claimData:{%s} proofData:{%s} timeStamp:{%s} signature:{%s}\n",
|
log.Printf("censusId:{%s} rootHash:{%s} claimData:{%s} proofData:{%s} timeStamp:{%s} signature:{%s}\n",
|
||||||
@@ -111,73 +130,61 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) {
|
|||||||
if !censusFound {
|
if !censusFound {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = "censusId not valid or not found"
|
resp.Response = "censusId not valid or not found"
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "add" {
|
//Methods without rootHash
|
||||||
|
|
||||||
|
if op == "getRoot" {
|
||||||
|
resp.Response = MkTrees[c.CensusID].GetRoot()
|
||||||
|
return &resp
|
||||||
|
}
|
||||||
|
|
||||||
|
if op == "addClaim" {
|
||||||
if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); auth {
|
if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); auth {
|
||||||
err = MkTrees[c.CensusID].AddClaim([]byte(c.ClaimData))
|
err = MkTrees[c.CensusID].AddClaim([]byte(c.ClaimData))
|
||||||
} else {
|
} else {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = "invalid authentication"
|
resp.Response = "invalid authentication"
|
||||||
}
|
}
|
||||||
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "gen" {
|
//Methods with rootHash, if rootHash specified snapshot the tree
|
||||||
|
|
||||||
var t *tree.Tree
|
var t *tree.Tree
|
||||||
var err error
|
|
||||||
if len(c.RootHash) > 1 { //if rootHash specified
|
if len(c.RootHash) > 1 { //if rootHash specified
|
||||||
t, err = MkTrees[c.CensusID].Snapshot(c.RootHash)
|
t, err = MkTrees[c.CensusID].Snapshot(c.RootHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Snapshot error: %s", err.Error())
|
log.Printf("Snapshot error: %s", err.Error())
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = "invalid root hash"
|
resp.Response = "invalid root hash"
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
return
|
|
||||||
}
|
}
|
||||||
} else { //if rootHash not specified use current tree
|
} else { //if rootHash not specified use current tree
|
||||||
t = MkTrees[c.CensusID]
|
t = MkTrees[c.CensusID]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if op == "genProof" {
|
||||||
resp.Response, err = t.GenProof([]byte(c.ClaimData))
|
resp.Response, err = t.GenProof([]byte(c.ClaimData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = err.Error()
|
resp.Response = err.Error()
|
||||||
reply(&resp, w)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "root" {
|
if op == "getIdx" {
|
||||||
resp.Response = MkTrees[c.CensusID].GetRoot()
|
resp.Response, err = t.GetIndex([]byte(c.ClaimData))
|
||||||
}
|
return &resp
|
||||||
|
|
||||||
if op == "idx" {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "dump" {
|
if op == "dump" {
|
||||||
var t *tree.Tree
|
|
||||||
if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); !auth {
|
if auth := checkAuth(c.TimeStamp, c.Signature, Signatures[c.CensusID], authString); !auth {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = "invalid authentication"
|
resp.Response = "invalid authentication"
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.RootHash) > 1 { //if rootHash specified
|
|
||||||
t, err = MkTrees[c.CensusID].Snapshot(c.RootHash)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Snapshot error: %s", err.Error())
|
|
||||||
resp.Error = true
|
|
||||||
resp.Response = "invalid root hash"
|
|
||||||
reply(&resp, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else { //if rootHash not specified use current merkletree
|
|
||||||
t = MkTrees[c.CensusID]
|
|
||||||
}
|
|
||||||
|
|
||||||
//dump the claim data and return it
|
//dump the claim data and return it
|
||||||
values, err := t.Dump()
|
values, err := t.Dump()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -192,44 +199,31 @@ func claimHandler(w http.ResponseWriter, req *http.Request, op string) {
|
|||||||
resp.Response = fmt.Sprintf("%s", jValues)
|
resp.Response = fmt.Sprintf("%s", jValues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "check" {
|
if op == "checkProof" {
|
||||||
if len(c.ProofData) < 1 {
|
if len(c.ProofData) < 1 {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = "proofData not provided"
|
resp.Response = "proofData not provided"
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var t *tree.Tree
|
// Generate proof and return it
|
||||||
if len(c.RootHash) > 1 { //if rootHash specified
|
|
||||||
t, err = MkTrees[c.CensusID].Snapshot(c.RootHash)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Snapshot error: %s", err.Error())
|
|
||||||
resp.Error = true
|
|
||||||
resp.Response = "invalid root hash"
|
|
||||||
reply(&resp, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else { //if rootHash not specified use current merkletree
|
|
||||||
t = MkTrees[c.CensusID]
|
|
||||||
}
|
|
||||||
|
|
||||||
validProof, err := t.CheckProof([]byte(c.ClaimData), c.ProofData)
|
validProof, err := t.CheckProof([]byte(c.ClaimData), c.ProofData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Error = true
|
resp.Error = true
|
||||||
resp.Response = err.Error()
|
resp.Response = err.Error()
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if validProof {
|
if validProof {
|
||||||
resp.Response = "valid"
|
resp.Response = "valid"
|
||||||
} else {
|
} else {
|
||||||
resp.Response = "invalid"
|
resp.Response = "invalid"
|
||||||
}
|
}
|
||||||
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
reply(&resp, w)
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func addCorsHeaders(w *http.ResponseWriter, req *http.Request) {
|
func addCorsHeaders(w *http.ResponseWriter, req *http.Request) {
|
||||||
@@ -238,6 +232,7 @@ func addCorsHeaders(w *http.ResponseWriter, req *http.Request) {
|
|||||||
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen starts a census service defined of type "proto"
|
||||||
func Listen(port int, proto string) {
|
func Listen(port int, proto string) {
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", port),
|
Addr: fmt.Sprintf(":%d", port),
|
||||||
@@ -247,52 +242,14 @@ func Listen(port int, proto string) {
|
|||||||
IdleTimeout: 3 * time.Second,
|
IdleTimeout: 3 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/addClaim", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
addCorsHeaders(&w, r)
|
addCorsHeaders(&w, r)
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
claimHandler(w, r, "add")
|
httpHandler(w, r)
|
||||||
} else if r.Method != http.MethodOptions {
|
} else if r.Method != http.MethodOptions {
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
http.Error(w, "Not found", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
http.HandleFunc("/genProof", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
addCorsHeaders(&w, r)
|
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
|
||||||
claimHandler(w, r, "gen")
|
|
||||||
} else if r.Method != http.MethodOptions {
|
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
http.HandleFunc("/checkProof", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
addCorsHeaders(&w, r)
|
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
|
||||||
claimHandler(w, r, "check")
|
|
||||||
} else if r.Method != http.MethodOptions {
|
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
http.HandleFunc("/getRoot", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
addCorsHeaders(&w, r)
|
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
|
||||||
claimHandler(w, r, "root")
|
|
||||||
} else if r.Method != http.MethodOptions {
|
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
http.HandleFunc("/dump", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
addCorsHeaders(&w, r)
|
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
|
||||||
claimHandler(w, r, "dump")
|
|
||||||
} else if r.Method != http.MethodOptions {
|
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if proto == "https" {
|
if proto == "https" {
|
||||||
log.Print("Starting server in https mode")
|
log.Print("Starting server in https mode")
|
||||||
if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil {
|
if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user