From 20266b063c1be8818d4582bff7b59486551ee447 Mon Sep 17 00:00:00 2001
From: "kali kaneko (leap communications)" <kali@leap.se>
Date: Wed, 17 Jun 2020 21:14:35 +0200
Subject: [PATCH] [feat] pass initialization errors to gui

---
 gui/backend.go                      |  1 -
 gui/main.cpp                        |  2 +-
 gui/qml/main.qml                    | 22 +++++---
 pkg/backend/callbacks.go            |  2 +-
 pkg/backend/donate.go               |  9 ++++
 pkg/backend/{bitmask.go => init.go} | 83 ++++++++++++++++-------------
 pkg/backend/status.go               |  1 +
 pkg/bitmask/init.go                 | 39 ++++----------
 pkg/config/gui.go                   |  1 -
 pkg/vpn/launcher_linux.go           | 53 +++++++++++-------
 pkg/vpn/main.go                     | 11 ++--
 pkg/vpn/openvpn.go                  |  5 +-
 12 files changed, 127 insertions(+), 102 deletions(-)
 rename pkg/backend/{bitmask.go => init.go} (64%)

diff --git a/gui/backend.go b/gui/backend.go
index edb2b173..92cda6e2 100644
--- a/gui/backend.go
+++ b/gui/backend.go
@@ -30,7 +30,6 @@ func Unblock() {
 //export Quit
 func Quit() {
 	backend.Quit()
-
 }
 
 //export DonateAccepted
diff --git a/gui/main.cpp b/gui/main.cpp
index eca834a9..670e6649 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -34,7 +34,7 @@ std::string getEnv(std::string const& key)
     return val == NULL ? std::string() : std::string(val);
 }
 
-void signalHandler(int signum) {
+void signalHandler(int) {
     Quit();
     exit(0);
 }
diff --git a/gui/qml/main.qml b/gui/qml/main.qml
index 8d756c6c..efcfef21 100644
--- a/gui/qml/main.qml
+++ b/gui/qml/main.qml
@@ -11,7 +11,6 @@ ApplicationWindow {
 
     property var     ctx
 
-
     Connections {
         target: jsonModel
         onDataChanged: {
@@ -20,9 +19,24 @@ ApplicationWindow {
                 console.debug(jsonModel.getJson())
                 donate.visible = true
             }
+            if (ctx.errors ) {
+               // TODO consider disabling on/off buttons, or quit after closing the dialog
+               if ( ctx.errors  == "nohelpers" ) {
+                   showInitFailure(qsTr("Could not find helpers. Check your installation"))
+               } else if ( ctx.errors == "nopolkit" ) {
+                   showInitFailure(qsTr("Could not find polkit agent."))
+               } else {
+                   console.debug(ctx.errors)
+               }
+            }
         }
     }
 
+    function showInitFailure(msg) {
+          initFailure.text = msg
+          initFailure.visible  = true
+    }
+
     Component.onCompleted: {
         /* stupid as it sounds, windows doesn't like to have the systray icon
          not being attached to an actual application window.
@@ -210,9 +224,6 @@ ApplicationWindow {
         text: ""
         detailedText: ""
         visible: false
-        //text: ctx ? qsTr("Can't connect to %1").arg(ctx.appName) : ""
-        //detailedText: ctx ? ctx.errorStartingMsg : ""
-        //visible: ctx.errorStartingMsg != ""
     }
 
     MessageDialog {
@@ -222,7 +233,6 @@ ApplicationWindow {
         title: qsTr("Missing authentication agent")
         text: qsTr("Could not find a polkit authentication agent. Please run one and try again.")
         visible: false
-        //visible: ctx.missingAuthAgent == "true"
     }
 
     MessageDialog {
@@ -232,7 +242,5 @@ ApplicationWindow {
         title: qsTr("Initialization Error")
         text: ""
         visible: false
-        //text: ctx ? ctx.errorInitMsg : ""
-        //visible: ctx.errorInitMsg != ""
     }
 }
diff --git a/pkg/backend/callbacks.go b/pkg/backend/callbacks.go
index 5ea3b048..f3bb39fb 100644
--- a/pkg/backend/callbacks.go
+++ b/pkg/backend/callbacks.go
@@ -7,7 +7,7 @@ import (
 	"unsafe"
 )
 
-/* NOTE! ATCHUNG! what follow are not silly comments. Well, *this one* is, but
+/* ATCHUNG! what follow are not silly comments. Well, *this one* is, but
    the lines after this are not.
    Those are inline C functions, that are invoked by CGO later on.
    it's also crucial that you don't any extra space between the function
diff --git a/pkg/backend/donate.go b/pkg/backend/donate.go
index d2166876..608128f4 100644
--- a/pkg/backend/donate.go
+++ b/pkg/backend/donate.go
@@ -3,8 +3,17 @@ package backend
 import (
 	"log"
 	"time"
+
+	"0xacab.org/leap/bitmask-vpn/pkg/config"
 )
 
+func wantDonations() bool {
+	if config.AskForDonations == "true" {
+		return true
+	}
+	return false
+}
+
 func needsDonationReminder() bool {
 	return ctx.cfg.NeedsDonationReminder()
 }
diff --git a/pkg/backend/bitmask.go b/pkg/backend/init.go
similarity index 64%
rename from pkg/backend/bitmask.go
rename to pkg/backend/init.go
index 2b588596..5abb05ec 100644
--- a/pkg/backend/bitmask.go
+++ b/pkg/backend/init.go
@@ -9,43 +9,6 @@ import (
 	"0xacab.org/leap/bitmask-vpn/pkg/config/version"
 )
 
-func initializeBitmask() {
-	if ctx == nil {
-		log.Println("error: cannot initialize bitmask, ctx is nil")
-		os.Exit(1)
-	}
-	bitmask.InitializeLogger()
-
-	b, err := bitmask.InitializeBitmask()
-	if err != nil {
-		log.Println("error: cannot initialize bitmask")
-	}
-	ctx.bm = b
-	ctx.cfg = config.ParseConfig()
-}
-
-func startVPN() {
-	err := ctx.bm.StartVPN(ctx.Provider)
-	if err != nil {
-		log.Println(err)
-		os.Exit(1)
-	}
-}
-
-func stopVPN() {
-	err := ctx.bm.StopVPN()
-	if err != nil {
-		log.Println(err)
-	}
-}
-
-func wantDonations() bool {
-	if config.AskForDonations == "true" {
-		return true
-	}
-	return false
-}
-
 // initializeContext initializes an empty connStatus and assigns it to the
 // global ctx holder. This is expected to be called only once, so the public
 // api uses the sync.Once primitive to call this.
@@ -62,6 +25,50 @@ func initializeContext(provider, appName string) {
 		Version:         version.VERSION,
 		Status:          st,
 	}
+	errCh := make(chan string)
 	go trigger(OnStatusChanged)
-	initializeBitmask()
+	go checkErrors(errCh)
+	initializeBitmask(errCh)
+}
+
+func checkErrors(errCh chan string) {
+	for {
+		err := <-errCh
+		ctx.Errors = err
+		go trigger(OnStatusChanged)
+	}
+}
+
+func initializeBitmask(errCh chan string) {
+	if ctx == nil {
+		log.Println("bug: cannot initialize bitmask, ctx is nil!")
+		os.Exit(1)
+	}
+	bitmask.InitializeLogger()
+
+	b, err := bitmask.InitializeBitmask()
+	if err != nil {
+		log.Println("error: cannot initialize bitmask")
+		errCh <- err.Error()
+		return
+	}
+
+	helpers, privilege, err := b.VPNCheck()
+
+	if err != nil {
+		log.Println("error doing vpn check")
+		errCh <- err.Error()
+	}
+
+	if helpers == false {
+		log.Println("no helpers")
+		errCh <- "nohelpers"
+	}
+	if privilege == false {
+		log.Println("no polkit")
+		errCh <- "nopolkit"
+	}
+
+	ctx.bm = b
+	ctx.cfg = config.ParseConfig()
 }
diff --git a/pkg/backend/status.go b/pkg/backend/status.go
index 84b27b7c..2e9c282d 100644
--- a/pkg/backend/status.go
+++ b/pkg/backend/status.go
@@ -35,6 +35,7 @@ type connectionCtx struct {
 	DonateDialog    bool   `json:"donateDialog"`
 	DonateURL       string `json:"donateURL"`
 	Version         string `json:"version"`
+	Errors          string `json:"errors"`
 	Status          status `json:"status"`
 	bm              bitmask.Bitmask
 	cfg             *config.Config
diff --git a/pkg/bitmask/init.go b/pkg/bitmask/init.go
index 7f10ab9d..33a5911f 100644
--- a/pkg/bitmask/init.go
+++ b/pkg/bitmask/init.go
@@ -68,15 +68,17 @@ func InitializeBitmask() (Bitmask, error) {
 	defer pid.ReleasePID()
 
 	conf := config.ParseConfig()
-	conf.Version = "unknown"
 	conf.Printer = initPrinter()
 
 	b, err := initBitmask(conf.Printer)
 	if err != nil {
-		// TODO notify failure
-		log.Fatal(err)
+		return nil, err
+	}
+
+	err = checkAndStartBitmask(b, conf)
+	if err != nil {
+		return nil, err
 	}
-	go checkAndStartBitmask(b, conf)
 
 	var as Autostart
 	if conf.DisableAustostart {
@@ -84,6 +86,7 @@ func InitializeBitmask() (Bitmask, error) {
 	} else {
 		as = newAutostart(config.ApplicationName, "")
 	}
+
 	err = as.Enable()
 	if err != nil {
 		log.Printf("Error enabling autostart: %v", err)
@@ -100,40 +103,20 @@ func initPrinter() *message.Printer {
 	return message.NewPrinter(message.MatchLanguage(locale, "en"))
 }
 
-func checkAndStartBitmask(b Bitmask, conf *config.Config) {
+func checkAndStartBitmask(b Bitmask, conf *config.Config) error {
 	if conf.Obfs4 {
 		err := b.UseTransport("obfs4")
 		if err != nil {
 			log.Printf("Error setting transport: %v", err)
+			return err
 		}
 	}
-	err := checkAndInstallHelpers(b)
-	if err != nil {
-		log.Printf("Is bitmask running? %v", err)
-		os.Exit(1)
-	}
-	err = maybeStartVPN(b, conf)
+
+	err := maybeStartVPN(b, conf)
 	if err != nil {
 		log.Println("Error starting VPN: ", err)
-	}
-}
-
-func checkAndInstallHelpers(b Bitmask) error {
-	helpers, privilege, err := b.VPNCheck()
-	if (err != nil && err.Error() == "nopolkit") || (err == nil && !privilege) {
-		log.Printf("No polkit found")
-		os.Exit(1)
-	} else if err != nil {
-		log.Printf("Error checking vpn: %v", err)
 		return err
 	}
-
-	if !helpers {
-		err = b.InstallHelpers()
-		if err != nil {
-			log.Println("Error installing helpers: ", err)
-		}
-	}
 	return nil
 }
 
diff --git a/pkg/config/gui.go b/pkg/config/gui.go
index 5fa4886f..7f2515ce 100644
--- a/pkg/config/gui.go
+++ b/pkg/config/gui.go
@@ -48,7 +48,6 @@ type Config struct {
 	Obfs4             bool
 	DisableAustostart bool
 	StartVPN          bool
-	Version           string
 	Printer           *message.Printer
 }
 
diff --git a/pkg/vpn/launcher_linux.go b/pkg/vpn/launcher_linux.go
index 71a74eaf..f92cf6ff 100644
--- a/pkg/vpn/launcher_linux.go
+++ b/pkg/vpn/launcher_linux.go
@@ -1,5 +1,5 @@
 // +build linux
-// Copyright (C) 2018 LEAP
+// Copyright (C) 2018-2020 LEAP
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -53,32 +53,49 @@ func (l *launcher) close() error {
 	return nil
 }
 
-func (l *launcher) check() (helpers bool, priviledge bool, err error) {
+func (l *launcher) check() (helpers bool, privilege bool, err error) {
+	hasHelpers, err := hasHelpers()
+	if err != nil {
+		return
+	}
+	if !hasHelpers {
+		return false, true, nil
+	}
 
-	/*
-		isRunning, err := isPolkitRunning()
+	isRunning, err := isPolkitRunning()
+	if err != nil {
+		return
+	}
+
+	if !isRunning {
+		polkitPath := getPolkitPath()
+		if polkitPath == "" {
+			return true, false, nil
+		}
+		cmd := exec.Command("setsid", polkitPath)
+		err = cmd.Start()
 		if err != nil {
 			return
 		}
-		if !isRunning {
-			polkitPath := getPolkitPath()
-			if polkitPath == "" {
-				return true, false, nil
-			}
-			cmd := exec.Command("setsid", polkitPath)
-			err = cmd.Start()
-			if err != nil {
-				return
-			}
-			isRunning, err = isPolkitRunning()
-			return true, isRunning, err
-		}
-	*/
+		isRunning, err = isPolkitRunning()
+		return true, isRunning, err
+	}
 
 	return true, true, nil
 }
 
+func hasHelpers() (bool, error) {
+	/* TODO add polkit file too */
+	for _, f := range bitmaskRootPaths {
+		if _, err := os.Stat(f); err == nil {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
 func isPolkitRunning() (bool, error) {
+	// TODO shouldn't we also check for polkitd running?
 	var polkitProcNames = [...]string{
 		"polkit-gnome-authentication-agent-1",
 		"polkit-kde-authentication-agent-1",
diff --git a/pkg/vpn/main.go b/pkg/vpn/main.go
index ce599c94..9d59131b 100644
--- a/pkg/vpn/main.go
+++ b/pkg/vpn/main.go
@@ -51,10 +51,13 @@ func Init() (*Bitmask, error) {
 	}
 	b := Bitmask{tempdir, statusCh, nil, bonafide, launch, "", nil}
 
-	err = b.StopVPN()
-	if err != nil {
-		return nil, err
-	}
+	/*
+		err = b.StopVPN()
+		if err != nil {
+			return nil, err
+		}
+	*/
+
 	err = ioutil.WriteFile(b.getCaCertPath(), config.CaCert, 0600)
 
 	go b.openvpnManagement()
diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go
index a75b830a..984aa09c 100644
--- a/pkg/vpn/openvpn.go
+++ b/pkg/vpn/openvpn.go
@@ -207,14 +207,13 @@ func (b *Bitmask) GetStatus() (string, error) {
 	return status, nil
 }
 
-// InstallHelpers into the system
 func (b *Bitmask) InstallHelpers() error {
-	// TODO
+	// TODO use pickle module from here
 	return nil
 }
 
 // VPNCheck returns if the helpers are installed and up to date and if polkit is running
-func (b *Bitmask) VPNCheck() (helpers bool, priviledge bool, err error) {
+func (b *Bitmask) VPNCheck() (helpers bool, privilege bool, err error) {
 	return b.launch.check()
 }
 
-- 
GitLab