fix(editor): should check url origin and ip address url (#12663)
Closes: [BS-3578](https://linear.app/affine-design/issue/BS-3578/复制本的-url-无法识别) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Improved URL validation to recognize and allow IPv4 addresses when the origin matches the provided base URL. - **Tests** - Added a test to ensure URLs with IP addresses (e.g., http://127.0.0.1) are considered valid when the origin matches. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -80,4 +80,8 @@ describe('isValidUrl: determining whether a URL is valid is very complicated', (
|
|||||||
// See also https://stackoverflow.com/questions/9238640/how-long-can-a-tld-possibly-be#:~:text=Longest%20TLD%20up%20to%20date,17%20when%20decoded%20%5Bverm%C3%B6gensberatung%5D.
|
// See also https://stackoverflow.com/questions/9238640/how-long-can-a-tld-possibly-be#:~:text=Longest%20TLD%20up%20to%20date,17%20when%20decoded%20%5Bverm%C3%B6gensberatung%5D.
|
||||||
expect(isValidUrl('example.xn--vermgensberatung-pwb')).toEqual(false);
|
expect(isValidUrl('example.xn--vermgensberatung-pwb')).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should allow ip address url when origin is same', () => {
|
||||||
|
expect(isValidUrl('http://127.0.0.1', 'http://127.0.0.1')).toEqual(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const ALLOWED_SCHEMES = new Set([
|
|||||||
// https://publicsuffix.org/
|
// https://publicsuffix.org/
|
||||||
const TLD_REGEXP = /(?:\.[a-zA-Z]+)?(\.[a-zA-Z]{2,})$/;
|
const TLD_REGEXP = /(?:\.[a-zA-Z]+)?(\.[a-zA-Z]{2,})$/;
|
||||||
|
|
||||||
|
const IPV4_ADDR_REGEXP =
|
||||||
|
/^(25[0-5]|2[0-4]\d|[01]?\d\d?)(\.(25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/;
|
||||||
|
|
||||||
const toURL = (str: string) => {
|
const toURL = (str: string) => {
|
||||||
try {
|
try {
|
||||||
if (!URL.canParse(str)) return null;
|
if (!URL.canParse(str)) return null;
|
||||||
@@ -21,16 +24,20 @@ const toURL = (str: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function resolveURL(str: string) {
|
function resolveURL(str: string, baseUrl: string, padded = false) {
|
||||||
const url = toURL(str);
|
const url = toURL(str);
|
||||||
if (!url) return null;
|
if (!url) return null;
|
||||||
|
|
||||||
const protocol = url.protocol.substring(0, url.protocol.length - 1);
|
const protocol = url.protocol.substring(0, url.protocol.length - 1);
|
||||||
const hostname = url.hostname;
|
const hostname = url.hostname;
|
||||||
|
const origin = url.origin;
|
||||||
|
|
||||||
let allowed = ALLOWED_SCHEMES.has(protocol);
|
let allowed = ALLOWED_SCHEMES.has(protocol);
|
||||||
if (allowed && hostname.includes('.')) {
|
if (allowed && hostname.includes('.')) {
|
||||||
allowed = TLD_REGEXP.test(hostname);
|
allowed =
|
||||||
|
origin === baseUrl ||
|
||||||
|
TLD_REGEXP.test(hostname) ||
|
||||||
|
(padded ? false : IPV4_ADDR_REGEXP.test(hostname));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { url, allowed };
|
return { url, allowed };
|
||||||
@@ -68,10 +75,10 @@ export function normalizeUrl(str: string) {
|
|||||||
*
|
*
|
||||||
* For more detail see https://www.ietf.org/rfc/rfc1738.txt
|
* For more detail see https://www.ietf.org/rfc/rfc1738.txt
|
||||||
*/
|
*/
|
||||||
export function isValidUrl(str: string) {
|
export function isValidUrl(str: string, baseUrl = location.origin) {
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
|
|
||||||
let result = resolveURL(str);
|
let result = resolveURL(str, baseUrl);
|
||||||
|
|
||||||
if (result && !result.allowed) return false;
|
if (result && !result.allowed) return false;
|
||||||
|
|
||||||
@@ -80,7 +87,7 @@ export function isValidUrl(str: string) {
|
|||||||
if (!hasScheme) {
|
if (!hasScheme) {
|
||||||
const dotIdx = str.indexOf('.');
|
const dotIdx = str.indexOf('.');
|
||||||
if (dotIdx > 0 && dotIdx < str.length - 1) {
|
if (dotIdx > 0 && dotIdx < str.length - 1) {
|
||||||
result = resolveURL(`https://${str}`);
|
result = resolveURL(`https://${str}`, baseUrl, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user