Merge pull request #878 from thecodingmachine/localStorageGhost
FIX: improved the validation from localstorage for username and characterLayers
This commit is contained in:
commit
29d43d7776
@ -1,3 +1,5 @@
|
|||||||
|
import {MAX_USERNAME_LENGTH} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export interface CharacterTexture {
|
export interface CharacterTexture {
|
||||||
id: number,
|
id: number,
|
||||||
level: number,
|
level: number,
|
||||||
@ -5,6 +7,23 @@ export interface CharacterTexture {
|
|||||||
rights: string
|
rights: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
|
||||||
|
|
||||||
|
export function isUserNameValid(value: string): boolean {
|
||||||
|
const regexp = new RegExp('^[A-Za-z]{1,'+maxUserNameLength+'}$');
|
||||||
|
return regexp.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function areCharacterLayersValid(value: string[]): boolean {
|
||||||
|
if (!value.length) return false;
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
if (/^\w+$/.exec(value[i]) === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
export class LocalUser {
|
export class LocalUser {
|
||||||
constructor(public readonly uuid:string, public readonly jwtToken: string, public readonly textures: CharacterTexture[]) {
|
constructor(public readonly uuid:string, public readonly jwtToken: string, public readonly textures: CharacterTexture[]) {
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {LocalUser} from "./LocalUser";
|
import {areCharacterLayersValid, isUserNameValid, LocalUser} from "./LocalUser";
|
||||||
|
|
||||||
const playerNameKey = 'playerName';
|
const playerNameKey = 'playerName';
|
||||||
const selectedPlayerKey = 'selectedPlayer';
|
const selectedPlayerKey = 'selectedPlayer';
|
||||||
@ -22,8 +22,9 @@ class LocalUserStore {
|
|||||||
setName(name:string): void {
|
setName(name:string): void {
|
||||||
localStorage.setItem(playerNameKey, name);
|
localStorage.setItem(playerNameKey, name);
|
||||||
}
|
}
|
||||||
getName(): string {
|
getName(): string|null {
|
||||||
return localStorage.getItem(playerNameKey) || '';
|
const value = localStorage.getItem(playerNameKey) || '';
|
||||||
|
return isUserNameValid(value) ? value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
||||||
@ -44,7 +45,8 @@ class LocalUserStore {
|
|||||||
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
|
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
|
||||||
}
|
}
|
||||||
getCharacterLayers(): string[]|null {
|
getCharacterLayers(): string[]|null {
|
||||||
return JSON.parse(localStorage.getItem(characterLayersKey) || "null");
|
const value = JSON.parse(localStorage.getItem(characterLayersKey) || "null");
|
||||||
|
return areCharacterLayersValid(value) ? value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setGameQualityValue(value: number): void {
|
setGameQualityValue(value: number): void {
|
||||||
|
@ -14,6 +14,7 @@ const RESOLUTION = 2;
|
|||||||
const ZOOM_LEVEL = 1/*3/4*/;
|
const ZOOM_LEVEL = 1/*3/4*/;
|
||||||
const POSITION_DELAY = 200; // Wait 200ms between sending position events
|
const POSITION_DELAY = 200; // Wait 200ms between sending position events
|
||||||
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
|
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
|
||||||
|
export const MAX_USERNAME_LENGTH = parseInt(process.env.MAX_USERNAME_LENGTH || '') || 8;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DEBUG_MODE,
|
DEBUG_MODE,
|
||||||
|
@ -35,7 +35,7 @@ export class GameManager {
|
|||||||
|
|
||||||
if (!this.playerName) {
|
if (!this.playerName) {
|
||||||
return LoginSceneName;
|
return LoginSceneName;
|
||||||
} else if (!this.characterLayers) {
|
} else if (!this.characterLayers || !this.characterLayers.length) {
|
||||||
return SelectCharacterSceneName;
|
return SelectCharacterSceneName;
|
||||||
} else {
|
} else {
|
||||||
return EnableCameraSceneName;
|
return EnableCameraSceneName;
|
||||||
|
@ -11,6 +11,7 @@ import {localUserStore} from "../../Connexion/LocalUserStore";
|
|||||||
import {addLoader} from "../Components/Loader";
|
import {addLoader} from "../Components/Loader";
|
||||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||||
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
||||||
|
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
|
||||||
|
|
||||||
export const CustomizeSceneName = "CustomizeScene";
|
export const CustomizeSceneName = "CustomizeScene";
|
||||||
|
|
||||||
@ -111,6 +112,9 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if (!areCharacterLayersValid(layers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gameManager.setCharacterLayers(layers);
|
gameManager.setCharacterLayers(layers);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import {TextInput} from "../Components/TextInput";
|
|||||||
import Image = Phaser.GameObjects.Image;
|
import Image = Phaser.GameObjects.Image;
|
||||||
import {SelectCharacterSceneName} from "./SelectCharacterScene";
|
import {SelectCharacterSceneName} from "./SelectCharacterScene";
|
||||||
import {ResizableScene} from "./ResizableScene";
|
import {ResizableScene} from "./ResizableScene";
|
||||||
|
import {isUserNameValid, maxUserNameLength} from "../../Connexion/LocalUser";
|
||||||
|
|
||||||
//todo: put this constants in a dedicated file
|
//todo: put this constants in a dedicated file
|
||||||
export const LoginSceneName = "LoginScene";
|
export const LoginSceneName = "LoginScene";
|
||||||
@ -37,7 +38,7 @@ export class LoginScene extends ResizableScene {
|
|||||||
create() {
|
create() {
|
||||||
|
|
||||||
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Enter your name:');
|
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Enter your name:');
|
||||||
this.nameInput = new TextInput(this, this.game.renderer.width / 2, 70, 8, this.name,(text: string) => {
|
this.nameInput = new TextInput(this, this.game.renderer.width / 2, 70, maxUserNameLength, this.name,(text: string) => {
|
||||||
this.name = text;
|
this.name = text;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,10 +51,9 @@ export class LoginScene extends ResizableScene {
|
|||||||
this.infoTextField = new TextField(this, 10, this.game.renderer.height - 35, infoText, false);
|
this.infoTextField = new TextField(this, 10, this.game.renderer.height - 35, infoText, false);
|
||||||
|
|
||||||
this.input.keyboard.on('keyup-ENTER', () => {
|
this.input.keyboard.on('keyup-ENTER', () => {
|
||||||
if (this.name === '') {
|
if (isUserNameValid(this.name)) {
|
||||||
return
|
|
||||||
}
|
|
||||||
this.login(this.name);
|
this.login(this.name);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import {loadAllDefaultModels, loadCustomTexture} from "../Entity/PlayerTexturesL
|
|||||||
import {addLoader} from "../Components/Loader";
|
import {addLoader} from "../Components/Loader";
|
||||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||||
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
||||||
|
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
|
||||||
|
|
||||||
|
|
||||||
//todo: put this constants in a dedicated file
|
//todo: put this constants in a dedicated file
|
||||||
@ -142,6 +143,9 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private nextScene(): void {
|
private nextScene(): void {
|
||||||
|
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.scene.stop(SelectCharacterSceneName);
|
this.scene.stop(SelectCharacterSceneName);
|
||||||
if (this.selectedPlayer !== null) {
|
if (this.selectedPlayer !== null) {
|
||||||
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
|
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
|
||||||
|
45
front/tests/Phaser/Connexion/LocalUserTest.ts
Normal file
45
front/tests/Phaser/Connexion/LocalUserTest.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import "jasmine";
|
||||||
|
import {areCharacterLayersValid, isUserNameValid, maxUserNameLength} from "../../../src/Connexion/LocalUser";
|
||||||
|
|
||||||
|
describe("isUserNameValid()", () => {
|
||||||
|
it("should validate name with letters", () => {
|
||||||
|
expect(isUserNameValid('toto')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not validate empty name", () => {
|
||||||
|
expect(isUserNameValid('')).toBe(false);
|
||||||
|
});
|
||||||
|
it("should not validate string with too many letters", () => {
|
||||||
|
let testString = '';
|
||||||
|
for (let i = 0; i < maxUserNameLength + 2; i++) {
|
||||||
|
testString += 'a';
|
||||||
|
}
|
||||||
|
expect(isUserNameValid(testString)).toBe(false);
|
||||||
|
});
|
||||||
|
it("should not validate spaces", () => {
|
||||||
|
expect(isUserNameValid(' ')).toBe(false);
|
||||||
|
});
|
||||||
|
it("should not validate numbers", () => {
|
||||||
|
expect(isUserNameValid('a12')).toBe(false);
|
||||||
|
});
|
||||||
|
it("should not validate special characters", () => {
|
||||||
|
expect(isUserNameValid('a&-')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("areCharacterLayersValid()", () => {
|
||||||
|
it("should validate default textures array", () => {
|
||||||
|
expect(areCharacterLayersValid(['male1', 'male2'])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not validate an empty array", () => {
|
||||||
|
expect(areCharacterLayersValid([])).toBe(false);
|
||||||
|
});
|
||||||
|
it("should not validate space only strings", () => {
|
||||||
|
expect(areCharacterLayersValid([' ', 'male1'])).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not validate empty strings", () => {
|
||||||
|
expect(areCharacterLayersValid(['', 'male1'])).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user