diff --git a/package-lock.json b/package-lock.json index e4b359e..0274616 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "clsx": "^2.0.0", "file-type": "^18.5.0", "is-ipfs": "^8.0.1", + "proper-url-join": "^2.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.3" @@ -39,6 +40,7 @@ "@astrojs/tailwind": "^5.0.2", "@lumeweb/libresolver": "^0.1.0-develop.1", "@lumeweb/node-library-preset": "^0.2.7", + "@types/proper-url-join": "^2.1.2", "@types/react": "^18.2.28", "@types/react-dom": "^18.2.13", "astro": "^3.2.4", @@ -4767,6 +4769,15 @@ "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", "devOptional": true }, + "node_modules/@types/proper-url-join": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/proper-url-join/-/proper-url-join-2.1.2.tgz", + "integrity": "sha512-JeRURa8K0/4IVRd47h7nb+c5FEnCZXps6YcC70ZFKd6bPi7NfK+72wCJlwB6U8TD8abn1962s/YigkOkKsdT/g==", + "dev": true, + "dependencies": { + "query-string": "^6.3.0" + } + }, "node_modules/@types/react": { "version": "18.2.28", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", @@ -8490,6 +8501,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -10241,6 +10260,14 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -22345,6 +22372,14 @@ "signal-exit": "^3.0.2" } }, + "node_modules/proper-url-join": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/proper-url-join/-/proper-url-join-2.1.1.tgz", + "integrity": "sha512-40x6taKMwsDn4TrWx4YvnVxv5mO1O9KUrbK/jx8N0oDYf38ZFUK/OHNSAwTvu7Aj+cQcjBuf5aDh5R328YrrXg==", + "dependencies": { + "query-string": "^6.3.0" + } + }, "node_modules/property-information": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.3.0.tgz", @@ -22498,6 +22533,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-string": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", + "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", @@ -24765,6 +24817,14 @@ "node": "*" } }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -25153,6 +25213,14 @@ "queue-tick": "^1.0.1" } }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/package.json b/package.json index 19068dc..0cc300d 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "@lumeweb/kernel-peer-discovery-client": "^0.0.2-develop.18", "@lumeweb/kernel-swarm-client": "^0.1.0-develop.12", "@lumeweb/libresolver": "^0.1.0-develop.1", - "@lumeweb/tld-enum": "^0.1.0-develop.1", "@lumeweb/sdk": "^0.1.0-develop.39", + "@lumeweb/tld-enum": "^0.1.0-develop.1", "@radix-ui/react-form": "^0.0.3", "@radix-ui/react-slot": "^1.0.2", "@types/react": "^18.2.25", @@ -33,6 +33,7 @@ "clsx": "^2.0.0", "file-type": "^18.5.0", "is-ipfs": "^8.0.1", + "proper-url-join": "^2.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.3" @@ -42,6 +43,7 @@ "@astrojs/tailwind": "^5.0.2", "@lumeweb/libresolver": "^0.1.0-develop.1", "@lumeweb/node-library-preset": "^0.2.7", + "@types/proper-url-join": "^2.1.2", "@types/react": "^18.2.28", "@types/react-dom": "^18.2.13", "astro": "^3.2.4", diff --git a/src/backend/filters/urlRewrite.ts b/src/backend/filters/urlRewrite.ts index 3522201..1cadd90 100644 --- a/src/backend/filters/urlRewrite.ts +++ b/src/backend/filters/urlRewrite.ts @@ -2,6 +2,7 @@ import type { ContentFilter } from "../types.js"; import { getTld } from "@lumeweb/libresolver"; import tldEnum from "@lumeweb/tld-enum"; import * as cheerio from "cheerio"; +import urlJoin from "proper-url-join"; export default class URLRewriteFilter implements ContentFilter { async process(response: Response, mimeType: string): Promise { @@ -20,8 +21,17 @@ export default class URLRewriteFilter implements ContentFilter { let attrName = ["a", "link"].includes(tag) ? "href" : "src"; let urlValue = $(element).attr(attrName); if (urlValue) { - if (!urlValue.startsWith("http") || !isICANN(urlValue)) { - $(element).attr(attrName, `/browse${urlValue}`); + const isExternal = urlValue.startsWith("http"); + if (!isExternal || !isICANN(urlValue)) { + if (!isExternal) { + urlValue = urlJoin("/browse/", urlValue); + } else { + urlValue = `/browse/${urlValue}`; + } + + console.log(urlValue); + + $(element).attr(attrName, urlValue); } } });