sparkast/lib/url/validLink.ts
alikia2x 2810c2f324
fix: TLD list
add: i18n of prompt text of link suggestion
2025-01-20 04:49:09 +08:00

79 lines
1.8 KiB
TypeScript

import { toASCII } from "tr46";
import { getTLD } from "./tldList";
export default function validLink(link: string) {
let finalURL;
try {
new URL(link);
return true;
} catch (error) {
// if the URL is invalid, try to add the protocol
try {
finalURL = new URL("http://" + link);
} catch (error) {
return false;
}
}
if (finalURL.host.endsWith(".")) return false;
return validTLD(finalURL.host) ||
isValidIPv6(link.slice(1, finalURL.host.length - 1)) ||
isValidIPv4(link);
}
export function validTLD(domain: string): boolean {
if (!domain.includes(".")) return false;
const tld = toASCII(domain.split(".").reverse()[0]);
const tldList = getTLD();
return !!tldList.includes(tld.toUpperCase());
}
export function isValidIPv6(ip: string): boolean {
const length = ip.length;
let groups = 1;
let groupDigits = 0;
let doubleColonCount = 0;
for (let i = 0; i < length; i++) {
const char = ip[i];
if ("0" <= char && char <= "9") {
groupDigits++;
} else if ("a" <= char && char <= "f") {
groupDigits++;
} else if ("A" <= char && char <= "F") {
groupDigits++;
} else if (char === ":" && i + 1 < length && ip[i + 1] !== ":") {
groups++;
groupDigits = 0;
} else if (char === ":" && i + 1 < length && ip[i + 1] === ":") {
doubleColonCount++;
i++;
groupDigits = 0;
} else {
return false;
}
if (groups > 8) {
return false;
} else if (groupDigits > 4) {
return false;
} else if (doubleColonCount > 1) {
return false;
}
}
return !(doubleColonCount === 0 && groups !== 8);
}
export function isValidIPv4(ip: string): boolean {
const parts = ip.split(".");
if (parts.length !== 4) {
return false;
}
for (const part of parts) {
const num = Number(part);
if (isNaN(num) || num < 0 || num > 255 || !part.match(/^\d+$/)) {
return false;
}
}
return true;
}