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 {
|
||||
id: number,
|
||||
level: number,
|
||||
@ -5,6 +7,23 @@ export interface CharacterTexture {
|
||||
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 {
|
||||
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 selectedPlayerKey = 'selectedPlayer';
|
||||
@ -22,8 +22,9 @@ class LocalUserStore {
|
||||
setName(name:string): void {
|
||||
localStorage.setItem(playerNameKey, name);
|
||||
}
|
||||
getName(): string {
|
||||
return localStorage.getItem(playerNameKey) || '';
|
||||
getName(): string|null {
|
||||
const value = localStorage.getItem(playerNameKey) || '';
|
||||
return isUserNameValid(value) ? value : null;
|
||||
}
|
||||
|
||||
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
||||
@ -44,7 +45,8 @@ class LocalUserStore {
|
||||
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
|
||||
}
|
||||
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 {
|
||||
|
@ -14,6 +14,7 @@ const RESOLUTION = 2;
|
||||
const ZOOM_LEVEL = 1/*3/4*/;
|
||||
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
|
||||
export const MAX_USERNAME_LENGTH = parseInt(process.env.MAX_USERNAME_LENGTH || '') || 8;
|
||||
|
||||
export {
|
||||
DEBUG_MODE,
|
||||
|
@ -35,7 +35,7 @@ export class GameManager {
|
||||
|
||||
if (!this.playerName) {
|
||||
return LoginSceneName;
|
||||
} else if (!this.characterLayers) {
|
||||
} else if (!this.characterLayers || !this.characterLayers.length) {
|
||||
return SelectCharacterSceneName;
|
||||
} else {
|
||||
return EnableCameraSceneName;
|
||||
|
@ -11,6 +11,7 @@ import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {addLoader} from "../Components/Loader";
|
||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
||||
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
|
||||
|
||||
export const CustomizeSceneName = "CustomizeScene";
|
||||
|
||||
@ -111,6 +112,9 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!areCharacterLayersValid(layers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gameManager.setCharacterLayers(layers);
|
||||
|
||||
|
@ -4,6 +4,7 @@ import {TextInput} from "../Components/TextInput";
|
||||
import Image = Phaser.GameObjects.Image;
|
||||
import {SelectCharacterSceneName} from "./SelectCharacterScene";
|
||||
import {ResizableScene} from "./ResizableScene";
|
||||
import {isUserNameValid, maxUserNameLength} from "../../Connexion/LocalUser";
|
||||
|
||||
//todo: put this constants in a dedicated file
|
||||
export const LoginSceneName = "LoginScene";
|
||||
@ -37,7 +38,7 @@ export class LoginScene extends ResizableScene {
|
||||
create() {
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
@ -50,10 +51,9 @@ export class LoginScene extends ResizableScene {
|
||||
this.infoTextField = new TextField(this, 10, this.game.renderer.height - 35, infoText, false);
|
||||
|
||||
this.input.keyboard.on('keyup-ENTER', () => {
|
||||
if (this.name === '') {
|
||||
return
|
||||
if (isUserNameValid(this.name)) {
|
||||
this.login(this.name);
|
||||
}
|
||||
this.login(this.name);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import {loadAllDefaultModels, loadCustomTexture} from "../Entity/PlayerTexturesL
|
||||
import {addLoader} from "../Components/Loader";
|
||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
||||
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
|
||||
|
||||
|
||||
//todo: put this constants in a dedicated file
|
||||
@ -142,6 +143,9 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
}
|
||||
|
||||
private nextScene(): void {
|
||||
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
|
||||
return;
|
||||
}
|
||||
this.scene.stop(SelectCharacterSceneName);
|
||||
if (this.selectedPlayer !== null) {
|
||||
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