From 095c1c88a4409e81b96836c87ad7c9bd72534341 Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 10 May 2023 22:31:59 -0400 Subject: Separate server code into multiple files --- client/client.go | 7 -- client/main.go | 13 ++++ server/dht.go | 139 ++++++++++++++++++++++++++++++++++++++++ server/main.go | 63 ++++++++++++++++++ server/message.go | 10 +++ server/server.go | 188 ------------------------------------------------------ server/storage.go | 19 ++++++ 7 files changed, 244 insertions(+), 195 deletions(-) delete mode 100644 client/client.go create mode 100644 client/main.go create mode 100644 server/dht.go create mode 100644 server/main.go create mode 100644 server/message.go delete mode 100644 server/server.go create mode 100644 server/storage.go diff --git a/client/client.go b/client/client.go deleted file mode 100644 index b7d2a32..0000000 --- a/client/client.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "fmt" - -func main() { - fmt.Println("Hello, World!") -} diff --git a/client/main.go b/client/main.go new file mode 100644 index 0000000..d996531 --- /dev/null +++ b/client/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "crypto/ed25519" + "flag" +) + +func main() { + flag.Parse() + if flag.Arg(0) == "register" { + + } +} diff --git a/server/dht.go b/server/dht.go new file mode 100644 index 0000000..e5d96f1 --- /dev/null +++ b/server/dht.go @@ -0,0 +1,139 @@ +package main + +import ( + "crypto/ed25519" + "encoding/base64" + "fmt" + "io" + "log" + "net/http" + "sort" + "strings" +) + +// Try to peer with another server +func addPeer(peer string) error { + peerHash := sha256sum(peer) + // Check if already peered + mu.Lock() + _, ok := hashToDomain[peerHash] + mu.Unlock() + if ok { + return nil + } + mu.Lock() + hashToDomain[peerHash] = peer + mu.Unlock() + + // Try request to peer + log.Printf("%s trying to peer with %s", me, peer) + resp, err := http.Get(peer + "/peer?peer=" + me) + if err != nil { + // Request failed, delete peer + mu.Lock() + delete(hashToDomain, peerHash) + mu.Unlock() + return err + } + + log.Printf("%s successfully peered with %s", me, peer) + mu.Lock() + i := sort.SearchStrings(peerHashes, peerHash) + peerHashes = append(peerHashes, "") + copy(peerHashes[i+1:], peerHashes[i:]) + peerHashes[i] = peerHash + myPos = sort.SearchStrings(peerHashes, me) + mu.Unlock() + // Read response body + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + // Try adding all peers of this peer + newPeers := strings.Split(string(body), "\n") + for _, newPeer := range newPeers[:len(newPeers)-1] { + go addPeer(newPeer) + } + return nil +} + +// Handle incoming peer requests +func peerHandler(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + peer := r.Form.Get("peer") + if peer == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + for _, p := range hashToDomain { + fmt.Fprintf(w, "%s\n", p) + } + go addPeer(peer) +} + +// Handle DHT requests +func dhtHandler(w http.ResponseWriter, r *http.Request) { + key := r.URL.String()[5:] + keyHash := sha256sum(key) + pubKey := asPubKey(key) + fmt.Println(key, keyHash, pubKey) + mu.Lock() + keyPos := sort.SearchStrings(peerHashes, keyHash) + if keyPos < myPos { + keyPos += len(peerHashes) + } + mu.Unlock() + if r.Method == "GET" { + if keyPos - myPos < 5 { + mu.Lock() + if val, ok := kvstore[key]; ok { + w.Write([]byte(val)) + } else { + w.WriteHeader(http.StatusNotFound) + } + mu.Unlock() + } else { + for i := 0; i < 5 && i < len(peerHashes); i++ { + j := hashToDomain[peerHashes[(keyPos+i)%len(peerHashes)]] + go func() string { + resp, err := http.Get(j + r.URL.String()) + if err != nil { + return "" + } + b, err := io.ReadAll(resp.Body) + if err != nil { + return "" + } + return string(b) + }() + + } + + + } + } else if r.Method == "PUT" { + // Read request body + b, err := io.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + // Extract signature + valSplit := strings.Split(string(b), "\n") + sig := valSplit[len(valSplit)-1] + // Verify signature + if !ed25519.Verify(pubKey, b[:len(b)-len(sig)-1], []byte(sig)) { + w.WriteHeader(http.StatusUnauthorized) + return + } + if keyPos - myPos < 5 { + mu.Lock() + kvstore[key] = string(b[:len(b)-len(sig)-1]) + mu.Unlock() + } else { + + } + } else { + w.WriteHeader(http.StatusMethodNotAllowed) + } +} diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..c0f7450 --- /dev/null +++ b/server/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "crypto/ed25519" + "crypto/sha256" + "encoding/base64" + "flag" + "log" + "net/http" + "sync" +) + +type user struct { + pubkey []byte +} + +var mu sync.Mutex +var me string +var myHash string +var myPos int +var hashToDomain map[string]string +var peerHashes []string +var kvstore map[string]string + +// Get the sha256sum of string as a URL-safe unpadded base64 string +func sha256sum(s string) string { + b := sha256.Sum256([]byte(s)) + return base64.RawURLEncoding.EncodeToString(b[:]) +} + +// Decode an ID to a public key +func asPubKey(s string) ed25519.PublicKey { + b, err := base64.RawURLEncoding.DecodeString(s) + if err != nil { + return nil + } + return ed25519.PublicKey(b) +} + +func main() { + bindAddr := flag.String("b", ":4200", "bind address") + publicURL := flag.String("u", "http://localhost:4200", "public URL") + peer := flag.String("i", "", "initial peer") + flag.Parse() + log.Printf("Starting %s %s %s", *bindAddr, *publicURL, *peer) + + // Record myself + me = *publicURL + myHash = sha256sum(me) + myPos = 0 + peerHashes = append(peerHashes, sha256sum(me)) + hashToDomain = map[string]string{peerHashes[0]: me} + + if *peer != "" { + go addPeer(*peer) + } + + http.HandleFunc("/peer", peerHandler) + http.HandleFunc("/dht", dhtHandler) + http.HandleFunc("/storage", storageHandler) + http.HandleFunc("/message", messageHandler) + log.Fatal(http.ListenAndServe(*bindAddr, nil)) +} diff --git a/server/message.go b/server/message.go new file mode 100644 index 0000000..b127727 --- /dev/null +++ b/server/message.go @@ -0,0 +1,10 @@ +package main + +import ( + "net/http" +) + +// Handle message requests +func messageHandler(w http.ResponseWriter, r *http.Request) { + +} diff --git a/server/server.go b/server/server.go deleted file mode 100644 index 11aae25..0000000 --- a/server/server.go +++ /dev/null @@ -1,188 +0,0 @@ -package main - -import ( - "crypto/ed25519" - "crypto/sha256" - "encoding/hex" - "flag" - "fmt" - "io" - "log" - "net/http" - "sort" - "strings" - "sync" -) - -type user struct { - pubkey []byte -} - -var mu sync.Mutex -var me string -var myHash string -var myPos int -var hashToDomain map[string]string -var peerHashes []string -var kvstore map[string]string - -// Get the sha256sum of string as a hex string -func sha256sum(s string) string { - b := sha256.Sum256([]byte(s)) - return hex.EncodeToString(b[:]) -} - -// Try to peer with another server -func addPeer(peer string) error { - peerHash := sha256sum(peer) - // Check if already peered - mu.Lock() - _, ok := hashToDomain[peerHash] - mu.Unlock() - if ok { - return nil - } - mu.Lock() - hashToDomain[peerHash] = peer - mu.Unlock() - - // Try request to peer - log.Printf("%s trying to peer with %s", me, peer) - resp, err := http.Get(peer + "/peer?peer=" + me) - if err != nil { - // Request failed, delete peer - mu.Lock() - delete(hashToDomain, peerHash) - mu.Unlock() - return err - } - - log.Printf("%s successfully peered with %s", me, peer) - mu.Lock() - i := sort.SearchStrings(peerHashes, peerHash) - peerHashes = append(peerHashes, "") - copy(peerHashes[i+1:], peerHashes[i:]) - peerHashes[i] = peerHash - myPos = sort.SearchStrings(peerHashes, me) - mu.Unlock() - // Read response body - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - // Try adding all peers of this peer - newPeers := strings.Split(string(body), "\n") - for _, newPeer := range newPeers[:len(newPeers)-1] { - go addPeer(newPeer) - } - return nil -} - -// Handle incoming peer requests -func peerHandler(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - peer := r.Form.Get("peer") - if peer == "" { - w.WriteHeader(http.StatusBadRequest) - return - } - for _, p := range hashToDomain { - fmt.Fprintf(w, "%s\n", p) - } - go addPeer(peer) -} - -// Handle DHT requests -func dhtHandler(w http.ResponseWriter, r *http.Request) { - key := r.URL.String()[5:] - keyHash := sha256sum(key) - fmt.Println(key, keyHash) - mu.Lock() - keyPos := sort.SearchStrings(peerHashes, keyHash) - if keyPos < myPos { - keyPos += len(peerHashes) - } - mu.Unlock() - if r.Method == "GET" { - if keyPos - myPos < 5 { - mu.Lock() - if val, ok := kvstore[key]; ok { - w.Write([]byte(val)) - } else { - w.WriteHeader(http.StatusNotFound) - } - mu.Unlock() - } else { - for i := 0; i < 5 && i < len(peerHashes); i++ { - j := hashToDomain[peerHashes[(keyPos+i)%len(peerHashes)]] - go func() string { - resp, err := http.Get(j + r.URL.String()) - if err != nil { - return "" - } - b, err := io.ReadAll(resp.Body) - if err != nil { - return "" - } - return string(b) - }() - - } - - - } - } else if r.Method == "PUT" { - b, err := io.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - } - - - if keyPos - myPos < 5 { - mu.Lock() - kvstore[key] = string(b) - } - } else { - w.WriteHeader(http.StatusMethodNotAllowed) - } -} - -// Handle storage requests -func storageHandler(w http.ResponseWriter, r *http.Request) { - filename := r.URL.String()[5:] - if r.Method == "GET" { - - } else if r.Method == "PUT" { - - } else if r.Method == "DELETE" { - - } else { - w.WriteHeader(http.StatusMethodNotAllowed) - } -} - -func main() { - bindAddr := flag.String("b", ":4200", "bind address") - domain := flag.String("d", "http://localhost:4200", "full domain name") - peer := flag.String("i", "", "initial peer") - flag.Parse() - - log.Printf("Starting %s %s %s", *bindAddr, *domain, *peer) - - // Record myself - me = *domain - myHash = sha256sum(me) - myPos = 0 - peerHashes = append(peerHashes, sha256sum(me)) - hashToDomain = map[string]string{peerHashes[0]: me} - - if *peer != "" { - go addPeer(*peer) - } - - http.HandleFunc("/peer", peerHandler) - http.HandleFunc("/dht", dhtHandler) - http.HandleFunc("/storage", storageHandler) - log.Fatal(http.ListenAndServe(*bindAddr, nil)) -} diff --git a/server/storage.go b/server/storage.go new file mode 100644 index 0000000..dd11f22 --- /dev/null +++ b/server/storage.go @@ -0,0 +1,19 @@ +package main + +import ( + "net/http" +) + +// Handle storage requests +func storageHandler(w http.ResponseWriter, r *http.Request) { + // filename := r.URL.String()[5:] + if r.Method == "GET" { + + } else if r.Method == "PUT" { + + } else if r.Method == "DELETE" { + + } else { + w.WriteHeader(http.StatusMethodNotAllowed) + } +} -- cgit v1.2.3-70-g09d2