// The 'name' argument is not the nick name shown, it is the login name used to // authenticate the player. func (up *user) CmdLogin_WLwWLuWLqBlWLc(email string) { // fmt.Printf("CmdLogin: New player %v\n", email) // It may be that there is no license for this player. But we can only give one type of error // message, which means wrong email or password. validTestUser := false remote := up.conn.RemoteAddr().String() addr := strings.Split(remote, ":") // The format is expected to be NNN.NNN.NNN.NNN:NNNN. if *allowTestUser && strings.HasPrefix(email, CnfgTestPlayerNamePrefix) { if len(addr) == 2 { ip := addr[0] cnfg, err := config.ReadDefault(*configFileName) if err == nil && cnfg.HasSection("login") { testplayersallowed, _ := cnfg.Bool("login", "testplayer") testiplist, err := cnfg.String("login", "testip") if testplayersallowed && err == nil && strings.Contains(testiplist, ip) { validTestUser = true } else if err != nil { validTestUser = true // Allow testuser if no "testip" key. } } else { validTestUser = true // Allow testuser if no config file or no "Login" section } } } else { log.Println("Denied testuser from", remote) } if validTestUser { // This test player is allowed login without password, but it is never saved uid := up.pl.New_WLwWLc(email) up.uid = uid up.loginAck_WLuWLqBlWLa() up.pl.adminLevel = 9 } else { lic := license.Load_Bl(email) up.Lock() up.lic = lic up.challenge = make([]byte, LoginChallengeLength) cryptrand.Read(up.challenge) if lic != nil && len(lic.Names) > 0 { uid, ok := up.pl.Load_WLwBlWLc(lic.Names[0]) if ok { up.uid = uid } else { up.lic = nil // Failed to load player data, have fail login (do not know avatar name) } } else if lic == nil { if *verboseFlag > 0 { log.Printf("Login failed or no license for '%v'\n", email) } } else if len(lic.Names) == 0 { log.Printf("No avatar for email '%v'\n", email) up.lic = nil // Force the next login phase to fail. } up.connState = PlayerConnStatePass up.Unlock() // Request a password, even though the license may be incorrect. up.writeBlocking_Bl([]byte{3 + LoginChallengeLength, 0, client_prot.CMD_REQ_PASSWORD}) up.writeBlocking_Bl(up.challenge) } }
func DoTestLicense_Bl() { const ( email = "a@b" name = "nm" pass = "******" ) lic := license.Make(email) lic.Names = []string{name} lic.License = license.GenerateKey() lic.NewPassword(pass) if *verboseFlag > 0 { fmt.Printf("DoTestLicense load lic1 %#v\n", lic) } DoTestCheck("DoTestLicense VerifyPassword1", lic.VerifyPassword(pass, encryptionSalt)) saveSuccess := lic.Save_Bl() DoTestCheck("DoTestLicense Save", saveSuccess) lic2 := license.Load_Bl(email) if *verboseFlag > 0 { fmt.Printf("DoTestLicense load lic2 %#v\n", lic2) } DoTestCheck("DoTestLicense Load", lic2 != nil) if lic2 != nil { DoTestCheck("DoTestLicense VerifyPassword2", lic2.VerifyPassword(pass, encryptionSalt)) } }
// The player sent a string message func (up *user) playerStringMessage_RLuWLwRLqBlWLaWLc(buff []byte) { str := strings.TrimRight(string(buff), " ") // Remove trailing spaces, if any if *verboseFlag > 1 { log.Printf("User %v cmd: '%v'\n", up.pl.name, str) } message := strings.SplitN(str, " ", 2) switch message[0] { case "/keys": for _, key := range up.pl.Keys { up.Printf_Bl("!%s(%d), uid %d", key.Descr, key.Kid, key.Uid) } case "/activator": if len(message) < 2 { return } up.ActivatorControl(message[1]) case "/home": if len(message) == 1 { up.Lock() up.pl.coord = up.pl.homeSP up.updatedStats = true up.Unlock() } case "/sethome": cc := up.pl.coord.GetChunkCoord() cp := ChunkFind_WLwWLc(cc) if cp.owner != up.uid { up.Printf_Bl("#FAIL Not your territory") break } if len(message) == 1 { up.Lock() up.pl.homeSP = up.pl.coord up.Unlock() up.Printf_Bl("Home spawn point updated!") } case "/territory": if len(message) < 2 { return } up.TerritoryCommand_WLwWLcBl(strings.Split(message[1], " ")) case "/revive": if len(message) == 1 && up.pl.dead { up.Lock() up.pl.dead = false up.pl.hitPoints = 0.3 up.updatedStats = true up.pl.coord = up.pl.reviveSP up.Unlock() } case "/level": if (up.pl.adminLevel >= 8 || *allowTestUser) && len(message) == 2 { lvl, err := strconv.ParseUint(message[1], 10, 0) if err != nil { up.Printf_Bl("%s", err) } else { up.pl.level = uint32(lvl) up.updatedStats = true } } case "/timers": if up.pl.adminLevel >= 2 || *allowTestUser { timerstats.Report(up) } case "/panic": if up.pl.adminLevel >= 8 || *allowTestUser { log.Panic("client_prot.DEBUG command 'panic'") } case "/status": var m runtime.MemStats runtime.ReadMemStats(&m) up.Printf_Bl("!!Status") up.Printf_Bl("!Chunks loaded: %d, super chunks %d", worldCacheNumChunks, superChunkManager.Size()) up.Printf_Bl("!Num players:%v, monsters %v, near monsters %d", numPlayers, len(monsterData.m), CountNearMonsters_RLq(up.GetPreviousPos())) up.Printf_Bl("!Mem in use %vMB, total alloc %vMB, num malloc %vM, num free %vM", m.Alloc/1e6, m.TotalAlloc/1e6, m.Mallocs/1e6, m.Frees/1e6) up.Printf_Bl("!Worst message write %.6f s, Worst chunk read %.6f s", float64(WorstWriteTime)/float64(time.Second), float64(DBStats.WorstRead)/float64(time.Second)) up.Printf_Bl("!Num chunks read: %d, average read time %.6f", DBStats.NumRead, float64(DBStats.TotRead)/float64(DBStats.NumRead)/float64(time.Second)) up.Printf_Bl("!Created chunks: %d, average time %.6f", DBCreateStats.Num, float64(DBCreateStats.TotTime)/float64(DBCreateStats.Num)/float64(time.Second)) up.Printf_Bl("!%s", trafficStatistics) WorstWriteTime = 0 DBStats.WorstRead = 0 case "/players": up.ReportPlayers() case "/flying": up.pl.flying = !up.pl.flying up.pl.climbing = false // Always turn off climbing up.Printf_Bl("Flying: %v", up.pl.flying) case "/inv": fallthrough case "/inventory": if len(message) == 2 && up.pl.adminLevel > 8 { maker, ok := objectTable[message[1]] if message[1] == "clear" { up.pl.inventory.Clear() // There is no update message generated, so client won't know. up.pl.WeaponType = 0 up.pl.ArmorType = 0 up.pl.HelmetType = 0 up.pl.WeaponLvl = 0 up.pl.ArmorLvl = 0 up.pl.HelmetLvl = 0 } else if !ok { up.Printf_Bl("!Available objects:") for key, maker := range objectTable { up.Printf_Bl("!%v (%v)", maker(MonsterDifficulty(&up.pl.coord)), key) } } else { AddOneObjectToUser_WLuBl(up, maker(MonsterDifficulty(&up.pl.coord))) } } else { up.pl.inventory.Report(up) up.Printf_Bl("!Equip modifiers: armor %.0f%%, helmet %.0f%%, weapon %.0f%%", (ArmorLevelDiffMultiplier(up.pl.level, up.pl.ArmorLvl, up.pl.ArmorType)-1)*100, (ArmorLevelDiffMultiplier(up.pl.level, up.pl.HelmetLvl, up.pl.HelmetType)-1)*100, (WeaponLevelDiffMultiplier(up.pl.level, up.pl.WeaponLvl, up.pl.WeaponType)-1)*100) } case "/GC": var m runtime.MemStats runtime.ReadMemStats(&m) up.Printf_Bl("GC next: %v, num: %v, paus total: %v", m.NextGC, m.NumGC, m.PauseTotalNs) // runtime.GC() case "/shutdown": if up.pl.adminLevel >= 8 { if *cpuprofile != "" { pprof.StopCPUProfile() } GraceFulShutdown() // Will not return } case "/evalsync": for _, str := range evalsync.Eval() { up.Printf_Bl("!%s", str) } case "/resetpos": up.pl.coord.X = 0 up.pl.coord.Y = 0 up.pl.coord.Z = FLOATING_ISLANDS_LIM - PlayerHeight // As high as possible up.pl.flying = false up.pl.climbing = false case "/prof": if up.pl.adminLevel >= 8 || *allowTestUser { const fn = "profdata.tmp" f, _ := os.OpenFile(fn, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) pprof.WriteHeapProfile(f) f.Close() up.Printf_Bl("pprof written to %s\n", fn) } case "/makelicense": if up.pl.adminLevel >= 8 && len(message) == 2 { args := strings.Split(message[1], " ") // split the rest of the input string into the arguments needed if len(args) != 3 { up.Printf_Bl("#FAIL Usage: /makelicense email password avatar") } else { email := args[0] oldlic := license.Load_Bl(email) if oldlic != nil { up.Printf_Bl("email %v already used (avatar %v)", email, oldlic.Names) } else { lic := license.Make(email) lic.NewPassword(args[1]) lic.License = license.GenerateKey() lic.Names = []string{args[2]} // Array of names, initialized with one entry ok := lic.Save_Bl() if ok { up.Printf_Bl("Saved %v", email) } else { up.Printf_Bl("#FAIL Failed to save %v", email) } } } } case "/loadlicense": if (up.pl.adminLevel >= 8 || *allowTestUser) && len(message) == 2 { email := message[1] lic := license.Load_Bl(email) up.Printf_Bl("%v", lic) } case "/say": if len(message) < 2 { break } near := playerQuadtree.FindNearObjects_RLq(up.GetPreviousPos(), client_prot.NEAR_OBJECTS) n := 0 for _, o := range near { other, ok := o.(*user) if !ok { continue // Only need to tell players, not monsters etc. } if other == up { continue // Found self } // Tell 'other' that we moved other.Printf("%s says: %s", up.pl.name, message[1]) n++ } if n == 0 { up.Printf_Bl("#FAIL No one is near") } else { up.Printf_Bl("You say: %s", message[1]) } case "/tell": if len(message) < 2 { break } up.TellOthers_RLaBl(message[1]) case "/friend": if len(message) < 2 { break } up.FriendCommand_RLaWLu(message[1]) case "/score": score.Report(up) case "/target": if len(message) < 2 { break } up.TargetCommand(message[1:]) } }