diff --git a/README.md b/README.md index 0352748..57fdcf6 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,18 @@

- txt.
- GitHub - GitHub release (with filter) - Static Badge - - + txt. +
+ MIT license + Latest release + Matrix chat

HTTP proxy that parses only text, links and pictures from pages reducing internet traffic, removing ads and heavy scripts. +Uses [Mozilla's readability.js](https://github.com/mozilla/readability), +[JSDOM](https://github.com/jsdom/jsdom), +[Fastify web framework](https://github.com/fastify/fastify). + ## Installation ```bash @@ -30,7 +33,3 @@ npm run dev npm run build npm run start ``` - -Uses [Mozilla's readability.js](https://github.com/mozilla/readability), -[JSDOM](https://github.com/jsdom/jsdom), -[Fastify web framework](https://github.com/fastify/fastify). diff --git a/package-lock.json b/package-lock.json index 5bb3bb6..a18ba24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "dotenv": "^16.3.1", "ejs": "^3.1.9", "fastify": "^4.21.0", + "ip-range-check": "^0.2.0", "jsdom": "^22.1.0" }, "devDependencies": { @@ -1968,6 +1969,14 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/ip-range-check": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.2.0.tgz", + "integrity": "sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==", + "dependencies": { + "ipaddr.js": "^1.0.1" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", diff --git a/package.json b/package.json index fdebae3..6f3f68a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dotenv": "^16.3.1", "ejs": "^3.1.9", "fastify": "^4.21.0", + "ip-range-check": "^0.2.0", "jsdom": "^22.1.0" }, "devDependencies": { diff --git a/src/errors/main.ts b/src/errors/main.ts index 679a2da..bd528bd 100644 --- a/src/errors/main.ts +++ b/src/errors/main.ts @@ -1,5 +1,6 @@ export class EngineParseError extends Error {} export class InvalidParameterError extends Error {} +export class LocalResourceError extends Error {} export class NotHtmlMimetypeError extends Error { url: string; constructor(params: { url: string }) { diff --git a/src/handlers/main.ts b/src/handlers/main.ts index e14f7e9..cd483f1 100644 --- a/src/handlers/main.ts +++ b/src/handlers/main.ts @@ -6,15 +6,24 @@ import { DOMWindow } from "jsdom"; import readability from "./readability"; import google from "./google"; -import { generateProxyUrl } from "../utils"; -import { InvalidParameterError, NotHtmlMimetypeError } from "../errors/main"; +import { generateProxyUrl } from "../utils"; +import isLocalResource from "../islocal"; + +import { InvalidParameterError, LocalResourceError, NotHtmlMimetypeError } from "../errors/main"; export default async function handlePage( - url: string, - requestUrl: URL, + url: string, // remote URL + requestUrl: URL, // proxy URL engine?: string ): Promise { + + const urlObj = new URL(url); + + if (await isLocalResource(urlObj)) { + throw new LocalResourceError(); + } + if (engine && engineList.indexOf(engine) === -1) { throw new InvalidParameterError("Invalid engine"); } @@ -26,7 +35,7 @@ export default async function handlePage( throw new NotHtmlMimetypeError({ url }); } - const window = new JSDOM(response.data, { url: url }).window; + const window = new JSDOM(response.data, { url }).window; [...window.document.getElementsByTagName("a")].forEach((link) => { link.href = generateProxyUrl(requestUrl, link.href, engine); @@ -36,9 +45,7 @@ export default async function handlePage( return engines[engine](window); } - const host = new URL(url).hostname; - - return fallback[host]?.(window) || fallback["*"](window); + return fallback[urlObj.host]?.(window) || fallback["*"](window); } interface Engines { diff --git a/src/islocal.ts b/src/islocal.ts new file mode 100644 index 0000000..c997c01 --- /dev/null +++ b/src/islocal.ts @@ -0,0 +1,46 @@ +import dns from "dns"; +import ipRangeCheck from "ip-range-check"; + +const subnets = [ + "0.0.0.0/8", + "127.0.0.0/8", + "10.0.0.0/8", + "100.64.0.0/10", + "169.254.0.0/16", + "172.16.0.0/12", + "192.0.0.0/24", + "192.0.2.0/24", + "192.88.99.0/24", + "192.168.0.0/16", + "198.18.0.0/15", + "198.51.100.0/24", + "203.0.113.0/24", + "224.0.0.0/4", + "233.252.0.0/24", + "240.0.0.0/4", + "255.255.255.255/32", + "::/128", + "::1/128", + "::ffff:0:0/96", + "::ffff:0:0:0/96", + "64:ff9b::/96", + "64:ff9b:1::/48", + "100::/64", + "2001:0000::/32", + "2001:20::/28", + "2001:db8::/32", + "2002::/16", + "fc00::/7", + "fe80::/64", + "ff00::/8", +]; + +export default async function isLocalResource(url: URL): Promise { + // Resolve domain name + const addr = ( + await dns.promises.lookup(url.hostname) + ).address; + + // Check if IP is in local network + return ipRangeCheck(addr, subnets); +}