Compare commits
42 Commits
fix/proxy_
...
errorpage
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee26eafb3e | ||
|
|
8947647116 | ||
|
|
f901e4aee0 | ||
|
|
5492921fef | ||
|
|
10d4b6818e | ||
|
|
ad415bee8c | ||
|
|
c2d6a2c461 | ||
|
|
02eb06995c | ||
|
|
0940bbb21b | ||
|
|
70033b8685 | ||
|
|
39852011e6 | ||
|
|
6a9d010e36 | ||
|
|
16df26c3a5 | ||
|
|
9159d44c1e | ||
|
|
8c741f0401 | ||
|
|
0082acf7c9 | ||
|
|
6effb51da6 | ||
|
|
1e41e6f2b0 | ||
|
|
82b5a74d8c | ||
|
|
f165a406f1 | ||
|
|
22533dc739 | ||
|
|
27c3892b0b | ||
|
|
8ffaa5fde1 | ||
|
|
7d379f935d | ||
|
|
b0af02830b | ||
|
|
c8a3c55ed6 | ||
|
|
9fa00188a6 | ||
|
|
2f6a67fc67 | ||
|
|
22f0007478 | ||
|
|
165ffcef89 | ||
|
|
9533f66a13 | ||
|
|
4d37046ff6 | ||
|
|
de640ce08c | ||
|
|
cc42ce10cb | ||
|
|
b3d799e36d | ||
|
|
81c99821f0 | ||
|
|
5bb6b872ba | ||
|
|
b94e64a4d3 | ||
|
|
b76a941164 | ||
|
|
424893a5a3 | ||
|
|
aabc34bac7 | ||
|
|
518f4d65d2 |
@@ -12,7 +12,7 @@ tmp_dir = "tmp"
|
|||||||
exclude_regex = ["_test.go"]
|
exclude_regex = ["_test.go"]
|
||||||
exclude_unchanged = false
|
exclude_unchanged = false
|
||||||
follow_symlink = false
|
follow_symlink = false
|
||||||
full_bin = "./tmp/main --ruleset ./ruleset_v2.yaml"
|
full_bin = "./tmp/main --ruleset ./rulesets_v2"
|
||||||
include_dir = []
|
include_dir = []
|
||||||
include_ext = ["go", "tpl", "tmpl", "yaml", "html", "js"]
|
include_ext = ["go", "tpl", "tmpl", "yaml", "html", "js"]
|
||||||
include_file = []
|
include_file = []
|
||||||
|
|||||||
5
.github/workflows/build-css.yaml
vendored
5
.github/workflows/build-css.yaml
vendored
@@ -3,7 +3,9 @@ name: Build Tailwind CSS
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
|
- "handlers/error_page.html"
|
||||||
- "handlers/form.html"
|
- "handlers/form.html"
|
||||||
|
- "handlers/playground.html"
|
||||||
- "proxychain/responsemodifiers/vendor/generate_readable_outline.html"
|
- "proxychain/responsemodifiers/vendor/generate_readable_outline.html"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ jobs:
|
|||||||
name: Build Tailwind CSS
|
name: Build Tailwind CSS
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
-
|
-
|
||||||
name: Commit generated stylesheet
|
name: Commit generated stylesheet for handlers/styles.css
|
||||||
run: |
|
run: |
|
||||||
if git diff --quiet handlers/styles.css; then
|
if git diff --quiet handlers/styles.css; then
|
||||||
echo "No changes to commit."
|
echo "No changes to commit."
|
||||||
@@ -38,6 +40,7 @@ jobs:
|
|||||||
git config --global user.name "Github action"
|
git config --global user.name "Github action"
|
||||||
git config --global user.email "username@users.noreply.github.com"
|
git config --global user.email "username@users.noreply.github.com"
|
||||||
git add handlers
|
git add handlers
|
||||||
|
git add proxychain/responsemodifiers/vendor/
|
||||||
git commit -m "Generated stylesheet"
|
git commit -m "Generated stylesheet"
|
||||||
git push
|
git push
|
||||||
fi
|
fi
|
||||||
|
|||||||
14
cmd/main.go
14
cmd/main.go
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -15,7 +14,6 @@ import (
|
|||||||
|
|
||||||
"github.com/akamensky/argparse"
|
"github.com/akamensky/argparse"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/template/html/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed VERSION
|
//go:embed VERSION
|
||||||
@@ -130,26 +128,18 @@ func main() {
|
|||||||
rs = ruleset_v2.NewRulesetFromEnv()
|
rs = ruleset_v2.NewRulesetFromEnv()
|
||||||
}
|
}
|
||||||
|
|
||||||
engine := html.New("./handlers", ".html")
|
|
||||||
engine.AddFunc(
|
|
||||||
// add unescape function
|
|
||||||
"unescape", func(s string) template.HTML {
|
|
||||||
return template.HTML(s)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
app := fiber.New(
|
app := fiber.New(
|
||||||
fiber.Config{
|
fiber.Config{
|
||||||
Prefork: *prefork,
|
Prefork: *prefork,
|
||||||
GETOnly: false,
|
GETOnly: false,
|
||||||
ReadBufferSize: 4096 * 4, // increase max header size
|
ReadBufferSize: 4096 * 4, // increase max header size
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
Views: engine,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
app.Use(handlers.Auth())
|
app.Use(handlers.Auth())
|
||||||
app.Use(handlers.Favicon())
|
app.Use(handlers.Favicon())
|
||||||
|
app.Use(handlers.RenderErrorPage())
|
||||||
|
|
||||||
if os.Getenv("NOLOGS") != "true" {
|
if os.Getenv("NOLOGS") != "true" {
|
||||||
app.Use(func(c *fiber.Ctx) error {
|
app.Use(func(c *fiber.Ctx) error {
|
||||||
@@ -168,6 +158,7 @@ func main() {
|
|||||||
|
|
||||||
app.Get("styles.css", handlers.Styles)
|
app.Get("styles.css", handlers.Styles)
|
||||||
app.Get("script.js", handlers.Script)
|
app.Get("script.js", handlers.Script)
|
||||||
|
app.Get("playground-script.js", handlers.Script)
|
||||||
|
|
||||||
app.All("api/raw/*", handlers.NewRawProxySiteHandler(proxyOpts))
|
app.All("api/raw/*", handlers.NewRawProxySiteHandler(proxyOpts))
|
||||||
|
|
||||||
@@ -176,6 +167,7 @@ func main() {
|
|||||||
app.Get("api/content/*", handlers.NewAPIContentHandler("api/outline/*", proxyOpts))
|
app.Get("api/content/*", handlers.NewAPIContentHandler("api/outline/*", proxyOpts))
|
||||||
|
|
||||||
app.Get("outline/*", handlers.NewOutlineHandler("outline/*", proxyOpts))
|
app.Get("outline/*", handlers.NewOutlineHandler("outline/*", proxyOpts))
|
||||||
|
app.All("playground/*", handlers.PlaygroundHandler("playground/*", proxyOpts))
|
||||||
|
|
||||||
app.All("/*", handlers.NewProxySiteHandler(proxyOpts))
|
app.All("/*", handlers.NewProxySiteHandler(proxyOpts))
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "AddCacheBusterQuery",
|
Name: "AddCacheBusterQuery",
|
||||||
Description: "AddCacheBusterQuery modifies query params to add a random parameter key In order to get the upstream network stack to serve a fresh copy of the page.",
|
Description: "AddCacheBusterQuery modifies query params to add a random parameter key In order to get the upstream network stack to serve a fresh copy of the page.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/add_cache_buster_query.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/add_cache_buster_query.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "ForwardRequestHeaders",
|
Name: "ForwardRequestHeaders",
|
||||||
Description: "ForwardRequestHeaders forwards the requests headers sent from the client to the upstream server",
|
Description: "ForwardRequestHeaders forwards the requests headers sent from the client to the upstream server",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/forward_request_headers.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/forward_request_headers.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -52,7 +52,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsGoogleBot",
|
Name: "MasqueradeAsGoogleBot",
|
||||||
Description: "MasqueradeAsGoogleBot modifies user agent and x-forwarded for to appear to be a Google Bot",
|
Description: "MasqueradeAsGoogleBot modifies user agent and x-forwarded for to appear to be a Google Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -60,7 +60,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsBingBot",
|
Name: "MasqueradeAsBingBot",
|
||||||
Description: "MasqueradeAsBingBot modifies user agent and x-forwarded for to appear to be a Bing Bot",
|
Description: "MasqueradeAsBingBot modifies user agent and x-forwarded for to appear to be a Bing Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -68,7 +68,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsWaybackMachineBot",
|
Name: "MasqueradeAsWaybackMachineBot",
|
||||||
Description: "MasqueradeAsWaybackMachineBot modifies user agent and x-forwarded for to appear to be a archive.org (wayback machine) Bot",
|
Description: "MasqueradeAsWaybackMachineBot modifies user agent and x-forwarded for to appear to be a archive.org (wayback machine) Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -76,7 +76,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsFacebookBot",
|
Name: "MasqueradeAsFacebookBot",
|
||||||
Description: "MasqueradeAsFacebookBot modifies user agent and x-forwarded for to appear to be a Facebook Bot (link previews?)",
|
Description: "MasqueradeAsFacebookBot modifies user agent and x-forwarded for to appear to be a Facebook Bot (link previews?)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -84,7 +84,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsYandexBot",
|
Name: "MasqueradeAsYandexBot",
|
||||||
Description: "MasqueradeAsYandexBot modifies user agent and x-forwarded for to appear to be a Yandex Spider Bot",
|
Description: "MasqueradeAsYandexBot modifies user agent and x-forwarded for to appear to be a Yandex Spider Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -92,7 +92,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsBaiduBot",
|
Name: "MasqueradeAsBaiduBot",
|
||||||
Description: "MasqueradeAsBaiduBot modifies user agent and x-forwarded for to appear to be a Baidu Spider Bot",
|
Description: "MasqueradeAsBaiduBot modifies user agent and x-forwarded for to appear to be a Baidu Spider Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -100,7 +100,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsDuckDuckBot",
|
Name: "MasqueradeAsDuckDuckBot",
|
||||||
Description: "MasqueradeAsDuckDuckBot modifies user agent and x-forwarded for to appear to be a DuckDuckGo Bot",
|
Description: "MasqueradeAsDuckDuckBot modifies user agent and x-forwarded for to appear to be a DuckDuckGo Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -108,7 +108,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "MasqueradeAsYahooBot",
|
Name: "MasqueradeAsYahooBot",
|
||||||
Description: "MasqueradeAsYahooBot modifies user agent and x-forwarded for to appear to be a Yahoo Bot",
|
Description: "MasqueradeAsYahooBot modifies user agent and x-forwarded for to appear to be a Yahoo Bot",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/masquerade_as_trusted_bot.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -116,7 +116,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "ModifyDomainWithRegex",
|
Name: "ModifyDomainWithRegex",
|
||||||
Description: "",
|
Description: "",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_domain_with_regex.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_domain_with_regex.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "matchRegex", Type: "string"},
|
{Name: "matchRegex", Type: "string"},
|
||||||
{Name: "replacement", Type: "string"},
|
{Name: "replacement", Type: "string"},
|
||||||
@@ -125,7 +125,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SetOutgoingCookie",
|
Name: "SetOutgoingCookie",
|
||||||
Description: "SetOutgoingCookie modifes a specific cookie name by modifying the request cookie headers going to the upstream server. If the cookie name does not already exist, it is created.",
|
Description: "SetOutgoingCookie modifes a specific cookie name by modifying the request cookie headers going to the upstream server. If the cookie name does not already exist, it is created.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "name", Type: "string"},
|
{Name: "name", Type: "string"},
|
||||||
{Name: "val", Type: "string"},
|
{Name: "val", Type: "string"},
|
||||||
@@ -134,7 +134,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SetOutgoingCookies",
|
Name: "SetOutgoingCookies",
|
||||||
Description: "SetOutgoingCookies modifies a client request's cookie header to a raw Cookie string, overwriting existing cookies",
|
Description: "SetOutgoingCookies modifies a client request's cookie header to a raw Cookie string, overwriting existing cookies",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "cookies", Type: "string"},
|
{Name: "cookies", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -142,7 +142,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteOutgoingCookie",
|
Name: "DeleteOutgoingCookie",
|
||||||
Description: "DeleteOutgoingCookie modifies the http request's cookies header to delete a specific request cookie going to the upstream server. If the cookie does not exist, it does not do anything.",
|
Description: "DeleteOutgoingCookie modifies the http request's cookies header to delete a specific request cookie going to the upstream server. If the cookie does not exist, it does not do anything.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "name", Type: "string"},
|
{Name: "name", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -150,7 +150,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteOutgoingCookies",
|
Name: "DeleteOutgoingCookies",
|
||||||
Description: "DeleteOutgoingCookies removes the cookie header entirely, preventing any cookies from reaching the upstream server.",
|
Description: "DeleteOutgoingCookies removes the cookie header entirely, preventing any cookies from reaching the upstream server.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -158,15 +158,15 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteOutgoingCookiesExcept",
|
Name: "DeleteOutgoingCookiesExcept",
|
||||||
Description: "DeleteOutGoingCookiesExcept prevents non-whitelisted cookies from being sent from the client to the upstream proxy server. Cookies whose names are in the whitelist are not removed.",
|
Description: "DeleteOutGoingCookiesExcept prevents non-whitelisted cookies from being sent from the client to the upstream proxy server. Cookies whose names are in the whitelist are not removed.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "whitelist", Type: "&{Ellipsis:12348 Elt:string}"},
|
{Name: "whitelist", Type: "&{Ellipsis:12476 Elt:string}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "ModifyPathWithRegex",
|
Name: "ModifyPathWithRegex",
|
||||||
Description: "",
|
Description: "",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_path_with_regex.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_path_with_regex.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "matchRegex", Type: "string"},
|
{Name: "matchRegex", Type: "string"},
|
||||||
{Name: "replacement", Type: "string"},
|
{Name: "replacement", Type: "string"},
|
||||||
@@ -175,7 +175,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "ModifyQueryParams",
|
Name: "ModifyQueryParams",
|
||||||
Description: "ModifyQueryParams replaces query parameter values in URL's query params in a ProxyChain's URL. If the query param key doesn't exist, it is created.",
|
Description: "ModifyQueryParams replaces query parameter values in URL's query params in a ProxyChain's URL. If the query param key doesn't exist, it is created.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_query_params.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_query_params.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "key", Type: "string"},
|
{Name: "key", Type: "string"},
|
||||||
{Name: "value", Type: "string"},
|
{Name: "value", Type: "string"},
|
||||||
@@ -184,7 +184,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SetRequestHeader",
|
Name: "SetRequestHeader",
|
||||||
Description: "SetRequestHeader modifies a specific outgoing header This is the header that the upstream server will see.",
|
Description: "SetRequestHeader modifies a specific outgoing header This is the header that the upstream server will see.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_request_headers.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_request_headers.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "name", Type: "string"},
|
{Name: "name", Type: "string"},
|
||||||
{Name: "val", Type: "string"},
|
{Name: "val", Type: "string"},
|
||||||
@@ -193,7 +193,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteRequestHeader",
|
Name: "DeleteRequestHeader",
|
||||||
Description: "DeleteRequestHeader modifies a specific outgoing header This is the header that the upstream server will see.",
|
Description: "DeleteRequestHeader modifies a specific outgoing header This is the header that the upstream server will see.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_request_headers.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/modify_request_headers.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "name", Type: "string"},
|
{Name: "name", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -201,7 +201,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "RequestArchiveIs",
|
Name: "RequestArchiveIs",
|
||||||
Description: "RequestArchiveIs modifies a ProxyChain's URL to request an archived version from archive.is",
|
Description: "RequestArchiveIs modifies a ProxyChain's URL to request an archived version from archive.is",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/request_archive_is.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/request_archive_is.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -209,7 +209,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "RequestGoogleCache",
|
Name: "RequestGoogleCache",
|
||||||
Description: "RequestGoogleCache modifies a ProxyChain's URL to request its Google Cache version.",
|
Description: "RequestGoogleCache modifies a ProxyChain's URL to request its Google Cache version.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/request_google_cache.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/request_google_cache.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -217,7 +217,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "RequestWaybackMachine",
|
Name: "RequestWaybackMachine",
|
||||||
Description: "RequestWaybackMachine modifies a ProxyChain's URL to request the wayback machine (archive.org) version.",
|
Description: "RequestWaybackMachine modifies a ProxyChain's URL to request the wayback machine (archive.org) version.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/request_wayback_machine.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/request_wayback_machine.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -225,7 +225,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "ResolveWithGoogleDoH",
|
Name: "ResolveWithGoogleDoH",
|
||||||
Description: "ResolveWithGoogleDoH modifies a ProxyChain's client to make the request by resolving the URL using Google's DNS over HTTPs service",
|
Description: "ResolveWithGoogleDoH modifies a ProxyChain's client to make the request by resolving the URL using Google's DNS over HTTPs service",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/resolve_with_google_doh.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/resolve_with_google_doh.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -233,7 +233,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofOrigin",
|
Name: "SpoofOrigin",
|
||||||
Description: "SpoofOrigin modifies the origin header if the upstream server returns a Vary header it means you might get a different response if you change this",
|
Description: "SpoofOrigin modifies the origin header if the upstream server returns a Vary header it means you might get a different response if you change this",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_origin.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_origin.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "url", Type: "string"},
|
{Name: "url", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -241,7 +241,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "HideOrigin",
|
Name: "HideOrigin",
|
||||||
Description: "HideOrigin modifies the origin header so that it is the original origin, not the proxy",
|
Description: "HideOrigin modifies the origin header so that it is the original origin, not the proxy",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_origin.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_origin.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -249,7 +249,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrer",
|
Name: "SpoofReferrer",
|
||||||
Description: "SpoofReferrer modifies the referrer header. It is useful if the page can be accessed from a search engine or social media site, but not by browsing the website itself. if url is \"\", then the referrer header is removed.",
|
Description: "SpoofReferrer modifies the referrer header. It is useful if the page can be accessed from a search engine or social media site, but not by browsing the website itself. if url is \"\", then the referrer header is removed.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "url", Type: "string"},
|
{Name: "url", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -257,7 +257,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "HideReferrer",
|
Name: "HideReferrer",
|
||||||
Description: "HideReferrer modifies the referrer header so that it is the original referrer, not the proxy",
|
Description: "HideReferrer modifies the referrer header so that it is the original referrer, not the proxy",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -265,7 +265,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromBaiduSearch",
|
Name: "SpoofReferrerFromBaiduSearch",
|
||||||
Description: "SpoofReferrerFromBaiduSearch modifies the referrer header pretending to be from a BaiduSearch",
|
Description: "SpoofReferrerFromBaiduSearch modifies the referrer header pretending to be from a BaiduSearch",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_baidu_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_baidu_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -273,7 +273,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromBingSearch",
|
Name: "SpoofReferrerFromBingSearch",
|
||||||
Description: "SpoofReferrerFromBingSearch modifies the referrer header pretending to be from a bing search site",
|
Description: "SpoofReferrerFromBingSearch modifies the referrer header pretending to be from a bing search site",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_bing_search.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_bing_search.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -281,7 +281,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromGoogleSearch",
|
Name: "SpoofReferrerFromGoogleSearch",
|
||||||
Description: "SpoofReferrerFromGoogleSearch modifies the referrer header pretending to be from a google search site",
|
Description: "SpoofReferrerFromGoogleSearch modifies the referrer header pretending to be from a google search site",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_google_search.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_google_search.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -289,7 +289,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromLinkedInPost",
|
Name: "SpoofReferrerFromLinkedInPost",
|
||||||
Description: "SpoofReferrerFromLinkedInPost modifies the referrer header pretending to be from a linkedin post",
|
Description: "SpoofReferrerFromLinkedInPost modifies the referrer header pretending to be from a linkedin post",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_linkedin_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_linkedin_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -297,7 +297,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromNaverSearch",
|
Name: "SpoofReferrerFromNaverSearch",
|
||||||
Description: "SpoofReferrerFromNaverSearch modifies the referrer header pretending to be from a Naver search (popular in South Korea)",
|
Description: "SpoofReferrerFromNaverSearch modifies the referrer header pretending to be from a Naver search (popular in South Korea)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_naver_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_naver_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -305,7 +305,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromPinterestPost",
|
Name: "SpoofReferrerFromPinterestPost",
|
||||||
Description: "SpoofReferrerFromPinterestPost modifies the referrer header pretending to be from a pinterest post",
|
Description: "SpoofReferrerFromPinterestPost modifies the referrer header pretending to be from a pinterest post",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_pinterest_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_pinterest_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -313,7 +313,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromQQPost",
|
Name: "SpoofReferrerFromQQPost",
|
||||||
Description: "SpoofReferrerFromQQPost modifies the referrer header pretending to be from a QQ post (popular social media in China)",
|
Description: "SpoofReferrerFromQQPost modifies the referrer header pretending to be from a QQ post (popular social media in China)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_qq_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_qq_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -321,7 +321,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromRedditPost",
|
Name: "SpoofReferrerFromRedditPost",
|
||||||
Description: "SpoofReferrerFromRedditPost modifies the referrer header pretending to be from a reddit post",
|
Description: "SpoofReferrerFromRedditPost modifies the referrer header pretending to be from a reddit post",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_reddit_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_reddit_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -329,7 +329,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromTumblrPost",
|
Name: "SpoofReferrerFromTumblrPost",
|
||||||
Description: "SpoofReferrerFromTumblrPost modifies the referrer header pretending to be from a tumblr post",
|
Description: "SpoofReferrerFromTumblrPost modifies the referrer header pretending to be from a tumblr post",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_tumblr_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_tumblr_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -337,7 +337,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromTwitterPost",
|
Name: "SpoofReferrerFromTwitterPost",
|
||||||
Description: "SpoofReferrerFromTwitterPost modifies the referrer header pretending to be from a twitter post",
|
Description: "SpoofReferrerFromTwitterPost modifies the referrer header pretending to be from a twitter post",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_twitter_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_twitter_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -345,7 +345,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromVkontaktePost",
|
Name: "SpoofReferrerFromVkontaktePost",
|
||||||
Description: "SpoofReferrerFromVkontaktePost modifies the referrer header pretending to be from a vkontakte post (popular in Russia)",
|
Description: "SpoofReferrerFromVkontaktePost modifies the referrer header pretending to be from a vkontakte post (popular in Russia)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_vkontake_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_vkontake_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -353,7 +353,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofReferrerFromWeiboPost",
|
Name: "SpoofReferrerFromWeiboPost",
|
||||||
Description: "SpoofReferrerFromWeiboPost modifies the referrer header pretending to be from a Weibo post (popular in China)",
|
Description: "SpoofReferrerFromWeiboPost modifies the referrer header pretending to be from a Weibo post (popular in China)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_weibo_post.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_referrer_from_weibo_post.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -361,7 +361,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofUserAgent",
|
Name: "SpoofUserAgent",
|
||||||
Description: "SpoofUserAgent modifies the user agent",
|
Description: "SpoofUserAgent modifies the user agent",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_user_agent.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_user_agent.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "ua", Type: "string"},
|
{Name: "ua", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -369,7 +369,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SpoofXForwardedFor",
|
Name: "SpoofXForwardedFor",
|
||||||
Description: "SpoofXForwardedFor modifies the X-Forwarded-For header in some cases, a forward proxy may interpret this as the source IP",
|
Description: "SpoofXForwardedFor modifies the X-Forwarded-For header in some cases, a forward proxy may interpret this as the source IP",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/spoof_x_forwarded_for.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/requestmodifiers/spoof_x_forwarded_for.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "ip", Type: "string"},
|
{Name: "ip", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -379,7 +379,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "APIContent",
|
Name: "APIContent",
|
||||||
Description: "APIContent creates an JSON representation of the article and returns it as an API response.",
|
Description: "APIContent creates an JSON representation of the article and returns it as an API response.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/api_content.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/api_content.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -387,7 +387,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "BlockElementRemoval",
|
Name: "BlockElementRemoval",
|
||||||
Description: "BlockElementRemoval prevents paywall javascript from removing a particular element by detecting the removal, then immediately reinserting it. This is useful when a page will return a \"fake\" 404, after flashing the content briefly. If the /outline/ API works, but the regular API doesn't, try this modifier.",
|
Description: "BlockElementRemoval prevents paywall javascript from removing a particular element by detecting the removal, then immediately reinserting it. This is useful when a page will return a \"fake\" 404, after flashing the content briefly. If the /outline/ API works, but the regular API doesn't, try this modifier.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/block_element_removal.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/block_element_removal.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "cssSelector", Type: "string"},
|
{Name: "cssSelector", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -395,7 +395,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "BlockThirdPartyScripts",
|
Name: "BlockThirdPartyScripts",
|
||||||
Description: "BlockThirdPartyScripts rewrites HTML and injects JS to block all third party JS from loading.",
|
Description: "BlockThirdPartyScripts rewrites HTML and injects JS to block all third party JS from loading.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/block_third_party_scripts.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/block_third_party_scripts.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -403,7 +403,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "BypassCORS",
|
Name: "BypassCORS",
|
||||||
Description: "BypassCORS modifies response headers to prevent the browser from enforcing any CORS restrictions. This should run at the end of the chain.",
|
Description: "BypassCORS modifies response headers to prevent the browser from enforcing any CORS restrictions. This should run at the end of the chain.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/bypass_cors.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/bypass_cors.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -411,7 +411,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "BypassContentSecurityPolicy",
|
Name: "BypassContentSecurityPolicy",
|
||||||
Description: "BypassContentSecurityPolicy modifies response headers to prevent the browser from enforcing any CSP restrictions. This should run at the end of the chain.",
|
Description: "BypassContentSecurityPolicy modifies response headers to prevent the browser from enforcing any CSP restrictions. This should run at the end of the chain.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/bypass_csp.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/bypass_csp.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -419,7 +419,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SetContentSecurityPolicy",
|
Name: "SetContentSecurityPolicy",
|
||||||
Description: "SetContentSecurityPolicy modifies response headers to a specific CSP",
|
Description: "SetContentSecurityPolicy modifies response headers to a specific CSP",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/bypass_csp.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/bypass_csp.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "csp", Type: "string"},
|
{Name: "csp", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -427,7 +427,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteLocalStorageData",
|
Name: "DeleteLocalStorageData",
|
||||||
Description: "DeleteLocalStorageData deletes localstorage cookies. If the page works once in a fresh incognito window, but fails for subsequent loads, try this response modifier alongside DeleteSessionStorageData and DeleteIncomingCookies",
|
Description: "DeleteLocalStorageData deletes localstorage cookies. If the page works once in a fresh incognito window, but fails for subsequent loads, try this response modifier alongside DeleteSessionStorageData and DeleteIncomingCookies",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/delete_localstorage_data.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/delete_localstorage_data.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -435,7 +435,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteSessionStorageData",
|
Name: "DeleteSessionStorageData",
|
||||||
Description: "DeleteSessionStorageData deletes localstorage cookies. If the page works once in a fresh incognito window, but fails for subsequent loads, try this response modifier alongside DeleteLocalStorageData and DeleteIncomingCookies",
|
Description: "DeleteSessionStorageData deletes localstorage cookies. If the page works once in a fresh incognito window, but fails for subsequent loads, try this response modifier alongside DeleteLocalStorageData and DeleteIncomingCookies",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/delete_sessionstorage_data.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/delete_sessionstorage_data.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -443,7 +443,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "ForwardResponseHeaders",
|
Name: "ForwardResponseHeaders",
|
||||||
Description: "ForwardResponseHeaders forwards the response headers from the upstream server to the client",
|
Description: "ForwardResponseHeaders forwards the response headers from the upstream server to the client",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/forward_response_headers.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/forward_response_headers.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -451,7 +451,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "GenerateReadableOutline",
|
Name: "GenerateReadableOutline",
|
||||||
Description: "GenerateReadableOutline creates an reader-friendly distilled representation of the article. This is a reliable way of bypassing soft-paywalled articles, where the content is hidden, but still present in the DOM.",
|
Description: "GenerateReadableOutline creates an reader-friendly distilled representation of the article. This is a reliable way of bypassing soft-paywalled articles, where the content is hidden, but still present in the DOM.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/generate_readable_outline.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/generate_readable_outline.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -459,7 +459,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "InjectScriptBeforeDOMContentLoaded",
|
Name: "InjectScriptBeforeDOMContentLoaded",
|
||||||
Description: "InjectScriptBeforeDOMContentLoaded modifies HTTP responses to inject a JS before DOM Content is loaded (script tag in head)",
|
Description: "InjectScriptBeforeDOMContentLoaded modifies HTTP responses to inject a JS before DOM Content is loaded (script tag in head)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "js", Type: "string"},
|
{Name: "js", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -467,7 +467,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "InjectScriptAfterDOMContentLoaded",
|
Name: "InjectScriptAfterDOMContentLoaded",
|
||||||
Description: "InjectScriptAfterDOMContentLoaded modifies HTTP responses to inject a JS after DOM Content is loaded (script tag in head)",
|
Description: "InjectScriptAfterDOMContentLoaded modifies HTTP responses to inject a JS after DOM Content is loaded (script tag in head)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "js", Type: "string"},
|
{Name: "js", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -475,7 +475,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "InjectScriptAfterDOMIdle",
|
Name: "InjectScriptAfterDOMIdle",
|
||||||
Description: "InjectScriptAfterDOMIdle modifies HTTP responses to inject a JS after the DOM is idle (ie: js framework loaded)",
|
Description: "InjectScriptAfterDOMIdle modifies HTTP responses to inject a JS after the DOM is idle (ie: js framework loaded)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/inject_script.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "js", Type: "string"},
|
{Name: "js", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -483,23 +483,23 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteIncomingCookies",
|
Name: "DeleteIncomingCookies",
|
||||||
Description: "DeleteIncomingCookies prevents ALL cookies from being sent from the proxy server back down to the client.",
|
Description: "DeleteIncomingCookies prevents ALL cookies from being sent from the proxy server back down to the client.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "_", Type: "&{Ellipsis:16319 Elt:string}"},
|
{Name: "_", Type: "&{Ellipsis:18780 Elt:string}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "DeleteIncomingCookiesExcept",
|
Name: "DeleteIncomingCookiesExcept",
|
||||||
Description: "DeleteIncomingCookiesExcept prevents non-whitelisted cookies from being sent from the proxy server to the client. Cookies whose names are in the whitelist are not removed.",
|
Description: "DeleteIncomingCookiesExcept prevents non-whitelisted cookies from being sent from the proxy server to the client. Cookies whose names are in the whitelist are not removed.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "whitelist", Type: "&{Ellipsis:16864 Elt:string}"},
|
{Name: "whitelist", Type: "&{Ellipsis:19325 Elt:string}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "SetIncomingCookies",
|
Name: "SetIncomingCookies",
|
||||||
Description: "SetIncomingCookies adds a raw cookie string being sent from the proxy server down to the client",
|
Description: "SetIncomingCookies adds a raw cookie string being sent from the proxy server down to the client",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "cookies", Type: "string"},
|
{Name: "cookies", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -507,16 +507,25 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "SetIncomingCookie",
|
Name: "SetIncomingCookie",
|
||||||
Description: "SetIncomingCookie modifies a specific cookie in the response from the proxy server to the client.",
|
Description: "SetIncomingCookie modifies a specific cookie in the response from the proxy server to the client.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "name", Type: "string"},
|
{Name: "name", Type: "string"},
|
||||||
{Name: "val", Type: "string"},
|
{Name: "val", Type: "string"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "ModifyIncomingScriptsWithRegex",
|
||||||
|
Description: "ModifyIncomingScriptsWithRegex modifies all incoming javascript (application/javascript and inline <script> in text/html) using a regex match and replacement.",
|
||||||
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_scripts_with_regex.go",
|
||||||
|
Params: []Param{
|
||||||
|
{Name: "matchRegex", Type: "string"},
|
||||||
|
{Name: "replacement", Type: "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "SetResponseHeader",
|
Name: "SetResponseHeader",
|
||||||
Description: "SetResponseHeader modifies response headers from the upstream server",
|
Description: "SetResponseHeader modifies response headers from the upstream server",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_response_header.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_response_header.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "key", Type: "string"},
|
{Name: "key", Type: "string"},
|
||||||
{Name: "value", Type: "string"},
|
{Name: "value", Type: "string"},
|
||||||
@@ -525,7 +534,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "DeleteResponseHeader",
|
Name: "DeleteResponseHeader",
|
||||||
Description: "DeleteResponseHeader removes response headers from the upstream server",
|
Description: "DeleteResponseHeader removes response headers from the upstream server",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_response_header.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/modify_response_header.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
{Name: "key", Type: "string"},
|
{Name: "key", Type: "string"},
|
||||||
},
|
},
|
||||||
@@ -533,7 +542,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "PatchDynamicResourceURLs",
|
Name: "PatchDynamicResourceURLs",
|
||||||
Description: "PatchDynamicResourceURLs patches the javascript runtime to rewrite URLs client-side. - This function is designed to allow the proxified page to still be browsible by routing all resource URLs through the proxy. - Native APIs capable of network requests will be hooked and the URLs arguments modified to point to the proxy instead. - fetch('/relative_path') -> fetch('/https://proxiedsite.com/relative_path') - Element.setAttribute('src', \"/assets/img.jpg\") -> Element.setAttribute('src', \"/https://proxiedsite.com/assets/img.jpg\") -> fetch('/https://proxiedsite.com/relative_path')",
|
Description: "PatchDynamicResourceURLs patches the javascript runtime to rewrite URLs client-side. - This function is designed to allow the proxified page to still be browsible by routing all resource URLs through the proxy. - Native APIs capable of network requests will be hooked and the URLs arguments modified to point to the proxy instead. - fetch('/relative_path') -> fetch('/https://proxiedsite.com/relative_path') - Element.setAttribute('src', \"/assets/img.jpg\") -> Element.setAttribute('src', \"/https://proxiedsite.com/assets/img.jpg\") -> fetch('/https://proxiedsite.com/relative_path')",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/patch_dynamic_resource_urls.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/patch_dynamic_resource_urls.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -541,7 +550,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "PatchTrackerScripts",
|
Name: "PatchTrackerScripts",
|
||||||
Description: "PatchTrackerScripts replaces any request to tracker scripts such as google analytics with a no-op stub that mocks the API structure of the original scripts they replace. Some pages depend on the existence of these structures for proper loading, so this may fix some broken elements. Surrogate script code borrowed from: DuckDuckGo Privacy Essentials browser extension for Firefox, Chrome. (Apache 2.0 license)",
|
Description: "PatchTrackerScripts replaces any request to tracker scripts such as google analytics with a no-op stub that mocks the API structure of the original scripts they replace. Some pages depend on the existence of these structures for proper loading, so this may fix some broken elements. Surrogate script code borrowed from: DuckDuckGo Privacy Essentials browser extension for Firefox, Chrome. (Apache 2.0 license)",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/patch_tracker_scripts.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/patch_tracker_scripts.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -549,7 +558,7 @@ var AllMods Modifiers = Modifiers{
|
|||||||
{
|
{
|
||||||
Name: "RewriteHTMLResourceURLs",
|
Name: "RewriteHTMLResourceURLs",
|
||||||
Description: "RewriteHTMLResourceURLs modifies HTTP responses to rewrite URLs attributes in HTML content (such as src, href) - `<img src='/relative_path'>` -> `<img src='/https://proxiedsite.com/relative_path'>` - This function is designed to allow the proxified page to still be browsible by routing all resource URLs through the proxy.",
|
Description: "RewriteHTMLResourceURLs modifies HTTP responses to rewrite URLs attributes in HTML content (such as src, href) - `<img src='/relative_path'>` -> `<img src='/https://proxiedsite.com/relative_path'>` - This function is designed to allow the proxified page to still be browsible by routing all resource URLs through the proxy.",
|
||||||
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/rewrite_http_resource_urls.go",
|
CodeEditLink: "https://github.com/everywall/ladder.git/edit/heads/origin/proxy_v2/proxychain/responsemodifiers/rewrite_http_resource_urls.go",
|
||||||
Params: []Param{
|
Params: []Param{
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
32
handlers/error_page.go
Normal file
32
handlers/error_page.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed error_page.html
|
||||||
|
var errorHTML embed.FS
|
||||||
|
|
||||||
|
func RenderErrorPage() fiber.Handler {
|
||||||
|
f := "error_page.html"
|
||||||
|
tmpl, err := template.ParseFS(errorHTML, f)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("RenderErrorPage Error: %s not found", f))
|
||||||
|
}
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
if err := c.Next(); err != nil {
|
||||||
|
if strings.Contains(c.Get("Accept"), "text/html") {
|
||||||
|
c.Set("Content-Type", "text/html")
|
||||||
|
tmpl.Execute(c.Response().BodyWriter(), err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.SendString(err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
238
handlers/error_page.html
Normal file
238
handlers/error_page.html
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="/styles.css" />
|
||||||
|
<script src="/script.js" defer></script>
|
||||||
|
<script>
|
||||||
|
const handleThemeChange = () => {
|
||||||
|
let theme = localStorage.getItem("theme");
|
||||||
|
if (theme === null) {
|
||||||
|
localStorage.setItem("theme", "system");
|
||||||
|
theme = "system";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
theme === "dark" ||
|
||||||
|
(theme === "system" &&
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||||
|
) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("dark");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handleThemeChange();
|
||||||
|
</script>
|
||||||
|
<title>ladder | error</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body
|
||||||
|
class="antialiased bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-200"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-4 max-w-3xl mx-auto pt-10">
|
||||||
|
<div class="flex justify-between place-items-center">
|
||||||
|
<div
|
||||||
|
class="hover:drop-shadow-[0_0px_4px_rgba(122,167,209,.3)] ring-offset-white dark:ring-offset-slate-900 transition-colors duration-300 focus:outline-none focus:ring ring-offset-2"
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
aria-label="ladder"
|
||||||
|
class="flex -ml-2 h-8 font-extrabold tracking-tight no-underline focus:outline-none ring-offset-white dark:ring-offset-slate-900 focus:ring ring-offset-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
class="h-8 focus:outline-none focus:ring ring-offset-white dark:ring-offset-slate-900 ring-offset-2"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#7AA7D1"
|
||||||
|
d="M262.074 485.246C254.809 485.265 247.407 485.534 240.165 484.99L226.178 483.306C119.737 468.826 34.1354 383.43 25.3176 274.714C24.3655 262.975 23.5876 253.161 24.3295 241.148C31.4284 126.212 123.985 31.919 238.633 24.1259L250.022 23.8366C258.02 23.8001 266.212 23.491 274.183 24.1306C320.519 27.8489 366.348 45.9743 402.232 75.4548L416.996 88.2751C444.342 114.373 464.257 146.819 475.911 182.72L480.415 197.211C486.174 219.054 488.67 242.773 487.436 265.259L486.416 275.75C478.783 352.041 436.405 418.1 369.36 455.394L355.463 462.875C326.247 477.031 294.517 484.631 262.074 485.246ZM253.547 72.4475C161.905 73.0454 83.5901 144.289 73.0095 234.5C69.9101 260.926 74.7763 292.594 83.9003 317.156C104.53 372.691 153.9 416.616 211.281 430.903C226.663 434.733 242.223 436.307 258.044 436.227C353.394 435.507 430.296 361.835 438.445 267.978C439.794 252.442 438.591 236.759 435.59 221.5C419.554 139.955 353.067 79.4187 269.856 72.7052C264.479 72.2714 258.981 72.423 253.586 72.4127L253.547 72.4475Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#7AA7D1"
|
||||||
|
d="M153.196 310.121L133.153 285.021C140.83 283.798 148.978 285.092 156.741 284.353L156.637 277.725L124.406 278.002C123.298 277.325 122.856 276.187 122.058 275.193L116.089 267.862C110.469 260.975 103.827 254.843 98.6026 247.669C103.918 246.839 105.248 246.537 111.14 246.523L129.093 246.327C130.152 238.785 128.62 240.843 122.138 240.758C111.929 240.623 110.659 242.014 105.004 234.661L97.9953 225.654C94.8172 221.729 91.2219 218.104 88.2631 214.005C84.1351 208.286 90.1658 209.504 94.601 209.489L236.752 209.545C257.761 209.569 268.184 211.009 285.766 221.678L285.835 206.051C285.837 197.542 286.201 189.141 284.549 180.748C280.22 158.757 260.541 143.877 240.897 135.739C238.055 134.561 232.259 133.654 235.575 129.851C244.784 119.288 263.680 111.990 277.085 111.105C288.697 109.828 301.096 113.537 311.75 117.703C360.649 136.827 393.225 183.042 398.561 234.866C402.204 270.253 391.733 308.356 367.999 335.1C332.832 374.727 269.877 384.883 223.294 360.397C206.156 351.388 183.673 333.299 175.08 316.6C173.511 313.551 174.005 313.555 170.443 313.52L160.641 313.449C158.957 313.435 156.263 314.031 155.122 312.487L153.196 310.121Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="text-3xl ml-1 text-[#7AA7D1] leading-8 align-middle"
|
||||||
|
>ladder</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-center z-10">
|
||||||
|
<div class="relative" id="dropdown">
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
id="dropdownButton"
|
||||||
|
aria-label="Toggle dropdown menu"
|
||||||
|
onclick="toggleDropdown()"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-center whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-white dark:ring-offset transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"
|
||||||
|
/>
|
||||||
|
<circle cx="12" cy="12" r="3" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="dropdown_panel"
|
||||||
|
class="hidden absolute right-0 mt-2 w-52 rounded-md bg-white dark:bg-slate-900 shadow-md border border-slate-400 dark:border-slate-700"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm"
|
||||||
|
>
|
||||||
|
Appearance
|
||||||
|
<div class="grid grid-cols-4 gap-2">
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="light"
|
||||||
|
value="light"
|
||||||
|
class="peer hidden"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="light"
|
||||||
|
tabindex="0"
|
||||||
|
title="Light"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-sm text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="4" />
|
||||||
|
<path d="M12 2v2" />
|
||||||
|
<path d="M12 20v2" />
|
||||||
|
<path d="m4.93 4.93 1.41 1.41" />
|
||||||
|
<path d="m17.66 17.66 1.41 1.41" />
|
||||||
|
<path d="M2 12h2" />
|
||||||
|
<path d="M20 12h2" />
|
||||||
|
<path d="m6.34 17.66-1.41 1.41" />
|
||||||
|
<path d="m19.07 4.93-1.41 1.41" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="dark"
|
||||||
|
value="dark"
|
||||||
|
class="peer hidden"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="dark"
|
||||||
|
tabindex="0"
|
||||||
|
title="Dark"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-base text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="system"
|
||||||
|
value="system"
|
||||||
|
class="peer hidden"
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="system"
|
||||||
|
tabindex="0"
|
||||||
|
title="System preference"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-lg text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path d="M12 8a2.83 2.83 0 0 0 4 4 4 4 0 1 1-4-4" />
|
||||||
|
<path d="M12 2v2" />
|
||||||
|
<path d="M12 20v2" />
|
||||||
|
<path d="m4.9 4.9 1.4 1.4" />
|
||||||
|
<path d="m17.7 17.7 1.4 1.4" />
|
||||||
|
<path d="M2 12h2" />
|
||||||
|
<path d="M20 12h2" />
|
||||||
|
<path d="m6.3 17.7-1.4 1.4" />
|
||||||
|
<path d="m19.1 4.9-1.4 1.4" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col space-y-3">
|
||||||
|
<h1>Error</h1>
|
||||||
|
<div class="my-4"></div>
|
||||||
|
<code class="p-4 mx-auto text-red-500 dark:text-red-400"> {{.}} </code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="mx-4 my-2 text-center text-slate-600 dark:text-slate-400">
|
||||||
|
<small>
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Everywall</a
|
||||||
|
>
|
||||||
|
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall/ladder"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Source</a
|
||||||
|
>
|
||||||
|
| Code Licensed Under GPL v3.0
|
||||||
|
</small>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -32,7 +32,9 @@
|
|||||||
<div class="place-self-end z-10">
|
<div class="place-self-end z-10">
|
||||||
<div class="relative" id="dropdown">
|
<div class="relative" id="dropdown">
|
||||||
<button
|
<button
|
||||||
aria-expanded="closed"
|
aria-expanded="false"
|
||||||
|
id="dropdownButton"
|
||||||
|
aria-label="Toggle dropdown menu"
|
||||||
onclick="toggleDropdown()"
|
onclick="toggleDropdown()"
|
||||||
type="button"
|
type="button"
|
||||||
class="inline-flex items-center justify-center whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
class="inline-flex items-center justify-center whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
||||||
@@ -248,6 +250,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
id="submitButton"
|
||||||
class="inline-flex items-center justify-center h-11 px-8 whitespace-nowrap rounded-md text-sm font-medium text-slate-200 dark:text-slate-900 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-slate-800 dark:bg-slate-200 hover:bg-slate-800/90 dark:hover:bg-slate-200/90"
|
class="inline-flex items-center justify-center h-11 px-8 whitespace-nowrap rounded-md text-sm font-medium text-slate-200 dark:text-slate-900 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-slate-800 dark:bg-slate-200 hover:bg-slate-800/90 dark:hover:bg-slate-200/90"
|
||||||
>
|
>
|
||||||
Proxy Search
|
Proxy Search
|
||||||
@@ -255,21 +258,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<footer class="mx-4 text-center text-slate-600 dark:text-slate-400">
|
<div class="flex flex-col justify-center my-4 mx-auto">
|
||||||
<p>
|
|
||||||
Code Licensed Under GPL v3.0 |
|
|
||||||
<a
|
<a
|
||||||
href="https://github.com/everywall/ladder"
|
href="/playground"
|
||||||
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
class="inline-flex items-center justify-center h-8 px-8 whitespace-nowrap no-underline rounded-md text-sm font-medium text-slate-900 dark:text-slate-200 hover:text-slate-900 hover:dark:text-slate-200 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none hover:bg-slate-200/90 dark:hover:bg-slate-800/90 border border-slate-600 dark:border-slate-400"
|
||||||
>View Source</a
|
|
||||||
>
|
>
|
||||||
|
|
Experiment with modifiers in the playground
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-4 w-4 ml-1"
|
||||||
|
>
|
||||||
|
<path d="M13 5H19V11" />
|
||||||
|
<path d="M19 5L5 19" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="mx-4 my-2 text-center text-slate-600 dark:text-slate-400">
|
||||||
|
<small>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/everywall"
|
href="https://github.com/everywall"
|
||||||
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
>Everywall</a
|
>Everywall</a
|
||||||
>
|
>
|
||||||
</p>
|
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall/ladder"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Source</a
|
||||||
|
>
|
||||||
|
| Code Licensed Under GPL v3.0
|
||||||
|
</small>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
491
handlers/playground-script.js
Normal file
491
handlers/playground-script.js
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
const modifierContainer = document.getElementById("modifierContainer");
|
||||||
|
const modalContainer = document.getElementById("modalContainer");
|
||||||
|
const modalBody = document.getElementById("modal-body");
|
||||||
|
const modalContent = document.getElementById("modal-content");
|
||||||
|
const modalSubmitButton = document.getElementById("modal-submit");
|
||||||
|
const modalClose = document.getElementById("modal-close");
|
||||||
|
|
||||||
|
let hasFetched = false;
|
||||||
|
let payload = {
|
||||||
|
requestmodifications: [],
|
||||||
|
responsemodifications: [],
|
||||||
|
};
|
||||||
|
let ninjaData = [];
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
// Rerun handleThemeChange() so style is applied to Ninja Keys
|
||||||
|
handleThemeChange();
|
||||||
|
|
||||||
|
// Add event listener to the iframe so it closes dropdown when clicked
|
||||||
|
closeDropdownOnClickWithinIframe();
|
||||||
|
|
||||||
|
async function initialize() {
|
||||||
|
if (!hasFetched) {
|
||||||
|
try {
|
||||||
|
await fetchPayload();
|
||||||
|
hasFetched = true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Fetch error:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDropdownOnClickWithinIframe() {
|
||||||
|
const iframe = document.getElementById("resultIframe");
|
||||||
|
iframe.contentWindow.document.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
if (
|
||||||
|
!document.getElementById("dropdown_panel").classList.contains("hidden")
|
||||||
|
) {
|
||||||
|
toggleDropdown();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchPayload() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/modifiers");
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
Object.entries(data.result.requestmodifiers ?? []).forEach(([_, value]) => {
|
||||||
|
addModifierToNinjaData(
|
||||||
|
value.name,
|
||||||
|
value.description,
|
||||||
|
value.params,
|
||||||
|
"requestmodifications"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(data.result.responsemodifiers ?? []).forEach(
|
||||||
|
([_, value]) => {
|
||||||
|
addModifierToNinjaData(
|
||||||
|
value.name,
|
||||||
|
value.description,
|
||||||
|
value.params,
|
||||||
|
"responsemodifications"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Fetch error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitForm() {
|
||||||
|
if (!document.getElementById("inputForm").checkValidity()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/playground/" + inputField.value, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Request failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.text();
|
||||||
|
updateResultIframe(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateResultIframe(result) {
|
||||||
|
const resultIframe = parent.document.getElementById("resultIframe");
|
||||||
|
resultIframe.contentDocument.open();
|
||||||
|
resultIframe.contentDocument.write(result);
|
||||||
|
closeDropdownOnClickWithinIframe();
|
||||||
|
resultIframe.contentDocument.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("inputForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
submitForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (navigator.userAgent.includes("Mac")) {
|
||||||
|
document.getElementById("ninjaKey").textContent = "⌘";
|
||||||
|
} else {
|
||||||
|
document.getElementById("ninjaKey").textContent = "Ctrl";
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadYaml() {
|
||||||
|
function jsonToYaml(payload) {
|
||||||
|
const jsonObject = {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
domains: [hostname],
|
||||||
|
responsemodifications: [],
|
||||||
|
requestmodifications: [],
|
||||||
|
...payload,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return jsyaml.dump(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!document.getElementById("inputForm").checkValidity()) {
|
||||||
|
alert("Please enter a valid URL.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hostname = new URL(inputField.value).hostname;
|
||||||
|
const ruleHostname = hostname.replace(/^www\./, "").replace(/\./g, "-");
|
||||||
|
const yamlString = jsonToYaml(payload);
|
||||||
|
const blob = new Blob([yamlString], { type: "text/yaml;charset=utf-8" });
|
||||||
|
const href = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = href;
|
||||||
|
link.download = `${ruleHostname}.yaml`;
|
||||||
|
link.click();
|
||||||
|
URL.revokeObjectURL(href);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValues(type, id, description, params) {
|
||||||
|
const focusTrap = trap(modalBody);
|
||||||
|
let values = [];
|
||||||
|
let existingValues = [];
|
||||||
|
const inputs = [];
|
||||||
|
const inputEventListeners = [];
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
focusTrap.destroy();
|
||||||
|
modalBody.removeEventListener("keydown", handleKeyboardEvents);
|
||||||
|
modalContainer.removeEventListener("click", handleClickOutside);
|
||||||
|
modalSubmitButton.removeEventListener("click", closeModal);
|
||||||
|
modalClose.removeEventListener("click", closeModal);
|
||||||
|
inputEventListeners.forEach((listener, index) => {
|
||||||
|
if (listener !== undefined && inputs[index] !== undefined)
|
||||||
|
inputs[index].removeEventListener("input", listener);
|
||||||
|
});
|
||||||
|
modalContent.classList.remove("relative", "h-[220px]");
|
||||||
|
inputEventListeners.length = 0;
|
||||||
|
inputs.length = 0;
|
||||||
|
modalContainer.classList.add("hidden");
|
||||||
|
modalContent.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClickOutside(e) {
|
||||||
|
if (modalBody !== null && !modalBody.contains(e.target)) {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyboardEvents(e) {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
if (e.target.tagName.toLowerCase() === "textarea") {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
modalSubmitButton.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("modal-title").textContent = id;
|
||||||
|
document.getElementById("modal-description").textContent = description;
|
||||||
|
|
||||||
|
existingValues =
|
||||||
|
payload[type].find(
|
||||||
|
(modifier) => modifier.name === id && modifier.params !== undefined
|
||||||
|
)?.params ?? [];
|
||||||
|
|
||||||
|
params.map((param, i) => {
|
||||||
|
function textareaEventListener(e) {
|
||||||
|
const codeElement = document.querySelector("code");
|
||||||
|
let text = e.target.value;
|
||||||
|
|
||||||
|
if (text[text.length - 1] == "\n") {
|
||||||
|
text += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
codeElement.innerHTML = text
|
||||||
|
.replace(new RegExp("&", "g"), "&")
|
||||||
|
.replace(new RegExp("<", "g"), "<");
|
||||||
|
|
||||||
|
Prism.highlightElement(codeElement);
|
||||||
|
values[i] = text;
|
||||||
|
syncScroll(e.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function textareaKeyEventListener(e) {
|
||||||
|
if (e.key === "Tab" && !e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
let text = e.target.value;
|
||||||
|
const start = e.target.selectionStart;
|
||||||
|
const end = e.target.selectionEnd;
|
||||||
|
e.target.value = text.substring(0, start) + "\t" + text.substring(end);
|
||||||
|
e.target.setSelectionRange(start + 1, start + 1);
|
||||||
|
e.target.dispatchEvent(new Event("input"));
|
||||||
|
}
|
||||||
|
syncScroll(e.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncScroll(el) {
|
||||||
|
const codeElement = document.querySelector("code");
|
||||||
|
codeElement.scrollTop = el.scrollTop;
|
||||||
|
codeElement.scrollLeft = el.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputEventListener(e) {
|
||||||
|
if (e.key !== "Enter") {
|
||||||
|
values[i] = e.target.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.textContent = param.name;
|
||||||
|
label.setAttribute("for", `input-${i}`);
|
||||||
|
let input;
|
||||||
|
if (param.name === "js") {
|
||||||
|
input = document.createElement("textarea");
|
||||||
|
input.type = "textarea";
|
||||||
|
input.setAttribute("spellcheck", "false");
|
||||||
|
input.placeholder = "Enter your JavaScript injection code ...";
|
||||||
|
input.classList.add(
|
||||||
|
"h-[200px]",
|
||||||
|
"w-full",
|
||||||
|
"font-mono",
|
||||||
|
"whitespace-nowrap",
|
||||||
|
"font-semibold",
|
||||||
|
"absolute",
|
||||||
|
"text-base",
|
||||||
|
"leading-6",
|
||||||
|
"rounded-md",
|
||||||
|
"ring-1",
|
||||||
|
"ring-slate-900/10",
|
||||||
|
"shadow-sm",
|
||||||
|
"z-10",
|
||||||
|
"p-4",
|
||||||
|
"m-0",
|
||||||
|
"my-2",
|
||||||
|
"bg-transparent",
|
||||||
|
"dark:bg-transparent",
|
||||||
|
"text-transparent",
|
||||||
|
"overflow-auto",
|
||||||
|
"resize-none",
|
||||||
|
"caret-white",
|
||||||
|
"hover:ring-slate-300",
|
||||||
|
"hyphens-none"
|
||||||
|
);
|
||||||
|
input.style.tabSize = "4";
|
||||||
|
} else {
|
||||||
|
input = document.createElement("input");
|
||||||
|
input.type = "text";
|
||||||
|
input.classList.add(
|
||||||
|
"w-full",
|
||||||
|
"text-sm",
|
||||||
|
"leading-6",
|
||||||
|
"text-slate-400",
|
||||||
|
"rounded-md",
|
||||||
|
"ring-1",
|
||||||
|
"ring-slate-900/10",
|
||||||
|
"shadow-sm",
|
||||||
|
"py-1.5",
|
||||||
|
"pl-2",
|
||||||
|
"pr-3",
|
||||||
|
"mt-0",
|
||||||
|
"hover:ring-slate-300",
|
||||||
|
"dark:bg-slate-800",
|
||||||
|
"dark:highlight-white/5",
|
||||||
|
"overflow-auto"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
input.id = `input-${i}`;
|
||||||
|
input.value = existingValues[i] ?? "";
|
||||||
|
modalContent.appendChild(label);
|
||||||
|
modalContent.appendChild(input);
|
||||||
|
if (input.type === "textarea") {
|
||||||
|
label.classList.add("sr-only", "hidden");
|
||||||
|
preElement = document.createElement("pre");
|
||||||
|
codeElement = document.createElement("code");
|
||||||
|
preElement.setAttribute("aria-hidden", "true");
|
||||||
|
preElement.classList.add(
|
||||||
|
"bg-[#2d2d2d]",
|
||||||
|
"dark:bg-[#2d2d2d]",
|
||||||
|
"h-[200px]",
|
||||||
|
"w-full",
|
||||||
|
"rounded-md",
|
||||||
|
"ring-1",
|
||||||
|
"ring-slate-900/10",
|
||||||
|
"shadow-sm",
|
||||||
|
"p-0",
|
||||||
|
"m-0",
|
||||||
|
"my-2",
|
||||||
|
"font-mono",
|
||||||
|
"text-base",
|
||||||
|
"leading-6",
|
||||||
|
"overflow-auto",
|
||||||
|
"whitespace-nowrap",
|
||||||
|
"font-semibold",
|
||||||
|
"absolute",
|
||||||
|
"z-0",
|
||||||
|
"hyphens-none"
|
||||||
|
);
|
||||||
|
modalContent.classList.add("relative", "h-[220px]");
|
||||||
|
preElement.setAttribute("tabindex", "-1");
|
||||||
|
codeElement.classList.add(
|
||||||
|
"language-javascript",
|
||||||
|
"absolute",
|
||||||
|
"w-full",
|
||||||
|
"font-mono",
|
||||||
|
"text-base",
|
||||||
|
"leading-6",
|
||||||
|
"z-0",
|
||||||
|
"p-4",
|
||||||
|
"-mx-4",
|
||||||
|
"-my-4",
|
||||||
|
"h-full",
|
||||||
|
"whitespace-nowrap",
|
||||||
|
"overflow-auto",
|
||||||
|
"hyphens-none"
|
||||||
|
);
|
||||||
|
preElement.appendChild(codeElement);
|
||||||
|
modalContent.appendChild(preElement);
|
||||||
|
codeElement.innerHTML = input.value
|
||||||
|
.replace(new RegExp("&", "g"), "&")
|
||||||
|
.replace(new RegExp("<", "g"), "<");
|
||||||
|
Prism.highlightElement(codeElement);
|
||||||
|
input.addEventListener("input", textareaEventListener);
|
||||||
|
input.addEventListener("keydown", textareaKeyEventListener);
|
||||||
|
input.addEventListener("scroll", () => syncScroll(input));
|
||||||
|
inputEventListeners.push(
|
||||||
|
textareaEventListener,
|
||||||
|
textareaKeyEventListener,
|
||||||
|
syncScroll
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
input.addEventListener("input", inputEventListener);
|
||||||
|
inputEventListeners.push(inputEventListener);
|
||||||
|
}
|
||||||
|
inputs.push(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
modalContainer.classList.remove("hidden");
|
||||||
|
document.getElementById("input-0").focus();
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
modalBody.addEventListener("keydown", handleKeyboardEvents);
|
||||||
|
modalContainer.addEventListener("click", handleClickOutside);
|
||||||
|
modalClose.addEventListener("click", () => {
|
||||||
|
closeModal();
|
||||||
|
});
|
||||||
|
modalSubmitButton.addEventListener("click", (e) => {
|
||||||
|
inputs.forEach((input, i) => {
|
||||||
|
values[i] = input.value;
|
||||||
|
});
|
||||||
|
resolve(values);
|
||||||
|
closeModal();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleModifier(type, id, params = []) {
|
||||||
|
function pillClickHandler(pill) {
|
||||||
|
toggleModifier(pill.getAttribute("type"), pill.id);
|
||||||
|
pill.removeEventListener("click", () => pillClickHandler(pill));
|
||||||
|
pill.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPill(type, id) {
|
||||||
|
const pill = document.createElement("span");
|
||||||
|
pill.classList.add(
|
||||||
|
"inline-flex",
|
||||||
|
"items-center",
|
||||||
|
"rounded-md",
|
||||||
|
"bg-slate-100",
|
||||||
|
"dark:bg-slate-800",
|
||||||
|
"px-2",
|
||||||
|
"py-1",
|
||||||
|
"h-4",
|
||||||
|
"text-xs",
|
||||||
|
"font-medium",
|
||||||
|
"border",
|
||||||
|
"border-slate-400",
|
||||||
|
"dark:border-slate-700",
|
||||||
|
"cursor-pointer"
|
||||||
|
);
|
||||||
|
pill.id = id;
|
||||||
|
pill.setAttribute("type", type);
|
||||||
|
pill.textContent = id;
|
||||||
|
modifierContainer.appendChild(pill);
|
||||||
|
pill.addEventListener("click", () => pillClickHandler(pill));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
params === undefined &&
|
||||||
|
payload[type].some((modifier) => modifier.name === id)
|
||||||
|
) {
|
||||||
|
payload[type] = payload[type].filter((modifier) => modifier.name !== id);
|
||||||
|
const existingPill = document.getElementById(id);
|
||||||
|
if (existingPill !== null) {
|
||||||
|
existingPill.removeEventListener("click", () => pillClickHandler(pill));
|
||||||
|
existingPill.remove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const existingModifier = payload[type].find(
|
||||||
|
(modifier) => modifier.name === id
|
||||||
|
);
|
||||||
|
if (existingModifier) {
|
||||||
|
existingModifier.params = params;
|
||||||
|
} else {
|
||||||
|
payload[type].push({ name: id, params: params });
|
||||||
|
}
|
||||||
|
const existingPill = document.getElementById(id);
|
||||||
|
if (existingPill === null) {
|
||||||
|
createPill(type, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
submitForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addModifierToNinjaData(id, description, params, type) {
|
||||||
|
const section =
|
||||||
|
type === "requestmodifications"
|
||||||
|
? "Request Modifiers"
|
||||||
|
: "Response Modifiers";
|
||||||
|
const modifier = {
|
||||||
|
id: id,
|
||||||
|
title: id,
|
||||||
|
section: section,
|
||||||
|
|
||||||
|
handler: () => {
|
||||||
|
if (Object.keys(params).length === 0) {
|
||||||
|
toggleModifier(type, id);
|
||||||
|
} else {
|
||||||
|
if (params[0].name === "_") {
|
||||||
|
toggleModifier(type, id, (params = [""]));
|
||||||
|
} else {
|
||||||
|
getValues(type, id, description, params).then((values) => {
|
||||||
|
if (Object.keys(values).length === 0) return;
|
||||||
|
toggleModifier(type, id, values);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ninjaData.push(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ninja = document.querySelector("ninja-keys");
|
||||||
|
ninja.data = ninjaData;
|
||||||
|
document.getElementById("btnNinja").addEventListener("click", () => {
|
||||||
|
ninja.open();
|
||||||
|
});
|
||||||
42
handlers/playground.go
Normal file
42
handlers/playground.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/everywall/ladder/proxychain"
|
||||||
|
ruleset_v2 "github.com/everywall/ladder/proxychain/ruleset"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed playground.html
|
||||||
|
var playgroundHtml string
|
||||||
|
|
||||||
|
func PlaygroundHandler(path string, opts *ProxyOptions) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
if c.Method() == fiber.MethodGet {
|
||||||
|
c.Set("Content-Type", "text/html")
|
||||||
|
|
||||||
|
return c.SendString(playgroundHtml)
|
||||||
|
} else if c.Method() == fiber.MethodPost {
|
||||||
|
var modificationData ruleset_v2.Rule
|
||||||
|
if err := c.BodyParser(&modificationData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Method(fiber.MethodGet)
|
||||||
|
|
||||||
|
return proxychain.
|
||||||
|
NewProxyChain().
|
||||||
|
SetFiberCtx(c).
|
||||||
|
WithAPIPath(path).
|
||||||
|
AddOnceRequestModifications(modificationData.RequestModifications...).
|
||||||
|
AddOnceResponseModifications(modificationData.ResponseModifications...).
|
||||||
|
Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(http.StatusMethodNotAllowed).SendString("Method not allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
451
handlers/playground.html
Normal file
451
handlers/playground.html
Normal file
@@ -0,0 +1,451 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>ladder | playground</title>
|
||||||
|
<link rel="stylesheet" href="/styles.css" />
|
||||||
|
<style>
|
||||||
|
#modifierContainer::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
#modifierContainer::-webkit-scrollbar-track {
|
||||||
|
background: rgb(226 232 240);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
#modifierContainer::-webkit-scrollbar-thumb {
|
||||||
|
background: rgb(100 116 139);
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
ninja-keys {
|
||||||
|
--ninja-accent-color: #7aa7d1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="/script.js" defer></script>
|
||||||
|
<script src="/playground-script.js" defer></script>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"https://unpkg.com/lit-html@latest/directives/ref.js?module": "https://unpkg.com/lit-html@2.2.6/directives/ref.js?module"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="module" src="https://unpkg.com/ninja-keys?module"></script>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/prism/9000.0.1/themes/prism-tomorrow.min.css"
|
||||||
|
integrity="sha512-kSwGoyIkfz4+hMo5jkJngSByil9jxJPKbweYec/UgS+S1EgE45qm4Gea7Ks2oxQ7qiYyyZRn66A9df2lMtjIsw=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/prism/9000.0.1/prism.min.js"
|
||||||
|
integrity="sha512-UOoJElONeUNzQbbKQbjldDf9MwOHqxNz49NNJJ1d90yp+X9edsHyJoAs6O4K19CZGaIdjI5ohK+O2y5lBTW6uQ=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"
|
||||||
|
integrity="sha512-CSBhVREyzHAjAFfBlIBakjoRUKp5h7VSweP0InR/pAJyptH7peuhCsqAI/snV+TwZmXZqoUklpXp6R6wMnYf5Q=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
></script>
|
||||||
|
<script>
|
||||||
|
const handleThemeChange = () => {
|
||||||
|
let theme = localStorage.getItem("theme");
|
||||||
|
if (theme === null) {
|
||||||
|
localStorage.setItem("theme", "system");
|
||||||
|
theme = "system";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
theme === "dark" ||
|
||||||
|
(theme === "system" &&
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||||
|
) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
const ninjaKeys = document.querySelector("ninja-keys");
|
||||||
|
if (ninjaKeys !== null) ninjaKeys.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("dark");
|
||||||
|
const ninjaKeys = document.querySelector("ninja-keys");
|
||||||
|
if (ninjaKeys !== null) ninjaKeys.classList.remove("dark");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handleThemeChange();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body
|
||||||
|
class="antialiased bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-200"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col h-screen">
|
||||||
|
<div
|
||||||
|
class="fixed top-0 inset-x-0 h-48 flex-col gap-4 max-w-3xl mx-4 lg:mx-auto pt-4"
|
||||||
|
>
|
||||||
|
<header class="flex flex-col gap-2">
|
||||||
|
<div class="flex justify-between place-items-center">
|
||||||
|
<div
|
||||||
|
class="hover:drop-shadow-[0_0px_4px_rgba(122,167,209,.3)] ring-offset-white dark:ring-offset-slate-900 transition-colors duration-300 focus:outline-none focus:ring ring-offset-2"
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
aria-label="ladder"
|
||||||
|
class="flex -ml-2 h-8 font-extrabold tracking-tight no-underline focus:outline-none ring-offset-white dark:ring-offset-slate-900 focus:ring ring-offset-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
class="h-8 focus:outline-none focus:ring ring-offset-white dark:ring-offset-slate-900 ring-offset-2"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#7AA7D1"
|
||||||
|
d="M262.074 485.246C254.809 485.265 247.407 485.534 240.165 484.99L226.178 483.306C119.737 468.826 34.1354 383.43 25.3176 274.714C24.3655 262.975 23.5876 253.161 24.3295 241.148C31.4284 126.212 123.985 31.919 238.633 24.1259L250.022 23.8366C258.02 23.8001 266.212 23.491 274.183 24.1306C320.519 27.8489 366.348 45.9743 402.232 75.4548L416.996 88.2751C444.342 114.373 464.257 146.819 475.911 182.72L480.415 197.211C486.174 219.054 488.67 242.773 487.436 265.259L486.416 275.75C478.783 352.041 436.405 418.1 369.36 455.394L355.463 462.875C326.247 477.031 294.517 484.631 262.074 485.246ZM253.547 72.4475C161.905 73.0454 83.5901 144.289 73.0095 234.5C69.9101 260.926 74.7763 292.594 83.9003 317.156C104.53 372.691 153.9 416.616 211.281 430.903C226.663 434.733 242.223 436.307 258.044 436.227C353.394 435.507 430.296 361.835 438.445 267.978C439.794 252.442 438.591 236.759 435.59 221.5C419.554 139.955 353.067 79.4187 269.856 72.7052C264.479 72.2714 258.981 72.423 253.586 72.4127L253.547 72.4475Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#7AA7D1"
|
||||||
|
d="M153.196 310.121L133.153 285.021C140.83 283.798 148.978 285.092 156.741 284.353L156.637 277.725L124.406 278.002C123.298 277.325 122.856 276.187 122.058 275.193L116.089 267.862C110.469 260.975 103.827 254.843 98.6026 247.669C103.918 246.839 105.248 246.537 111.14 246.523L129.093 246.327C130.152 238.785 128.62 240.843 122.138 240.758C111.929 240.623 110.659 242.014 105.004 234.661L97.9953 225.654C94.8172 221.729 91.2219 218.104 88.2631 214.005C84.1351 208.286 90.1658 209.504 94.601 209.489L236.752 209.545C257.761 209.569 268.184 211.009 285.766 221.678L285.835 206.051C285.837 197.542 286.201 189.141 284.549 180.748C280.22 158.757 260.541 143.877 240.897 135.739C238.055 134.561 232.259 133.654 235.575 129.851C244.784 119.288 263.680 111.990 277.085 111.105C288.697 109.828 301.096 113.537 311.75 117.703C360.649 136.827 393.225 183.042 398.561 234.866C402.204 270.253 391.733 308.356 367.999 335.1C332.832 374.727 269.877 384.883 223.294 360.397C206.156 351.388 183.673 333.299 175.08 316.6C173.511 313.551 174.005 313.555 170.443 313.52L160.641 313.449C158.957 313.435 156.263 314.031 155.122 312.487L153.196 310.121Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
class="text-3xl ml-1 text-[#7AA7D1] leading-8 align-middle"
|
||||||
|
>ladder</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
<span
|
||||||
|
class="text-3xl mx-1 text-[#7AA7D1] leading-8 align-middle"
|
||||||
|
>|</span
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/playground"
|
||||||
|
class="flex h-8 font-extrabold tracking-tight no-underline focus:outline-none focus:ring ring-offset-2 ring-offset-white dark:ring-offset"
|
||||||
|
>
|
||||||
|
<span class="text-3xl text-[#7AA7D1] leading-8 align-middle"
|
||||||
|
>playground</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-center z-10">
|
||||||
|
<div class="relative" id="dropdown">
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
id="dropdownButton"
|
||||||
|
aria-label="Toggle dropdown menu"
|
||||||
|
onclick="toggleDropdown()"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-center whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-white dark:ring-offset transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"
|
||||||
|
/>
|
||||||
|
<circle cx="12" cy="12" r="3" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="dropdown_panel"
|
||||||
|
class="hidden absolute right-0 mt-2 w-52 rounded-md bg-white dark:bg-slate-900 shadow-md border border-slate-400 dark:border-slate-700"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-2 w-full first-of-type:rounded-t-md last-of-type:rounded-b-md px-4 py-2.5 text-left text-sm"
|
||||||
|
>
|
||||||
|
Appearance
|
||||||
|
<div class="grid grid-cols-4 gap-2">
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="light"
|
||||||
|
value="light"
|
||||||
|
class="peer hidden"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="light"
|
||||||
|
tabindex="0"
|
||||||
|
title="Light"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-sm text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="4" />
|
||||||
|
<path d="M12 2v2" />
|
||||||
|
<path d="M12 20v2" />
|
||||||
|
<path d="m4.93 4.93 1.41 1.41" />
|
||||||
|
<path d="m17.66 17.66 1.41 1.41" />
|
||||||
|
<path d="M2 12h2" />
|
||||||
|
<path d="M20 12h2" />
|
||||||
|
<path d="m6.34 17.66-1.41 1.41" />
|
||||||
|
<path d="m19.07 4.93-1.41 1.41" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="dark"
|
||||||
|
value="dark"
|
||||||
|
class="peer hidden"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="dark"
|
||||||
|
tabindex="0"
|
||||||
|
title="Dark"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-base text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
id="system"
|
||||||
|
value="system"
|
||||||
|
class="peer hidden"
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="system"
|
||||||
|
tabindex="0"
|
||||||
|
title="System preference"
|
||||||
|
class="flex items-end justify-center h-10 w-10 cursor-pointer select-none rounded-md p-2 text-lg text-slate-600 dark:text-slate-200 text-center hover:bg-slate-200 dark:hover:bg-slate-700 peer-checked:bg-slate-200 dark:peer-checked:bg-slate-700"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-5 w-5"
|
||||||
|
>
|
||||||
|
<path d="M12 8a2.83 2.83 0 0 0 4 4 4 4 0 1 1-4-4" />
|
||||||
|
<path d="M12 2v2" />
|
||||||
|
<path d="M12 20v2" />
|
||||||
|
<path d="m4.9 4.9 1.4 1.4" />
|
||||||
|
<path d="m17.7 17.7 1.4 1.4" />
|
||||||
|
<path d="M2 12h2" />
|
||||||
|
<path d="M20 12h2" />
|
||||||
|
<path d="m6.3 17.7-1.4 1.4" />
|
||||||
|
<path d="m19.1 4.9-1.4 1.4" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form id="inputForm" method="get" class="flex flex-col gap-2 mx-4">
|
||||||
|
<div class="flex gap-6">
|
||||||
|
<div class="flex-1 relative">
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
id="inputField"
|
||||||
|
placeholder="Enter URL"
|
||||||
|
name="inputField"
|
||||||
|
class="w-full text-sm leading-6 text-slate-400 rounded-md ring-1 ring-slate-900/10 shadow-sm py-1.5 pl-2 pr-3 hover:ring-slate-300 dark:bg-slate-800 dark:highlight-white/5 dark:hover:bg-slate-700"
|
||||||
|
autocomplete="off"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
id="clearButton"
|
||||||
|
type="reset"
|
||||||
|
aria-label="Clear Search"
|
||||||
|
title="Clear Search"
|
||||||
|
class="hidden absolute inset-y-0 right-0 items-center pr-2 text-slate-600 dark:text-slate-400 hover:text-slate-400 hover:dark:text-slate-300"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="h-4 w-4"
|
||||||
|
>
|
||||||
|
<path d="M18 6 6 18" />
|
||||||
|
<path d="m6 6 12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
id="btnNinja"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-center h-8 px-8 my-auto whitespace-nowrap rounded-xl text-sm font-medium text-slate-900 dark:text-slate-200 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200/90 dark:hover:bg-slate-800/90 border hover:bg-slate-200 dark:hover:bg-slate-500"
|
||||||
|
>
|
||||||
|
Press <span id="ninjaKey">⌘</span> + K to Apply
|
||||||
|
Modifiers
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="mt-2 mx-4 flex justify-between gap-2">
|
||||||
|
<div
|
||||||
|
id="modifierContainer"
|
||||||
|
class="flex flex-wrap grow overflow-y-auto max-h-14 w-full gap-1"
|
||||||
|
></div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-center h-11 px-4 py-2 whitespace-nowrap rounded-md text-sm font-medium text-slate-200 dark:text-slate-900 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-slate-800 dark:bg-slate-200 hover:bg-slate-800/90 dark:hover:bg-slate-200/90"
|
||||||
|
onclick="downloadYaml()"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="pl-0 mr-2 w-5 h-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"
|
||||||
|
/>
|
||||||
|
<polyline points="14 2 14 8 20 8" />
|
||||||
|
<path d="M12 18v-6" />
|
||||||
|
<path d="m9 15 3 3 3-3" />
|
||||||
|
</svg>
|
||||||
|
Export Rule
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<iframe
|
||||||
|
name="resultIframe"
|
||||||
|
id="resultIframe"
|
||||||
|
title="resultIframe"
|
||||||
|
class="mt-48 h-[calc(100vh-14.5rem)] w-full overflow-x-hidden overflow-y-auto border-t-2 border-b-2 border-slate-400 dark:border-slate-700"
|
||||||
|
></iframe>
|
||||||
|
|
||||||
|
<footer class="mx-4 my-2 text-center text-slate-600 dark:text-slate-400">
|
||||||
|
<small>
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Everywall</a
|
||||||
|
>
|
||||||
|
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall/ladder"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Source</a
|
||||||
|
>
|
||||||
|
| Code Licensed Under GPL v3.0
|
||||||
|
</small>
|
||||||
|
</footer>
|
||||||
|
<div
|
||||||
|
id="modalContainer"
|
||||||
|
tabindex="-1"
|
||||||
|
class="hidden relative z-10"
|
||||||
|
aria-labelledby="modal"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<div class="fixed inset-0 bg-slate-500/50 transition-opacity"></div>
|
||||||
|
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
|
||||||
|
<div
|
||||||
|
class="flex min-h-full items-center justify-center p-4 text-center sm:p-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id="modal-body"
|
||||||
|
class="relative transform overflow-hidden rounded-lg bg-white dark:bg-slate-900 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg"
|
||||||
|
>
|
||||||
|
<form>
|
||||||
|
<div class="px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
|
||||||
|
<div class="mt-3 text-left sm:ml-4 sm:mt-0">
|
||||||
|
<div class="flex w-full justify-between items-center">
|
||||||
|
<h3 id="modal-title">MODAL HEADER</h3>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="modal-close"
|
||||||
|
class="ml-2 text-slate-600 dark:text-slate-400 hover:text-slate-400 hover:dark:text-slate-300 bg-transparent text-sm w-6 h-6 inline-flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M18 6 6 18" />
|
||||||
|
<path d="m6 6 12 12" />
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Close modal</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<p id="modal-description">DESCRIPTION</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="my-2 flex flex-col gap-2 w-full"
|
||||||
|
id="modal-content"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-slate-200 dark:bg-slate-800 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="modal-submit"
|
||||||
|
class="inline-flex items-center justify-center h-11 px-4 py-2 whitespace-nowrap rounded-md text-sm font-medium text-slate-200 dark:text-slate-900 ring-offset-white dark:ring-offset-slate-900 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-slate-800 dark:bg-slate-200 hover:bg-slate-800/90 dark:hover:bg-slate-200/90"
|
||||||
|
>
|
||||||
|
Apply modification
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ninja-keys> </ninja-keys>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -45,7 +45,7 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler {
|
|||||||
).
|
).
|
||||||
AddResponseModifications(
|
AddResponseModifications(
|
||||||
tx.ForwardResponseHeaders(),
|
tx.ForwardResponseHeaders(),
|
||||||
//tx.BlockThirdPartyScripts(),
|
tx.BlockThirdPartyScripts(),
|
||||||
tx.DeleteIncomingCookies(),
|
tx.DeleteIncomingCookies(),
|
||||||
tx.DeleteLocalStorageData(),
|
tx.DeleteLocalStorageData(),
|
||||||
tx.DeleteSessionStorageData(),
|
tx.DeleteSessionStorageData(),
|
||||||
@@ -54,7 +54,7 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler {
|
|||||||
tx.RewriteHTMLResourceURLs(),
|
tx.RewriteHTMLResourceURLs(),
|
||||||
tx.PatchDynamicResourceURLs(),
|
tx.PatchDynamicResourceURLs(),
|
||||||
tx.PatchTrackerScripts(),
|
tx.PatchTrackerScripts(),
|
||||||
tx.BlockElementRemoval(".article-content"), // techcrunch
|
//tx.BlockElementRemoval(".article-content"), // techcrunch
|
||||||
//tx.BlockElementRemoval(".available-content"), // substack
|
//tx.BlockElementRemoval(".available-content"), // substack
|
||||||
// tx.SetContentSecurityPolicy("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"),
|
// tx.SetContentSecurityPolicy("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,15 +9,25 @@ import (
|
|||||||
//go:embed script.js
|
//go:embed script.js
|
||||||
var scriptData embed.FS
|
var scriptData embed.FS
|
||||||
|
|
||||||
func Script(c *fiber.Ctx) error {
|
//go:embed playground-script.js
|
||||||
|
var playgroundScriptData embed.FS
|
||||||
|
|
||||||
|
func Script(c *fiber.Ctx) error {
|
||||||
|
if c.Path() == "/script.js" {
|
||||||
scriptData, err := scriptData.ReadFile("script.js")
|
scriptData, err := scriptData.ReadFile("script.js")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
|
return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Set("Content-Type", "text/javascript")
|
c.Set("Content-Type", "text/javascript")
|
||||||
|
|
||||||
return c.Send(scriptData)
|
return c.Send(scriptData)
|
||||||
|
}
|
||||||
|
if c.Path() == "/playground-script.js" {
|
||||||
|
playgroundScriptData, err := playgroundScriptData.ReadFile("playground-script.js")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
|
||||||
|
}
|
||||||
|
c.Set("Content-Type", "text/javascript")
|
||||||
|
return c.Send(playgroundScriptData)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,11 +111,13 @@ function trap(node) {
|
|||||||
|
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
const dropdown = document.getElementById("dropdown");
|
const dropdown = document.getElementById("dropdown");
|
||||||
|
const dropdown_button = dropdown.querySelector("button");
|
||||||
const dropdown_panel = document.getElementById("dropdown_panel");
|
const dropdown_panel = document.getElementById("dropdown_panel");
|
||||||
const focusTrap = trap(dropdown);
|
const focusTrap = trap(dropdown);
|
||||||
|
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
dropdown_panel.classList.add("hidden");
|
dropdown_panel.classList.add("hidden");
|
||||||
|
dropdown_button.setAttribute("aria-expanded", "false");
|
||||||
focusTrap.destroy();
|
focusTrap.destroy();
|
||||||
dropdown.removeEventListener("keydown", handleEscapeKey);
|
dropdown.removeEventListener("keydown", handleEscapeKey);
|
||||||
document.removeEventListener("click", handleClickOutside);
|
document.removeEventListener("click", handleClickOutside);
|
||||||
@@ -175,6 +177,7 @@ const toggleDropdown = () => {
|
|||||||
|
|
||||||
if (dropdown_panel.classList.contains("hidden")) {
|
if (dropdown_panel.classList.contains("hidden")) {
|
||||||
dropdown_panel.classList.remove("hidden");
|
dropdown_panel.classList.remove("hidden");
|
||||||
|
dropdown_button.setAttribute("aria-expanded", "true");
|
||||||
dropdown.addEventListener("keydown", handleEscapeKey);
|
dropdown.addEventListener("keydown", handleEscapeKey);
|
||||||
inputs.forEach((input) => {
|
inputs.forEach((input) => {
|
||||||
input.addEventListener("change", handleInputChange);
|
input.addEventListener("change", handleInputChange);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,14 +3,15 @@ package proxychain
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
http "github.com/bogdanfinn/fhttp"
|
|
||||||
tls_client "github.com/bogdanfinn/tls-client"
|
|
||||||
profiles "github.com/bogdanfinn/tls-client/profiles"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
http "github.com/bogdanfinn/fhttp"
|
||||||
|
tls_client "github.com/bogdanfinn/tls-client"
|
||||||
|
profiles "github.com/bogdanfinn/tls-client/profiles"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -398,7 +399,7 @@ func (chain *ProxyChain) abort(err error) error {
|
|||||||
} else {
|
} else {
|
||||||
e = fmt.Errorf("ProxyChain error: '%s'", err.Error())
|
e = fmt.Errorf("ProxyChain error: '%s'", err.Error())
|
||||||
}
|
}
|
||||||
chain.Context.SendString(e.Error())
|
// chain.Context.SendString(e.Error()) // <- RenderErrorPage middleware to render error
|
||||||
log.Println(e.Error())
|
log.Println(e.Error())
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,15 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/everywall/ladder/proxychain"
|
"github.com/everywall/ladder/proxychain"
|
||||||
|
"github.com/markusmobius/go-trafilatura"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
"golang.org/x/net/html/atom"
|
"golang.org/x/net/html/atom"
|
||||||
|
|
||||||
//"github.com/go-shiori/dom"
|
|
||||||
"github.com/markusmobius/go-trafilatura"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed vendor/generate_readable_outline.html
|
//go:embed vendor/generate_readable_outline.html
|
||||||
@@ -63,19 +62,24 @@ func GenerateReadableOutline() proxychain.ResponseModification {
|
|||||||
html.Render(&b, extract.ContentNode)
|
html.Render(&b, extract.ContentNode)
|
||||||
distilledHTML := b.String()
|
distilledHTML := b.String()
|
||||||
|
|
||||||
|
siteName := strings.Split(extract.Metadata.Sitename, ";")[0]
|
||||||
|
title := strings.Split(extract.Metadata.Title, "|")[0]
|
||||||
|
fmtDate := createWikipediaDateLink(extract.Metadata.Date)
|
||||||
|
readingTime := formatDuration(estimateReadingTime(extract.ContentText))
|
||||||
|
|
||||||
// populate template parameters
|
// populate template parameters
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Success": true,
|
"Success": true,
|
||||||
"Image": extract.Metadata.Image,
|
"Image": extract.Metadata.Image,
|
||||||
"Description": extract.Metadata.Description,
|
"Description": extract.Metadata.Description,
|
||||||
"Sitename": extract.Metadata.Sitename,
|
"Sitename": siteName,
|
||||||
"Hostname": extract.Metadata.Hostname,
|
"Hostname": extract.Metadata.Hostname,
|
||||||
"Url": "/" + chain.Request.URL.String(),
|
"Url": "/" + chain.Request.URL.String(),
|
||||||
"Title": extract.Metadata.Title, // todo: modify CreateReadableDocument so we don't have <h1> titles duplicated?
|
"Title": title,
|
||||||
"Date": extract.Metadata.Date.String(),
|
"Date": fmtDate,
|
||||||
"Author": createWikipediaSearchLinks(extract.Metadata.Author),
|
"Author": createDDGFeelingLuckyLinks(extract.Metadata.Author, extract.Metadata.Hostname),
|
||||||
//"Author": extract.Metadata.Author,
|
|
||||||
"Body": distilledHTML,
|
"Body": distilledHTML,
|
||||||
|
"ReadingTime": readingTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -157,9 +161,20 @@ func rewriteHrefLinks(n *html.Node, baseURL string, apiPath string) {
|
|||||||
recurse(n)
|
recurse(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createWikipediaSearchLinks takes in comma or semicolon separated terms,
|
// createWikipediaDateLink takes in a date
|
||||||
// then turns them into <a> links searching for the term.
|
// and returns an <a> link pointing to the current events page for that day
|
||||||
func createWikipediaSearchLinks(searchTerms string) string {
|
func createWikipediaDateLink(t time.Time) string {
|
||||||
|
url := fmt.Sprintf("https://en.wikipedia.org/wiki/Portal:Current_events#%s", t.Format("2006_January_02"))
|
||||||
|
date := t.Format("January 02, 2006")
|
||||||
|
return fmt.Sprintf("<a rel=\"noreferrer\" href=\"%s\">%s</a>", url, date)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDDGFeelingLuckyLinks takes in comma or semicolon separated terms,
|
||||||
|
// then turns them into <a> links searching for the term using DuckDuckGo's I'm
|
||||||
|
// feeling lucky feature. It will redirect the user immediately to the first search result.
|
||||||
|
func createDDGFeelingLuckyLinks(searchTerms string, siteHostname string) string {
|
||||||
|
|
||||||
|
siteHostname = strings.TrimSpace(siteHostname)
|
||||||
semiColonSplit := strings.Split(searchTerms, ";")
|
semiColonSplit := strings.Split(searchTerms, ";")
|
||||||
|
|
||||||
var links []string
|
var links []string
|
||||||
@@ -171,11 +186,13 @@ func createWikipediaSearchLinks(searchTerms string) string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
encodedTerm := url.QueryEscape(trimmedTerm)
|
ddgQuery := fmt.Sprintf(` site:%s intitle:"%s"`, strings.TrimPrefix(siteHostname, "www."), trimmedTerm)
|
||||||
|
|
||||||
wikiURL := fmt.Sprintf("https://en.wikipedia.org/w/index.php?search=%s", encodedTerm)
|
encodedTerm := `\%s:` + url.QueryEscape(ddgQuery)
|
||||||
|
//ddgURL := `https://html.duckduckgo.com/html/?q=` + encodedTerm
|
||||||
|
ddgURL := `https://www.duckduckgo.com/?q=` + encodedTerm
|
||||||
|
|
||||||
link := fmt.Sprintf("<a href=\"%s\">%s</a>", wikiURL, trimmedTerm)
|
link := fmt.Sprintf("<a rel=\"noreferrer\" href=\"%s\">%s</a>", ddgURL, trimmedTerm)
|
||||||
links = append(links, link)
|
links = append(links, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,3 +204,66 @@ func createWikipediaSearchLinks(searchTerms string) string {
|
|||||||
|
|
||||||
return strings.Join(links, " ")
|
return strings.Join(links, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// estimateReadingTime estimates how long the given text will take to read using the given configuration.
|
||||||
|
func estimateReadingTime(text string) time.Duration {
|
||||||
|
if len(text) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init options with default values.
|
||||||
|
WordsPerMinute := 200
|
||||||
|
WordBound := func(b byte) bool {
|
||||||
|
return b == ' ' || b == '\n' || b == '\r' || b == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
|
words := 0
|
||||||
|
start := 0
|
||||||
|
end := len(text) - 1
|
||||||
|
|
||||||
|
// Fetch bounds.
|
||||||
|
for WordBound(text[start]) {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
for WordBound(text[end]) {
|
||||||
|
end--
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the number of words.
|
||||||
|
for i := start; i <= end; {
|
||||||
|
for i <= end && !WordBound(text[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
words++
|
||||||
|
|
||||||
|
for i <= end && WordBound(text[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading time stats.
|
||||||
|
minutes := math.Ceil(float64(words) / float64(WordsPerMinute))
|
||||||
|
duration := time.Duration(math.Ceil(minutes) * float64(time.Minute))
|
||||||
|
|
||||||
|
return duration
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatDuration(d time.Duration) string {
|
||||||
|
// Check if the duration is less than one minute
|
||||||
|
if d < time.Minute {
|
||||||
|
seconds := int(d.Seconds())
|
||||||
|
return fmt.Sprintf("%d seconds", seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the duration to minutes
|
||||||
|
minutes := int(d.Minutes())
|
||||||
|
|
||||||
|
// Format the string for one or more minutes
|
||||||
|
if minutes == 1 {
|
||||||
|
return "1 minute"
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%d minutes", minutes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package responsemodifiers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/everywall/ladder/proxychain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModifyIncomingScriptsWithRegex modifies all incoming javascript (application/javascript and inline <script> in text/html) using a regex match and replacement.
|
||||||
|
func ModifyIncomingScriptsWithRegex(matchRegex string, replacement string) proxychain.ResponseModification {
|
||||||
|
return func(chain *proxychain.ProxyChain) error {
|
||||||
|
path := chain.Request.URL.Path
|
||||||
|
ct := chain.Response.Header.Get("content-type")
|
||||||
|
isJavascript := strings.HasSuffix(path, ".js") || ct == "text/javascript" || ct == "application/javascript"
|
||||||
|
isHTML := strings.HasSuffix(chain.Request.URL.Path, ".html") || ct == "text/html"
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isJavascript:
|
||||||
|
rBody, err := modifyResponse(chain.Response.Body, matchRegex, replacement)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chain.Response.Body = rBody
|
||||||
|
case isHTML:
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyResponse(body io.ReadCloser, matchRegex, replacement string) (io.ReadCloser, error) {
|
||||||
|
content, err := io.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(matchRegex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedContent := re.ReplaceAll(content, []byte(replacement))
|
||||||
|
|
||||||
|
return io.NopCloser(bytes.NewReader(modifiedContent)), nil
|
||||||
|
}
|
||||||
@@ -52,6 +52,19 @@ func PatchDynamicResourceURLs() proxychain.ResponseModification {
|
|||||||
htmlRewriter := rewriters.NewHTMLRewriter(chain.Response.Body, rr)
|
htmlRewriter := rewriters.NewHTMLRewriter(chain.Response.Body, rr)
|
||||||
chain.Response.Body = htmlRewriter
|
chain.Response.Body = htmlRewriter
|
||||||
|
|
||||||
|
// window.location
|
||||||
|
/*
|
||||||
|
spoofedLocationAPI := fmt.Sprintf(`{href:"%s", origin:"%s", pathname:"%s", protocol:"%s:", port:"%s"}`,
|
||||||
|
reqURL.String(), reqURL.Host,
|
||||||
|
reqURL.Path, reqURL.Scheme, reqURL.Port())
|
||||||
|
spoofedLocationAPI := fmt.Sprintf(`{origin: "%s"}`, reqURL.Host)
|
||||||
|
fmt.Println(spoofedLocationAPI)
|
||||||
|
|
||||||
|
chain.AddOnceResponseModifications(
|
||||||
|
ModifyIncomingScriptsWithRegex(`window\.location`, spoofedLocationAPI),
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,26 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
handleThemeChange();
|
handleThemeChange();
|
||||||
|
function prepareForPrint() {
|
||||||
|
document.getElementById("readingtime").innerText =
|
||||||
|
"Date Accessed: " +
|
||||||
|
new Date().toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
});
|
||||||
|
[...document.querySelectorAll(".noprint")].forEach((e) =>
|
||||||
|
e.classList.toggle("hidden")
|
||||||
|
);
|
||||||
|
window.addEventListener("afterprint", handleAfterPrint);
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
function handleAfterPrint() {
|
||||||
|
[...document.querySelectorAll(".noprint")].forEach((e) =>
|
||||||
|
e.classList.toggle("hidden")
|
||||||
|
);
|
||||||
|
window.removeEventListener("afterprint", handleAfterPrint);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<title>ladder | {{.Title}}</title>
|
<title>ladder | {{.Title}}</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -35,17 +55,17 @@
|
|||||||
<div
|
<div
|
||||||
class="hover:drop-shadow-[0_0px_4px_rgba(122,167,209,.3)] transition-colors duration-300 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
class="hover:drop-shadow-[0_0px_4px_rgba(122,167,209,.3)] transition-colors duration-300 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
class="flex -ml-2 h-8 font-extrabold tracking-tight hover:no-underline focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
aria-label="ladder"
|
||||||
|
class="flex -ml-2 h-8 font-extrabold tracking-tight no-underline focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
viewBox="0 0 512 512"
|
viewBox="0 0 512 512"
|
||||||
class="h-8 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
class="noprint h-8 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill="#7AA7D1"
|
fill="#7AA7D1"
|
||||||
@@ -59,21 +79,24 @@
|
|||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="/https://{{.Hostname}}"
|
href="/https://{{.Hostname}}"
|
||||||
class="flex ml-1 h-8 font-extrabold tracking-tight hover:no-underline focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
class="flex ml-1 h-8 font-extrabold tracking-tight no-underline focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
|
||||||
|
>
|
||||||
|
<span class="text-3xl mr-1 text-[#7AA7D1] leading-8 align-middle"
|
||||||
|
>{{.Sitename}}</span
|
||||||
>
|
>
|
||||||
<span class="text-3xl mr-1 text-[#7AA7D1] leading-8 align-middle">{{.Sitename}}</span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center z-10">
|
<div class="noprint flex justify-center z-10">
|
||||||
<div class="relative" id="dropdown">
|
<div class="relative" id="dropdown">
|
||||||
<button
|
<button
|
||||||
aria-expanded="closed"
|
aria-expanded="false"
|
||||||
|
id="dropdownButton"
|
||||||
|
aria-label="Toggle preferences menu"
|
||||||
onclick="toggleDropdown()"
|
onclick="toggleDropdown()"
|
||||||
type="button"
|
type="button"
|
||||||
class="inline-flex items-center justify-center whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
class="inline-flex items-center justify-center align-middle whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -92,6 +115,25 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
title="Print"
|
||||||
|
onclick="prepareForPrint()"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-center align-middle whitespace-nowrap rounded-full h-12 px-4 py-2 text-sm font-medium text-slate-600 dark:text-slate-400 ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-white dark:bg-slate-900 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-500 dark:hover:text-slate-200"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
class="h-4 w-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zM432 248a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="dropdown_panel"
|
id="dropdown_panel"
|
||||||
class="hidden absolute right-0 mt-2 w-52 rounded-md bg-white dark:bg-slate-900 shadow-md border border-slate-400 dark:border-slate-700"
|
class="hidden absolute right-0 mt-2 w-52 rounded-md bg-white dark:bg-slate-900 shadow-md border border-slate-400 dark:border-slate-700"
|
||||||
@@ -315,28 +357,29 @@
|
|||||||
|
|
||||||
<main class="flex flex-col space-y-3">
|
<main class="flex flex-col space-y-3">
|
||||||
{{if not .Success}}
|
{{if not .Success}}
|
||||||
<h1>
|
<h1>Error</h1>
|
||||||
Error
|
|
||||||
</h1>
|
|
||||||
<p>
|
<p>
|
||||||
There was a problem querying
|
There was a problem querying
|
||||||
<a href="{{.Params}}">{{.Params}}</a>
|
<a href="{{.Params}}">{{.Params}}</a>
|
||||||
</p>
|
</p>
|
||||||
<code class="text-red-500 dark:text-red-400">
|
<code class="text-red-500 dark:text-red-400"> {{.Error}} </code>
|
||||||
{{.Error}}
|
|
||||||
</code>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
<div class="flex flex-col gap-1 mt-3">
|
<div class="flex flex-col gap-1 mt-3">
|
||||||
<h1>
|
<h1>
|
||||||
<a href="{{.Url}}" class="text-slate-900 dark:text-slate-200"> {{.Title}} </a>
|
<a
|
||||||
|
href="{{.Url}}"
|
||||||
|
class="text-slate-900 dark:text-slate-200 no-underline hover:underline"
|
||||||
|
>
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
{{if ne .Date ""}}
|
{{if ne .Date ""}}
|
||||||
<small
|
<small
|
||||||
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
||||||
>{{.Date}}</small
|
>{{.Date}}</small
|
||||||
>
|
>
|
||||||
{{end}}
|
{{end}} {{if ne .Author ""}}
|
||||||
{{if ne .Author ""}}
|
|
||||||
<small
|
<small
|
||||||
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
||||||
>{{.Author}}</small
|
>{{.Author}}</small
|
||||||
@@ -344,11 +387,50 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col space-y-3">
|
<h2>
|
||||||
|
<a
|
||||||
|
href="{{.Url}}"
|
||||||
|
class="text-slate-900 dark:text-slate-200 no-underline hover:underline"
|
||||||
|
>
|
||||||
|
{{.Title}}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center gap-1 mt-3">
|
||||||
<div>
|
<div>
|
||||||
|
{{if ne .Author ""}}
|
||||||
|
<small
|
||||||
|
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
||||||
|
>{{.Author}} |
|
||||||
|
</small>
|
||||||
|
{{end}} {{if ne .Date ""}}
|
||||||
|
<small
|
||||||
|
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
||||||
|
>{{.Date}}</small
|
||||||
|
>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<small
|
||||||
|
id="readingtime"
|
||||||
|
class="text-sm font-medium leading-none text-slate-600 dark:text-slate-400"
|
||||||
|
>Reading Time: {{.ReadingTime}}</small
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-3">
|
||||||
<div class="grid grid-cols-1 justify-items-center">
|
<div class="grid grid-cols-1 justify-items-center">
|
||||||
<div><img src="{{.Image}}" alt="{{.Description}}" class="h-auto w-auto object-cover max-w-full mx-auto rounded-md shadow-md dark:shadow-slate-700"/></div>
|
<div>
|
||||||
<div class="mt-2 text-sm text-slate-600 dark:text-slate-400">{{.Description}}</div>
|
<img
|
||||||
|
src="{{.Image}}"
|
||||||
|
alt="{{.Description}}"
|
||||||
|
class="h-auto w-auto object-cover max-w-full mx-auto rounded-md shadow-md dark:shadow-slate-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 text-sm text-slate-600 dark:text-slate-400">
|
||||||
|
{{.Description}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -356,25 +438,24 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div class="my-2"></div>
|
<footer
|
||||||
<footer class="mx-4 text-center text-slate-600 dark:text-slate-400">
|
class="noprint mx-4 my-2 pt-2 border-t border-gray-300 dark:border-gray-700 text-center text-slate-600 dark:text-slate-400"
|
||||||
<p>
|
|
||||||
Code Licensed Under GPL v3.0 |
|
|
||||||
<a
|
|
||||||
href="https://github.com/everywall/ladder"
|
|
||||||
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
|
||||||
>View Source</a
|
|
||||||
>
|
>
|
||||||
|
|
<small>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/everywall"
|
href="https://github.com/everywall"
|
||||||
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
>Everywall</a
|
>Everywall</a
|
||||||
>
|
>
|
||||||
</p>
|
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/everywall/ladder"
|
||||||
|
class="hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300"
|
||||||
|
>Source</a
|
||||||
|
>
|
||||||
|
| Code Licensed Under GPL v3.0
|
||||||
|
</small>
|
||||||
</footer>
|
</footer>
|
||||||
<div class="my-2"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ func init() {
|
|||||||
return tx.SetIncomingCookie(params[0], params[1])
|
return tx.SetIncomingCookie(params[0], params[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rsmModMap["ModifyIncomingScriptsWithRegex"] = func(params ...string) proxychain.ResponseModification {
|
||||||
|
return tx.ModifyIncomingScriptsWithRegex(params[0], params[1])
|
||||||
|
}
|
||||||
|
|
||||||
rsmModMap["SetResponseHeader"] = func(params ...string) proxychain.ResponseModification {
|
rsmModMap["SetResponseHeader"] = func(params ...string) proxychain.ResponseModification {
|
||||||
return tx.SetResponseHeader(params[0], params[1])
|
return tx.SetResponseHeader(params[0], params[1])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,21 @@ func (rs *Ruleset) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
type AuxRuleset struct {
|
type AuxRuleset struct {
|
||||||
Rules []Rule `yaml:"rules"`
|
Rules []Rule `yaml:"rules"`
|
||||||
}
|
}
|
||||||
yr := &AuxRuleset{}
|
yamlRuleset := &AuxRuleset{}
|
||||||
|
|
||||||
if err := unmarshal(&yr); err != nil {
|
// First, try to unmarshal as AuxRuleset
|
||||||
|
err := unmarshal(yamlRuleset)
|
||||||
|
if err != nil {
|
||||||
|
// If that fails, try to unmarshal directly into a slice of Rules
|
||||||
|
var directRules []Rule
|
||||||
|
if err := unmarshal(&directRules); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
yamlRuleset.Rules = directRules
|
||||||
|
}
|
||||||
|
|
||||||
rs._rulemap = make(map[string]*Rule)
|
rs._rulemap = make(map[string]*Rule)
|
||||||
rs.Rules = yr.Rules
|
rs.Rules = yamlRuleset.Rules
|
||||||
|
|
||||||
// create a map of pointers to rules loaded above based on domain string keys
|
// create a map of pointers to rules loaded above based on domain string keys
|
||||||
// this way we don't have two copies of the rule in ruleset
|
// this way we don't have two copies of the rule in ruleset
|
||||||
@@ -214,6 +221,7 @@ func (rs *Ruleset) loadRulesFromLocalDir(path string) error {
|
|||||||
if !isYAML {
|
if !isYAML {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Printf("loadRulesFromLocalDir :: loading rule: %s\n", path)
|
||||||
|
|
||||||
tmpRs := Ruleset{_rulemap: make(map[string]*Rule)}
|
tmpRs := Ruleset{_rulemap: make(map[string]*Rule)}
|
||||||
err = tmpRs.loadRulesFromLocalFile(path)
|
err = tmpRs.loadRulesFromLocalFile(path)
|
||||||
@@ -258,6 +266,7 @@ func (rs *Ruleset) loadRulesFromLocalFile(path string) error {
|
|||||||
e := fmt.Errorf("failed to read rules from local file: '%s'", path)
|
e := fmt.Errorf("failed to read rules from local file: '%s'", path)
|
||||||
return errors.Join(e, err)
|
return errors.Join(e, err)
|
||||||
}
|
}
|
||||||
|
fmt.Printf("loadRulesFromLocalFile :: %s\n", path)
|
||||||
|
|
||||||
isJSON := strings.HasSuffix(path, ".json")
|
isJSON := strings.HasSuffix(path, ".json")
|
||||||
if isJSON {
|
if isJSON {
|
||||||
|
|||||||
@@ -15,3 +15,22 @@ rules:
|
|||||||
requestmodifications:
|
requestmodifications:
|
||||||
- name: ForwardRequestHeaders
|
- name: ForwardRequestHeaders
|
||||||
params: []
|
params: []
|
||||||
|
|
||||||
|
- domains:
|
||||||
|
- quantamagzine.org
|
||||||
|
responsemodifications:
|
||||||
|
- name: BlockElementRemoval
|
||||||
|
params:
|
||||||
|
- "#postContent"
|
||||||
|
|
||||||
|
- domains:
|
||||||
|
- techcrunch.com
|
||||||
|
responsemodifications:
|
||||||
|
- name: ModifyIncomingScriptsWithRegex
|
||||||
|
params:
|
||||||
|
- "window\\.location"
|
||||||
|
- |
|
||||||
|
{origin: "techcrunch.com"}
|
||||||
|
- name: BlockElementRemoval
|
||||||
|
params:
|
||||||
|
- ".article-content"
|
||||||
|
|||||||
23
rulesets_v2/BE_Belgium/demorgen-be.yaml
Normal file
23
rulesets_v2/BE_Belgium/demorgen-be.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
- domains:
|
||||||
|
- demorgen.be
|
||||||
|
|
||||||
|
requestmodifiers:
|
||||||
|
- name: MasqueradeAsGoogleBot
|
||||||
|
|
||||||
|
- name: SpoofReferrer
|
||||||
|
params: ["https://news.google.com"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["isBot", "true"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["authId", "1"]
|
||||||
|
|
||||||
|
responsemodifiers:
|
||||||
|
- name: BypassContentSecurityPolicy
|
||||||
|
- name: InjectScriptAfterDOMContentLoaded
|
||||||
|
params:
|
||||||
|
- |
|
||||||
|
let paywall = document.querySelectorAll('script[src*="advertising-cdn.dpgmedia.cloud"], div[data-temptation-position="ARTICLE_BOTTOM"]');
|
||||||
|
paywall.forEach(el => { el.remove(); });
|
||||||
|
document.querySelector('div[data-advert-placeholder-collapses]').remove();
|
||||||
44
rulesets_v2/BE_Belgium/dpg-media.yaml
Normal file
44
rulesets_v2/BE_Belgium/dpg-media.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
- domains:
|
||||||
|
- myprivacy.dpgmedia.be
|
||||||
|
- myprivacy.dpgmedia.nl
|
||||||
|
|
||||||
|
requestmodifiers:
|
||||||
|
- name: SpoofReferrer
|
||||||
|
params: ["https://news.google.com"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["isBot", "true"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["authId", "1"]
|
||||||
|
|
||||||
|
- name: SpoofXForwardedFor
|
||||||
|
params: ["none"]
|
||||||
|
|
||||||
|
|
||||||
|
- domains:
|
||||||
|
- demorgen.be
|
||||||
|
|
||||||
|
requestmodifiers:
|
||||||
|
- name: MasqueradeAsGoogleBot
|
||||||
|
|
||||||
|
- name: SpoofReferrer
|
||||||
|
params: ["https://news.google.com"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["isBot", "true"]
|
||||||
|
|
||||||
|
- name: SetOutgoingCookie
|
||||||
|
params: ["authId", "1"]
|
||||||
|
|
||||||
|
- name: SpoofXForwardedFor
|
||||||
|
params: ["none"]
|
||||||
|
|
||||||
|
responsemodifiers:
|
||||||
|
- name: BypassContentSecurityPolicy
|
||||||
|
- name: InjectScriptAfterDOMContentLoaded
|
||||||
|
params:
|
||||||
|
- |
|
||||||
|
let paywall = document.querySelectorAll('script[src*="advertising-cdn.dpgmedia.cloud"], div[data-temptation-position="ARTICLE_BOTTOM"]');
|
||||||
|
paywall.forEach(el => { el.remove(); });
|
||||||
|
document.querySelector('div[data-advert-placeholder-collapses]').remove();
|
||||||
34
rulesets_v2/CA_Canada/_multi-metroland-media-group.yaml
Normal file
34
rulesets_v2/CA_Canada/_multi-metroland-media-group.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
rules:
|
||||||
|
- domains:
|
||||||
|
- thestar.com
|
||||||
|
- niagarafallsreview.ca
|
||||||
|
- stcatharinesstandard.ca
|
||||||
|
- thepeterboroughexaminer.com
|
||||||
|
- therecord.com
|
||||||
|
- thespec.com
|
||||||
|
- wellandtribune.ca
|
||||||
|
responsemodifications:
|
||||||
|
- name: DeleteLocalStorageData
|
||||||
|
- name: DeleteSessionStorageData
|
||||||
|
- name: InjectScriptAfterDOMContentLoaded
|
||||||
|
params:
|
||||||
|
- |
|
||||||
|
const paywall = document.querySelectorAll('div.subscriber-offers');
|
||||||
|
paywall.forEach(el => { el.remove(); });
|
||||||
|
const subscriber_only = document.querySelectorAll('div.subscriber-only');
|
||||||
|
for (const elem of subscriber_only) {
|
||||||
|
if (elem.classList.contains('encrypted-content') && dompurify_loaded) {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString('<div>' + DOMPurify.sanitize(unscramble(elem.innerText)) + '</div>', 'text/html');
|
||||||
|
const content_new = doc.querySelector('div');
|
||||||
|
elem.parentNode.replaceChild(content_new, elem);
|
||||||
|
}
|
||||||
|
elem.removeAttribute('style');
|
||||||
|
elem.removeAttribute('class');
|
||||||
|
}
|
||||||
|
const banners = document.querySelectorAll('div.subscription-required, div.redacted-overlay, div.subscriber-hide, div.tnt-ads-container');
|
||||||
|
banners.forEach(el => { el.remove(); });
|
||||||
|
const ads = document.querySelectorAll('div.tnt-ads-container, div[class*="adLabelWrapper"]');
|
||||||
|
ads.forEach(el => { el.remove(); });
|
||||||
|
const recommendations = document.querySelectorAll('div[id^="tncms-region-article"]');
|
||||||
|
recommendations.forEach(el => { el.remove(); });
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
a {
|
a {
|
||||||
@apply text-slate-600 dark:text-slate-400 hover:text-blue-500 dark:hover:text-blue-500 hover:underline underline-offset-2 transition-colors duration-300;
|
@apply text-slate-600 dark:text-slate-400 hover:text-blue-500 dark:hover:text-blue-500 underline underline-offset-4 transition-colors duration-300;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
@apply scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-slate-900 dark:text-slate-200;
|
@apply scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-slate-900 dark:text-slate-200;
|
||||||
|
|||||||
Reference in New Issue
Block a user