diff --git a/src/utils/validateAndSanitizeUrl.ts b/src/utils/validateAndSanitizeUrl.ts new file mode 100644 index 00000000..ab9edfa3 --- /dev/null +++ b/src/utils/validateAndSanitizeUrl.ts @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// URL validation function to prevent XSS +export function validateAndSanitizeUrl(inputUrl: string): { isValid: boolean; sanitizedUrl: string; error: string } { + if (!inputUrl.trim()) { + return { isValid: true, sanitizedUrl: "", error: "" }; + } + + try { + // Create URL object to validate the URL format + const urlObj = new URL(inputUrl); + + // Only allow HTTP and HTTPS protocols to prevent XSS + if (!["http:", "https:"].includes(urlObj.protocol)) { + return { + isValid: false, + sanitizedUrl: "", + error: "Only HTTP and HTTPS URLs are allowed", + }; + } + + // Additional security checks + const dangerousProtocols = ["javascript:", "data:", "vbscript:", "le:"]; + const lowerUrl = inputUrl.toLowerCase(); + + for (const protocol of dangerousProtocols) { + if (lowerUrl.includes(protocol)) { + return { + isValid: false, + sanitizedUrl: "", + error: "Dangerous protocols are not allowed", + }; + } + } + + // Return the sanitized URL (using the URL object to normalize it) + return { + isValid: true, + sanitizedUrl: urlObj.href, + error: "", + }; + } catch (error) { + return { + isValid: false, + sanitizedUrl: "", + error: "Please enter a valid URL", + }; + } +} diff --git a/src/views/dashboard/configuration/ThirdPartyApp.vue b/src/views/dashboard/configuration/ThirdPartyApp.vue index 59f2721f..d8b4f4cb 100644 --- a/src/views/dashboard/configuration/ThirdPartyApp.vue +++ b/src/views/dashboard/configuration/ThirdPartyApp.vue @@ -29,6 +29,7 @@ limitations under the License. --> import { useI18n } from "vue-i18n"; import { ref } from "vue"; import { useDashboardStore } from "@/store/modules/dashboard"; + import { validateAndSanitizeUrl } from "@/utils/validateAndSanitizeUrl"; const { t } = useI18n(); const dashboardStore = useDashboardStore(); @@ -37,54 +38,6 @@ limitations under the License. --> const url = ref(widget.url || ""); const urlError = ref(""); - // URL validation function to prevent XSS - function validateAndSanitizeUrl(inputUrl: string): { isValid: boolean; sanitizedUrl: string; error: string } { - if (!inputUrl.trim()) { - return { isValid: true, sanitizedUrl: "", error: "" }; - } - - try { - // Create URL object to validate the URL format - const urlObj = new URL(inputUrl); - - // Only allow HTTP and HTTPS protocols to prevent XSS - if (!["http:", "https:"].includes(urlObj.protocol)) { - return { - isValid: false, - sanitizedUrl: "", - error: "Only HTTP and HTTPS URLs are allowed", - }; - } - - // Additional security checks - const dangerousProtocols = ["javascript:", "data:", "vbscript:", "le:"]; - const lowerUrl = inputUrl.toLowerCase(); - - for (const protocol of dangerousProtocols) { - if (lowerUrl.includes(protocol)) { - return { - isValid: false, - sanitizedUrl: "", - error: "Dangerous protocols are not allowed", - }; - } - } - - // Return the sanitized URL (using the URL object to normalize it) - return { - isValid: true, - sanitizedUrl: urlObj.href, - error: "", - }; - } catch (error) { - return { - isValid: false, - sanitizedUrl: "", - error: "Please enter a valid URL", - }; - } - } - function handleUrlChange() { const validation = validateAndSanitizeUrl(url.value); urlError.value = validation.error; diff --git a/src/views/dashboard/controls/ThirdPartyApp.vue b/src/views/dashboard/controls/ThirdPartyApp.vue index 6d6a0340..f37dab0f 100644 --- a/src/views/dashboard/controls/ThirdPartyApp.vue +++ b/src/views/dashboard/controls/ThirdPartyApp.vue @@ -31,8 +31,8 @@ limitations under the License. -->