-
Notifications
You must be signed in to change notification settings - Fork 5
Redesign repo structure and get domains list from multiple sources #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3eb385d
1b9724c
2973ddc
f2bf1af
0173bdb
b7c2fd8
45468db
e4dcb6a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| node_modules | ||
| dist | ||
| sources/src/#generated-*.ts | ||
| sources/src/#generated-*.ts | ||
| .buildcache |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| { | ||
| "name": "@filteringdev/tinyshield-builder", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "lint": "tsc --noEmit && eslint **/*.ts", | ||
| "build": "tsx source/build.ts", | ||
| "debug": "tsx source/debug.ts", | ||
| "cache": "tsx source/cache.ts", | ||
| "clean": "rm -rf dist && rm -rf .buildcache" | ||
| }, | ||
| "dependencies": { | ||
| "@types/node": "^24.10.8" | ||
| }, | ||
| "devDependencies": { | ||
| "@adguard/agtree": "^3.4.3", | ||
| "@npmcli/package-json": "^7.0.4", | ||
| "@types/npmcli__package-json": "^4.0.4", | ||
| "@types/semver": "^7.7.1", | ||
| "@typescriptprime/parsing": "^1.0.4", | ||
| "@typescriptprime/securereq": "^1.0.1", | ||
| "chokidar": "^5.0.0", | ||
| "esbuild": "^0.27.2", | ||
| "eslint": "^9.39.2", | ||
| "semver": "^7.7.3", | ||
| "tldts": "^7.0.19", | ||
| "tsx": "^4.21.0", | ||
| "typescript": "^5.9.3", | ||
| "typescript-eslint": "^8.53.0", | ||
| "zod": "^4.3.5" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import * as Zod from 'zod' | ||
| import { HTTPSRequest } from '@typescriptprime/securereq' | ||
|
|
||
|
|
||
| const IABSellersJsonURL = 'https://info.ad-shield.io/sellers.json' | ||
|
|
||
| export async function FetchIABSellersJsonData(): Promise<string[]> { | ||
| const IABSellersJsonResponse: { StatusCode: number, Headers: Record<string, string | string[]>, Body: unknown } = await HTTPSRequest(new URL(IABSellersJsonURL), { ExpectedAs: 'JSON' }) | ||
| let IABSellersJsonData =IABSellersJsonResponse.Body as { | ||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| sellers: Array<{ | ||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| seller_id: number, | ||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| seller_type: string, | ||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| name: string, | ||
| // eslint-disable-next-line @typescript-eslint/naming-convention | ||
| domain: string | ||
| }> | ||
| } | ||
| IABSellersJsonData = await Zod.object({ | ||
| sellers: Zod.array(Zod.object({ | ||
| seller_id: Zod.number(), | ||
| seller_type: Zod.string(), | ||
| name: Zod.string(), | ||
| domain: Zod.string().refine(D => { | ||
| try { | ||
| new URL(`https://${D}`) | ||
| } catch { | ||
| return false | ||
| } | ||
| return true | ||
| }) | ||
| })) | ||
| }).parseAsync(IABSellersJsonData) | ||
| return [...new Set(IABSellersJsonData.sellers.map(S => S.domain))] | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as HTTP from 'node:http' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as Fs from 'node:fs' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function IsLoopBack(IP: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return IP === '127.0.0.1' || IP === '::1' || IP === '::ffff:127.0.0.1' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function RunDebugServer(Port: number, FileName: string[], ShouldPreventHTTPResponse: boolean) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const HTTPServer = HTTP.createServer((Req, Res) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!FileName.includes(Req.url?.substring(1) || '')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.writeHead(404) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.end() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (!IsLoopBack(Req.socket.remoteAddress)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.writeHead(403) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.end() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (ShouldPreventHTTPResponse || !Fs.existsSync(`${process.cwd()}/dist/${Req.url?.substring(1)}`)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.writeHead(503) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.end('File not built yet.') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Content = Fs.readFileSync(`${process.cwd()}/dist/${Req.url?.substring(1)}`, 'utf-8') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading
Copilot AutofixAI about 7 hours ago In general, the fix is to ensure that any path derived from user input is constrained to a safe root directory. That means: (1) normalize the combined path (root + user input) using For this snippet, the best minimal fix without changing functionality is:
Concretely, inside
This keeps the existing behavior (only serving files in
Suggested changeset
1
builder/source/utils/http-server.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.writeHead(200, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'content-type': 'application/javascript; charset=utf-8', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'content-length': new TextEncoder().encode(Content).byteLength.toString() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Res.end(Content) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HTTPServer.listen(Port) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "extends": "../tsconfig.json", | ||
| "include": [ | ||
| "source/**/*.ts", | ||
| "test/**/*.ts" | ||
| ] | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "name": "@filteringdev/tinyshield-userscript", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "lint": "tsc --noEmit && eslint **/*.ts" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/web": "^0.0.317" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "extends": "../tsconfig.json", | ||
| "include": [ | ||
| "source/**/*.ts" | ||
| ] | ||
| } |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
Copilot Autofix
AI about 7 hours ago
In general, to fix uncontrolled path usage, normalize the user input, resolve it relative to a known safe root directory, and then verify that the resulting path is contained within that root. If the normalized path escapes the root, reject the request. For this server, the safe root is effectively
${process.cwd()}/dist. We should usepath.resolveto join this root with the requested path, then ensure the resolved path starts with the root directory. This prevents directory traversal and absolute path attacks.The best fix here is: (1) introduce an import of Node’s
pathmodule; (2) computeconst distRoot = path.join(process.cwd(), 'dist')once per request (or outside the handler if appropriate); (3) takeReq.url?.substring(1) || ''as the requested path segment, resolve it withpath.resolve(distRoot, requestedPath), and (4) check that the resolved path starts withdistRoot + path.sepor equalsdistRoot. If not, return 403. Then use this sanitizedresolvedPathfor bothFs.existsSyncandFs.readFileSync. This preserves existing functionality (files are still only served if inFileName, from loopback, and if they exist) while adding robust path validation.Concretely in
builder/source/utils/http-server.ts:import * as Path from 'node:path'at the top.const distRoot = Path.join(process.cwd(), 'dist')andconst requestPath = Req.url?.substring(1) || ''.const resolvedPath = Path.resolve(distRoot, requestPath).FileName.includes/loopback/exists checks that depend on the path, add a guard: if!resolvedPath.startsWith(distRoot + Path.sep) && resolvedPath !== distRoot, respond with 403 and return.`${process.cwd()}/dist/${Req.url?.substring(1)}`withresolvedPath.No additional helper methods are strictly necessary beyond the new
Pathimport and local variables.