diff --git a/bun.lockb b/bun.lockb
index caaa0da..b9b8868 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/i18n/en.json b/i18n/en.json
index b91b234..a9fdd73 100755
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -13,8 +13,9 @@
},
"search-help-text": "Search {engine}"
},
- "404": {
- "title": "Page Not Found"
+ "notfound": {
+ "title": "page not found",
+ "desc": "Please check if there is a typo in the URL.
If SparkHome brought you to this page,
please contact us."
},
"about": {
"title": "SparkHome"
diff --git a/lib/url/validLink.ts b/lib/url/validLink.ts
index 04026eb..5489f6e 100644
--- a/lib/url/validLink.ts
+++ b/lib/url/validLink.ts
@@ -1,22 +1,26 @@
-import punycode from "punycode/";
+import punycode from "punycode";
import { tldList } from "./tldList";
export default function validLink(link: string) {
- let finalURL = '';
+ let finalURL;
try {
const url = new URL(link);
- finalURL = url.origin;
+ finalURL = url;
return true;
} catch (error) {
// if the URL is invalid, try to add the protocol
try {
const urlWithHTTP = new URL("http://" + link);
- finalURL = urlWithHTTP.origin;
+ finalURL = urlWithHTTP;
} catch (error) {
return false;
}
}
- if (validTLD(finalURL)) {
+ if (
+ validTLD(finalURL.host) ||
+ isValidIPv6(finalURL.host.slice(1, finalURL.host.length - 1)) ||
+ isValidIPv4(finalURL.host)
+ ) {
return true;
} else {
return false;
@@ -31,3 +35,54 @@ export function validTLD(domain: string): boolean {
return false;
}
}
+
+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;
+ }
+ }
+ if (doubleColonCount === 0 && groups !== 8) {
+ return false;
+ }
+ return true;
+}
+
+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;
+}
diff --git a/package.json b/package.json
index cd8479c..6061e1a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "sparkhome",
"private": false,
- "version": "5.2.1",
+ "version": "5.2.2",
"type": "module",
"scripts": {
"dev": "bun server.ts",
@@ -21,6 +21,7 @@
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-icu": "^2.3.0",
+ "jest": "^29.7.0",
"jotai": "^2.8.3",
"node-nlp": "^4.27.0",
"react": "^18.3.1",
diff --git a/pages/[...].tsx b/pages/[...].tsx
new file mode 100644
index 0000000..13233a7
--- /dev/null
+++ b/pages/[...].tsx
@@ -0,0 +1,17 @@
+import { useTranslation } from "react-i18next";
+
+export default function NotFound() {
+ const { t } = useTranslation();
+ return (
+