things + stff
This commit is contained in:
167
server/models/states/createPlayer.js
Executable file
167
server/models/states/createPlayer.js
Executable file
@@ -0,0 +1,167 @@
|
||||
import WebSocket from "ws";
|
||||
import { Session } from "../session.js";
|
||||
import * as msg from "../../utils/messages.js";
|
||||
import * as security from "../../utils/security.js";
|
||||
import { AuthState } from "./auth.js";
|
||||
import { Player } from "../player.js";
|
||||
|
||||
const USERNAME_PROMPT = "Enter a valid username (4-20 characters, [a-z], [A-Z], [0-9], and underscore)";
|
||||
const PASSWORD_PROMPT = "Enter a valid password";
|
||||
const PASSWORD_PROMPT2 = "Enter your password again";
|
||||
const ERROR_INSANE_PASSWORD = "Invalid password.";
|
||||
const ERROR_INSANE_USERNAME = "Invalid username. It must be 4-20 characters, and may only contain [a-z], [A-Z], [0-9] and underscore"
|
||||
const ERROR_INCORRECT_PASSWOD = "Incorrect password.";
|
||||
|
||||
/** @property {Session} session */
|
||||
export class CreatePlayerState {
|
||||
|
||||
/**
|
||||
* @proteted
|
||||
* @type {(msg: ClientMessage) => }
|
||||
*
|
||||
* Allows us to dynamically set which
|
||||
* method handles incoming messages.
|
||||
*/
|
||||
_dynamicMessageHandler;
|
||||
|
||||
/** @protected @type {Player} */
|
||||
_player;
|
||||
/** @protected @type {string} */
|
||||
_password;
|
||||
|
||||
/**
|
||||
* @param {Session} session
|
||||
*/
|
||||
constructor(session) {
|
||||
/** @type {Session} */
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
onAttach() {
|
||||
this.session.sendFigletMessage("New Player");
|
||||
this.session.sendPrompt("username", USERNAME_PROMPT);
|
||||
|
||||
// our initial substate is to receive a username
|
||||
this.setMessageHandler(this.receiveUsername);
|
||||
}
|
||||
|
||||
/** @param {msg.ClientMessage} message */
|
||||
onMessage(message) {
|
||||
this._dynamicMessageHandler(message);
|
||||
}
|
||||
|
||||
/* @param {(msg: ClientMessage) => } handler */
|
||||
setMessageHandler(handler) {
|
||||
this._dynamicMessageHandler = handler;
|
||||
}
|
||||
|
||||
/** @param {msg.ClientMessage} message */
|
||||
receiveUsername(message) {
|
||||
|
||||
//
|
||||
// NOTE FOR ACCOUNT CREATION
|
||||
// Do adult-word checks, so we dont have Fucky_McFuckFace
|
||||
// https://www.npmjs.com/package/glin-profanity
|
||||
|
||||
//
|
||||
// handle invalid message types
|
||||
if (!message.isUsernameResponse()) {
|
||||
this.session.sendError("Incorrect message type!");
|
||||
this.session.sendPrompt("username", USERNAME_PROMPT);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// do basic syntax checks on usernames
|
||||
if (!security.isUsernameSane(message.username)) {
|
||||
this.session.sendError(ERROR_INSANE_USERNAME);
|
||||
this.session.sendPrompt("username", USERNAME_PROMPT);
|
||||
return;
|
||||
}
|
||||
|
||||
const taken = this.session.game.players.has(message.username);
|
||||
|
||||
//
|
||||
// handle taken/occupied username
|
||||
if (taken) {
|
||||
// Telling the user right away that the username is taken can
|
||||
// lead to data leeching. But fukkit.
|
||||
|
||||
this.session.sendError(`Username _${message.username}_ was taken by another player.`);
|
||||
this.session.sendPrompt("username", USERNAME_PROMPT);
|
||||
return;
|
||||
}
|
||||
|
||||
this._player = new Player(message.username, undefined);
|
||||
|
||||
// _____ _
|
||||
// | ___(_)_ ___ __ ___ ___
|
||||
// | |_ | \ \/ / '_ ` _ \ / _ \
|
||||
// | _| | |> <| | | | | | __/
|
||||
// |_| |_/_/\_\_| |_| |_|\___|
|
||||
//
|
||||
// 1. Add mutex on the players table to avoid race conditions
|
||||
// 2. Prune "dead" players (players with 0 logins) after a short while
|
||||
this.session.game.players.set(message.username, this._player);
|
||||
this.session.sendMessage("Username available");
|
||||
this.session.sendMessage(`Username _*${message.username}*_ is available, and I've reserved it for you :)`);
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT);
|
||||
this.setMessageHandler(this.receivePassword);
|
||||
}
|
||||
|
||||
/** @param {msg.ClientMessage} message */
|
||||
receivePassword(message) {
|
||||
|
||||
//
|
||||
// handle invalid message types
|
||||
if (!message.isPasswordResponse()) {
|
||||
console.log("Invalid message type, expected password reply", message);
|
||||
this.session.sendError("Incorrect message type!");
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check that it's been hashed thoroughly before being sent here.
|
||||
if (!security.isPasswordSane(message.password)) {
|
||||
this.session.sendError(ERROR_INSANE_PASSWORD);
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT);
|
||||
return;
|
||||
}
|
||||
|
||||
this._password = message.password; // it's relatively safe to store the PW here temporarily. The client already hashed the hell out of it.
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT2);
|
||||
|
||||
this.setMessageHandler(this.receivePasswordConfirmation);
|
||||
}
|
||||
|
||||
/** @param {msg.ClientMessage} memssage */
|
||||
receivePasswordConfirmation(message) {
|
||||
|
||||
//
|
||||
// handle invalid message types
|
||||
if (!message.isPasswordResponse()) {
|
||||
console.log("Invalid message type, expected password reply", message);
|
||||
this.session.sendError("Incorrect message type!");
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT);
|
||||
this.setMessageHandler(this.receivePassword);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle mismatching passwords
|
||||
if (message.password !== this._password) {
|
||||
this.session.sendError("Incorrect, you have to enter your password twice in a row successfully");
|
||||
this.session.sendPrompt("password", PASSWORD_PROMPT);
|
||||
this.setMessageHandler(this.receivePassword);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Success!
|
||||
// Take the user to the login screen.
|
||||
this.session.sendMessage("*_Success_* ✅ You will now be asked to log in again, sorry for that ;)");
|
||||
this._player.setPasswordHash(security.generateHash(this._password));
|
||||
this.session.setState(new AuthState(this.session));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user