perf: Multi-domain validation in embedded systems uses semicolon delimiters

This commit is contained in:
fit2cloud-chenyw
2025-12-01 15:51:06 +08:00
committed by fit2cloud-chenyw
parent a6744dd9d1
commit 9ddbefe658
6 changed files with 56 additions and 44 deletions
+9 -3
View File
@@ -6,6 +6,7 @@ import logging
from datetime import datetime, timedelta, timezone
from logging.handlers import RotatingFileHandler
from pathlib import Path
import re
from urllib.parse import urlparse
from fastapi import Request
@@ -266,9 +267,14 @@ def get_origin_from_referer(request: Request):
def origin_match_domain(origin: str, domain: str) -> bool:
if not origin or not domain:
return False
origin_text = origin.rstrip('/')
domain_list = domain.replace(" ", "").split(',')
return origin_text in [d.rstrip('/') for d in domain_list]
origin_normalized = origin.rstrip('/')
for d in re.split(r'[,;]', domain):
if d.strip().rstrip('/') == origin_normalized:
return True
return False
def equals_ignore_case(str1: str, *args: str) -> bool:
if str1 is None:
+2 -2
View File
@@ -577,7 +577,7 @@
"application_name": "Application name",
"application_description": "Application description",
"cross_domain_settings": "Cross-domain settings",
"third_party_address": "Please enter the embedded third party address",
"third_party_address": "Please enter the embedded third party address,multiple items separated by semicolons",
"set_to_private": "Set as private",
"set_to_public": "Set as public",
"public": "Public",
@@ -586,7 +586,7 @@
"configure_interface": "Configure interface",
"interface_url": "Interface URL",
"format_is_incorrect": "format is incorrect{msg}",
"domain_format_incorrect": ",start with http/https, no trailing slash (/), multiple domains separated by half-width commas (,)",
"domain_format_incorrect": ", start with http:// or https://, no trailing slash (/), multiple domains separated by semicolons",
"interface_url_incorrect": ",enter a relative path starting with /",
"aes_enable": "Enable AES encryption",
"aes_enable_tips": "The fields (host, user, password, dataBase, schema) are all encrypted using the AES-CBC-PKCS5Padding encryption method",
+2 -2
View File
@@ -577,7 +577,7 @@
"application_name": "애플리케이션 이름",
"application_description": "애플리케이션 설명",
"cross_domain_settings": "교차 도메인 설정",
"third_party_address": "임베디드할 제3자 주소를 입력하십시오",
"third_party_address": "임베디드할 제3자 주소를 입력하십시오, 여러 항목을 세미콜론으로 구분",
"set_to_private": "비공개로 설정",
"set_to_public": "공개로 설정",
"public": "공개",
@@ -585,7 +585,7 @@
"configure_interface": "인터페이스 설정",
"interface_url": "인터페이스 URL",
"format_is_incorrect": "형식이 올바르지 않습니다{msg}",
"domain_format_incorrect": ", http/https로 시작, 슬래시(/)로 끝나지 않음, 여러 도메인은 반각 쉼표(,)로 구분",
"domain_format_incorrect": ", http:// 또는 https://로 시작해야 하며, 슬래시(/)로 끝날 수 없습니다. 여러 도메인은 세미콜론으로 구분합니다",
"interface_url_incorrect": ", 상대 경로를 입력해주세요. /로 시작합니다",
"aes_enable": "AES 암호화 활성화",
"aes_enable_tips": "암호화 필드 (host, user, password, dataBase, schema)는 모두 AES-CBC-PKCS5Padding 암호화 방식을 사용합니다",
+2 -2
View File
@@ -577,7 +577,7 @@
"application_name": "应用名称",
"application_description": "应用描述",
"cross_domain_settings": "跨域设置",
"third_party_address": "请输入嵌入的第三方地址",
"third_party_address": "请输入嵌入的第三方地址,多个以分号分割",
"set_to_private": "设为私有",
"set_to_public": "设为公共",
"public": "公共",
@@ -585,7 +585,7 @@
"configure_interface": "配置接口",
"interface_url": "接口 URL",
"format_is_incorrect": "格式不对{msg}",
"domain_format_incorrect": ",http或https开头,不能以 / 结尾,多个域名以逗号(半角)分隔",
"domain_format_incorrect": ",http或https开头,不能以 / 结尾,多个域名以分号(半角)分隔",
"interface_url_incorrect": ",请填写相对路径,以/开头",
"aes_enable": "开启 AES 加密",
"aes_enable_tips": "加密字段 (host, user, password, dataBase, schema) 均采用 AES-CBC-PKCS5Padding 加密方式",
+21 -21
View File
@@ -198,7 +198,15 @@ const search = () => {
searchLoading.value = false
})
}
const splitString = (str: string) => {
if (typeof str !== 'string') {
return []
}
return str
.split(/[,;]/)
.map((item) => item.trim())
.filter((item) => item !== '')
}
const termFormRef = ref()
const validateUrl = (_: any, value: any, callback: any) => {
if (value === '') {
@@ -209,20 +217,15 @@ const validateUrl = (_: any, value: any, callback: any) => {
)
} else {
// var Expression = /(https?:\/\/)?([\da-z\.-]+)\.([a-z]{2,6})(:\d{1,5})?([\/\w\.-]*)*\/?(#[\S]+)?/ // eslint-disable-line
value
.trim()
.split(',')
.forEach((tempVal: string) => {
var Expression = /^https?:\/\/[^\s/?#]+(:\d+)?/i
var objExp = new RegExp(Expression)
if (objExp.test(tempVal) && !tempVal.endsWith('/')) {
callback()
} else {
callback(
t('embedded.format_is_incorrect', { msg: t('embedded.domain_format_incorrect') })
)
}
})
splitString(value).forEach((tempVal: string) => {
var Expression = /^https?:\/\/[^\s/?#]+(:\d+)?/i
var objExp = new RegExp(Expression)
if (objExp.test(tempVal) && !tempVal.endsWith('/')) {
callback()
} else {
callback(t('embedded.format_is_incorrect', { msg: t('embedded.domain_format_incorrect') }))
}
})
}
}
const rules = {
@@ -602,13 +605,10 @@ const copyCode = (row: any, key: any = 'app_secret') => {
<el-form-item prop="domain" :label="t('embedded.cross_domain_settings')">
<el-input
v-model="pageForm.domain"
:placeholder="
$t('datasource.please_enter') +
$t('common.empty') +
$t('embedded.cross_domain_settings')
"
type="textarea"
:autosize="{ minRows: 2 }"
:placeholder="$t('embedded.third_party_address')"
autocomplete="off"
maxlength="50"
clearable
/>
</el-form-item>
+20 -14
View File
@@ -265,6 +265,15 @@ const setUiRef = ref()
const handleSetUi = (row: any) => {
setUiRef.value.open(row)
}
const splitString = (str: string) => {
if (typeof str !== 'string') {
return []
}
return str
.split(/[,;]/)
.map((item) => item.trim())
.filter((item) => item !== '')
}
const validateUrl = (_: any, value: any, callback: any) => {
if (value === '') {
callback(
@@ -274,20 +283,15 @@ const validateUrl = (_: any, value: any, callback: any) => {
)
} else {
// var Expression = /(https?:\/\/)?([\da-z\.-]+)\.([a-z]{2,6})(:\d{1,5})?([\/\w\.-]*)*\/?(#[\S]+)?/ // eslint-disable-line
value
.trim()
.split(',')
.forEach((tempVal: string) => {
var Expression = /^https?:\/\/[^\s/?#]+(:\d+)?/i
var objExp = new RegExp(Expression)
if (objExp.test(tempVal) && !tempVal.endsWith('/')) {
callback()
} else {
callback(
t('embedded.format_is_incorrect', { msg: t('embedded.domain_format_incorrect') })
)
}
})
splitString(value).forEach((tempVal: string) => {
var Expression = /^https?:\/\/[^\s/?#]+(:\d+)?/i
var objExp = new RegExp(Expression)
if (objExp.test(tempVal) && !tempVal.endsWith('/')) {
callback()
} else {
callback(t('embedded.format_is_incorrect', { msg: t('embedded.domain_format_incorrect') }))
}
})
}
}
const rules = {
@@ -759,6 +763,8 @@ const saveHandler = () => {
<el-form-item prop="domain" :label="t('embedded.cross_domain_settings')">
<el-input
v-model="currentEmbedded.domain"
type="textarea"
:autosize="{ minRows: 2 }"
clearable
:placeholder="$t('embedded.third_party_address')"
autocomplete="off"