Inititial commit
This commit is contained in:
32
core/communications.go
Normal file
32
core/communications.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// SendObject sends a object through the writer
|
||||
func SendObject(writer *http.ResponseWriter, data interface{}) {
|
||||
js := ToJSON(data)
|
||||
if js == "" {
|
||||
SendJSON(writer, "{\"server_message\":\"internal_sending_error\"")
|
||||
return
|
||||
}
|
||||
SendJSON(writer, js)
|
||||
}
|
||||
|
||||
// SendJSON sends JSON string through the writer
|
||||
func SendJSON(writer *http.ResponseWriter, data string) {
|
||||
(*writer).Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf((*writer), data)
|
||||
}
|
||||
|
||||
// ToJSON converts an object to a JSON string
|
||||
func ToJSON(in interface{}) string {
|
||||
data, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
92
gamemanagment.go
Normal file
92
gamemanagment.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"werwolf/core"
|
||||
)
|
||||
|
||||
var games []JSON_Game
|
||||
|
||||
type JSON_Game struct {
|
||||
Token string `json:"token"`
|
||||
Username string `json:"username"`
|
||||
Gamename string `json:"gamename"`
|
||||
}
|
||||
|
||||
// getGame returns a reference to a game-Object identified by token
|
||||
func getGame(token string) (*JSON_Game, bool) {
|
||||
for _, g := range games {
|
||||
if g.Token == token {
|
||||
return &g, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// addGame adds a game-Object game to the list of active games or replaces an inactive game.
|
||||
func addGame(game JSON_Game) bool {
|
||||
a := true
|
||||
for _, g := range games {
|
||||
if g.Token == "" {
|
||||
g = game
|
||||
a = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
if a {
|
||||
games = append(games, game)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// removeGame disables a game-Object by setting its token to none. Object to be edited is identified by token. Returns true if successfull or false if not found.
|
||||
func removeGame(token string) bool {
|
||||
for _, g := range games {
|
||||
if g.Token == token {
|
||||
g.Token = ""
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func newGame(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
var game = new(JSON_Game)
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(request.Body)
|
||||
|
||||
if json.Unmarshal(buf.Bytes(), game) == nil {
|
||||
game.Token = randomString(32)
|
||||
if addGame(*game) {
|
||||
core.SendObject(&responseWriter, game)
|
||||
addGame(*game)
|
||||
} else {
|
||||
sendError(&responseWriter, "game_creation")
|
||||
}
|
||||
} else {
|
||||
sendError(&responseWriter, "json")
|
||||
}
|
||||
}
|
||||
|
||||
func joinGame(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
var game = new(JSON_Game)
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(request.Body)
|
||||
|
||||
if json.Unmarshal(buf.Bytes(), game) == nil {
|
||||
game, succ := getGame(game.Token)
|
||||
if succ {
|
||||
core.SendObject(&responseWriter, *game)
|
||||
} else {
|
||||
sendError(&responseWriter, "game_notfound")
|
||||
}
|
||||
} else {
|
||||
sendError(&responseWriter, "json")
|
||||
}
|
||||
}
|
||||
|
||||
func sendError(responseWriter *http.ResponseWriter, errorMsg string) {
|
||||
core.SendObject(responseWriter, map[string]string{"state": errorMsg + "_error"})
|
||||
}
|
||||
31
index.html
Normal file
31
index.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Werwolf Test page</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script>
|
||||
function send(input, where)
|
||||
{
|
||||
jQuery.post("http://127.0.0.1:25566/"+where, input, function(data, textStatus, jqXHR ){console.log(data);});
|
||||
}
|
||||
|
||||
$("document").ready(function(){
|
||||
$("#send").click(send($("#in").val(),$("#where").val()));
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<form>
|
||||
<input id="in"/>
|
||||
<input id="where"/>
|
||||
<button id="send">SEND</button>
|
||||
</form>
|
||||
</main>
|
||||
<footer>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
19
main.go
Normal file
19
main.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Starting Werwolf Server")
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/werwolf/creategame", http.HandlerFunc(newGame))
|
||||
mux.HandleFunc("/werwolf/joingame", http.HandlerFunc(joinGame))
|
||||
|
||||
corsHandler := cors.Default().Handler(mux)
|
||||
http.ListenAndServe(":25566", corsHandler)
|
||||
}
|
||||
32
randomstring.go
Normal file
32
randomstring.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
letterIdxBits = 6
|
||||
letterIdxMask = 1<<letterIdxBits - 1
|
||||
letterIdxMax = 63 / letterIdxBits
|
||||
)
|
||||
const letterBytes = "abcdefghijkmnlopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
var src = rand.NewSource(time.Now().UnixNano())
|
||||
|
||||
func randomString(n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = src.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
89
realip/realip.go
Normal file
89
realip/realip.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package realip
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cidrs []*net.IPNet
|
||||
|
||||
func init() {
|
||||
maxCidrBlocks := []string{
|
||||
"127.0.0.1/8", // localhost
|
||||
"10.0.0.0/8", // 24-bit block
|
||||
"172.16.0.0/12", // 20-bit block
|
||||
"192.168.0.0/16", // 16-bit block
|
||||
"169.254.0.0/16", // link local address
|
||||
"::1/128", // localhost IPv6
|
||||
"fc00::/7", // unique local address IPv6
|
||||
"fe80::/10", // link local address IPv6
|
||||
}
|
||||
|
||||
cidrs = make([]*net.IPNet, len(maxCidrBlocks))
|
||||
for i, maxCidrBlock := range maxCidrBlocks {
|
||||
_, cidr, _ := net.ParseCIDR(maxCidrBlock)
|
||||
cidrs[i] = cidr
|
||||
}
|
||||
}
|
||||
|
||||
// isLocalAddress works by checking if the address is under private CIDR blocks.
|
||||
// List of private CIDR blocks can be seen on :
|
||||
//
|
||||
// https://en.wikipedia.org/wiki/Private_network
|
||||
//
|
||||
// https://en.wikipedia.org/wiki/Link-local_address
|
||||
func isPrivateAddress(address string) (bool, error) {
|
||||
ipAddress := net.ParseIP(address)
|
||||
if ipAddress == nil {
|
||||
return false, errors.New("address is not valid")
|
||||
}
|
||||
|
||||
for i := range cidrs {
|
||||
if cidrs[i].Contains(ipAddress) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// FromRequest return client's real public IP address from http request headers.
|
||||
func FromRequest(r *http.Request) string {
|
||||
// Fetch header value
|
||||
xRealIP := r.Header.Get("X-Real-Ip")
|
||||
xForwardedFor := r.Header.Get("X-Forwarded-For")
|
||||
|
||||
// If both empty, return IP from remote address
|
||||
if xRealIP == "" && xForwardedFor == "" {
|
||||
var remoteIP string
|
||||
|
||||
// If there are colon in remote address, remove the port number
|
||||
// otherwise, return remote address as is
|
||||
if strings.ContainsRune(r.RemoteAddr, ':') {
|
||||
remoteIP, _, _ = net.SplitHostPort(r.RemoteAddr)
|
||||
} else {
|
||||
remoteIP = r.RemoteAddr
|
||||
}
|
||||
|
||||
return remoteIP
|
||||
}
|
||||
|
||||
// Check list of IP in X-Forwarded-For and return the first global address
|
||||
for _, address := range strings.Split(xForwardedFor, ",") {
|
||||
address = strings.TrimSpace(address)
|
||||
isPrivate, err := isPrivateAddress(address)
|
||||
if !isPrivate && err == nil {
|
||||
return address
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing succeed, return X-Real-IP
|
||||
return xRealIP
|
||||
}
|
||||
|
||||
// RealIP is depreciated, use FromRequest instead
|
||||
func RealIP(r *http.Request) string {
|
||||
return FromRequest(r)
|
||||
}
|
||||
Reference in New Issue
Block a user