From bef52d956e26a6a614b3a4673ce5e85931259458 Mon Sep 17 00:00:00 2001 From: David Stotijn Date: Sun, 27 Feb 2022 17:56:24 +0100 Subject: [PATCH] Add support to launch Chrome --- cmd/hetty/main.go | 30 ++++++++++++++++++++++++++++++ go.mod | 10 +++++++++- go.sum | 22 +++++++++++++++++++++- pkg/chrome/chrome.go | 33 +++++++++++++++++++++++++++++++++ pkg/db/badger/sender_test.go | 2 +- pkg/sender/sender_test.go | 2 +- 6 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 pkg/chrome/chrome.go diff --git a/cmd/hetty/main.go b/cmd/hetty/main.go index 81d9630..4218822 100644 --- a/cmd/hetty/main.go +++ b/cmd/hetty/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "crypto/tls" "embed" "errors" @@ -11,10 +12,12 @@ import ( "net" "net/http" "os" + "os/exec" "strings" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" + "github.com/chromedp/chromedp" badgerdb "github.com/dgraph-io/badger/v3" "github.com/gorilla/mux" "github.com/mitchellh/go-homedir" @@ -22,6 +25,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/dstotijn/hetty/pkg/api" + "github.com/dstotijn/hetty/pkg/chrome" "github.com/dstotijn/hetty/pkg/db/badger" "github.com/dstotijn/hetty/pkg/log" "github.com/dstotijn/hetty/pkg/proj" @@ -39,6 +43,7 @@ var ( caKeyFile string dbPath string addr string + launchChrome bool debug bool noPrettyLogs bool ) @@ -50,12 +55,15 @@ var ( var adminContent embed.FS func main() { + ctx := context.Background() + flag.StringVar(&caCertFile, "cert", "~/.hetty/hetty_cert.pem", "CA certificate filepath. Creates a new CA certificate if file doesn't exist") flag.StringVar(&caKeyFile, "key", "~/.hetty/hetty_key.pem", "CA private key filepath. Creates a new CA private key if file doesn't exist") flag.StringVar(&dbPath, "db", "~/.hetty/db", "Database directory path") flag.StringVar(&addr, "addr", ":8080", "TCP address to listen on, in the form \"host:port\"") + flag.BoolVar(&launchChrome, "chrome", false, "Launch Chrome with proxy settings and certificate errors ignored") flag.BoolVar(&debug, "debug", false, "Enable debug mode") flag.BoolVar(&noPrettyLogs, "disable-pretty-logs", false, "Disable human readable console logs and encode with JSON.") flag.Parse() @@ -188,6 +196,28 @@ func main() { mainLogger.Info(fmt.Sprintf("Hetty (v%v) is running on %v ...", version, addr)) mainLogger.Info(fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(32), "Get started at "+url)) + if launchChrome { + ctx, cancel := chrome.NewExecAllocator(ctx, chrome.Config{ + ProxyServer: url, + ProxyBypassHosts: []string{url}, + }) + defer cancel() + + taskCtx, cancel := chromedp.NewContext(ctx) + defer cancel() + + err = chromedp.Run(taskCtx, chromedp.Navigate(url)) + + switch { + case errors.Is(err, exec.ErrNotFound): + mainLogger.Info("Chrome executable not found.") + case err != nil: + mainLogger.Error(fmt.Sprintf("Failed to navigate to %v.", url), zap.Error(err)) + default: + mainLogger.Info("Launched Chrome.") + } + } + err = httpServer.ListenAndServe() if err != nil && errors.Is(err, http.ErrServerClosed) { mainLogger.Fatal("HTTP server closed unexpected.", zap.Error(err)) diff --git a/go.mod b/go.mod index 445c373..a340b75 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/99designs/gqlgen v0.14.0 + github.com/chromedp/chromedp v0.7.8 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/google/go-cmp v0.5.6 github.com/gorilla/mux v1.7.4 @@ -18,9 +19,14 @@ require ( github.com/agnivade/levenshtein v1.1.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf // indirect + github.com/chromedp/sysutil v1.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect @@ -29,7 +35,9 @@ require ( github.com/google/flatbuffers v1.12.1 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.12.3 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect @@ -41,7 +49,7 @@ require ( go.uber.org/multierr v1.6.0 // indirect golang.org/x/mod v0.4.2 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect golang.org/x/tools v0.1.5 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect diff --git a/go.sum b/go.sum index 2d2edb6..fb8bdca 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,12 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf h1:1omDWNUsWxn2HpiMiMuyRmzjl9uG7RP3IE6GTlpgJWU= +github.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= +github.com/chromedp/chromedp v0.7.8 h1:JFPIFb28LPjcx6l6mUUzLOTD/TgswcTtg7KrDn8S/2I= +github.com/chromedp/chromedp v0.7.8/go.mod h1:HcIUFBa5vA+u2QI3+xljiU59llUQ8lgGoLzYSCBfmUA= +github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -40,6 +46,12 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -69,6 +81,8 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= @@ -80,6 +94,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/matryer/moq v0.2.5 h1:BGQISyhl7Gc9W/gMYmAJONh9mT6AYeyeTjNupNPknMs= github.com/matryer/moq v0.2.5/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= @@ -95,6 +111,8 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc= +github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -193,10 +211,12 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/chrome/chrome.go b/pkg/chrome/chrome.go new file mode 100644 index 0000000..43f90b0 --- /dev/null +++ b/pkg/chrome/chrome.go @@ -0,0 +1,33 @@ +package chrome + +import ( + "context" + "strings" + + "github.com/chromedp/chromedp" +) + +var defaultOpts = []chromedp.ExecAllocatorOption{ + chromedp.NoFirstRun, + chromedp.NoDefaultBrowserCheck, + chromedp.IgnoreCertErrors, + chromedp.Flag("test-type ", true), // This prevents the `ignore-certificate-errors` warning. +} + +type Config struct { + ProxyServer string + ProxyBypassHosts []string +} + +// NewExecAllocator returns a new context setup with a chromedp.ExecAllocator. +// Its `context.Context` return value can be used to create subsequent contexts for interacting +// with an allocated Chrome browser. +func NewExecAllocator(ctx context.Context, cfg Config) (context.Context, context.CancelFunc) { + proxyBypass := strings.Join(append([]string{"<-loopback"}, cfg.ProxyBypassHosts...), ";") + opts := append(defaultOpts, + chromedp.ProxyServer(cfg.ProxyServer), + chromedp.Flag("proxy-bypass-list", proxyBypass), + ) + + return chromedp.NewExecAllocator(ctx, opts...) +} diff --git a/pkg/db/badger/sender_test.go b/pkg/db/badger/sender_test.go index 99810cc..c6477b1 100644 --- a/pkg/db/badger/sender_test.go +++ b/pkg/db/badger/sender_test.go @@ -60,7 +60,7 @@ func TestFindRequestByID(t *testing.T) { URL: exampleURL, Method: http.MethodGet, - Proto: sender.HTTPProto2, + Proto: sender.HTTPProto20, Header: http.Header{ "X-Foo": []string{"bar"}, }, diff --git a/pkg/sender/sender_test.go b/pkg/sender/sender_test.go index e9326a4..253dff8 100644 --- a/pkg/sender/sender_test.go +++ b/pkg/sender/sender_test.go @@ -165,7 +165,7 @@ func TestCloneFromRequestLog(t *testing.T) { ProjectID: projectID, URL: exampleURL, Method: http.MethodPost, - Proto: sender.HTTPProto2, + Proto: sender.HTTPProto20, Header: http.Header{ "X-Foo": []string{"bar"}, },