Exemplo n.º 1
0
// Checks if the password matches the hash
//
// If the cost of the given hash is below the cost we currently use, the 2nd return value will contain a new and stronger hash.
// If the 2nd return value is present, you must update the hash for the password to it or you're missing out on the security benefits and wasting CPU cycles.
// If the given hash is already strong enough, the 2nd argument will be nil.
func (self *Hasher) Validate(password []byte, hash []byte) (bool, []byte, error) {
	err := bcrypt.CompareHashAndPassword(hash, password)

	if err != nil {
		// password and hash do not match
		return false, nil, nil
	} else {
		// password matches the hash

		costOfHash, err := bcrypt.Cost(hash)

		if err != nil || costOfHash < self.currentCost {
			// if unable to determine the cost (err != nil), treat it the same as an outdated hash

			newHash, err := self.Hash(password)

			if err != nil {
				return true, nil, err
			} else {
				return true, newHash, nil
			}
		} else {
			// the hash is valid and is sufficiently strong
			return true, nil, nil
		}
	}
}
Exemplo n.º 2
0
func (c *config) IsCurrent(encoded []byte) (isCurrent bool, err error) {
	cost, err := bcrypt.Cost(encoded)
	if err == nil {
		isCurrent = cost >= c.Cost
	}
	return
}
Exemplo n.º 3
0
// 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
}
Exemplo n.º 4
0
// Login returns a non-nil player and an empty error string OR a nil player
// and an error to show to the user.
func Login(addr string, packet *LoginPacket) (*Player, string) {
	login := strings.TrimSpace(packet.Login)
	if login == "" {
		return nil, "A username is required."
	}
	pass := []byte(packet.Pass)
	if len(pass) <= 2 {
		return nil, "A password is required."
	}
	filename := loginToFilename(login)

	loginLock.Lock()
	defer loginLock.Unlock()

	loginAttempts[addr]++
	if loginAttempts[addr] == 5 {
		loginAttempts[addr] += 60
	}
	if loginAttempts[addr] > 5 {
		return nil, fmt.Sprintf("Too many login attempts. Come back in %d minutes.", loginAttempts[addr]-5)
	}

	f, err := os.Open(filename)
	if err != nil {
		hashedPass, err := bcrypt.GenerateFromPassword(pass, CryptoCost)
		if err != nil {
			panic(err)
		}
		p := &Player{
			Hero:              *GenerateHero(rand.New(rand.NewSource(rand.Int63()))),
			characterCreation: true,
			tileX:             127,
			tileY:             127,
			login:             login,
			password:          hashedPass,
			firstAddr:         addr,
			registered:        time.Now().UTC(),
			lastAddr:          addr,
			lastLogin:         time.Now().UTC(),
		}
		world.InitObject(p)
		for _, e := range p.Hero.equipped {
			e.wearer = p
		}
		savePlayer(p)
		onlinePlayers[login] = p
		return p, ""
	}
	defer f.Close()

	g, err := gzip.NewReader(f)
	if err != nil {
		panic(err)
	}
	defer g.Close()

	var data interface{}
	err = gob.NewDecoder(g).Decode(&data)
	if err != nil {
		panic(err)
	}

	p := world.LoadConvert(data).(*Player)

	if bcrypt.CompareHashAndPassword(p.password, pass) != nil {
		return nil, "Username or password incorrect."
	}

	loginAttempts[addr]--

	if other, ok := onlinePlayers[p.login]; ok {
		savePlayer(other)
		other.Kick("Logged in from a different location.")
		_, err = f.Seek(0, 0)
		if err != nil {
			panic(err)
		}

		g, err = gzip.NewReader(f)
		if err != nil {
			panic(err)
		}
		defer g.Close()

		data = nil
		err = gob.NewDecoder(g).Decode(&data)
		if err != nil {
			panic(err)
		}
		p = world.LoadConvert(data).(*Player)
	}

	cost, err := bcrypt.Cost(p.password)
	if err != nil {
		panic(err)
	}
	if cost != CryptoCost {
		p.password, err = bcrypt.GenerateFromPassword(pass, CryptoCost)
		if err != nil {
			panic(err)
		}
		savePlayer(p)
	}

	onlinePlayers[p.login] = p

	return p, ""
}