mirror of
https://github.com/tenox7/wrp.git
synced 2026-07-09 02:16:47 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42bba02a73 | ||
|
|
892758140d | ||
|
|
bd0c2d974c | ||
|
|
7b9ffea57f | ||
|
|
ef1c4c0760 | ||
|
|
78efc3210d | ||
|
|
6b372aca23 | ||
|
|
9d21aa5ce1 | ||
|
|
365a786a42 |
26
README.md
26
README.md
@@ -2,23 +2,25 @@
|
||||
|
||||
A browser-in-browser proxy server that allows to use historical / vintage web browsers on the modern web.
|
||||
|
||||

|
||||
|
||||
## Modes of operation
|
||||
|
||||
### Access
|
||||
### Access Types
|
||||
|
||||
- Browser in browser, navigate to the address of WRP and use built-in web form to naviate.
|
||||
- HTTP proxy mode which offers more seamless, but also limited use.
|
||||
- Browser-in-browser, navigate to the address of WRP and use the built-in web form to browse web.
|
||||
- HTTP proxy mode which offers more seamless, but also limited use. Semi compatible with https://.
|
||||
|
||||
### Rende modes
|
||||
|
||||
- ISMAP "graphical" mode, renders web page in to a GIF/PNG/JPG image with clickable imagemap.
|
||||
- Simple HTML mode converts pages into simplified HTML for old browsers.
|
||||
|
||||

|
||||
Different modes have different uses. ISMAP mode will be better for flashy modern web. Simple HTML mode will be better for reading articles or documentation.
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
* [Download a WRP binary](https://github.com/tenox7/wrp/releases/) run it on a machine that will become your WRP gateway/server. This should be modern hardware and OS. Google Chrome / Chromium Browser is required to be preinstalled. Do not try to run WRP on an old machine like Windows XP or 98.
|
||||
* [Download a WRP binary](https://github.com/tenox7/wrp/releases/) run it on a machine that will become your WRP gateway/server. This should be modern hardware and OS. Google Chrome / Chromium / Brave Browser is required to be preinstalled. Do not run WRP on an old machine like Windows XP or 98.
|
||||
* Make sure you have disabled firewall or open port WRP is listening on (by default 8080).
|
||||
* Point your legacy browser to `http://address:port` of the WRP server or set your proxy address there.
|
||||
* Type a search string or a full http/https URL and click **Go**.
|
||||
@@ -26,9 +28,9 @@ A browser-in-browser proxy server that allows to use historical / vintage web br
|
||||
|
||||
### Proxy mode
|
||||
|
||||
- Try to use http:// addresses only, the proxy will automatically rewrite them to https as needed.
|
||||
- https:// addresses are limited in functionality (no /suffix or path).
|
||||
- You can use `/proxy.pac` automatic configuration mode.
|
||||
- Stick to `http://` addresses only, the proxy will automatically rewrite them to `https://` as needed.
|
||||
- `https://` addresses are limited in functionality (no /suffix or paths).
|
||||
- Proxy mode doesn't have a customizable web interface with html forms. All configuration is done via flags.
|
||||
|
||||
### Image Map Mode
|
||||
@@ -40,9 +42,9 @@ A browser-in-browser proxy server that allows to use historical / vintage web br
|
||||
* You can re-capture screenshot without reloading page by using **St** (Stop). This is useful if page didn't render fully before screenshot is taken.
|
||||
* You can also reload page and re-capture screenshot with **Re** (Reload).
|
||||
* To send keystrokes, fill **K** input box and press **Go**. There also are buttons for backspace, enter and arrow keys.
|
||||
* The default image type GIP is a ultra fast, optimized, parallel encoded GIF type.
|
||||
* If your browser supports it, prefer PNG over GIF/JPG. PNG is much faster, whereas GIF/JPG requires a lot of additional processing on both client and server to encode/decode.
|
||||
* GIF images are by default encoded with 216 colors, "web safe" palette. This uses an ultra fast but not very accurate color mapping algorithm. If you want better color representation switch to 256 color mode.
|
||||
* The default image type is `GIP` - an ultra fast, optimized, parallel encoded GIF type.
|
||||
* If your browser supports it, prefer PNG over GIF/JPG. PNG is much faster, whereas GIF/JPG requires a lot of additional processing on both client and server to compress/uncompress.
|
||||
* GIF images are by default encoded with 216 colors, "web safe" palette. This uses an ultra fast encoding algorithm optimized mostly for text. Images have rather wonky color colors. If you want better color representation switch to 256 color mode.
|
||||
|
||||
### Simple HTML mode
|
||||
|
||||
@@ -183,8 +185,7 @@ Click `st` to re-capture screenshot. You may want to increase the page delay usi
|
||||
|
||||
### Websites are blocking headless browsers
|
||||
|
||||
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. By default WRP tries to obtain some current valid User Agent
|
||||
from https://github.com/jnrbsn/user-agents rather than using the internal "HeadlessChrome". You can override this to your own, for example:
|
||||
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. By default WRP tries to obtain some current valid User Agent from https://github.com/jnrbsn/user-agents rather than using the internal "HeadlessChrome". You can override this to your own, for example:
|
||||
|
||||
```shell
|
||||
$ wrp -ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
|
||||
@@ -229,6 +230,7 @@ You may also be interested in:
|
||||
|
||||
* [VncFox](https://github.com/tenox7/vncfox)
|
||||
* [webone](https://github.com/atauenis/webone)
|
||||
* [Pici Server](https://github.com/picidae-project/pici-server)
|
||||
* [Browservice](https://github.com/ttalvitie/browservice)
|
||||
* [Browsh](https://github.com/browsh-org/browsh)
|
||||
|
||||
|
||||
167
download.go
Normal file
167
download.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/browser"
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
)
|
||||
|
||||
var (
|
||||
dlDir string
|
||||
dlNotify = make(chan struct{}, 1)
|
||||
)
|
||||
|
||||
type dlEvent struct {
|
||||
guid string
|
||||
filename string
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
var dlTrack struct {
|
||||
sync.Mutex
|
||||
ev *dlEvent
|
||||
}
|
||||
|
||||
type dlFile struct {
|
||||
name string
|
||||
data []byte
|
||||
}
|
||||
|
||||
var dlCache struct {
|
||||
sync.Mutex
|
||||
files map[string]dlFile
|
||||
}
|
||||
|
||||
func setupDownloads() {
|
||||
if dlDir == "" {
|
||||
var err error
|
||||
dlDir, err = os.MkdirTemp("", "wrp-dl-")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create download dir: %v", err)
|
||||
}
|
||||
dlCache.files = make(map[string]dlFile)
|
||||
}
|
||||
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
||||
switch e := ev.(type) {
|
||||
case *browser.EventDownloadWillBegin:
|
||||
log.Printf("Download started: %s (%s)", e.SuggestedFilename, e.GUID)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = &dlEvent{
|
||||
guid: e.GUID,
|
||||
filename: e.SuggestedFilename,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
dlTrack.Unlock()
|
||||
select {
|
||||
case dlNotify <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
case *browser.EventDownloadProgress:
|
||||
dlTrack.Lock()
|
||||
ev := dlTrack.ev
|
||||
dlTrack.Unlock()
|
||||
if ev == nil || ev.guid != e.GUID {
|
||||
return
|
||||
}
|
||||
if e.State == browser.DownloadProgressStateCompleted || e.State == browser.DownloadProgressStateCanceled {
|
||||
log.Printf("Download %s: %s", e.State, e.GUID)
|
||||
close(ev.done)
|
||||
}
|
||||
}
|
||||
})
|
||||
err := chromedp.Run(ctx,
|
||||
browser.SetDownloadBehavior(browser.SetDownloadBehaviorBehaviorAllowAndName).
|
||||
WithDownloadPath(dlDir).
|
||||
WithEventsEnabled(true),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to set download behavior: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func resetDownloadState() {
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
select {
|
||||
case <-dlNotify:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func waitForDownload() *dlFile {
|
||||
select {
|
||||
case <-dlNotify:
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
return nil
|
||||
}
|
||||
dlTrack.Lock()
|
||||
ev := dlTrack.ev
|
||||
dlTrack.Unlock()
|
||||
if ev == nil {
|
||||
return nil
|
||||
}
|
||||
log.Printf("Waiting for download: %s", ev.filename)
|
||||
select {
|
||||
case <-ev.done:
|
||||
case <-time.After(60 * time.Second):
|
||||
log.Printf("Download timed out: %s", ev.guid)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
return nil
|
||||
}
|
||||
fpath := filepath.Join(dlDir, ev.guid)
|
||||
data, err := os.ReadFile(fpath)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
if err != nil {
|
||||
log.Printf("Failed to read download %s: %v", fpath, err)
|
||||
return nil
|
||||
}
|
||||
os.Remove(fpath)
|
||||
return &dlFile{name: ev.filename, data: data}
|
||||
}
|
||||
|
||||
func cacheDownload(f *dlFile) string {
|
||||
id := shortuuid.New()
|
||||
dlCache.Lock()
|
||||
dlCache.files[id] = *f
|
||||
dlCache.Unlock()
|
||||
log.Printf("Download cached: /dl/%s (%s, %d bytes)", id, f.name, len(f.data))
|
||||
return "/dl/" + id
|
||||
}
|
||||
|
||||
func writeDownload(w http.ResponseWriter, f *dlFile) {
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, f.name))
|
||||
w.Header().Set("Content-Type", http.DetectContentType(f.data))
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(f.data)))
|
||||
w.Write(f.data)
|
||||
w.(http.Flusher).Flush()
|
||||
log.Printf("Download served inline: %s (%d bytes)", f.name, len(f.data))
|
||||
}
|
||||
|
||||
func dlServer(w http.ResponseWriter, r *http.Request) {
|
||||
id := strings.TrimPrefix(r.URL.Path, "/dl/")
|
||||
log.Printf("%s Download request for %s", r.RemoteAddr, id)
|
||||
dlCache.Lock()
|
||||
f, ok := dlCache.files[id]
|
||||
delete(dlCache.files, id)
|
||||
dlCache.Unlock()
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
writeDownload(w, &f)
|
||||
}
|
||||
18
go.mod
18
go.mod
@@ -4,18 +4,18 @@ go 1.26
|
||||
|
||||
require (
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb
|
||||
github.com/PuerkitoBio/goquery v1.11.0
|
||||
github.com/breml/rootcerts v0.3.4
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
|
||||
github.com/chromedp/chromedp v0.14.2
|
||||
github.com/PuerkitoBio/goquery v1.12.0
|
||||
github.com/breml/rootcerts v0.3.5
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a
|
||||
github.com/chromedp/chromedp v0.15.1
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4
|
||||
github.com/lithammer/shortuuid/v4 v4.2.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
|
||||
github.com/tenox7/gip v1.0.1
|
||||
golang.org/x/image v0.36.0
|
||||
golang.org/x/net v0.51.0
|
||||
github.com/tenox7/gip v1.0.2
|
||||
golang.org/x/image v0.39.0
|
||||
golang.org/x/net v0.53.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -26,6 +26,6 @@ require (
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.4.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
)
|
||||
|
||||
36
go.sum
36
go.sum
@@ -1,15 +1,15 @@
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb h1:YQ+d0g0P0F/06oDoeEgDHeZCIrnKgLxXcqYOpe8sTuU=
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb/go.mod h1:J86XzS1wgzJPjpQmpriJ+SetP17JSQUd9l+HWQK86jA=
|
||||
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
||||
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
|
||||
github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
|
||||
github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/breml/rootcerts v0.3.4 h1:9i7WNl/ctd9OEAOaTfLy//Wrlfxq/tRQ7v4okYFN9Ys=
|
||||
github.com/breml/rootcerts v0.3.4/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
|
||||
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
|
||||
github.com/breml/rootcerts v0.3.5 h1:oi7YiZ25HH52+mrKyjrMkcAFfnRDUf6HO8aUDr7RlJI=
|
||||
github.com/breml/rootcerts v0.3.5/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a h1:Kk4P1W58eAf+OUGtx51cM7CcJokJuBEmOxxwPdHFH4Q=
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a/go.mod h1:cbyjALe67vDvlvdiG9369P8w5U2w6IshwtyD2f2Tvag=
|
||||
github.com/chromedp/chromedp v0.15.1 h1:EJWiPm7BNqDqjYy6U0lTSL5wNH+iNt9GjC3a4gfjNyQ=
|
||||
github.com/chromedp/chromedp v0.15.1/go.mod h1:CdTHtUqD/dqaFw/cvFWtTydoEQS44wLBuwbMR9EkOY4=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
||||
@@ -37,8 +37,8 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiY
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/tenox7/gip v1.0.1 h1:yRcHROzwBjV2BhCjnh1y19wIg5Ei5CTMaZ+lx9nMl3Q=
|
||||
github.com/tenox7/gip v1.0.1/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
|
||||
github.com/tenox7/gip v1.0.2 h1:VQcaQub/bKu87pQZ1PxeSJPcRWpPRcpIGwP70w6ovQ8=
|
||||
github.com/tenox7/gip v1.0.2/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
@@ -46,8 +46,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
golang.org/x/image v0.39.0 h1:skVYidAEVKgn8lZ602XO75asgXBgLj9G/FE3RbuPFww=
|
||||
golang.org/x/image v0.39.0/go.mod h1:sIbmppfU+xFLPIG0FoVUTvyBMmgng1/XAMhQ2ft0hpA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -62,8 +62,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -83,8 +83,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -103,8 +103,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
22
ismap.go
22
ismap.go
@@ -94,8 +94,14 @@ func chromedpStart() (context.CancelFunc, context.CancelFunc) {
|
||||
if *userAgent != "" {
|
||||
opts = append(opts, chromedp.UserAgent(*userAgent))
|
||||
}
|
||||
if *browserPath == "" {
|
||||
*browserPath = findBrowser()
|
||||
}
|
||||
if *browserPath != "" {
|
||||
log.Printf("Using browser: %s", *browserPath)
|
||||
opts = append(opts, chromedp.ExecPath(*browserPath))
|
||||
} else {
|
||||
log.Printf("No browser detected, falling back to chromedp default lookup")
|
||||
}
|
||||
if *userDataDir != "" {
|
||||
opts = append(opts, chromedp.UserDataDir(*userDataDir))
|
||||
@@ -152,9 +158,11 @@ func (rq *wrpReq) action() chromedp.Action {
|
||||
return chromedp.Navigate(rq.url)
|
||||
}
|
||||
|
||||
// Navigate to the desired URL.
|
||||
func (rq *wrpReq) navigate() {
|
||||
// Navigate to the desired URL, returns the downloaded file if one was triggered.
|
||||
func (rq *wrpReq) navigate() *dlFile {
|
||||
resetDownloadState()
|
||||
ctxErr(chromedp.Run(ctx, rq.action()), rq.w)
|
||||
return waitForDownload()
|
||||
}
|
||||
|
||||
// Handle context errors
|
||||
@@ -170,6 +178,7 @@ func ctxErr(err error, w io.Writer) {
|
||||
return
|
||||
}
|
||||
ctx, cncl = chromedp.NewContext(actx)
|
||||
setupDownloads()
|
||||
log.Printf("Created new context, try again")
|
||||
fmt.Fprintln(w, "Created new context, try again")
|
||||
}
|
||||
@@ -382,7 +391,14 @@ func mapServer(w http.ResponseWriter, r *http.Request) {
|
||||
rq.printUI(uiParams{})
|
||||
return
|
||||
}
|
||||
rq.navigate() // TODO: if error from navigate do not capture
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
if rq.proxy {
|
||||
writeDownload(w, dl)
|
||||
} else {
|
||||
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
|
||||
}
|
||||
return
|
||||
}
|
||||
if rq.proxy {
|
||||
chromedp.Run(ctx, waitForRender())
|
||||
var loc string
|
||||
|
||||
70
util.go
70
util.go
@@ -8,6 +8,10 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -72,6 +76,72 @@ func asciify(s []byte) []byte {
|
||||
return a
|
||||
}
|
||||
|
||||
func findBrowser() string {
|
||||
var paths []string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
paths = []string{
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
||||
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
||||
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
||||
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
||||
"/Applications/Brave Browser Beta.app/Contents/MacOS/Brave Browser Beta",
|
||||
"/Applications/Brave Browser Nightly.app/Contents/MacOS/Brave Browser Nightly",
|
||||
"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi",
|
||||
"/Applications/Arc.app/Contents/MacOS/Arc",
|
||||
}
|
||||
case "windows":
|
||||
pf := os.Getenv("ProgramFiles")
|
||||
pfx86 := os.Getenv("ProgramFiles(x86)")
|
||||
lad := os.Getenv("LOCALAPPDATA")
|
||||
paths = []string{
|
||||
filepath.Join(pf, `Google\Chrome\Application\chrome.exe`),
|
||||
filepath.Join(pfx86, `Google\Chrome\Application\chrome.exe`),
|
||||
filepath.Join(lad, `Google\Chrome\Application\chrome.exe`),
|
||||
filepath.Join(pf, `BraveSoftware\Brave-Browser\Application\brave.exe`),
|
||||
filepath.Join(pfx86, `BraveSoftware\Brave-Browser\Application\brave.exe`),
|
||||
filepath.Join(lad, `BraveSoftware\Brave-Browser\Application\brave.exe`),
|
||||
filepath.Join(pf, `Chromium\Application\chrome.exe`),
|
||||
filepath.Join(lad, `Chromium\Application\chrome.exe`),
|
||||
filepath.Join(pf, `Microsoft\Edge\Application\msedge.exe`),
|
||||
filepath.Join(pfx86, `Microsoft\Edge\Application\msedge.exe`),
|
||||
filepath.Join(pf, `Vivaldi\Application\vivaldi.exe`),
|
||||
}
|
||||
default:
|
||||
paths = []string{
|
||||
"/usr/bin/google-chrome",
|
||||
"/usr/bin/google-chrome-stable",
|
||||
"/usr/bin/chromium",
|
||||
"/usr/bin/chromium-browser",
|
||||
"/usr/bin/brave-browser",
|
||||
"/usr/bin/brave-browser-stable",
|
||||
"/usr/bin/brave",
|
||||
"/usr/bin/microsoft-edge",
|
||||
"/usr/bin/vivaldi",
|
||||
"/snap/bin/chromium",
|
||||
"/snap/bin/brave",
|
||||
"/opt/brave.com/brave/brave",
|
||||
"/opt/google/chrome/chrome",
|
||||
"/opt/vivaldi/vivaldi",
|
||||
"/usr/local/bin/chrome",
|
||||
"/usr/local/bin/chromium",
|
||||
"/usr/local/bin/brave",
|
||||
}
|
||||
}
|
||||
for _, p := range paths {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return p
|
||||
}
|
||||
}
|
||||
for _, n := range []string{"google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "brave-browser", "brave", "microsoft-edge", "vivaldi", "chrome"} {
|
||||
if p, err := exec.LookPath(n); err == nil {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func fetchJnrbsnUserAgent() string {
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Get("https://jnrbsn.github.io/user-agents/user-agents.json")
|
||||
|
||||
15
wrp.go
15
wrp.go
@@ -239,7 +239,10 @@ func proxyServer(w http.ResponseWriter, r *http.Request) {
|
||||
chromedp.Run(ctx, chromedp.Location(¤tURL))
|
||||
currentURL = strings.Replace(currentURL, "https://", "http://", 1)
|
||||
if currentURL != strings.Replace(rq.url, "https://", "http://", 1) {
|
||||
rq.navigate()
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
writeDownload(w, dl)
|
||||
return
|
||||
}
|
||||
}
|
||||
rq.url = strings.Replace(rq.url, "https://", "http://", 1)
|
||||
if r.Method == "CONNECT" {
|
||||
@@ -273,7 +276,10 @@ func pageServer(w http.ResponseWriter, r *http.Request) {
|
||||
rq.printUI(uiParams{})
|
||||
return
|
||||
}
|
||||
rq.navigate() // TODO: if error from navigate do not capture
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
|
||||
return
|
||||
}
|
||||
if rq.wrpMode == "html" {
|
||||
rq.captureMarkdown()
|
||||
return
|
||||
@@ -359,12 +365,14 @@ func main() {
|
||||
cncl, acncl = chromedpStart()
|
||||
defer cncl()
|
||||
defer acncl()
|
||||
setupDownloads()
|
||||
|
||||
c := make(chan os.Signal)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
log.Printf("Interrupt - shutting down.")
|
||||
os.RemoveAll(dlDir)
|
||||
cncl()
|
||||
acncl()
|
||||
srv.Shutdown(context.Background())
|
||||
@@ -380,6 +388,7 @@ func main() {
|
||||
http.HandleFunc(imgZpfx, imgServerTxt)
|
||||
http.HandleFunc("/proxy.pac", pacServer)
|
||||
http.HandleFunc("/shutdown/", haltServer)
|
||||
http.HandleFunc("/dl/", dlServer)
|
||||
http.HandleFunc("/favicon.ico", http.NotFound)
|
||||
|
||||
log.Printf("Default Img Type: %v, Geometry: %+v", *defType, defGeom)
|
||||
|
||||
Reference in New Issue
Block a user