From 3174681d37d0d01c02428c3ddf7ac7e66499ef7d Mon Sep 17 00:00:00 2001 From: Alexander Zaslonov Date: Fri, 3 Dec 2021 11:57:05 -0800 Subject: [PATCH] Added sanitization for returnURL. (#1555) --- package-lock.json | 11 +++++++++++ package.json | 1 + src/components/defaultAuthenticator.ts | 8 ++++---- src/components/setup/setupDialog.ts | 3 ++- .../users/signin/ko/runtime/signin.ts | 19 ++++++++++--------- src/routing/signOutRouteGuard.ts | 2 +- src/services/aadService.ts | 3 ++- src/services/provisioningService.ts | 2 +- 8 files changed, 32 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e32969b0..a5006d293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "2.11.0", "license": "MIT", "dependencies": { + "@braintree/sanitize-url": "^5.0.2", "@monaco-editor/loader": "^1.2.0", "@paperbits/azure": "0.1.468", "@paperbits/common": "0.1.468", @@ -323,6 +324,11 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-5.0.2.tgz", + "integrity": "sha512-NBEJlHWrhQucLhZGHtSxM2loSaNUMajC7KOYJLyfcdW/6goVoff2HoYI3bz8YCDN0wKGbxtUL0gx2dvHpvnWlw==" + }, "node_modules/@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -14789,6 +14795,11 @@ "regenerator-runtime": "^0.13.4" } }, + "@braintree/sanitize-url": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-5.0.2.tgz", + "integrity": "sha512-NBEJlHWrhQucLhZGHtSxM2loSaNUMajC7KOYJLyfcdW/6goVoff2HoYI3bz8YCDN0wKGbxtUL0gx2dvHpvnWlw==" + }, "@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", diff --git a/package.json b/package.json index f82e4eb23..b16bfb4ae 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "webpack-merge": "^5.2.0" }, "dependencies": { + "@braintree/sanitize-url": "^5.0.2", "@monaco-editor/loader": "^1.2.0", "@paperbits/azure": "0.1.468", "@paperbits/common": "0.1.468", diff --git a/src/components/defaultAuthenticator.ts b/src/components/defaultAuthenticator.ts index b81c167d7..5cf810e3c 100644 --- a/src/components/defaultAuthenticator.ts +++ b/src/components/defaultAuthenticator.ts @@ -1,9 +1,9 @@ -import { IAuthenticator, AccessToken } from "./../authentication"; import * as Constants from "./../constants"; +import { sanitizeUrl } from "@braintree/sanitize-url"; +import { AccessToken, IAuthenticator } from "./../authentication"; -export class DefaultAuthenticator implements IAuthenticator { - constructor() { } +export class DefaultAuthenticator implements IAuthenticator { private runSsoFlow(): Promise { return new Promise(async () => { const url = new URL(location.href); @@ -20,7 +20,7 @@ export class DefaultAuthenticator implements IAuthenticator { await this.setAccessToken(token); // wait for redirect to happen, deliberatly not resolving the promise - window.location.assign(returnUrl); + window.location.assign(sanitizeUrl(returnUrl)); }); } diff --git a/src/components/setup/setupDialog.ts b/src/components/setup/setupDialog.ts index 6de4ac502..d33bb6fdb 100644 --- a/src/components/setup/setupDialog.ts +++ b/src/components/setup/setupDialog.ts @@ -1,4 +1,5 @@ import template from "./setupDialog.html"; +import * as Constants from "../../constants"; import { Component, OnMounted } from "@paperbits/common/ko/decorators"; import { ViewManager } from "@paperbits/common/ui"; import { Router } from "@paperbits/common/routing"; @@ -21,7 +22,7 @@ export class SetupDialog { try { this.viewManager.removeShutter(); await this.provisioningService.provision(); - await this.router.navigateTo("/"); + await this.router.navigateTo(Constants.pageUrlHome); window.location.reload(); } diff --git a/src/components/users/signin/ko/runtime/signin.ts b/src/components/users/signin/ko/runtime/signin.ts index 34bde02a9..66c2251a2 100644 --- a/src/components/users/signin/ko/runtime/signin.ts +++ b/src/components/users/signin/ko/runtime/signin.ts @@ -1,13 +1,14 @@ import * as ko from "knockout"; import * as validation from "knockout.validation"; import template from "./signin.html"; +import { sanitizeUrl } from "@braintree/sanitize-url"; import { EventManager } from "@paperbits/common/events"; -import { Component, RuntimeComponent, OnMounted, Param } from "@paperbits/common/ko/decorators"; -import { UsersService } from "../../../../../services/usersService"; -import { MapiError } from "../../../../../errors/mapiError"; +import { Component, OnMounted, Param, RuntimeComponent } from "@paperbits/common/ko/decorators"; +import { Router } from "@paperbits/common/routing/router"; import { ValidationReport } from "../../../../../contracts/validationReport"; +import { MapiError } from "../../../../../errors/mapiError"; import { RouteHelper } from "../../../../../routing/routeHelper"; -import { Router } from "@paperbits/common/routing/router"; +import { UsersService } from "../../../../../services/usersService"; @RuntimeComponent({ selector: "signin-runtime" @@ -102,18 +103,18 @@ export class Signin { try { this.working(true); - + const userId = await this.usersService.signIn(this.username(), this.password()); if (userId) { const clientReturnUrl = sessionStorage.getItem("returnUrl"); const returnUrl = this.routeHelper.getQueryParameter("returnUrl") || clientReturnUrl; - + if (returnUrl) { - this.router.navigateTo(returnUrl); + await this.router.navigateTo(sanitizeUrl(returnUrl)); return; } - + this.navigateToHome(); const validationReport: ValidationReport = { @@ -130,7 +131,7 @@ export class Signin { source: "signin", errors: ["Please provide a valid email and password."] }; - + this.eventManager.dispatchEvent("onValidationErrors", validationReport); } } diff --git a/src/routing/signOutRouteGuard.ts b/src/routing/signOutRouteGuard.ts index a6c410720..626cc8dfd 100644 --- a/src/routing/signOutRouteGuard.ts +++ b/src/routing/signOutRouteGuard.ts @@ -54,6 +54,6 @@ export class SignOutRouteGuard implements RouteGuard { } this.authenticator.clearAccessToken(); - location.assign("/"); + location.assign(Constants.pageUrlHome); } } \ No newline at end of file diff --git a/src/services/aadService.ts b/src/services/aadService.ts index 4ea6698e1..28f1c07f8 100644 --- a/src/services/aadService.ts +++ b/src/services/aadService.ts @@ -1,5 +1,6 @@ import * as Msal from "msal"; import * as Constants from "../constants"; +import { sanitizeUrl } from "@braintree/sanitize-url"; import { HttpClient } from "@paperbits/common/http"; import { Router } from "@paperbits/common/routing"; import { RouteHelper } from "../routing/routeHelper"; @@ -46,7 +47,7 @@ export class AadService { this.router.getCurrentUrl() === returnUrl ? location.reload() - : await this.router.navigateTo(returnUrl); + : await this.router.navigateTo(sanitizeUrl(returnUrl)); } /** diff --git a/src/services/provisioningService.ts b/src/services/provisioningService.ts index c0896e9bd..b30e8afda 100644 --- a/src/services/provisioningService.ts +++ b/src/services/provisioningService.ts @@ -70,7 +70,7 @@ export class ProvisionService { throw new Error("Unable to setup website."); } } - this.router.navigateTo("/"); + this.router.navigateTo(Constants.pageUrlHome); this.viewManager.setHost({ name: "page-host" }); this.viewManager.showToolboxes(); }