// checkPass verifies that the given user exists and that the password matches. func checkPass(username, pass string, ip net.Addr) (user *world.User, err error) { if world.FindPlayer(username) != nil { return nil, ErrDupe } hash, err := db.Password(username) if err != nil { return nil, err } passb := []byte(pass) if hash == nil { // User does not exist. Fake out the time we would otherwise take to run // the hash. Ignore the error, we really only care about sucking up // some CPU cycles here. _ = bcrypt.CompareHashAndPassword(fakehash, passb) return nil, ErrAuth } err = bcrypt.CompareHashAndPassword(hash, passb) if err == bcrypt.ErrMismatchedHashAndPassword { return nil, ErrAuth } if err != nil { return nil, err } cost, err := bcrypt.Cost(hash) if err != nil { return nil, err } // Handle bcrypt cost change, rehash with new cost. if cost != bcryptCost { hash, err = bcrypt.GenerateFromPassword(passb, bcryptCost) if err != nil { return nil, err } } // Login successful, update info. if err := db.SaveUser(username, ip, hash); err != nil { return nil, err } return &world.User{Username: username, IP: ip}, nil }
// createUser creates the user if it does not exist. If it does exist, // createUser will return ErrExists. func createUser(username, pw string, ip net.Addr) (user *world.User, err error) { // do the expensive hash outside the critical section!! hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcryptCost) if err != nil { return nil, err } exists, err := db.UserExists(username) if err != nil { return nil, err } if exists { return nil, ErrExists } if err := db.SaveUser(username, ip, hash); err != nil { return nil, err } user = &world.User{ Username: username, } return user, nil }