diff --git a/app/browserforwarder/config.proto b/app/browserforwarder/config.proto new file mode 100644 index 000000000..876914549 --- /dev/null +++ b/app/browserforwarder/config.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package v2ray.core.app.browserforwarder; + +option csharp_namespace = "V2Ray.Core.App.Browserforwarder"; +option go_package = "github.com/v2fly/v2ray-core/v4/app/browserforwarder"; +option java_package = "com.v2ray.core.app.browserforwarder"; +option java_multiple_files = true; + +// Config is the settings for BrowserForwarder. +message Config { + string listen_addr = 1; + int32 listen_port = 2; +} \ No newline at end of file diff --git a/app/browserforwarder/forwarder.go b/app/browserforwarder/forwarder.go new file mode 100644 index 000000000..41e5a40e7 --- /dev/null +++ b/app/browserforwarder/forwarder.go @@ -0,0 +1,94 @@ +package browserforwarder + +import ( + "bytes" + "context" + "github.com/v2fly/BrowserBridge/handler" + "github.com/v2fly/v2ray-core/v4/common" + "github.com/v2fly/v2ray-core/v4/common/net" + "github.com/v2fly/v2ray-core/v4/common/platform/securedload" + "github.com/v2fly/v2ray-core/v4/features/ext" + "github.com/v2fly/v2ray-core/v4/transport/internet" + "io" + "net/http" + "time" +) + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen + +type Forwarder struct { + ctx context.Context + + forwarder *handler.HTTPHandle + httpserver *http.Server + + config *Config +} + +func (f *Forwarder) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + requestPath := request.URL.Path[1:] + + switch requestPath { + case "": + fallthrough + case "index.js": + BridgeResource(writer, request, requestPath) + break + case "link": + f.forwarder.ServeBridge(writer, request) + } +} + +func (f *Forwarder) DialWebsocket(url string, header http.Header) (io.ReadWriteCloser, error) { + return f.forwarder.Dial(url) +} + +func (f *Forwarder) Type() interface{} { + return ext.BrowserForwarderType() +} + +func (f *Forwarder) Start() error { + f.forwarder = handler.NewHttpHandle() + f.httpserver = &http.Server{Handler: f} + address := net.ParseAddress(f.config.ListenAddr) + listener, err := internet.ListenSystem(f.ctx, &net.TCPAddr{IP: address.IP(), Port: int(f.config.ListenPort)}, nil) + if err != nil { + return newError("forwarder cannot listen on the port").Base(err) + } + go func() { + err = f.httpserver.Serve(listener) + if err != nil { + newError("cannot serve http forward server").Base(err).WriteToLog() + } + }() + return nil +} + +func (f *Forwarder) Close() error { + if f.httpserver != nil { + return f.httpserver.Close() + } + return nil +} + +func BridgeResource(rw http.ResponseWriter, r *http.Request, path string) { + content := path + data, err := securedload.GetAssetSecured("browserforwarder/" + content) + if err != nil { + err = newError("cannot load necessary resources").Base(err) + http.Error(rw, err.Error(), 403) + return + } + + http.ServeContent(rw, r, path, time.Now(), bytes.NewReader(data)) +} + +func NewForwarder(ctx context.Context, cfg *Config) *Forwarder { + return &Forwarder{config: cfg, ctx: ctx} +} + +func init() { + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { + return NewForwarder(ctx, cfg.(*Config)), nil + })) +} diff --git a/common/platform/securedload/file.go b/common/platform/securedload/file.go index 8b87ec517..2a5b64e6f 100644 --- a/common/platform/securedload/file.go +++ b/common/platform/securedload/file.go @@ -1,6 +1,11 @@ package securedload +import "path/filepath" + func GetAssetSecured(name string) ([]byte, error) { + + name = filepath.FromSlash(name) + var err error for k, v := range knownProtectedLoader { if loadedData, errLoad := v.VerifyAndLoad(name); errLoad == nil { diff --git a/features/ext/browser.go b/features/ext/browser.go index bdf287045..d9ce8f79e 100644 --- a/features/ext/browser.go +++ b/features/ext/browser.go @@ -8,3 +8,7 @@ import ( type BrowserForwarder interface { DialWebsocket(url string, header http.Header) (io.ReadWriteCloser, error) } + +func BrowserForwarderType() interface{} { + return (*BrowserForwarder)(nil) +} diff --git a/go.mod b/go.mod index 84236bd02..c223861f7 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/pires/go-proxyproto v0.5.0 github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c github.com/stretchr/testify v1.7.0 + github.com/v2fly/BrowserBridge v0.0.0-20210316223221-b4ab84595cdc // indirect github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848 go.starlark.net v0.0.0-20210305151048-6a590ae7f4eb golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83