Merge pull request #878 from thecodingmachine/localStorageGhost

FIX: improved the validation from localstorage for username and characterLayers
This commit is contained in:
Kharhamel 2021-04-12 14:56:51 +02:00 committed by GitHub
commit 29d43d7776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 9 deletions

View File

@ -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[]) {
}

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
});
}

View File

@ -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]);

View 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);
});
});