2018-01-07 03:21:29 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-02-01 07:37:38 +00:00
|
|
|
"bufio"
|
|
|
|
"encoding/base64"
|
2018-01-21 03:56:05 +00:00
|
|
|
"encoding/json"
|
2018-01-07 03:21:29 +00:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
2018-01-21 03:56:05 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"net"
|
2018-01-07 03:21:29 +00:00
|
|
|
"net/http"
|
2018-01-10 14:54:51 +00:00
|
|
|
"os"
|
2018-01-21 03:56:05 +00:00
|
|
|
"os/exec"
|
2018-01-10 14:54:51 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2018-01-21 03:56:05 +00:00
|
|
|
"time"
|
2018-01-07 03:21:29 +00:00
|
|
|
|
|
|
|
// Termbox seems to be one of the best projects in any language for handling terminal input.
|
2018-01-28 08:13:13 +00:00
|
|
|
// It"s cross-platform and the maintainer is disciplined about supporting the baseline of escape
|
2018-01-07 03:21:29 +00:00
|
|
|
// codes that work across the majority of terminals.
|
2018-01-10 14:54:51 +00:00
|
|
|
"github.com/nsf/termbox-go"
|
2018-01-21 03:56:05 +00:00
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
2018-01-07 03:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-01-21 03:56:05 +00:00
|
|
|
logfile string
|
|
|
|
webSocketAddresss = flag.String("port", ":3334", "Web socket service address")
|
|
|
|
firefoxBinary = flag.String("firefox", "firefox", "Path to Firefox executable")
|
|
|
|
isFFGui = flag.Bool("with-gui", false, "Don't use headless Firefox")
|
2018-01-28 08:13:13 +00:00
|
|
|
isUseExistingFirefox = flag.Bool("use-existing-ff", false, "Whether Browsh should launch Firefox or not")
|
2018-01-24 08:32:52 +00:00
|
|
|
useFFProfile = flag.String("ff-profile", "default", "Firefox profile to use")
|
2018-01-21 03:56:05 +00:00
|
|
|
upgrader = websocket.Upgrader{
|
2018-01-10 14:54:51 +00:00
|
|
|
CheckOrigin: func(r *http.Request) bool { return true },
|
2018-01-07 03:21:29 +00:00
|
|
|
ReadBufferSize: 1024,
|
|
|
|
WriteBufferSize: 1024,
|
|
|
|
}
|
2018-01-21 03:56:05 +00:00
|
|
|
stdinChannel = make(chan string)
|
|
|
|
marionette net.Conn
|
|
|
|
ffCommandCount = 0
|
2018-01-28 08:13:13 +00:00
|
|
|
defaultFFPrefs = map[string]string{
|
2018-02-01 07:37:38 +00:00
|
|
|
"browser.startup.homepage": "'about:blank'",
|
|
|
|
"startup.homepage_welcome_url": "'about:blank'",
|
2018-01-28 08:13:13 +00:00
|
|
|
"startup.homepage_welcome_url.additional": "''",
|
2018-02-01 07:37:38 +00:00
|
|
|
"devtools.errorconsole.enabled": "true",
|
|
|
|
"devtools.chrome.enabled": "true",
|
2018-01-28 08:13:13 +00:00
|
|
|
|
|
|
|
// Send Browser Console (different from Devtools console) output to
|
|
|
|
// STDOUT.
|
|
|
|
"browser.dom.window.dump.enabled": "true",
|
|
|
|
|
|
|
|
// From:
|
|
|
|
// http://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in//l388
|
|
|
|
// Make url-classifier updates so rare that they won"t affect tests.
|
|
|
|
"urlclassifier.updateinterval": "172800",
|
|
|
|
// Point the url-classifier to a nonexistent local URL for fast failures.
|
2018-02-01 07:37:38 +00:00
|
|
|
"browser.safebrowsing.provider.0.gethashURL": "'http://localhost/safebrowsing-dummy/gethash'",
|
|
|
|
"browser.safebrowsing.provider.0.keyURL": "'http://localhost/safebrowsing-dummy/newkey'",
|
|
|
|
"browser.safebrowsing.provider.0.updateURL": "'http://localhost/safebrowsing-dummy/update'",
|
2018-01-28 08:13:13 +00:00
|
|
|
|
|
|
|
// Disable self repair/SHIELD
|
|
|
|
"browser.selfsupport.url": "'https://localhost/selfrepair'",
|
|
|
|
// Disable Reader Mode UI tour
|
|
|
|
"browser.reader.detectedFirstArticle": "true",
|
|
|
|
|
|
|
|
// Set the policy firstURL to an empty string to prevent
|
|
|
|
// the privacy info page to be opened on every "web-ext run".
|
|
|
|
// (See #1114 for rationale)
|
|
|
|
"datareporting.policy.firstRunURL": "''",
|
|
|
|
}
|
2018-01-07 03:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func setupLogging() {
|
|
|
|
dir, err := os.Getwd()
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
logfile = fmt.Sprintf(filepath.Join(dir, "debug.log"))
|
|
|
|
if _, err := os.Stat(logfile); err == nil {
|
|
|
|
os.Truncate(logfile, 0)
|
|
|
|
}
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func log(msg string) {
|
|
|
|
f, oErr := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
|
|
|
if oErr != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(oErr.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
msg = msg + "\n"
|
|
|
|
if _, wErr := f.WriteString(msg); wErr != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(wErr.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func initialise() {
|
2018-01-21 03:56:05 +00:00
|
|
|
flag.Parse()
|
2018-01-07 03:21:29 +00:00
|
|
|
setupTermbox()
|
2018-01-10 14:54:51 +00:00
|
|
|
setupLogging()
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func setupTermbox() {
|
|
|
|
err := termbox.Init()
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
termbox.SetInputMode(termbox.InputAlt | termbox.InputMouse)
|
|
|
|
}
|
|
|
|
|
2018-01-24 08:32:52 +00:00
|
|
|
func shutdown(message string) {
|
2018-02-01 07:37:38 +00:00
|
|
|
exitCode := 0
|
|
|
|
if message != "normal" {
|
2018-01-24 08:32:52 +00:00
|
|
|
exitCode = 1
|
|
|
|
}
|
|
|
|
println(message)
|
|
|
|
log("Shutting down with: " + message)
|
|
|
|
termbox.Close()
|
|
|
|
os.Exit(exitCode)
|
|
|
|
}
|
|
|
|
|
2018-01-07 03:21:29 +00:00
|
|
|
func sendTtySize() {
|
|
|
|
x, y := termbox.Size()
|
2018-02-01 07:37:38 +00:00
|
|
|
sendMessageToWebExtension(fmt.Sprintf("/tty_size,%d,%d", x, y))
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func readStdin() {
|
|
|
|
defer termbox.Close()
|
|
|
|
for {
|
|
|
|
switch ev := termbox.PollEvent(); ev.Type {
|
|
|
|
case termbox.EventKey:
|
|
|
|
if ev.Key == termbox.KeyCtrlQ {
|
2018-02-01 07:37:38 +00:00
|
|
|
if !*isUseExistingFirefox {
|
2018-01-21 03:56:05 +00:00
|
|
|
sendFirefoxCommand("quitApplication", map[string]interface{}{})
|
|
|
|
}
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown("normal")
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
2018-01-11 04:22:27 +00:00
|
|
|
log(fmt.Sprintf("EventKey: k: %d, c: %c, mod: %s", ev.Key, ev.Ch, ev.Mod))
|
|
|
|
eventMap := map[string]interface{}{
|
2018-01-21 03:56:05 +00:00
|
|
|
"key": int(ev.Key),
|
2018-01-11 04:22:27 +00:00
|
|
|
"char": string(ev.Ch),
|
2018-01-21 03:56:05 +00:00
|
|
|
"mod": int(ev.Mod),
|
2018-01-11 04:22:27 +00:00
|
|
|
}
|
|
|
|
marshalled, _ := json.Marshal(eventMap)
|
2018-02-01 07:37:38 +00:00
|
|
|
sendMessageToWebExtension("/stdin," + string(marshalled))
|
2018-01-07 03:21:29 +00:00
|
|
|
case termbox.EventResize:
|
2018-01-12 13:58:32 +00:00
|
|
|
// Need to flush STDOUT before getting the new TTY size because there
|
|
|
|
// can be a discrepancy between the "internal buffer" size and the
|
|
|
|
// actual size.
|
|
|
|
termbox.Flush()
|
2018-01-07 03:21:29 +00:00
|
|
|
sendTtySize()
|
|
|
|
case termbox.EventMouse:
|
2018-01-17 03:00:37 +00:00
|
|
|
log(fmt.Sprintf("Mouse: k: %d, x: %d, y: %d, mod: %s", ev.Key, ev.MouseX, ev.MouseY, ev.Mod))
|
|
|
|
eventMap := map[string]interface{}{
|
2018-01-21 03:56:05 +00:00
|
|
|
"key": int(ev.Key),
|
2018-01-17 03:00:37 +00:00
|
|
|
"mouse_x": int(ev.MouseX),
|
|
|
|
"mouse_y": int(ev.MouseY),
|
2018-01-21 03:56:05 +00:00
|
|
|
"mod": int(ev.Mod),
|
2018-01-17 03:00:37 +00:00
|
|
|
}
|
|
|
|
marshalled, _ := json.Marshal(eventMap)
|
2018-02-01 07:37:38 +00:00
|
|
|
sendMessageToWebExtension("/stdin," + string(marshalled))
|
2018-01-07 03:21:29 +00:00
|
|
|
case termbox.EventError:
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(ev.Err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-01 07:37:38 +00:00
|
|
|
func sendMessageToWebExtension(message string) {
|
|
|
|
stdinChannel <- message
|
|
|
|
}
|
|
|
|
|
2018-01-21 03:56:05 +00:00
|
|
|
func webSocketReader(ws *websocket.Conn) {
|
2018-01-07 03:21:29 +00:00
|
|
|
defer ws.Close()
|
|
|
|
for {
|
|
|
|
_, message, err := ws.ReadMessage()
|
2018-02-01 07:37:38 +00:00
|
|
|
handleWebextensionCommand(message)
|
2018-01-07 03:21:29 +00:00
|
|
|
if err != nil {
|
2018-01-10 14:54:51 +00:00
|
|
|
if websocket.IsCloseError(err, websocket.CloseGoingAway) {
|
|
|
|
log("Socket reader detected that the browser closed the websocket")
|
|
|
|
triggerSocketWriterClose()
|
|
|
|
return
|
|
|
|
}
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-01 07:37:38 +00:00
|
|
|
func handleWebextensionCommand(message []byte) {
|
|
|
|
parts := strings.Split(string(message), ",")
|
|
|
|
command := parts[0]
|
|
|
|
switch command {
|
|
|
|
case "/frame":
|
|
|
|
renderFrame(strings.Join(parts[1:], ","))
|
|
|
|
case "/screenshot":
|
|
|
|
saveScreenshot(parts[1])
|
|
|
|
default:
|
|
|
|
log("WEBEXT: " + string(message))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderFrame(frame string) {
|
|
|
|
termbox.SetCursor(0, 0)
|
|
|
|
os.Stdout.Write([]byte(frame))
|
|
|
|
termbox.HideCursor()
|
|
|
|
termbox.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
func saveScreenshot(base64String string) {
|
|
|
|
dec, err := base64.StdEncoding.DecodeString(base64String)
|
|
|
|
if err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
file, err := ioutil.TempFile(os.TempDir(), "browsh-screenshot")
|
|
|
|
if err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
if _, err := file.Write(dec); err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
if err := file.Sync(); err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
fullPath := file.Name() + ".jpg"
|
|
|
|
if err := os.Rename(file.Name(), fullPath); err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
message := "Screenshot saved to " + fullPath
|
|
|
|
sendMessageToWebExtension("/status," + message)
|
|
|
|
file.Close()
|
|
|
|
}
|
|
|
|
|
2018-01-10 14:54:51 +00:00
|
|
|
// When the socket reader attempts to read from a closed websocket it quickly and
|
|
|
|
// simply closes its associated Go routine. However the socket writer won't
|
|
|
|
// automatically notice until it actually needs to send something. So we force that
|
|
|
|
// by sending this NOOP text.
|
|
|
|
// TODO: There's a potential race condition because new connections share the same
|
|
|
|
// Go channel. So we need to setup a new channel for every connection.
|
|
|
|
func triggerSocketWriterClose() {
|
|
|
|
stdinChannel <- "BROWSH CLIENT FORCING CLOSE OF WEBSOCKET WRITER"
|
|
|
|
}
|
|
|
|
|
2018-01-21 03:56:05 +00:00
|
|
|
func webSocketWriter(ws *websocket.Conn) {
|
2018-01-07 03:21:29 +00:00
|
|
|
var message string
|
|
|
|
defer ws.Close()
|
|
|
|
for {
|
2018-01-10 14:54:51 +00:00
|
|
|
message = <-stdinChannel
|
|
|
|
log(fmt.Sprintf("TTY sending: %s", message))
|
2018-01-07 03:21:29 +00:00
|
|
|
if err := ws.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
|
2018-01-10 14:54:51 +00:00
|
|
|
if err == websocket.ErrCloseSent {
|
|
|
|
log("Socket writer detected that the browser closed the websocket")
|
|
|
|
return
|
|
|
|
}
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
2018-01-28 08:13:13 +00:00
|
|
|
log(fmt.Sprintf("TTY sent: %s", message))
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-21 03:56:05 +00:00
|
|
|
func webSocketServer(w http.ResponseWriter, r *http.Request) {
|
2018-01-10 14:54:51 +00:00
|
|
|
log("Incoming web request from browser")
|
2018-01-07 03:21:29 +00:00
|
|
|
ws, err := upgrader.Upgrade(w, r, nil)
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 03:56:05 +00:00
|
|
|
go webSocketWriter(ws)
|
|
|
|
go webSocketReader(ws)
|
2018-01-07 03:21:29 +00:00
|
|
|
|
|
|
|
sendTtySize()
|
|
|
|
}
|
|
|
|
|
2018-01-21 03:56:05 +00:00
|
|
|
func startHeadlessFirefox() {
|
|
|
|
println("Starting...")
|
|
|
|
log("Starting Firefox in headless mode")
|
2018-01-24 02:59:57 +00:00
|
|
|
args := []string{"--marionette"}
|
2018-01-21 03:56:05 +00:00
|
|
|
if !*isFFGui {
|
|
|
|
args = append(args, "--headless")
|
|
|
|
}
|
2018-02-01 07:37:38 +00:00
|
|
|
if *useFFProfile != "default" {
|
2018-01-24 08:32:52 +00:00
|
|
|
args = append(args, "-P", *useFFProfile)
|
|
|
|
}
|
2018-01-21 03:56:05 +00:00
|
|
|
firefoxProcess := exec.Command(*firefoxBinary, args...)
|
|
|
|
defer firefoxProcess.Process.Kill()
|
2018-01-24 08:32:52 +00:00
|
|
|
stdout, err := firefoxProcess.StdoutPipe()
|
2018-01-21 03:56:05 +00:00
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
if err := firefoxProcess.Start(); err != nil {
|
|
|
|
shutdown(err.Error())
|
|
|
|
}
|
|
|
|
in := bufio.NewScanner(stdout)
|
|
|
|
for in.Scan() {
|
|
|
|
log("FF-CONSOLE: " + in.Text()) // write each line to your log, or anything you need
|
2018-01-21 03:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 08:32:52 +00:00
|
|
|
// Connect to Firefox's Marionette service.
|
|
|
|
// RANT: Firefox's remote control tools are so confusing. There seem to be 2
|
|
|
|
// services that come with your Firefox binary; Marionette and the Remote
|
|
|
|
// Debugger. The latter you would expect to follow the widely supported
|
|
|
|
// Chrome standard, but no, it's merely on the roadmap. There is very little
|
|
|
|
// documentation on either. I have the impression, but I'm not sure why, that
|
|
|
|
// the Remote Debugger is better, seemingly more API methods, and as mentioned
|
|
|
|
// is on the roadmap to follow the Chrome standard.
|
|
|
|
// I've used Marionette here, simply because it was easier to reverse engineer
|
|
|
|
// from the Python Marionette package.
|
2018-01-21 03:56:05 +00:00
|
|
|
func firefoxMarionette() {
|
|
|
|
log("Attempting to connect to Firefox Marionette")
|
|
|
|
conn, err := net.Dial("tcp", "127.0.0.1:2828")
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-21 03:56:05 +00:00
|
|
|
}
|
2018-01-24 08:32:52 +00:00
|
|
|
marionette = conn
|
|
|
|
readMarionette()
|
2018-01-21 03:56:05 +00:00
|
|
|
sendFirefoxCommand("newSession", map[string]interface{}{})
|
|
|
|
}
|
|
|
|
|
2018-01-24 08:32:52 +00:00
|
|
|
// Install the Browsh extension that was bundled with `go-bindata` under
|
|
|
|
// `webextension.go`.
|
2018-01-21 03:56:05 +00:00
|
|
|
func installWebextension() {
|
|
|
|
data, err := Asset("webext/dist/web-ext-artifacts/browsh.xpi")
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-21 03:56:05 +00:00
|
|
|
}
|
|
|
|
file, err := ioutil.TempFile(os.TempDir(), "prefix")
|
|
|
|
defer os.Remove(file.Name())
|
|
|
|
ioutil.WriteFile(file.Name(), []byte(data), 0644)
|
2018-02-01 07:37:38 +00:00
|
|
|
args := map[string]interface{}{"path": file.Name()}
|
2018-01-21 03:56:05 +00:00
|
|
|
sendFirefoxCommand("addon:install", args)
|
|
|
|
}
|
|
|
|
|
2018-01-24 08:32:52 +00:00
|
|
|
// Set a Firefox preference as you would in `about:config`
|
|
|
|
// `value` needs to be supplied with quotes if it's to be used as a JS string
|
|
|
|
func setFFPreference(key string, value string) {
|
|
|
|
sendFirefoxCommand("setContext", map[string]interface{}{"value": "chrome"})
|
|
|
|
script := fmt.Sprintf(`
|
|
|
|
Components.utils.import("resource://gre/modules/Preferences.jsm");
|
|
|
|
prefs = new Preferences({defaultBranch: false});
|
|
|
|
prefs.set("%s", %s);`, key, value)
|
|
|
|
args := map[string]interface{}{"script": script}
|
|
|
|
sendFirefoxCommand("executeScript", args)
|
|
|
|
sendFirefoxCommand("setContext", map[string]interface{}{"value": "content"})
|
|
|
|
}
|
|
|
|
|
2018-01-28 08:13:13 +00:00
|
|
|
// Consume output from Marionette, we don't do anything with it. It"s just
|
2018-01-24 08:32:52 +00:00
|
|
|
// useful to have it in the logs.
|
2018-01-21 03:56:05 +00:00
|
|
|
func readMarionette() {
|
|
|
|
buffer := make([]byte, 4096)
|
|
|
|
count, err := marionette.Read(buffer)
|
|
|
|
if err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-21 03:56:05 +00:00
|
|
|
}
|
|
|
|
log("FF-MRNT: " + string(buffer[:count]))
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendFirefoxCommand(command string, args map[string]interface{}) {
|
|
|
|
log("Sending `" + command + "` to Firefox Marionette")
|
|
|
|
fullCommand := []interface{}{0, ffCommandCount, command, args}
|
|
|
|
marshalled, _ := json.Marshal(fullCommand)
|
|
|
|
message := fmt.Sprintf("%d:%s", len(marshalled), marshalled)
|
|
|
|
fmt.Fprintf(marionette, message)
|
|
|
|
ffCommandCount++
|
|
|
|
readMarionette()
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadHomePage() {
|
|
|
|
// Wait for the CLI websocket server to start listening
|
|
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
args := map[string]interface{}{
|
|
|
|
"url": "https://google.com",
|
|
|
|
}
|
|
|
|
sendFirefoxCommand("get", args)
|
|
|
|
}
|
|
|
|
|
2018-01-28 08:13:13 +00:00
|
|
|
func setDefaultPreferences() {
|
|
|
|
for key, value := range defaultFFPrefs {
|
|
|
|
setFFPreference(key, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:58:19 +00:00
|
|
|
// Note that everything executed in and from this function is not covered by the integration
|
|
|
|
// tests, because it uses the officially signed webextension, of which there can be only one.
|
|
|
|
// We can't bump the version and create a new signed webextension for every commit.
|
2018-01-21 03:56:05 +00:00
|
|
|
func setupFirefox() {
|
|
|
|
go startHeadlessFirefox()
|
2018-01-24 02:59:57 +00:00
|
|
|
// TODO: Do something better than just waiting
|
|
|
|
time.Sleep(3 * time.Second)
|
2018-01-21 03:56:05 +00:00
|
|
|
firefoxMarionette()
|
2018-01-28 08:13:13 +00:00
|
|
|
setDefaultPreferences()
|
2018-01-21 03:56:05 +00:00
|
|
|
installWebextension()
|
|
|
|
go loadHomePage()
|
|
|
|
}
|
|
|
|
|
2018-01-07 03:21:29 +00:00
|
|
|
func main() {
|
|
|
|
initialise()
|
2018-01-21 03:56:05 +00:00
|
|
|
if !*isUseExistingFirefox {
|
2018-01-28 08:13:13 +00:00
|
|
|
println("Starting Browsh...")
|
2018-01-21 03:56:05 +00:00
|
|
|
setupFirefox()
|
|
|
|
} else {
|
|
|
|
println("Waiting for a Firefox instance to connect...")
|
|
|
|
}
|
2018-01-10 14:54:51 +00:00
|
|
|
log("Starting Browsh CLI client")
|
2018-01-07 03:21:29 +00:00
|
|
|
go readStdin()
|
2018-01-21 03:56:05 +00:00
|
|
|
http.HandleFunc("/", webSocketServer)
|
|
|
|
if err := http.ListenAndServe(*webSocketAddresss, nil); err != nil {
|
2018-01-24 08:32:52 +00:00
|
|
|
shutdown(err.Error())
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|
2018-01-10 14:54:51 +00:00
|
|
|
log("Exiting at end of main()")
|
2018-01-07 03:21:29 +00:00
|
|
|
}
|