diff --git a/common/encryption.go b/common/encryption.go new file mode 100644 index 0000000..54ad968 --- /dev/null +++ b/common/encryption.go @@ -0,0 +1,174 @@ +package common + +import ( + "time" +) + +func EncryptTypeX(key []byte, challenge []byte, data []byte) []byte { + returnData := make([]byte, 20) + returnData = append(returnData, data...) + + keyLen := len(key) + challengeLen := len(challenge) + rnd := time.Now().Unix() + + for i := 0; i < 20; i++ { + rnd = (rnd * 0x343FD) + 0x269EC3 + returnData[i] = byte(rnd ^ int64(key[i%keyLen]) ^ int64(challenge[i%challengeLen])) + } + + headerLen := 7 + returnData[0] = byte((headerLen - 2) ^ 0xec) + returnData[1] = 0x00 + returnData[2] = 0x00 + returnData[headerLen-1] = byte((20 - headerLen) ^ 0xea) + + header := returnData[:20] + encxkey := make([]byte, 261) + returnData = initEncrypt(encxkey, key, challenge, returnData) + func6e(encxkey, returnData) + + return append(header, returnData...) +} + +func initEncrypt(encxkey, key, validate, data []byte) []byte { + // TODO: Bounds + headerLen := (data[0] ^ 0xec) + 2 + dataStart := (data[headerLen-1] ^ 0xea) + + data = enctypexFuncX(encxkey, key, validate, data[headerLen:]) + return data[dataStart:] +} + +func enctypexFuncX(encxkey, key, challenge, data []byte) []byte { + keyLen := len(key) + for i := 0; i < len(data); i++ { + challenge[(key[i%keyLen]*byte(i))&7] ^= challenge[i&7] ^ data[i] + } + + func4(encxkey, challenge, 8) + return data +} + +func func4(encxkey, challenge []byte, challengeLen int) { + for i := 0; i < 256; i++ { + encxkey[i] = byte(i) + } + + n1 := 0 + n2 := 0 + t1 := 0 + for i := 255; i != -1; i-- { + t1, n1, n2 = func5(encxkey, i, challenge, challengeLen, n1, n2) + t2 := encxkey[i] + encxkey[i] = encxkey[t1] + encxkey[t1] = t2 + } + + encxkey[256] = encxkey[1] + encxkey[257] = encxkey[3] + encxkey[258] = encxkey[5] + encxkey[259] = encxkey[7] + encxkey[260] = encxkey[n1&0xff] +} + +func func5(encxkey []byte, cnt int, id []byte, idLen, n1, n2 int) (int, int, int) { + if cnt == 0 { + return 0, n1, n2 + } + + mask := 1 + doLoop := true + if cnt > 1 { + for doLoop { + mask = (mask << 1) + 1 + doLoop = mask < cnt + } + } + + i := 0 + tmp := 0 + doLoop = true + for doLoop { + n1 = int(encxkey[n1&0xff] + id[n2]) + n2 += 1 + + if n2 >= idLen { + n2 = 0 + n1 += idLen + } + + tmp = n1 & mask + + i += 1 + if i > 11 { + tmp %= cnt + } + + doLoop = tmp > cnt + } + + return tmp, n1, n2 +} + +func func6e(encxkey []byte, data []byte) []byte { + for i := 0; i < len(data); i++ { + data[i] = func7e(encxkey, data[i]) + } + + return data +} + +func func7e(encxkey []byte, d byte) byte { + a := encxkey[256] + b := encxkey[257] + c := encxkey[a] + encxkey[256] = (a + 1) & 0xff + encxkey[257] = (b + c) & 0xff + + a = encxkey[260] + b = encxkey[257] + b = encxkey[b] + c = encxkey[a] + encxkey[a] = b + + a = encxkey[259] + b = encxkey[257] + a = encxkey[a] + encxkey[b] = a + + a = encxkey[256] + b = encxkey[259] + a = encxkey[a] + encxkey[b] = a + + a = encxkey[256] + encxkey[a] = c + + b = encxkey[258] + a = encxkey[c] + c = encxkey[259] + b = (a + b) & 0xff + encxkey[258] = b + + a = b + c = encxkey[c] + b = encxkey[257] + b = encxkey[b] + a = encxkey[a] + c = (b + c) & 0xff + b = encxkey[260] + b = encxkey[b] + c = (b + c) & 0xff + b = encxkey[c] + c = encxkey[256] + c = encxkey[c] + a = (a + c) & 0xff + c = encxkey[b] + b = encxkey[a] + c ^= b ^ d + encxkey[260] = c + encxkey[259] = d + + return c +} diff --git a/common/strings.go b/common/strings.go new file mode 100644 index 0000000..f342c61 --- /dev/null +++ b/common/strings.go @@ -0,0 +1,36 @@ +package common + +import ( + "bytes" + "math/rand" + "time" +) + +var letterRunes = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func RandomString(n int) string { + rand.Seed(time.Now().UnixNano()) + + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} + +var hexRunes = []rune("0123456789abcdefabcdef") + +func RandomHexString(n int) string { + rand.Seed(time.Now().UnixNano()) + + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(hexRunes))] + } + return string(b) +} + +func GetString(buf []byte) string { + nullTerminator := bytes.IndexByte(buf, 0) + return string(buf[:nullTerminator]) +} diff --git a/database/login.go b/database/login.go index e2a1691..7696e30 100644 --- a/database/login.go +++ b/database/login.go @@ -2,9 +2,8 @@ package database import ( "context" - "wwfc/common" - "github.com/jackc/pgx/v4/pgxpool" + "wwfc/common" ) const ( diff --git a/database/user.go b/database/user.go index ec20cc7..4e077f5 100644 --- a/database/user.go +++ b/database/user.go @@ -3,10 +3,9 @@ package database import ( "context" "errors" - "wwfc/common" - "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/pgxpool" + "wwfc/common" ) const ( diff --git a/gcsp/login.go b/gcsp/login.go new file mode 100644 index 0000000..d2590ee --- /dev/null +++ b/gcsp/login.go @@ -0,0 +1,66 @@ +package gcsp + +import ( + "context" + "crypto/md5" + "encoding/base64" + "encoding/hex" + "github.com/jackc/pgx/v4/pgxpool" + "log" + "strconv" + "strings" + "wwfc/common" + "wwfc/database" +) + +func generateResponse(gpcmChallenge, nasChallenge, authToken, clientChallenge string) string { + hasher := md5.New() + hasher.Write([]byte(nasChallenge)) + str := hex.EncodeToString(hasher.Sum(nil)) + str += " " + str += authToken + str += clientChallenge + str += gpcmChallenge + str += hex.EncodeToString(hasher.Sum(nil)) + + _hasher := md5.New() + _hasher.Write([]byte(str)) + return hex.EncodeToString(_hasher.Sum(nil)) +} + +func generateProof(gpcmChallenge, nasChallenge, authToken, clientChallenge string) string { + return generateResponse(clientChallenge, nasChallenge, authToken, gpcmChallenge) +} + +func login(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand, challenge string) string { + // TODO: Validate login token with one in database + authToken := command.OtherValues["authtoken"] + response := generateResponse(challenge, "0qUekMb4", authToken, command.OtherValues["challenge"]) + if response != command.OtherValues["response"] { + log.Fatalf("i hate my life") + } + + proof := generateProof(challenge, "0qUekMb4", command.OtherValues["authtoken"], command.OtherValues["challenge"]) + + // Perform the login with the database. + user := database.LoginUserToGCPM(pool, ctx, authToken) + loginTicket := strings.Replace(base64.StdEncoding.EncodeToString([]byte(common.RandomString(16))), "=", "_", -1) + // TODO: REMOVE!!!!! + userId = user.UserId + // Now initiate the session + _ = database.CreateSession(pool, ctx, user.ProfileId, loginTicket) + + return common.CreateGameSpyMessage(common.GameSpyCommand{ + Command: "lc", + CommandValue: "2", + OtherValues: map[string]string{ + "sesskey": "199714190", + "proof": proof, + "userid": strconv.Itoa(user.UserId), + "profileid": strconv.Itoa(user.ProfileId), + "uniquenick": user.UniqueNick, + "lt": loginTicket, + "id": command.OtherValues["id"], + }, + }) +} diff --git a/gcsp/main.go b/gcsp/main.go new file mode 100644 index 0000000..4228c0d --- /dev/null +++ b/gcsp/main.go @@ -0,0 +1,117 @@ +package gcsp + +import ( + "bufio" + "context" + "errors" + "fmt" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/logrusorgru/aurora/v3" + "io" + "log" + "net" + "os" + "time" + "wwfc/common" + "wwfc/logging" +) + +var ( + ctx = context.Background() + pool *pgxpool.Pool + userId int +) + +func checkError(err error) { + if err != nil { + log.Fatalf("GCSP server has encountered a fatal error! Reason: %v\n", err) + } +} + +func StartServer() { + // Get config + config := common.GetConfig() + + // Start SQL + dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName) + dbConf, err := pgxpool.ParseConfig(dbString) + checkError(err) + pool, err = pgxpool.ConnectConfig(ctx, dbConf) + checkError(err) + + l, err := net.Listen("tcp", "127.0.0.1:29901") + if err != nil { + fmt.Println("Error listening:", err.Error()) + os.Exit(1) + } + // Close the listener when the application closes. + defer l.Close() + fmt.Println("Listening on " + "127.0.0.1:29901") + for { + // Listen for an incoming connection. + conn, err := l.Accept() + if err != nil { + fmt.Println("Error accepting: ", err.Error()) + os.Exit(1) + } + + // Handle connections in a new goroutine. + go handleRequest(conn) + } +} + +// Handles incoming requests. +func handleRequest(conn net.Conn) { + defer conn.Close() + + err := conn.(*net.TCPConn).SetKeepAlive(true) + if err != nil { + fmt.Printf("Unable to set keepalive - %s", err) + } + + err = conn.(*net.TCPConn).SetKeepAlivePeriod(time.Hour * 1000) + if err != nil { + fmt.Printf("Unable to set keepalive - %s", err) + } + + // log.Printf("%s: Connection established from %s. Sending challenge.", aurora.Green("[NOTICE]"), aurora.Yellow(conn.RemoteAddr())) + // conn.Write([]byte(fmt.Sprintf(`\lc\1\challenge\%s\id\1\final\`, challenge))) + + // Here we go into the listening loop + for { + buffer := make([]byte, 1024) + _, err := bufio.NewReader(conn).Read(buffer) + if err != nil { + if errors.Is(err, io.EOF) { + // Client closed connection, terminate. + return + } + } + + commands, err := common.ParseGameSpyMessage(string(buffer)) + if err != nil { + log.Fatal(err) + } + + for _, command := range commands { + logging.Notice("GCSP", "Message received. Command:", aurora.Yellow(command.Command).String()) + switch command.Command { + case "ka": + conn.Write([]byte(`\ka\\final\`)) + break + case "otherslist": + payload := common.CreateGameSpyMessage(common.GameSpyCommand{ + Command: "otherslist", + CommandValue: "", + OtherValues: map[string]string{ + "o": "0", + "uniquenick": "7me4ijr5sRMCJ3d9uhvh", + "oldone": "", + }, + }) + conn.Write([]byte(payload)) + break + } + } + } +} diff --git a/gcsp/profile.go b/gcsp/profile.go new file mode 100644 index 0000000..6f2025a --- /dev/null +++ b/gcsp/profile.go @@ -0,0 +1,62 @@ +package gcsp + +import ( + "context" + "github.com/jackc/pgx/v4/pgxpool" + "strconv" + "wwfc/common" + "wwfc/database" +) + +func getProfile(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) string { + strProfileId := command.OtherValues["profileid"] + profileId, _ := strconv.Atoi(strProfileId) + + user := database.GetProfile(pool, ctx, profileId) + + _ = common.RandomHexString(32) + return common.CreateGameSpyMessage(common.GameSpyCommand{ + Command: "pi", + CommandValue: "", + OtherValues: map[string]string{ + "profileid": command.OtherValues["profileid"], + "nick": user.UniqueNick, + "userid": strconv.Itoa(user.UserId), + "email": user.Email, + "sig": "b126556e5ee62d4da9629dfad0f6b2a8", + "uniquenick": user.UniqueNick, + "firstname": user.FirstName, + "lastname": user.LastName, + "pid": "11", + "lon": "0.000000", + "lat": "0.000000", + "loc": "", + "id": command.OtherValues["id"], + }, + }) +} + +func updateProfile(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) { + var firstName string + var lastName string + if v, ok := command.OtherValues["firstname"]; ok { + firstName = v + } + + if v, ok := command.OtherValues["lastname"]; ok { + lastName = v + } + + database.UpdateUser(pool, ctx, firstName, lastName, userId) +} + +func createStatus() string { + return common.CreateGameSpyMessage(common.GameSpyCommand{ + Command: "bm", + CommandValue: "100", + OtherValues: map[string]string{ + "f": "5", + "msg": "|s|0|ss|Offline", + }, + }) +} diff --git a/gpcm/login.go b/gpcm/login.go index cd204e1..914a43b 100644 --- a/gpcm/login.go +++ b/gpcm/login.go @@ -5,13 +5,12 @@ import ( "crypto/md5" "encoding/base64" "encoding/hex" + "github.com/jackc/pgx/v4/pgxpool" "log" "strconv" "strings" "wwfc/common" "wwfc/database" - - "github.com/jackc/pgx/v4/pgxpool" ) func generateResponse(gpcmChallenge, nasChallenge, authToken, clientChallenge string) string { @@ -46,7 +45,8 @@ func login(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyComman // Perform the login with the database. user := database.LoginUserToGCPM(pool, ctx, authToken) loginTicket := strings.Replace(base64.StdEncoding.EncodeToString([]byte(common.RandomString(16))), "=", "_", -1) - + // TODO: Remove in favour of proper thread safe holding + userId = user.UserId // Now initiate the session _ = database.CreateSession(pool, ctx, user.ProfileId, loginTicket) diff --git a/gpcm/main.go b/gpcm/main.go index d94a457..4957c01 100644 --- a/gpcm/main.go +++ b/gpcm/main.go @@ -5,15 +5,14 @@ import ( "context" "errors" "fmt" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/logrusorgru/aurora/v3" "io" "log" "net" "os" "time" "wwfc/common" - - "github.com/jackc/pgx/v4/pgxpool" - "github.com/logrusorgru/aurora/v3" ) var ( @@ -121,7 +120,6 @@ func handleRequest(conn net.Conn) { break case "getprofile": payload := getProfile(pool, ctx, command) - fmt.Println(payload) conn.Write([]byte(payload)) break } diff --git a/logging/log.go b/logging/log.go new file mode 100644 index 0000000..322e5fd --- /dev/null +++ b/logging/log.go @@ -0,0 +1,16 @@ +package logging + +import ( + "github.com/logrusorgru/aurora/v3" + "log" +) + +func Notice(module string, arguments ...string) { + var finalStr string + for _, argument := range arguments { + finalStr += argument + finalStr += " " + } + + log.Printf("[%s]: %s", aurora.Green(module), finalStr) +} diff --git a/main.go b/main.go index 9a09e8b..b94438e 100644 --- a/main.go +++ b/main.go @@ -2,15 +2,17 @@ package main import ( "sync" + "wwfc/gcsp" "wwfc/gpcm" - "wwfc/gpsp" + "wwfc/master" + "wwfc/matchmaking" "wwfc/nas" ) func main() { wg := &sync.WaitGroup{} - actions := []func(){nas.StartServer, gpcm.StartServer, gpsp.StartServer} - wg.Add(3) + actions := []func(){nas.StartServer, gpcm.StartServer, master.StartServer, gcsp.StartServer, matchmaking.StartServer} + wg.Add(4) for _, action := range actions { go func(ac func()) { defer wg.Done() diff --git a/master/challenge.go b/master/challenge.go new file mode 100644 index 0000000..853c7c5 --- /dev/null +++ b/master/challenge.go @@ -0,0 +1,5 @@ +package master + +func challenge() { + +} diff --git a/master/heartbeat.go b/master/heartbeat.go new file mode 100644 index 0000000..6b76f1c --- /dev/null +++ b/master/heartbeat.go @@ -0,0 +1,57 @@ +package master + +import ( + "encoding/binary" + "fmt" + "net" + "strconv" + "strings" + "wwfc/common" + "wwfc/logging" +) + +func heartbeat(conn net.PacketConn, addr net.Addr, buffer []byte) { + sessionId := binary.BigEndian.Uint32(buffer[1:5]) + logging.Notice("AVAILABLE", "Received heartbeat from", addr.String()) + values := strings.Split(string(buffer[5:]), "\u0000") + + payload := map[string]string{} + for i := 0; i < len(values); i += 2 { + if values[i] == "" { + break + } + + payload[values[i]] = values[i+1] + } + + // Generate challenge and send to server + var hexIP string + for _, i := range strings.Split(payload["localip0"], ".") { + val, err := strconv.ParseUint(i, 10, 64) + if err != nil { + panic(err) + } + + hexIP += fmt.Sprintf("%02X", val) + } + + port, err := strconv.ParseUint(payload["localport"], 10, 64) + if err != nil { + panic(err) + } + + hexPort := fmt.Sprintf("%04X", port) + + challenge := common.RandomString(6) + "00" + hexIP + hexPort + mutex.Lock() + session := sessions[sessionId] + session.Challenge = challenge + mutex.Unlock() + + response := []byte{0xfe, 0xfd, 0x01} + response = binary.BigEndian.AppendUint32(response, sessionId) + response = append(response, []byte(challenge)...) + response = append(response, 0) + + conn.WriteTo(response, addr) +} diff --git a/master/main.go b/master/main.go new file mode 100644 index 0000000..58b344e --- /dev/null +++ b/master/main.go @@ -0,0 +1,57 @@ +package master + +import ( + "encoding/binary" + "log" + "net" + "sync" +) + +var ( + // I would use a sync.Map instead of the map mutex combo, but this performs better. + sessions = map[uint32]*Session{} + mutex = sync.RWMutex{} +) + +func StartServer() { + conn, err := net.ListenPacket("udp", ":27900") + if err != nil { + log.Fatal(err) + } + + defer conn.Close() + + for { + buf := make([]byte, 1024) + _, addr, err := conn.ReadFrom(buf) + if err != nil { + continue + } + + go handleConnection(conn, addr, buf) + } +} + +func handleConnection(conn net.PacketConn, addr net.Addr, buffer []byte) { + if buffer[0] != 9 { + addSession(addr, buffer) + } + + switch buffer[0] { + case 1: + // Challenge + sessionId := binary.BigEndian.Uint32(buffer[1:5]) + response := []byte{0xfe, 0xfd, 0x0a} + response = binary.BigEndian.AppendUint32(response, sessionId) + conn.WriteTo(response, addr) + break + case 3: + heartbeat(conn, addr, buffer) + break + case 9: + conn.WriteTo([]byte{0xfe, 0xfd, 0x09, 0x00, 0x00, 0x00, 0x00}, addr) + break + default: + return + } +} diff --git a/master/session.go b/master/session.go new file mode 100644 index 0000000..9ed133e --- /dev/null +++ b/master/session.go @@ -0,0 +1,29 @@ +package master + +import ( + "encoding/binary" + "net" +) + +type Session struct { + SessionID uint32 + Challenge string + SecretKey string + IsConnected bool +} + +func addSession(addr net.Addr, buffer []byte) { + sessionId := binary.BigEndian.Uint32(buffer[1:5]) + + mutex.Lock() + if _, ok := sessions[sessionId]; !ok { + sessions[sessionId] = &Session{ + SessionID: sessionId, + Challenge: "", + // TODO: This is hardcoded for Mario Kart Wii + SecretKey: "9r3Rmy", + IsConnected: true, + } + } + mutex.Unlock() +} diff --git a/matchmaking/main.go b/matchmaking/main.go new file mode 100644 index 0000000..71c733e --- /dev/null +++ b/matchmaking/main.go @@ -0,0 +1,102 @@ +package matchmaking + +import ( + "bufio" + "context" + "errors" + "fmt" + "github.com/jackc/pgx/v4/pgxpool" + "io" + "log" + "net" + "os" + "time" + "wwfc/common" + "wwfc/logging" +) + +var ( + ctx = context.Background() + pool *pgxpool.Pool + userId int +) + +const ( + ServerList = iota + ModuleName = "MATCHMAKING" +) + +func checkError(err error) { + if err != nil { + log.Fatalf("GCSP server has encountered a fatal error! Reason: %v\n", err) + } +} + +func StartServer() { + // Get config + config := common.GetConfig() + + // Start SQL + dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName) + dbConf, err := pgxpool.ParseConfig(dbString) + checkError(err) + pool, err = pgxpool.ConnectConfig(ctx, dbConf) + checkError(err) + + l, err := net.Listen("tcp", "127.0.0.1:28910") + if err != nil { + fmt.Println("Error listening:", err.Error()) + os.Exit(1) + } + // Close the listener when the application closes. + defer l.Close() + fmt.Println("Listening on " + "127.0.0.1:28910") + for { + // Listen for an incoming connection. + conn, err := l.Accept() + if err != nil { + fmt.Println("Error accepting: ", err.Error()) + os.Exit(1) + } + + // Handle connections in a new goroutine. + go handleRequest(conn) + } +} + +// Handles incoming requests. +func handleRequest(conn net.Conn) { + defer conn.Close() + + err := conn.(*net.TCPConn).SetKeepAlive(true) + if err != nil { + fmt.Printf("Unable to set keepalive - %s", err) + } + + err = conn.(*net.TCPConn).SetKeepAlivePeriod(time.Hour * 1000) + if err != nil { + fmt.Printf("Unable to set keepalive - %s", err) + } + + // log.Printf("%s: Connection established from %s. Sending challenge.", aurora.Green("[NOTICE]"), aurora.Yellow(conn.RemoteAddr())) + // conn.Write([]byte(fmt.Sprintf(`\lc\1\challenge\%s\id\1\final\`, challenge))) + + // Here we go into the listening loop + for { + buffer := make([]byte, 1024) + _, err := bufio.NewReader(conn).Read(buffer) + if err != nil { + if errors.Is(err, io.EOF) { + // Client closed connection, terminate. + return + } + } + + logging.Notice(ModuleName, "Help me please") + switch buffer[2] { + case ServerList: + serverList(conn, buffer) + break + } + } +} diff --git a/matchmaking/server.go b/matchmaking/server.go new file mode 100644 index 0000000..7ad5069 --- /dev/null +++ b/matchmaking/server.go @@ -0,0 +1,43 @@ +package matchmaking + +import ( + "encoding/binary" + "net" + "strings" + "wwfc/common" + "wwfc/logging" +) + +func serverList(conn net.Conn, buffer []byte) { + logging.Notice(ModuleName, "Received server list command") + // TODO: Make a custom decoder for this? Go's binary decoder does not support strings as they are not a fixed width. + //listVersion := buffer[3] + //encodingVersion := buffer[4] + //gameVersion := binary.BigEndian.Uint32(buffer[5:]) + + index := 9 + queryGame := common.GetString(buffer[index:]) + index += len(queryGame) + 1 + gameName := common.GetString(buffer[index:]) + index += len(gameName) + 1 + + challenge := buffer[index : index+8] + index += 8 + + filter := common.GetString(buffer[index:]) + index += len(filter) + 1 + fields := common.GetString(buffer[index:]) + index += len(fields) + 1 + + options := binary.BigEndian.Uint32(buffer[index:]) + index += 4 + + logging.Notice(ModuleName, "Values", queryGame, gameName, string(challenge), string(options)) + + // TODO: Find a game if possible, but there is nobody to do that with yet! + output := []byte(strings.Replace(conn.RemoteAddr().String(), ".", "", -1)) + output = binary.BigEndian.AppendUint16(output, 6500) + + // encrypted := common.EncryptTypeX([]byte("9r3Rmy"), challenge, output) + conn.Write(output) +} diff --git a/nas/route.go b/nas/route.go index 5072187..74da67f 100644 --- a/nas/route.go +++ b/nas/route.go @@ -2,7 +2,6 @@ package nas import ( "encoding/base64" - "fmt" "github.com/logrusorgru/aurora/v3" "log" "net/http" @@ -60,7 +59,6 @@ func (route *Route) Handle() http.Handler { path := strings.Replace(r.URL.Path, "/", "", -1) actionName, _ := base64.StdEncoding.DecodeString(strings.Replace(r.PostForm.Get("action"), "*", "=", -1)) - fmt.Println(string(actionName)) var action Action for _, _action := range route.Actions { if path == _action.ServiceType && string(actionName) == _action.ActionName {