mirror of
https://github.com/projectdiscovery/httpx.git
synced 2024-09-11 09:35:28 +03:00
* Update headless.go * adding headless generic option --------- Co-authored-by: mzack <marco.rivoli.nvh@gmail.com>
138 lines
3.6 KiB
Go
138 lines
3.6 KiB
Go
package runner
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/go-rod/rod"
|
|
"github.com/go-rod/rod/lib/launcher"
|
|
"github.com/go-rod/rod/lib/launcher/flags"
|
|
"github.com/go-rod/rod/lib/proto"
|
|
"github.com/pkg/errors"
|
|
fileutil "github.com/projectdiscovery/utils/file"
|
|
osutils "github.com/projectdiscovery/utils/os"
|
|
)
|
|
|
|
// MustDisableSandbox determines if the current os and user needs sandbox mode disabled
|
|
func MustDisableSandbox() bool {
|
|
// linux with root user needs "--no-sandbox" option
|
|
// https://github.com/chromium/chromium/blob/c4d3c31083a2e1481253ff2d24298a1dfe19c754/chrome/test/chromedriver/client/chromedriver.py#L209
|
|
return osutils.IsLinux() && os.Geteuid() == 0
|
|
}
|
|
|
|
type Browser struct {
|
|
tempDir string
|
|
engine *rod.Browser
|
|
// TODO: Remove the Chrome PID kill code in favor of using Leakless(true).
|
|
// This change will be made if there are no complaints about zombie Chrome processes.
|
|
// Reference: https://github.com/projectdiscovery/httpx/pull/1426
|
|
// pids map[int32]struct{}
|
|
}
|
|
|
|
func NewBrowser(proxy string, useLocal bool, optionalArgs map[string]string) (*Browser, error) {
|
|
dataStore, err := os.MkdirTemp("", "nuclei-*")
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not create temporary directory")
|
|
}
|
|
|
|
// pids := processutil.FindProcesses(processutil.IsChromeProcess)
|
|
|
|
chromeLauncher := launcher.New().
|
|
Leakless(true).
|
|
Set("disable-gpu", "true").
|
|
Set("ignore-certificate-errors", "true").
|
|
Set("ignore-certificate-errors", "1").
|
|
Set("disable-crash-reporter", "true").
|
|
Set("disable-notifications", "true").
|
|
Set("hide-scrollbars", "true").
|
|
Set("window-size", fmt.Sprintf("%d,%d", 1080, 1920)).
|
|
Set("mute-audio", "true").
|
|
Set("incognito", "true").
|
|
Delete("use-mock-keychain").
|
|
Headless(true).
|
|
UserDataDir(dataStore)
|
|
|
|
if MustDisableSandbox() {
|
|
chromeLauncher = chromeLauncher.NoSandbox(true)
|
|
}
|
|
|
|
executablePath, err := os.Executable()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// if musl is used, most likely we are on alpine linux which is not supported by go-rod, so we fallback to default chrome
|
|
useMusl, _ := fileutil.UseMusl(executablePath)
|
|
if useLocal || useMusl {
|
|
if chromePath, hasChrome := launcher.LookPath(); hasChrome {
|
|
chromeLauncher.Bin(chromePath)
|
|
} else {
|
|
return nil, errors.New("the chrome browser is not installed")
|
|
}
|
|
}
|
|
|
|
if proxy != "" {
|
|
chromeLauncher = chromeLauncher.Proxy(proxy)
|
|
}
|
|
|
|
for k, v := range optionalArgs {
|
|
chromeLauncher.Set(flags.Flag(k), v)
|
|
}
|
|
|
|
launcherURL, err := chromeLauncher.Launch()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
browser := rod.New().ControlURL(launcherURL)
|
|
if browserErr := browser.Connect(); browserErr != nil {
|
|
return nil, browserErr
|
|
}
|
|
|
|
engine := &Browser{
|
|
tempDir: dataStore,
|
|
engine: browser,
|
|
// pids: pids,
|
|
}
|
|
return engine, nil
|
|
}
|
|
|
|
func (b *Browser) ScreenshotWithBody(url string, timeout time.Duration) ([]byte, string, error) {
|
|
page, err := b.engine.Page(proto.TargetCreateTarget{})
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
page = page.Timeout(timeout)
|
|
defer page.Close()
|
|
|
|
if err := page.Navigate(url); err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
page.Timeout(5 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)()
|
|
|
|
if err := page.WaitLoad(); err != nil {
|
|
return nil, "", err
|
|
}
|
|
_ = page.WaitIdle(1 * time.Second)
|
|
|
|
screenshot, err := page.Screenshot(true, &proto.PageCaptureScreenshot{})
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
body, err := page.HTML()
|
|
if err != nil {
|
|
return screenshot, "", err
|
|
}
|
|
|
|
return screenshot, body, nil
|
|
}
|
|
|
|
func (b *Browser) Close() {
|
|
b.engine.Close()
|
|
os.RemoveAll(b.tempDir)
|
|
// processutil.CloseProcesses(processutil.IsChromeProcess, b.pids)
|
|
}
|