Fixes to get the Docker image building again

Firstly Firefox 60 now throws an error if its run as root inside a
user's home path. Which is great because that revelead my naivety about
using `RUN su user` in the Dockerfile. So now Firefox is running as a
non-root user inside Docker which is what was always best.

Also it turns out that the crude 3 second wait at startup hoping that
Firefox's Marionette had started listening, wasn't good enough. So now
we're actually listening for a log message to know when it's started
now.

Finally make all startup methods use a the post-webext connection state
to send the startup URL to the browser, the other methods just seemed to
flakey.

Includes version bump to 1.0.9
This commit is contained in:
Thomas Buckley-Houston 2018-06-12 15:40:49 +08:00
parent c13e8d26f6
commit 2577ea896b
5 changed files with 41 additions and 28 deletions

View file

@ -1,6 +1,6 @@
FROM bitnami/minideb:stretch FROM bitnami/minideb:stretch
RUN install_packages xvfb libgtk-3-0 curl ca-certificates bzip2 libdbus-glib-1-2 RUN install_packages xvfb libgtk-3-0 curl ca-certificates bzip2 libdbus-glib-1-2 procps
# Logging client for Google's Stackdriver logging service. # Logging client for Google's Stackdriver logging service.
# NB Not used by default. Only used by the Browsh as a Service platform on the # NB Not used by default. Only used by the Browsh as a Service platform on the
@ -8,19 +8,19 @@ RUN install_packages xvfb libgtk-3-0 curl ca-certificates bzip2 libdbus-glib-1-2
RUN curl -L -o /usr/local/bin/gcloud_logger https://github.com/tombh/gcloud_pipe_logger/releases/download/v0.0.5/gcloud_pipe_logger_0.0.5_linux_amd64 RUN curl -L -o /usr/local/bin/gcloud_logger https://github.com/tombh/gcloud_pipe_logger/releases/download/v0.0.5/gcloud_pipe_logger_0.0.5_linux_amd64
RUN chmod a+x /usr/local/bin/gcloud_logger RUN chmod a+x /usr/local/bin/gcloud_logger
RUN useradd -m user
RUN su user
ENV HOME=/home/user
WORKDIR $HOME
RUN curl -o /etc/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts RUN curl -o /etc/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts
RUN useradd -m user --home /app
USER user
ENV HOME=/app
WORKDIR /app
# These are needed to detect versions # These are needed to detect versions
ADD .travis.yml . ADD .travis.yml .
ADD ./webext/manifest.json . ADD ./webext/manifest.json .
# Setup Firefox # Setup Firefox
ENV PATH="/home/user/bin/firefox:${PATH}" ENV PATH="/app/bin/firefox:${PATH}"
ADD ./interfacer/contrib/setup_firefox.sh . ADD ./interfacer/contrib/setup_firefox.sh .
RUN ./setup_firefox.sh RUN ./setup_firefox.sh
RUN rm ./setup_firefox.sh && rm .travis.yml RUN rm ./setup_firefox.sh && rm .travis.yml
@ -33,11 +33,11 @@ RUN ./setup_browsh.sh
# that all future runs will be consistent. # that all future runs will be consistent.
RUN TERM=xterm script \ RUN TERM=xterm script \
--return \ --return \
-c "/home/user/browsh" \ -c "/app/browsh" \
/dev/null \ /dev/null \
>/dev/null & \ >/dev/null & \
sleep 10 sleep 10
RUN rm ./setup_browsh.sh && rm manifest.json RUN rm ./setup_browsh.sh && rm manifest.json
CMD ["/home/user/browsh"] CMD ["/app/browsh"]

View file

@ -28,8 +28,9 @@ var (
isUseExistingFirefox = flag.Bool("use-existing-ff", false, "Whether Browsh should launch Firefox or not") isUseExistingFirefox = flag.Bool("use-existing-ff", false, "Whether Browsh should launch Firefox or not")
useFFProfile = flag.String("ff-profile", "default", "Firefox profile to use") useFFProfile = flag.String("ff-profile", "default", "Firefox profile to use")
isDebug = flag.Bool("debug", false, "Log to ./debug.log") isDebug = flag.Bool("debug", false, "Log to ./debug.log")
StartupURL = flag.String("startup-url", "https://google.com", "URL to launch at startup")
timeLimit = flag.Int("time-limit", 0, "Kill Browsh after the specified number of seconds") timeLimit = flag.Int("time-limit", 0, "Kill Browsh after the specified number of seconds")
// StartupURL is the URL of the first tab at boot
StartupURL = flag.String("startup-url", "https://google.com", "URL to launch at startup")
// IsHTTPServer needs to be exported for use in tests // IsHTTPServer needs to be exported for use in tests
IsHTTPServer = flag.Bool("http-server", false, "Run as an HTTP service") IsHTTPServer = flag.Bool("http-server", false, "Run as an HTTP service")
// HTTPServerPort also needs to be exported for use in tests // HTTPServerPort also needs to be exported for use in tests

View file

@ -144,9 +144,7 @@ func webSocketServer(w http.ResponseWriter, r *http.Request) {
} else { } else {
sendTtySize() sendTtySize()
} }
if IsTesting { // For some reason, using Firefox's CLI arg `--url https://google.com` doesn't consistently
// For some reason, using Firefox's CLI arg `--url https://google.com` doesn't consistently // work. So we do it here instead.
// work on Travis. So we do it here inse sendMessageToWebExtension("/new_tab," + *StartupURL)
sendMessageToWebExtension("/new_tab," + *StartupURL)
}
} }

View file

@ -10,6 +10,7 @@ import (
"os/exec" "os/exec"
"runtime" "runtime"
"strings" "strings"
"regexp"
"time" "time"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
@ -18,6 +19,7 @@ import (
var ( var (
marionette net.Conn marionette net.Conn
isMarionetteListening = false
ffCommandCount = 0 ffCommandCount = 0
defaultFFPrefs = map[string]string{ defaultFFPrefs = map[string]string{
"browser.startup.homepage": "'https://www.google.com'", "browser.startup.homepage": "'https://www.google.com'",
@ -52,6 +54,8 @@ var (
) )
func startHeadlessFirefox() { func startHeadlessFirefox() {
var isMarionette, isListening bool
checkIfFirefoxIsAlreadyRunning()
Log("Starting Firefox in headless mode") Log("Starting Firefox in headless mode")
ensureFirefoxBinary() ensureFirefoxBinary()
args := []string{"--marionette"} args := []string{"--marionette"}
@ -77,10 +81,22 @@ func startHeadlessFirefox() {
} }
in := bufio.NewScanner(stdout) in := bufio.NewScanner(stdout)
for in.Scan() { for in.Scan() {
isMarionette = strings.Contains(in.Text(), "Marionette")
isListening = strings.Contains(in.Text(), "Listening on port")
if isMarionette && isListening { isMarionetteListening = true }
Log("FF-CONSOLE: " + in.Text()) Log("FF-CONSOLE: " + in.Text())
} }
} }
func checkIfFirefoxIsAlreadyRunning() {
if runtime.GOOS == "windows" { return }
processes := Shell("ps aux")
r, _ := regexp.Compile("firefox.*--headless")
if r.MatchString(processes) {
Shutdown(errors.New("A headless Firefox is already running"))
}
}
func ensureFirefoxBinary() { func ensureFirefoxBinary() {
if *firefoxBinary == "firefox" { if *firefoxBinary == "firefox" {
switch runtime.GOOS { switch runtime.GOOS {
@ -199,15 +215,6 @@ func sendFirefoxCommand(command string, args map[string]interface{}) {
readMarionette() readMarionette()
} }
func loadHomePage() {
// Wait for the CLI websocket server to start listening
time.Sleep(200 * time.Millisecond)
args := map[string]interface{}{
"url": *StartupURL,
}
sendFirefoxCommand("get", args)
}
func setDefaultPreferences() { func setDefaultPreferences() {
for key, value := range defaultFFPrefs { for key, value := range defaultFFPrefs {
setFFPreference(key, value) setFFPreference(key, value)
@ -233,12 +240,19 @@ func setupFirefox() {
if (*timeLimit > 0) { if (*timeLimit > 0) {
go beginTimeLimit() go beginTimeLimit()
} }
// TODO: Do something better than just waiting waitForMarionette()
time.Sleep(3 * time.Second)
firefoxMarionette() firefoxMarionette()
setDefaultPreferences() setDefaultPreferences()
installWebextension() installWebextension()
go loadHomePage() }
func waitForMarionette() {
start := time.Now()
for time.Since(start) < 60 * time.Second {
if isMarionetteListening { return }
time.Sleep(10 * time.Millisecond)
}
Shutdown(errors.New("Marionette didn't start within 60 seconds."))
} }
func startFirefox() { func startFirefox() {

View file

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Browsh", "name": "Browsh",
"version": "1.0.8", "version": "1.0.9",
"description": "Renders the browser as realtime, interactive, TTY-compatible text", "description": "Renders the browser as realtime, interactive, TTY-compatible text",