// 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)
	}
}
Beispiel #2
0
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:])
	}
}