From b743f3a90cbf49f63439ed82674406be73d89a0d Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Sat, 11 Feb 2023 17:42:05 +0200 Subject: [PATCH] 1.0.2 - Validate that Tuitio's URL parameter is a valid URL --- src/__tests__/TuitioClient.test.ts | 29 +++++++++++++++++------------ src/__tests__/Utils.test.ts | 26 ++++++++++++++++++++++++++ src/client.ts | 13 +++++++++---- src/utils.ts | 15 ++++++++++++++- 4 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/__tests__/Utils.test.ts diff --git a/src/__tests__/TuitioClient.test.ts b/src/__tests__/TuitioClient.test.ts index cda6ffc..f087720 100644 --- a/src/__tests__/TuitioClient.test.ts +++ b/src/__tests__/TuitioClient.test.ts @@ -1,18 +1,7 @@ import { getUrlTemplates } from "../config"; -import { combineUrls } from "../utils"; import { TuitioClient } from "../client"; import type { TuitioAuthenticationResult, TuitioToken } from "../client"; -test("Combine urls with trailing slash", () => { - const result = combineUrls("https://test.com/api/", "/test"); - expect(result).toBe("https://test.com/api/test"); -}); - -test("Combine urls without trailing slash", () => { - const result = combineUrls("https://test.com/api", "/test"); - expect(result).toBe("https://test.com/api/test"); -}); - test("Get url templates", () => { const result = getUrlTemplates("https://test.com/api"); expect(result).toHaveProperty("authentication"); @@ -23,7 +12,23 @@ test("Get url templates", () => { test("Tuitio client initialization", () => { const client = new TuitioClient("https://test.com/api"); - expect(client.baseUrl).toBe("https://test.com/api"); + expect(client.tuitioUrl).toBe("https://test.com/api"); +}); + +test("Tuitio client initialization with null URL", () => { + try { + new TuitioClient(null); + } catch (error: any) { + expect(error.message).toContain("is not a valid URL"); + } +}); + +test("Tuitio client initialization with invalid URL", () => { + try { + new TuitioClient("test"); + } catch (error: any) { + expect(error.message).toContain("is not a valid URL"); + } }); test("Tuitio client fake authentication", async () => { diff --git a/src/__tests__/Utils.test.ts b/src/__tests__/Utils.test.ts new file mode 100644 index 0000000..c347153 --- /dev/null +++ b/src/__tests__/Utils.test.ts @@ -0,0 +1,26 @@ +import { combineUrls, isValidURL } from "../utils"; + +test("Combine urls with trailing slash", () => { + const result = combineUrls("https://test.com/api/", "/test"); + expect(result).toBe("https://test.com/api/test"); +}); + +test("Combine urls without trailing slash", () => { + const result = combineUrls("https://test.com/api", "/test"); + expect(result).toBe("https://test.com/api/test"); +}); + +test("Check valid https URL", () => { + const result = isValidURL("https://test.com/api"); + expect(result).toBe(true); +}); + +test("Check valid http URL", () => { + const result = isValidURL("http://test.com/api"); + expect(result).toBe(true); +}); + +test("Check invalid URL", () => { + const result = isValidURL("test/api"); + expect(result).toBe(false); +}); diff --git a/src/client.ts b/src/client.ts index 3987bc9..b6848f9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2,6 +2,7 @@ import axios from "axios"; import { localStorage } from "@flare/js-utils"; import { storageKeys } from "./constants"; import { getUrlTemplates } from "./config"; +import { isValidURL } from "./utils"; const { setItem, getItem, removeItem } = localStorage; @@ -25,14 +26,18 @@ export type TuitioToken = { raw: string; validFrom: Date; validUntil: Date }; export type TuitioAuthenticationResult = { token: TuitioToken; status: string }; class TuitioClient { - baseUrl: string; + tuitioUrl: string; - constructor(baseUrl: string) { - this.baseUrl = baseUrl; + constructor(tuitioUrl: string | null) { + if (tuitioUrl === null || tuitioUrl === "" || isValidURL(tuitioUrl) === false) { + throw new Error(`TuitioClient: ${tuitioUrl} is not a valid URL.`); + } + + this.tuitioUrl = tuitioUrl; } async authenticate(userName: string, password: string): Promise { - const templates = getUrlTemplates(this.baseUrl); + const templates = getUrlTemplates(this.tuitioUrl); const url = templates.authentication.replace("{username}", userName).replace("{password}", password); const response = await request(url, "post"); diff --git a/src/utils.ts b/src/utils.ts index 2551ccf..1d2bef3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,4 +4,17 @@ const combineUrls = (piece1: string, piece2: string): string => { return baseElement + piece2; }; -export { combineUrls }; +const isValidURL = (str: string): boolean => { + const pattern = new RegExp( + "^(https?:\\/\\/)?" + // protocol + "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name + "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address + "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path + "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string + "(\\#[-a-z\\d_]*)?$", + "i" + ); // fragment locater + return !!pattern.test(str); +}; + +export { combineUrls, isValidURL };