diff --git a/Makefile b/Makefile
index 54fdf331fd4c5adabff14606a219331ecbed7e0e..d3ae5f50660a1a7de059abbc936bd3471f6b70c5 100644
--- a/Makefile
+++ b/Makefile
@@ -262,6 +262,10 @@ clean:
 qmllint:
 	@qmllint gui/qml/*.qml
 
+qmlfmt:
+	# needs https://github.com/jesperhh/qmlfmt in your path
+	@qmlfmt -w gui/qml/*.qml
+
 test:
 	@go test -tags "integration $(TAGS)" ./pkg/...
 
diff --git a/gui/providers/providers.json b/gui/providers/providers.json
index 28918557016deb6431267ae7ea1d9f5548ad00f6..d0d3a6272c7da8fc591022d65fd7e9ae9e5c3231 100644
--- a/gui/providers/providers.json
+++ b/gui/providers/providers.json
@@ -15,7 +15,7 @@
             "apiURL": "https://api.black.riseup.net/",
             "geolocationAPI": "https://api.black.riseup.net:9001/json",
             "caCertString": "-----BEGIN CERTIFICATE-----\nMIIFjTCCA3WgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBZMRgwFgYDVQQKDA9SaXNl\ndXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UE\nAwwXUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EwHhcNMTQwNDI4MDAwMDAwWhcNMjQw\nNDI4MDAwMDAwWjBZMRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsM\nEmh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UEAwwXUmlzZXVwIE5ldHdvcmtzIFJv\nb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC76J4ciMJ8Sg0m\nTP7DF2DT9zNe0Csk4myoMFC57rfJeqsAlJCv1XMzBmXrw8wq/9z7XHv6n/0sWU7a\n7cF2hLR33ktjwODlx7vorU39/lXLndo492ZBhXQtG1INMShyv+nlmzO6GT7ESfNE\nLliFitEzwIegpMqxCIHXFuobGSCWF4N0qLHkq/SYUMoOJ96O3hmPSl1kFDRMtWXY\niw1SEKjUvpyDJpVs3NGxeLCaA7bAWhDY5s5Yb2fA1o8ICAqhowurowJpW7n5ZuLK\n5VNTlNy6nZpkjt1QycYvNycffyPOFm/Q/RKDlvnorJIrihPkyniV3YY5cGgP+Qkx\nHUOT0uLA6LHtzfiyaOqkXwc4b0ZcQD5Vbf6Prd20Ppt6ei0zazkUPwxld3hgyw58\nm/4UIjG3PInWTNf293GngK2Bnz8Qx9e/6TueMSAn/3JBLem56E0WtmbLVjvko+LF\nPM5xA+m0BmuSJtrD1MUCXMhqYTtiOvgLBlUm5zkNxALzG+cXB28k6XikXt6MRG7q\nhzIPG38zwkooM55yy5i1YfcIi5NjMH6A+t4IJxxwb67MSb6UFOwg5kFokdONZcwj\nshczHdG9gLKSBIvrKa03Nd3W2dF9hMbRu//STcQxOailDBQCnXXfAATj9pYzdY4k\nha8VCAREGAKTDAex9oXf1yRuktES4QIDAQABo2AwXjAdBgNVHQ4EFgQUC4tdmLVu\nf9hwfK4AGliaet5KkcgwDgYDVR0PAQH/BAQDAgIEMAwGA1UdEwQFMAMBAf8wHwYD\nVR0jBBgwFoAUC4tdmLVuf9hwfK4AGliaet5KkcgwDQYJKoZIhvcNAQENBQADggIB\nAGzL+GRnYu99zFoy0bXJKOGCF5XUXP/3gIXPRDqQf5g7Cu/jYMID9dB3No4Zmf7v\nqHjiSXiS8jx1j/6/Luk6PpFbT7QYm4QLs1f4BlfZOti2KE8r7KRDPIecUsUXW6P/\n3GJAVYH/+7OjA39za9AieM7+H5BELGccGrM5wfl7JeEz8in+V2ZWDzHQO4hMkiTQ\n4ZckuaL201F68YpiItBNnJ9N5nHr1MRiGyApHmLXY/wvlrOpclh95qn+lG6/2jk7\n3AmihLOKYMlPwPakJg4PYczm3icFLgTpjV5sq2md9bRyAg3oPGfAuWHmKj2Ikqch\nTd5CHKGxEEWbGUWEMP0s1A/JHWiCbDigc4Cfxhy56CWG4q0tYtnc2GMw8OAUO6Wf\nXu5pYKNkzKSEtT/MrNJt44tTZWbKV/Pi/N2Fx36my7TgTUj7g3xcE9eF4JV2H/sg\ntsK3pwE0FEqGnT4qMFbixQmc8bGyuakr23wjMvfO7eZUxBuWYR2SkcP26sozF9PF\ntGhbZHQVGZUTVPyvwahMUEhbPGVerOW0IYpxkm0x/eaWdTc4vPpf/rIlgbAjarnJ\nUN9SaWRlWKSdP4haujnzCoJbM7dU9bjvlGZNyXEekgeT0W2qFeGGp+yyUWw8tNsp\n0BuC1b7uW/bBn/xKm319wXVDvBgZgcktMolak39V7DVO\n-----END CERTIFICATE-----",
-            "timeStamp": "2020-11-30 22:04:27"
+            "timeStamp": "2021-02-08 23:57:09"
         }
     ]
 }
\ No newline at end of file
diff --git a/gui/qml/AboutDialog.qml b/gui/qml/AboutDialog.qml
index 97be25e309d89d052e0f01385d1c687e6147234b..7c673d23c3fe2c02d7c8cced7f50aef6df2fa717 100644
--- a/gui/qml/AboutDialog.qml
+++ b/gui/qml/AboutDialog.qml
@@ -4,35 +4,37 @@ import QtQuick.Dialogs 1.2
 MessageDialog {
     title: qsTr("About")
     text: getText()
-    informativeText: getVersion() 
+    informativeText: getVersion()
     icon: StandardIcon.Information
 
     function getText() {
         var _name = ctx ? ctx.appName : "vpn"
         var _provider = ctx ? ctx.provider : "unknown"
-        var _donateURL= ctx ? ctx.donateURL : ""
+        var _donateURL = ctx ? ctx.donateURL : ""
         var _tosURL = ctx ? ctx.tosURL : "..."
         var _donateTXT = ""
         if (_donateURL) {
             //: donation text of the about dialog
-            _donateTXT = qsTr("<p>This service is paid for entirely by donations from users like you. <a href=\"%1\">Please donate</a>.</p>").arg(_donateURL)
+            _donateTXT = qsTr(
+                        "<p>This service is paid for entirely by donations from users like you. <a href=\"%1\">Please donate</a>.</p>").arg(
+                        _donateURL)
         }
-	//: about dialog
-	//: %1 -> application name
-	//: %2 -> provider name
-	//: %3 -> donation text if activated
+        //: about dialog
+        //: %1 -> application name
+        //: %2 -> provider name
+        //: %3 -> donation text if activated
         var _txt = qsTr(
-            "<p>%1 is an easy, fast, and secure VPN service from %2. %1 does not require a user account, keep logs, or track you in any way.</p> %3 <p>By using this application, you agree to the <a href=\"%4\">Terms of Service</a>. This service is provided as-is, without any warranty, and is intended for people who work to make the world a better place.</p>").arg(_name).arg(_provider).arg(_donateTXT).arg(_tosURL)
+                    "<p>%1 is an easy, fast, and secure VPN service from %2. %1 does not require a user account, keep logs, or track you in any way.</p> %3 <p>By using this application, you agree to the <a href=\"%4\">Terms of Service</a>. This service is provided as-is, without any warranty, and is intended for people who work to make the world a better place.</p>").arg(
+                    _name).arg(_provider).arg(_donateTXT).arg(_tosURL)
         return _txt
     }
 
     function getVersion() {
         var _name = ctx ? ctx.appName : "vpn"
-        var _ver  = ctx ? ctx.version : "unknown"
-	//: %1 -> application name
-	//: %2 -> version string
-        var _txt  = qsTr("%1 version: %2").arg(_name).arg(_ver)
+        var _ver = ctx ? ctx.version : "unknown"
+        //: %1 -> application name
+        //: %2 -> version string
+        var _txt = qsTr("%1 version: %2").arg(_name).arg(_ver)
         return _txt
     }
 }
-
diff --git a/gui/qml/DonateDialog.qml b/gui/qml/DonateDialog.qml
index 366d5590314f6f8a75d87c213438bc0d8b11bc88..1604e412b127c81c34fdd639e63871d58bab09ad 100644
--- a/gui/qml/DonateDialog.qml
+++ b/gui/qml/DonateDialog.qml
@@ -9,10 +9,11 @@ MessageDialog {
 
     function getText() {
         var _name = ctx ? ctx.appName : "vpn"
-	//: donate dialog
-	//: %1 -> application name
+        //: donate dialog
+        //: %1 -> application name
         var _txt = qsTr(
-            "The %1 service is expensive to run. Because we don't want to store personal information about you, there are no accounts or billing for this service. But if you want the service to continue, donate at least $5 each month.\n\nDo you want to donate now?").arg(_name)
+                    "The %1 service is expensive to run. Because we don't want to store personal information about you, there are no accounts or billing for this service. But if you want the service to continue, donate at least $5 each month.\n\nDo you want to donate now?").arg(
+                    _name)
         return _txt
     }
 
diff --git a/gui/qml/FailDialog.qml b/gui/qml/FailDialog.qml
index 3da421bfd3586ad40f164db9e0f524f6c13896d6..a78690e5cdaff74a59d8553343cf50767ee4b932 100644
--- a/gui/qml/FailDialog.qml
+++ b/gui/qml/FailDialog.qml
@@ -20,4 +20,3 @@ MessageDialog {
         }
     }
 }
-
diff --git a/gui/qml/LoginOKDialog.qml b/gui/qml/LoginOKDialog.qml
index bceda1862265a83fde727c013ccd2fcf481df727..f00a0ab13fb22c2fc5606e2561c7611f007f5be5 100644
--- a/gui/qml/LoginOKDialog.qml
+++ b/gui/qml/LoginOKDialog.qml
@@ -13,8 +13,8 @@ Dialog {
     }
 
     function _loginOk() {
-        visible: false;
-        backend.resetNotification("login_ok");
+        visible: false
+        backend.resetNotification("login_ok")
     }
 
     visible: false
diff --git a/gui/qml/main.qml b/gui/qml/main.qml
index 4fce2c4f3b6413a01603535ab1b174a646947551..4115922d1647bdd2171dd2cbfeda9d125335ea01 100644
--- a/gui/qml/main.qml
+++ b/gui/qml/main.qml
@@ -10,13 +10,13 @@ ApplicationWindow {
     visible: false
 
     property var ctx
-    property var loginDone 
+    property var loginDone
     property var allowEmptyPass
 
     Connections {
         target: jsonModel
         onDataChanged: {
-            ctx = JSON.parse(jsonModel.getJson());
+            ctx = JSON.parse(jsonModel.getJson())
 
             // FIXME -- we need to inform the backend that we've already seen
             // this. Otherwise this keeps popping randonmly on state changes.
@@ -32,15 +32,16 @@ ApplicationWindow {
             if (ctx.loginOk == 'true') {
                 loginOk.visible = true
             }
-            if (ctx.errors ) {
-               login.visible = false
-               if ( ctx.errors  == "nohelpers" ) {
-                   showInitFailure(qsTr("Could not find helpers. Please check your installation"))
-               } else if ( ctx.errors == "nopolkit" ) {
-                   showInitFailure(qsTr("Could not find polkit agent."))
-               } else {
-                   showInitFailure()
-               }
+            if (ctx.errors) {
+                login.visible = false
+                if (ctx.errors == "nohelpers") {
+                    showInitFailure(
+                                qsTr("Could not find helpers. Please check your installation"))
+                } else if (ctx.errors == "nopolkit") {
+                    showInitFailure(qsTr("Could not find polkit agent."))
+                } else {
+                    showInitFailure()
+                }
             }
             if (ctx.donateURL) {
                 donateItem.visible = true
@@ -51,11 +52,11 @@ ApplicationWindow {
     function showInitFailure(msg) {
         console.debug("ERRORS:", ctx.errors)
         if (msg == undefined) {
-            if (ctx.errors == 'bad_auth_502' || ctx.errors == 'bad_auth_timeout') {
-                    msg = qsTr("Oops! The authentication service seems down. Please try again later")
+            if (ctx.errors == 'bad_auth_502'
+                    || ctx.errors == 'bad_auth_timeout') {
+                msg = qsTr("Oops! The authentication service seems down. Please try again later")
                 initFailure.title = qsTr("Service Error")
-            }
-            else if (ctx.errors == 'bad_auth') {
+            } else if (ctx.errors == 'bad_auth') {
                 if (allowEmptyPass) {
                     // For now, this is a libraryVPN, so we can be explicit about what credentials are here.
                     // Another option to consider is to customize the error strings while vendoring.
@@ -68,18 +69,19 @@ ApplicationWindow {
             } else {
                 //: %1 -> application name
                 //: %2 -> error string
-                msg = qsTr("Got an error starting %1: %2").arg(ctx.appName).arg(ctx.errors)
+                msg = qsTr("Got an error starting %1: %2").arg(ctx.appName).arg(
+                            ctx.errors)
             }
         }
         initFailure.text = msg
-        initFailure.visible  = true
+        initFailure.visible = true
     }
 
     function shouldAllowEmptyPass() {
         let obj = JSON.parse(providers.getJson())
         let active = obj['default']
         let allProviders = obj['providers']
-        for (let i = 0; i < allProviders.length; i++) {
+        for (var i = 0; i < allProviders.length; i++) {
             if (allProviders[i]['name'] === active) {
                 return (allProviders[i]['authEmptyPass'] === 'true')
             }
@@ -88,44 +90,44 @@ ApplicationWindow {
     }
 
     Component.onCompleted: {
-        loginDone = false;
-        console.debug("Platform:", Qt.platform.os);
-        console.debug("DEBUG: Pre-seeded providers:");
-        console.debug(providers.getJson());
-        allowEmptyPass = shouldAllowEmptyPass();
+        loginDone = false
+        console.debug("Platform:", Qt.platform.os)
+        console.debug("DEBUG: Pre-seeded providers:")
+        console.debug(providers.getJson())
+        allowEmptyPass = shouldAllowEmptyPass()
 
         /* TODO get appVisible flag from backend */
-        app.visible = false;
+        app.visible = false
     }
 
     function toHuman(st) {
-        switch(st) {
-            case "off":
-                //: %1 -> application name
-                return qsTr("%1 off").arg(ctx.appName);
-            case "on":
-                //: %1 -> application name
-                return qsTr("%1 on").arg(ctx.appName);
-            case "connecting":
-                //: %1 -> application name
-                return qsTr("Connecting to %1").arg(ctx.appName);
-            case "stopping":
-                 //: %1 -> application name
-                return qsTr("Stopping %1").arg(ctx.appName);
-            case "failed":
-                //: %1 -> application name
-                return qsTr("%1 blocking internet").arg(ctx.appName); // TODO failed is not handed yet
+        switch (st) {
+        case "off":
+            //: %1 -> application name
+            return qsTr("%1 off").arg(ctx.appName)
+        case "on":
+            //: %1 -> application name
+            return qsTr("%1 on").arg(ctx.appName)
+        case "connecting":
+            //: %1 -> application name
+            return qsTr("Connecting to %1").arg(ctx.appName)
+        case "stopping":
+            //: %1 -> application name
+            return qsTr("Stopping %1").arg(ctx.appName)
+        case "failed":
+            //: %1 -> application name
+            return qsTr("%1 blocking internet").arg(
+                        ctx.appName) // TODO failed is not handed yet
         }
     }
 
     property var icons: {
-        "off":     "qrc:/assets/icon/png/black/vpn_off.png",
-        "on":      "qrc:/assets/icon/png/black/vpn_on.png",
-        "wait":    "qrc:/assets/icon/png/black/vpn_wait_0.png",
-        "blocked": "qrc:/assets/icon/png/black/vpn_blocked.png",
+        "off": "qrc:/assets/icon/png/black/vpn_off.png",
+        "on": "qrc:/assets/icon/png/black/vpn_on.png",
+        "wait": "qrc:/assets/icon/png/black/vpn_wait_0.png",
+        "blocked": "qrc:/assets/icon/png/black/vpn_blocked.png"
     }
 
-
     SystemTrayIcon {
 
         id: systray
@@ -136,31 +138,31 @@ ApplicationWindow {
             // produce a segfault when trying to call menu.open()
             // left and right click seem to be working fine, so let's ignore this for now.
             switch (reason) {
-                case SystemTrayIcon.Unknown:
-                    console.debug("activated: unknown event")
+            case SystemTrayIcon.Unknown:
+                console.debug("activated: unknown event")
+                menu.open()
+                break
+            case SystemTrayIcon.Context:
+                console.debug("activated: context")
+                /* segfaults in osx and linux */
+                if (Qt.platform.os === "windows") {
                     menu.open()
-                    break
-                case SystemTrayIcon.Context:
-                    console.debug("activated: context")
-                    /* segfaults in osx and linux */
-                    if (Qt.platform.os === "windows") {
-                        menu.open()
-                    }
-                    break
-                case SystemTrayIcon.DoubleClick:
-                    console.debug("activated: double click")
-                    if (Qt.platform.os === "windows") {
-                        menu.open()
-                    }
-                    break
-                case SystemTrayIcon.Trigger:
-                    console.debug("activated: left click")
-                    if (Qt.platform.os === "windows") {
-                        menu.open()
-                    }
-                    break
-                case SystemTrayIcon.MiddleClick:
-                    break
+                }
+                break
+            case SystemTrayIcon.DoubleClick:
+                console.debug("activated: double click")
+                if (Qt.platform.os === "windows") {
+                    menu.open()
+                }
+                break
+            case SystemTrayIcon.Trigger:
+                console.debug("activated: left click")
+                if (Qt.platform.os === "windows") {
+                    menu.open()
+                }
+                break
+            case SystemTrayIcon.MiddleClick:
+                break
             }
         }
 
@@ -168,24 +170,26 @@ ApplicationWindow {
             icon.source = icons["off"]
             tooltip = qsTr("Checking status...")
             console.debug("systray init completed")
-            hide();
+            hide()
             if (systrayVisible) {
-                show();
+                show()
                 if (Qt.platform.os === "windows") {
-                    let appname = ctx ? ctx.appName: "VPN";
-                    showNotification(appname + " is up and running. Please use system tray icon to control it.");
+                    let appname = ctx ? ctx.appName : "VPN"
+                    showNotification(
+                                appname
+                                + " is up and running. Please use system tray icon to control it.")
                 }
             }
         }
 
         // Helper to show notification messages
         function showNotification(msg) {
-            console.log("Going to show notification message: ", msg);
+            console.log("Going to show notification message: ", msg)
             if (supportsMessages) {
-                let appname = ctx ? ctx.appName: "VPN";
-                showMessage(appname, msg, null, 15000);
+                let appname = ctx ? ctx.appName : "VPN"
+                showMessage(appname, msg, null, 15000)
             } else {
-                console.log("System doesn't support systray notifications");
+                console.log("System doesn't support systray notifications")
             }
         }
 
@@ -198,31 +202,68 @@ ApplicationWindow {
                 state: ctx ? ctx.status : ""
 
                 states: [
-                    State { name: "initializing" },
+                    State {
+                        name: "initializing"
+                    },
                     State {
                         name: "off"
-                        PropertyChanges { target: systray; tooltip: toHuman("off"); icon.source: icons["off"] }
-                        PropertyChanges { target: statusItem; text: toHuman("off") }
+                        PropertyChanges {
+                            target: systray
+                            tooltip: toHuman("off")
+                            icon.source: icons["off"]
+                        }
+                        PropertyChanges {
+                            target: statusItem
+                            text: toHuman("off")
+                        }
                     },
                     State {
                         name: "on"
-                        PropertyChanges { target: systray; tooltip: toHuman("on"); icon.source: icons["on"] }
-                        PropertyChanges { target: statusItem; text: toHuman("on") }
+                        PropertyChanges {
+                            target: systray
+                            tooltip: toHuman("on")
+                            icon.source: icons["on"]
+                        }
+                        PropertyChanges {
+                            target: statusItem
+                            text: toHuman("on")
+                        }
                     },
                     State {
                         name: "starting"
-                        PropertyChanges { target: systray; tooltip: toHuman("connecting"); icon.source: icons["wait"] }
-                        PropertyChanges { target: statusItem; text: toHuman("connecting") }
+                        PropertyChanges {
+                            target: systray
+                            tooltip: toHuman("connecting")
+                            icon.source: icons["wait"]
+                        }
+                        PropertyChanges {
+                            target: statusItem
+                            text: toHuman("connecting")
+                        }
                     },
                     State {
                         name: "stopping"
-                        PropertyChanges { target: systray; tooltip: toHuman("stopping"); icon.source: icons["wait"] }
-                        PropertyChanges { target: statusItem; text: toHuman("stopping") }
+                        PropertyChanges {
+                            target: systray
+                            tooltip: toHuman("stopping")
+                            icon.source: icons["wait"]
+                        }
+                        PropertyChanges {
+                            target: statusItem
+                            text: toHuman("stopping")
+                        }
                     },
                     State {
                         name: "failed"
-                        PropertyChanges { target: systray; tooltip: toHuman("failed"); icon.source: icons["blocked"] }
-                        PropertyChanges { target: statusItem; text: toHuman("failed") }
+                        PropertyChanges {
+                            target: systray
+                            tooltip: toHuman("failed")
+                            icon.source: icons["blocked"]
+                        }
+                        PropertyChanges {
+                            target: statusItem
+                            text: toHuman("failed")
+                        }
                     }
                 ]
             }
@@ -243,7 +284,8 @@ ApplicationWindow {
                 onTriggered: {
                     backend.switchOn()
                 }
-                visible: ctx ? (ctx.status == "off" || ctx.status == "failed") : false
+                visible: ctx ? (ctx.status == "off"
+                                || ctx.status == "failed") : false
             }
 
             MenuItem {
@@ -256,22 +298,26 @@ ApplicationWindow {
                 onTriggered: {
                     backend.switchOff()
                 }
-                visible: ctx ? (ctx.status == "on" || ctx.status == "starting" || ctx.status == "failed") : false
+                visible: ctx ? (ctx.status == "on" || ctx.status == "starting"
+                                || ctx.status == "failed") : false
             }
 
             MenuSeparator {}
 
-
             MenuItem {
                 text: qsTr("About...")
-                onTriggered: { about.visible = true }
+                onTriggered: {
+                    about.visible = true
+                }
             }
 
             MenuItem {
                 id: donateItem
                 text: qsTr("Donate...")
                 visible: ctx ? ctx.donateURL : false
-                onTriggered: { donate.visible = true }
+                onTriggered: {
+                    donate.visible = true
+                }
             }
 
             MenuSeparator {}
@@ -280,7 +326,7 @@ ApplicationWindow {
                 text: qsTr("Help...")
 
                 onTriggered: {
-                    console.debug(Qt.resolvedUrl(ctx.helpURL));
+                    console.debug(Qt.resolvedUrl(ctx.helpURL))
                     Qt.openUrlExternally(Qt.resolvedUrl(ctx.helpURL))
                 }
             }
@@ -289,7 +335,9 @@ ApplicationWindow {
                 text: qsTr("Report a bug...")
 
                 onTriggered: {
-                    Qt.openUrlExternally(Qt.resolvedUrl("https://0xacab.org/leap/bitmask-vpn/issues"))
+                    Qt.openUrlExternally(
+                                Qt.resolvedUrl(
+                                    "https://0xacab.org/leap/bitmask-vpn/issues"))
                 }
             }
 
@@ -317,7 +365,7 @@ ApplicationWindow {
         visible: false
     }
 
-    LoginOKDialog{
+    LoginOKDialog {
         id: loginOk
         visible: false
     }