Inititial commit

This commit is contained in:
Christian Barth
2018-04-29 01:25:38 +02:00
commit b4e2e4a52a
7 changed files with 295 additions and 0 deletions

32
core/communications.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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)
}

BIN
werwolf Executable file

Binary file not shown.