diff --git a/README.md b/README.md
index 0352748..57fdcf6 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,18 @@
-
-
-
-
-
-
+
+
+
+
+
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..6769283 100644
--- a/src/handlers/main.ts
+++ b/src/handlers/main.ts
@@ -6,15 +6,27 @@ 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/generate";
+import isLocalResource from "../utils/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 +38,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 +48,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/routes/get.ts b/src/routes/get.ts
index f2d19f8..dbd1e59 100644
--- a/src/routes/get.ts
+++ b/src/routes/get.ts
@@ -2,7 +2,7 @@ import { FastifyInstance } from "fastify";
import { GetSchema, IGetSchema } from "../types/requests";
import handlePage from "../handlers/main";
-import { generateRequestUrl } from "../utils";
+import { generateRequestUrl } from "../utils/generate";
export default async function getRoute(fastify: FastifyInstance) {
fastify.get(
diff --git a/src/routes/parse.ts b/src/routes/parse.ts
index 5523ff3..bca6363 100644
--- a/src/routes/parse.ts
+++ b/src/routes/parse.ts
@@ -1,7 +1,7 @@
import { EngineRequest, IParseSchema, parseSchema } from "../types/requests";
import { FastifyInstance } from "fastify";
import handlePage from "../handlers/main";
-import { generateRequestUrl } from "../utils";
+import { generateRequestUrl } from "../utils/generate";
export default async function parseRoute(fastify: FastifyInstance) {
fastify.get(
diff --git a/src/routes/raw-html.ts b/src/routes/raw-html.ts
index 38fad4b..30c520f 100644
--- a/src/routes/raw-html.ts
+++ b/src/routes/raw-html.ts
@@ -2,7 +2,7 @@ import { FastifyInstance } from "fastify";
import { GetRequest, IParseSchema, rawHtmlSchema } from "../types/requests";
import handlePage from "../handlers/main";
-import { generateRequestUrl } from "../utils";
+import { generateRequestUrl } from "../utils/generate";
export default async function rawHtml(fastify: FastifyInstance) {
fastify.get(
diff --git a/src/utils.ts b/src/utils/generate.ts
similarity index 100%
rename from src/utils.ts
rename to src/utils/generate.ts
diff --git a/src/utils/islocal.ts b/src/utils/islocal.ts
new file mode 100644
index 0000000..c997c01
--- /dev/null
+++ b/src/utils/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);
+}