Add input validation and tests for Station names
Some checks failed
Testing / run-tests (push) Failing after 31s

This commit is contained in:
Fred Boniface 2025-09-08 20:29:03 +01:00
parent bfcacebe8f
commit 054ff40cf9
4 changed files with 38 additions and 3 deletions

View File

@ -1,4 +1,4 @@
import { validateCrs, validateNlc, validateReasonCode, validateStanox, validateTiploc } from "../inputValidation/inputValidation"; import { validateCrs, validateNlc, validateReasonCode, validateStanox, validateTiploc, validateStation } from "../inputValidation/inputValidation";
import { ReferenceV2_LocationReferenceCodes, ReferenceV2_LocationReferenceCodeType, ReferenceV2_ReasonCode } from "../types/reference/ReferenceTypesV2"; import { ReferenceV2_LocationReferenceCodes, ReferenceV2_LocationReferenceCodeType, ReferenceV2_ReasonCode } from "../types/reference/ReferenceTypesV2";
import { BaseOwlBoardClient } from "./client"; import { BaseOwlBoardClient } from "./client";
@ -21,6 +21,7 @@ export class ReferenceClientV2 {
tiploc: validateTiploc, tiploc: validateTiploc,
nlc: validateNlc, nlc: validateNlc,
stanox: validateStanox, stanox: validateStanox,
station: validateStation,
}; };
const validate = validators[type]; const validate = validators[type];

View File

@ -6,7 +6,8 @@ import { validateCrs,
validateUuid, validateUuid,
validateHeadcode, validateHeadcode,
validateNlc, validateNlc,
validateStanox} from "./inputValidation"; validateStanox,
validateStation} from "./inputValidation";
import { ValidationError } from "../errors"; import { ValidationError } from "../errors";
describe("PIS Validation Tests", () => { describe("PIS Validation Tests", () => {
@ -118,6 +119,29 @@ describe("STANOX Validation Tests", () => {
expect(() => validateStanox(false)).toThrow(ValidationError); expect(() => validateStanox(false)).toThrow(ValidationError);
expect(() => validateStanox("3543ab")).toThrow(ValidationError); expect(() => validateStanox("3543ab")).toThrow(ValidationError);
}) })
test("Station inputs that should pass validation", () => {
expect(() => validateStation("Heathrow Terminal 5")).toBe(true);
expect(() => validateStation("King's Cross")).toBe(true);
expect(() => validateStation("St Budeaux Ferry Road/Victoria Road")).toBe(true);
expect(() => validateStation("Queenstown Road (Battersea)")).toBe(true);
expect(() => validateStation("Rhoose Cardiff International Airport")).toBe(true);
expect(() => validateStation("Chappel & Wakes Colne")).toBe(true);
expect(() => validateStation("Duncraig")).toBe(true);
})
test("Station inputs that contain unusul characters or invalid types should throw ValidationError", () => {
expect(() => validateStation([])).toThrow(ValidationError);
expect(() => validateStation({})).toThrow(ValidationError);
expect(() => validateStation(null)).toThrow(ValidationError);
expect(() => validateStation(undefined)).toThrow(ValidationError);
expect(() => validateStation(false)).toThrow(ValidationError);
expect(() => validateStation("Br*ra")).toThrow(ValidationError);
expect(() => validateStation("DROP TABLE stations;--")).toThrow(ValidationError);
expect(() => validateStation("King's Cross; DELETE FROM users;")).toThrow(ValidationError);
expect(() => validateStation("St Pancras' OR '1'='1")).toThrow(ValidationError);
expect(() => validateStation("<script>alert('xss')</script>")).toThrow(ValidationError);
})
}) })
describe("UUID Validation Tests", () => { describe("UUID Validation Tests", () => {

View File

@ -84,6 +84,16 @@ export function validateUuid(uuid: unknown): boolean {
return true; return true;
} }
export function validateStation(station: unknown): boolean {
if (typeof station !== "string") {
throw new ValidationError("Invalid input: The station name should be a string");
}
if (!/^[A-Za-z0-9\s&'()-]+$/.test(station)) {
throw new ValidationError("Invalid input: Station name should include letters, spaces, ', '/', '-', '&' only");
}
return true;
}
export function validateReasonCode(code: unknown): boolean { export function validateReasonCode(code: unknown): boolean {
if (typeof code === "number") { if (typeof code === "number") {
// Ensure it's a 3-digit number (100-999) // Ensure it's a 3-digit number (100-999)

View File

@ -19,4 +19,4 @@ interface ReferenceV2_ReasonCodeObject {
export type ReferenceV2_ReasonCode = ReferenceV2_ReasonCodeObject[] export type ReferenceV2_ReasonCode = ReferenceV2_ReasonCodeObject[]
export type ReferenceV2_LocationReferenceCodeType = "tiploc" | "crs" | "stanox" | "nlc" export type ReferenceV2_LocationReferenceCodeType = "tiploc" | "crs" | "stanox" | "nlc" | "station"