Files
Battle-for-Tismo/scripts/classes/login_manager.gd
T
adrien c49899a2fd Initial commit
Server-authoritative Godot 4.6 strategy game.

Includes the headless WebSocket game server, the browser client, and
Nix packaging (server and web-export derivations plus a NixOS module)
for deployment.
2026-09-15 14:48:34 +02:00

73 lines
2.1 KiB
GDScript

class_name LoginManager
extends RefCounted
## Per-game player credentials. There is no account system: a player picks a
## name and password the first time they join a particular game, and the same
## pair authenticates them when they come back to that game. A manager lives on
## the authoritative server for the lifetime of the game, so credentials never
## cross between games.
##
## Passwords are never kept in the clear. Each game salts and hashes them, so
## the stored value is useless outside this game.
## Name (stripped) -> salted SHA-256 hash of the password.
var _passwords: Dictionary = {}
var _salt: String
## `salt` is only supplied by tests; a real game gets a fresh random salt.
func _init(salt: String = "") -> void:
_salt = salt if not salt.is_empty() else _random_salt()
func has_player(name: String) -> bool:
return _passwords.has(_key(name))
func player_count() -> int:
return _passwords.size()
## Authenticates a joining player, registering them the first time their name is
## seen. That first join is the only "registration" in the game. Returns true
## when the player may enter.
func login(name: String, password: String) -> bool:
var key := _key(name)
if key.is_empty() or password.is_empty():
return false
if not _passwords.has(key):
_passwords[key] = _hash(password)
return true
return _passwords[key] == _hash(password)
## Explicitly sets a password for a new player. Returns false when the name is
## invalid or already taken.
func register(name: String, password: String) -> bool:
var key := _key(name)
if key.is_empty() or password.is_empty() or _passwords.has(key):
return false
_passwords[key] = _hash(password)
return true
## Checks a password for a name that is expected to exist.
func authenticate(name: String, password: String) -> bool:
var key := _key(name)
if key.is_empty() or not _passwords.has(key):
return false
return _passwords[key] == _hash(password)
func _key(name: String) -> String:
return name.strip_edges()
func _hash(password: String) -> String:
return (_salt + password).sha256_text()
func _random_salt() -> String:
return "%d:%d" % [Time.get_ticks_usec(), randi()]