// Load loads a player .wrj data file. The passed account should be a hash // returned by HashAccount. The name of the data file will be the account hash // with .wrj appended to it. // // If an error is returned a nil *Player will always be returned. // // If the data file cannot be opened a BadCredentials error is returned - the // account is incorrect if the file is not found. // // If the data file is opened but the password is incorrect a BadCredentials // error is returned. // // If the data file cannot be unmarshaled a BadPlayerFile error is returned. // // NOTE: We are manually opening the player's file, reading it as a recordjar, // peeking inside it, then unmarshaling it. This is so that we can abort at any // point - player not found, incorrect password, corrupt player file - having // done as little work as possible. In this way we are not unmarshaling players // which may have a lot of dependant stuff (inventory) to unmarshal just to // validate the login - someone could hit the server and tie up processing with // invalid logins otherwise if the unmarshaling took a significant amount of // time. func Load(account string, password string) (*Player, error) { // Can we open the player's file to get the current salt and password hash? f, err := os.Open(config.DataDir + "players/" + account + ".wrj") if err != nil { return nil, BadCredentials } defer f.Close() rj, _ := recordjar.Read(f) d := recordjar.Decoder(rj[0]) p := d.String("password") s := d.String("salt") // Password hash may be split over multiple lines in the data file which when // read will be concatenated together with spaces - which need removing. h := strings.Replace(p, " ", "", -1) if !PasswordValid(password, s, h) { return nil, BadCredentials } data := recordjar.UnmarshalJar(&rj) if data["PLAYER"] == nil { log.Printf("Error loading player: %#v", rj) return nil, BadPlayerFile } return data["PLAYER"].(*Player), nil }
// Read reads the config.wrj and sets new configuration values found in it. // // TODO: We should be able to reload and change settings at any time. // // TODO: Need to add more error checking of values coming in. func Read() { ps := string(os.PathSeparator) for _, path := range searchPaths { log.Printf("Checking for %s in: %s", configName, path) if dir, err := os.Open(path + ps + configName); err != nil { if !os.IsNotExist(err) { log.Printf("Error checking for %s: %s", configName, err) continue } } else { defer dir.Close() log.Printf("Using: %s%s%s", path, ps, configName) rj, _ := recordjar.Read(dir) d := recordjar.Decoder(rj[0]) ListenAddress = d.String("listen.address") ListenPort = d.String("listen.port") runtime.MemProfileRate = d.Int("mem.profile.rate") StatsRate = d.Duration("stats.rate") AccountIdMin = d.Int("account.id.min") AccountPasswordMin = d.Int("account.password.min") DataDir, _ = filepath.Abs(path + ps + d["data.dir"]) DataDir += ps log.Printf("listen.address: %s", ListenAddress) log.Printf("listen.port: %s", ListenPort) log.Printf("mem.profile.rate: %d", MemProfileRate) log.Printf("stats.rate: %s", StatsRate) log.Printf("data.dir: %s", DataDir) log.Printf("account.id.min: %d", AccountIdMin) log.Printf("account.password.min: %d", AccountPasswordMin) break } } }