summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkali kaneko (leap communications) <kali@leap.se>2020-09-02 23:47:05 +0200
committerkali kaneko (leap communications) <kali@leap.se>2021-05-04 14:58:39 +0200
commit4bd6bbd788454367cc89d78543312f333051b840 (patch)
tree6a3d01bf804ea4bd841c013dbe96ffe3df29323a
parent335bb742b957370bbf40ae77a661559805ab307f (diff)
[feat] expose gateway selector in gui
-rw-r--r--gui/gui.qrc3
-rw-r--r--gui/handlers.cpp5
-rw-r--r--gui/handlers.h1
-rw-r--r--gui/js/maps.js83
-rw-r--r--gui/qml/VpnState.qml64
-rw-r--r--gui/qml/main.qml238
-rw-r--r--pkg/backend/api.go9
-rw-r--r--pkg/backend/status.go36
-rw-r--r--pkg/bitmask/bitmask.go1
-rw-r--r--pkg/vpn/bonafide/bonafide.go6
-rw-r--r--pkg/vpn/bonafide/eip_service.go24
-rw-r--r--pkg/vpn/bonafide/gateways.go42
-rw-r--r--pkg/vpn/openvpn.go9
13 files changed, 373 insertions, 148 deletions
diff --git a/gui/gui.qrc b/gui/gui.qrc
index 5e0d4ae..fdea109 100644
--- a/gui/gui.qrc
+++ b/gui/gui.qrc
@@ -2,6 +2,7 @@
<qresource prefix="/">
<file>qml/main.qml</file>
+ <file>qml/VpnState.qml</file>
<file>qml/AboutDialog.qml</file>
<file>qml/DonateDialog.qml</file>
<file>qml/LoginDialog.qml</file>
@@ -24,5 +25,7 @@
<file alias="providers.json">providers/providers.json</file>
<file>assets/svg/world.svg</file>
+ <file>js/maps.js</file>
+
</qresource>
</RCC>
diff --git a/gui/handlers.cpp b/gui/handlers.cpp
index 8f0e0d0..370c67c 100644
--- a/gui/handlers.cpp
+++ b/gui/handlers.cpp
@@ -42,6 +42,11 @@ void Backend::donateSeen()
DonateSeen();
}
+void Backend::useGateway(QString label)
+{
+ UseGateway(toGoStr(label));
+}
+
void Backend::login(QString username, QString password)
{
Login(toGoStr(username), toGoStr(password));
diff --git a/gui/handlers.h b/gui/handlers.h
index 8283645..a783207 100644
--- a/gui/handlers.h
+++ b/gui/handlers.h
@@ -36,6 +36,7 @@ public slots:
void switchOff();
void donateAccepted();
void donateSeen();
+ void useGateway(QString username);
void login(QString username, QString password);
void resetError(QString errlabel);
void resetNotification(QString label);
diff --git a/gui/js/maps.js b/gui/js/maps.js
new file mode 100644
index 0000000..c6f44d2
--- /dev/null
+++ b/gui/js/maps.js
@@ -0,0 +1,83 @@
+// Robinson projection calculation
+
+// Written by Niklas Bichinger (bichinger.de). This code is Public Domain - use as you like.
+
+// source of robinson numbers: https://simplemaps.com/static/img/flash/robinson_projection_table.jpg
+var robinsonAA = [
+ 0.84870000,
+ 0.84751182,
+ 0.84479598,
+ 0.84021300,
+ 0.83359314,
+ 0.82578510,
+ 0.81475200,
+ 0.80006949,
+ 0.78216192,
+ 0.76060494,
+ 0.73658673,
+ 0.70866450,
+ 0.67777182,
+ 0.64475739,
+ 0.60987582,
+ 0.57134484,
+ 0.52729731,
+ 0.48562614,
+ 0.45167814
+];
+var robinsonBB = [
+ 0.00000000,
+ 0.08384260,
+ 0.16768520,
+ 0.25152780,
+ 0.33537040,
+ 0.41921300,
+ 0.50305560,
+ 0.58689820,
+ 0.67047034,
+ 0.75336633,
+ 0.83518048,
+ 0.91537187,
+ 0.99339958,
+ 1.06872269,
+ 1.14066505,
+ 1.20841528,
+ 1.27035062,
+ 1.31998003,
+ 1.35230000
+];
+
+function project(latitude, longitude, mapWidth, heightFactor, mapOffsetX, mapOffsetY) {
+ if (typeof heightFactor === 'undefined') { heightFactor = 1; }
+ if (typeof mapOffsetX === 'undefined') { mapOffsetX = 0; }
+ if (typeof mapOffsetY === 'undefined') { mapOffsetY = 0; }
+
+ // Robinson's latitude interpolation points are in 5-degree-steps
+ var latitudeAbs = Math.abs(latitude);
+ var latitudeStepFloor = Math.floor(latitudeAbs / 5);
+ var latitudeStepCeil = Math.ceil(latitudeAbs / 5);
+ // calc interpolation factor (>=0 to <1) between two steps
+ var latitudeInterpolation = (latitudeAbs - latitudeStepFloor * 5) / 5;
+
+ // interpolate robinson table values
+ var AA = robinsonAA[latitudeStepFloor] + (robinsonAA[latitudeStepCeil] - robinsonAA[latitudeStepFloor]) * latitudeInterpolation;
+ var BB = robinsonBB[latitudeStepFloor] + (robinsonBB[latitudeStepCeil] - robinsonBB[latitudeStepFloor]) * latitudeInterpolation;
+
+ var robinsonWidth = 2 * Math.PI * robinsonAA[0];
+ var widthFactor = mapWidth / robinsonWidth;
+ var latitudeSign = Math.sign(latitude) || 1;
+ var x = (widthFactor * AA * longitude * Math.PI) / 180 + mapOffsetX;
+ var y = widthFactor * BB * latitudeSign * heightFactor + mapOffsetY;
+
+ return {x: x, y: y};
+}
+
+function projectAbsolute(latitude, longitude, mapWidth, heightFactor, mapOffsetX, mapOffsetY) {
+ if (typeof heightFactor === 'undefined') { heightFactor = 1; }
+
+ var relative = project(latitude, longitude, mapWidth, heightFactor, mapOffsetX, mapOffsetY);
+ var widthHeightRatio = Math.PI * robinsonAA[0] / robinsonBB[18];
+ var x = mapWidth / 2 + relative.x;
+ var y = mapWidth / widthHeightRatio * heightFactor / 2 - relative.y;
+
+ return {x: x, y: y};
+}
diff --git a/gui/qml/VpnState.qml b/gui/qml/VpnState.qml
new file mode 100644
index 0000000..ea2a3b1
--- /dev/null
+++ b/gui/qml/VpnState.qml
@@ -0,0 +1,64 @@
+import QtQuick 2.0
+import QtQuick.Controls 1.4
+
+StateGroup {
+
+ state: ctx ? ctx.status : ""
+
+ states: [
+ State { name: "initializing" },
+ State {
+ name: "off"
+ PropertyChanges { target: systray; tooltip: toHuman("off"); icon.source: icons["off"] }
+ PropertyChanges { target: statusItem; text: toHuman("off") }
+ PropertyChanges { target: mainStatus; text: toHuman("off") }
+ PropertyChanges { target: mainCurrentGateway; text: "" }
+ PropertyChanges { target: mainOnBtn; visible: true }
+ PropertyChanges { target: mainOffBtn; visible: false }
+ PropertyChanges { target: gwMarker; color: "red"}
+ },
+ State {
+ name: "on"
+ StateChangeScript {
+ script: displayGatewayMarker()
+ }
+ PropertyChanges { target: systray; tooltip: toHuman("on"); icon.source: icons["on"] }
+ PropertyChanges { target: statusItem; text: toHumanWithLocation("on") }
+ PropertyChanges { target: mainStatus; text: toHuman("on") }
+ PropertyChanges { target: mainCurrentGateway; text: qsTr("Connected to ") + ctx.currentGateway }
+ PropertyChanges { target: mainOnBtn; visible: false }
+ PropertyChanges { target: mainOffBtn; visible: true }
+ PropertyChanges { target: gwMarker; color: "green"}
+ },
+ State {
+ name: "starting"
+ PropertyChanges { target: systray; tooltip: toHuman("connecting"); icon.source: icons["wait"] }
+ PropertyChanges { target: statusItem; text: toHumanWithLocation("connecting") }
+ PropertyChanges { target: mainStatus; text: qsTr("Connecting...") }
+ PropertyChanges { target: mainCurrentGateway; text: "" }
+ PropertyChanges { target: mainOnBtn; visible: false }
+ PropertyChanges { target: mainOffBtn; visible: true }
+ PropertyChanges { target: gwMarker; color: "orange"}
+ },
+ State {
+ name: "stopping"
+ PropertyChanges { target: systray; tooltip: toHuman("stopping"); icon.source: icons["wait"] }
+ PropertyChanges { target: statusItem; text: toHuman("stopping") }
+ PropertyChanges { target: mainStatus; text: toHuman("stopping") }
+ PropertyChanges { target: mainCurrentGateway; text: "" }
+ PropertyChanges { target: mainOnBtn; visible: true }
+ PropertyChanges { target: mainOffBtn; visible: false }
+ PropertyChanges { target: gwMarker; color: "orange"}
+ },
+ State {
+ name: "failed"
+ PropertyChanges { target: systray; tooltip: toHuman("failed"); icon.source: icons["wait"] }
+ PropertyChanges { target: statusItem; text: toHuman("failed") }
+ PropertyChanges { target: mainStatus; text: toHuman("failed") }
+ PropertyChanges { target: mainCurrentGateway; text: "" }
+ PropertyChanges { target: mainOnBtn; visible: true }
+ PropertyChanges { target: mainOffBtn; visible: false }
+ PropertyChanges { target: gwMarker; color: "red"}
+ }
+ ]
+}
diff --git a/gui/qml/main.qml b/gui/qml/main.qml
index 98a4445..bbc3f69 100644
--- a/gui/qml/main.qml
+++ b/gui/qml/main.qml
@@ -6,12 +6,19 @@ import QtQuick.Extras 1.2
import Qt.labs.platform 1.1 as LabsPlatform
+import "qrc:/js/maps.js" as Maps
+
ApplicationWindow {
id: app
visible: true
- width: 700
- height: 700
+ width: 300
+ height: 600
+ maximumWidth: 300
+ minimumWidth: 300
+ maximumHeight: 600
+ minimumHeight: 600
+ // TODO get a nice background color
flags: Qt.WindowsStaysOnTopHint | Qt.Popup
@@ -19,52 +26,121 @@ ApplicationWindow {
property var loginDone
property var allowEmptyPass
- ColumnLayout{
- anchors.centerIn: parent
- width: parent.width
- Layout.preferredHeight: parent.height
+ onWidthChanged: displayGatewayMarker()
+ onHeightChanged: displayGatewayMarker()
+
+ GridLayout {
+
visible: true
+ columns: 3
- Text{
- id: mainStatus
- text: "Status: off"
- font.pixelSize: 22
- Layout.preferredWidth: parent.width
- horizontalAlignment: Text.AlignHCenter
- }
+ Item {
+ Layout.column: 2
+ Layout.topMargin: app.height * 0.15
+ Layout.leftMargin: app.width * 0.10
- Label {
- text: "gateway selection:"
- font.pixelSize: 20
- }
+ ColumnLayout {
+ Layout.alignment: Qt.AlignHCenter
+
+ Text{
+ id: mainStatus
+ text: "off"
+ font.pixelSize: 26
+ Layout.alignment: Text.AlignHCenter
+ }
+
+ Text{
+ id: mainCurrentGateway
+ text: ""
+ font.pixelSize: 20
+ Layout.alignment: Text.AlignHCenter
+ }
- ComboBox {
- id: comboGw
- editable: false
- model: [ qsTr("Automatic"), qsTr("Paris"), qsTr("Amsterdam") ]
- onAccepted: {
- if (combo.find(currentText) === -1) {
- currentIndex = combo.find(editText)
- }
- }
+ Button {
+ id: mainOnBtn
+ x: 80
+ y: 200
+ text: qsTr("on")
+ visible: true
+ onClicked: backend.switchOn()
+ }
+
+ Button {
+ id: mainOffBtn
+ x: 180
+ y: 200
+ text: qsTr("off")
+ visible: false
+ onClicked: backend.switchOff()
+ }
+
+ ComboBox {
+ id: gwSelector
+ editable: false
+ model: [qsTr("Automatic")]
+ onActivated: {
+ console.debug("Selected gateway:", currentText);
+ backend.useGateway(currentText.toString());
+ }
+ }
+ }
}
- ColumnLayout{
- width: parent.width
+ Item {
+ Layout.topMargin: app.height * 0.40
+ Layout.row: 3
+ Layout.column: 1
+ Layout.columnSpan: 3
Image {
id: worldMap
+ width: app.width
source: "qrc:/assets/svg/world.svg"
- fillMode: Image.PreserveAspectCrop
+ fillMode: Image.PreserveAspectFit
+ smooth: true
}
- }
+
+ Rectangle {
+ id: gwMarker
+ x: worldMap.width * 0.5
+ y: worldMap.height * 0.5
+ width: 10
+ height: 10
+ radius: 10
+ color: "red"
+ z: worldMap.z + 1
+ }
+
+ }
+ }
+
+
+ function displayGatewayMarker() {
+ let coords = {
+ 'paris': {'x': 48, 'y': 2},
+ 'miami': {'x': 25.7 , 'y': -80.2 },
+ 'amsterdam': {'x': 52.4, 'y': 4.9 },
+ 'montreal': {'x': 45.3, 'y': -73.4 },
+ 'seattle': {'x': 47.4, 'y': -122.2 },
+ }
+ let city = ctx.currentGateway.split('-')[0]
+ let coord = coords[city]
+
+ // TODO the Robinson projection does not seem to fit super-nicely with
+ // our map, and this offset doesn't work with bigg-ish sizes. But good
+ // enough for a proof of concept - if we avoid resizing the window.
+ let xOffset = -1 * 0.10 * worldMap.width
+ let p = Maps.projectAbsolute(coord.x, coord.y, worldMap.width, 1, xOffset)
+ gwMarker.x = p.x
+ gwMarker.y = p.y
}
Connections {
target: jsonModel
onDataChanged: {
- ctx = JSON.parse(jsonModel.getJson())
+ ctx = JSON.parse(jsonModel.getJson());
+ gwSelector.model = Object.keys(ctx.gateways)
if (ctx.donateDialog == 'true') {
console.debug(jsonModel.getJson())
@@ -170,6 +246,28 @@ ApplicationWindow {
}
}
+ function toHumanWithLocation(st) {
+ switch(st) {
+ case "off":
+ //: %1 -> application name
+ return qsTr("%1 off").arg(ctx.appName);
+ case "on":
+ //: %1 -> application name
+ //: %2 -> current gateway
+ return qsTr("%1 on - %2").arg(ctx.appName).arg(ctx.currentGateway);
+ case "connecting":
+ //: %1 -> application name
+ //: %2 -> current gateway
+ return qsTr("Connecting to %1 - %2").arg(ctx.appName).arg(ctx.currentGateway);
+ 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",
@@ -177,8 +275,11 @@ ApplicationWindow {
"blocked": "qrc:/assets/icon/png/black/vpn_blocked.png"
}
+ VpnState {
+ id: vpn
+ }
-
+ SystemTrayIcon {
LabsPlatform.SystemTrayIcon {
id: systray
@@ -203,76 +304,6 @@ ApplicationWindow {
}
}
- StateGroup {
- id: vpn
- state: ctx ? ctx.status : ""
-
- states: [
- State {
- name: "initializing"
- },
- State {
- name: "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")
- }
- },
- State {
- name: "starting"
- 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")
- }
- },
- State {
- name: "failed"
- PropertyChanges {
- target: systray
- tooltip: toHuman("failed")
- icon.source: icons["blocked"]
- }
- PropertyChanges {
- target: statusItem
- text: toHuman("failed")
- }
- }
- ]
- }
LabsPlatform.MenuItem {
id: statusItem
@@ -385,8 +416,6 @@ ApplicationWindow {
console.log("System doesn't support systray notifications")
}
}
-
-
}
DonateDialog {
@@ -432,5 +461,4 @@ ApplicationWindow {
id: initFailure
visible: false
}
-
}
diff --git a/pkg/backend/api.go b/pkg/backend/api.go
index 8d6d049..761c03d 100644
--- a/pkg/backend/api.go
+++ b/pkg/backend/api.go
@@ -7,6 +7,7 @@ import (
"encoding/json"
"log"
"strconv"
+ "time"
"unsafe"
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
@@ -54,10 +55,14 @@ func SwitchOff() {
go stopVPN()
}
-// TODO implement Reconnect?
+// TODO implement Reconnect - do not tear whole fw down in between
func UseGateway(label string) {
- ctx.bm.UseGateway(label)
+ ctx.bm.UseGateway(string(label))
+ time.Sleep(200 * time.Millisecond)
+ SwitchOff()
+ time.Sleep(500 * time.Millisecond)
+ SwitchOn()
}
func UseTransport(label string) {
diff --git a/pkg/backend/status.go b/pkg/backend/status.go
index 16db227..20128ca 100644
--- a/pkg/backend/status.go
+++ b/pkg/backend/status.go
@@ -8,6 +8,7 @@ import (
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
"0xacab.org/leap/bitmask-vpn/pkg/config"
+ "0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide"
)
const (
@@ -32,18 +33,20 @@ var updateMutex sync.Mutex
// them.
type connectionCtx struct {
- AppName string `json:"appName"`
- Provider string `json:"provider"`
- TosURL string `json:"tosURL"`
- HelpURL string `json:"helpURL"`
- AskForDonations bool `json:"askForDonations"`
- DonateDialog bool `json:"donateDialog"`
- DonateURL string `json:"donateURL"`
- LoginDialog bool `json:"loginDialog"`
- LoginOk bool `json:"loginOk"`
- Version string `json:"version"`
- Errors string `json:"errors"`
- Status status `json:"status"`
+ AppName string `json:"appName"`
+ Provider string `json:"provider"`
+ TosURL string `json:"tosURL"`
+ HelpURL string `json:"helpURL"`
+ AskForDonations bool `json:"askForDonations"`
+ DonateDialog bool `json:"donateDialog"`
+ DonateURL string `json:"donateURL"`
+ LoginDialog bool `json:"loginDialog"`
+ LoginOk bool `json:"loginOk"`
+ Version string `json:"version"`
+ Errors string `json:"errors"`
+ Status status `json:"status"`
+ Gateways map[string]bonafide.Gateway `json:"gateways"`
+ CurrentGateway string `json:"currentGateway"`
bm bitmask.Bitmask
autostart bitmask.Autostart
cfg *config.Config
@@ -51,6 +54,15 @@ type connectionCtx struct {
func (c connectionCtx) toJson() ([]byte, error) {
statusMutex.Lock()
+ if c.bm != nil {
+ c.Gateways = map[string]bonafide.Gateway{}
+ gateways, _ := c.bm.ListGateways("openvpn")
+ for _, label := range gateways {
+ gw, _ := c.bm.GetGatewayDetails(label)
+ c.Gateways[label] = gw.(bonafide.Gateway)
+ }
+ c.CurrentGateway = c.bm.GetCurrentGateway()
+ }
defer statusMutex.Unlock()
b, err := json.Marshal(c)
if err != nil {
diff --git a/pkg/bitmask/bitmask.go b/pkg/bitmask/bitmask.go
index 7ffe01a..6d5fa33 100644
--- a/pkg/bitmask/bitmask.go
+++ b/pkg/bitmask/bitmask.go
@@ -29,6 +29,7 @@ type Bitmask interface {
ListGateways(provider string) ([]string, error)
UseGateway(name string) error
GetCurrentGateway() string
+ GetGatewayDetails(label string) (interface{}, error)
UseTransport(transport string) error
NeedsCredentials() bool
DoLogin(username, password string) (bool, error)
diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go
index 8b60641..561c2bb 100644
--- a/pkg/vpn/bonafide/bonafide.go
+++ b/pkg/vpn/bonafide/bonafide.go
@@ -224,8 +224,12 @@ func (b *Bonafide) GetAllGateways(transport string) ([]Gateway, error) {
return gws, err
}
+func (b *Bonafide) GetGatewayDetails(label string) (Gateway, error) {
+ return b.gateways.getGatewayByLabel(label)
+}
+
func (b *Bonafide) SetManualGateway(label string) {
- b.gateways.setUserChoice(label)
+ b.gateways.setUserChoice([]byte(label))
}
func (b *Bonafide) SetAutomaticGateway() {
diff --git a/pkg/vpn/bonafide/eip_service.go b/pkg/vpn/bonafide/eip_service.go
index 26a8f3c..d5dd751 100644
--- a/pkg/vpn/bonafide/eip_service.go
+++ b/pkg/vpn/bonafide/eip_service.go
@@ -14,7 +14,7 @@ import (
type eipService struct {
Gateways []gatewayV3
defaultGateway string
- Locations map[string]location
+ Locations map[string]Location
OpenvpnConfiguration openvpnConfig `json:"openvpn_configuration"`
auth string
}
@@ -22,7 +22,7 @@ type eipService struct {
type eipServiceV1 struct {
Gateways []gatewayV1
defaultGateway string
- Locations map[string]location
+ Locations map[string]Location
OpenvpnConfiguration openvpnConfig `json:"openvpn_configuration"`
}
@@ -45,8 +45,8 @@ type gatewayV3 struct {
Location string
}
-type location struct {
- CountryCode string
+type Location struct {
+ CountryCode string `json:"country_code"`
Hemisphere string
Name string
Timezone string
@@ -159,13 +159,15 @@ func (eip eipService) getGateways() []Gateway {
for _, g := range eip.Gateways {
for _, t := range g.Capabilities.Transport {
gateway := Gateway{
- Host: g.Host,
- IPAddress: g.IPAddress,
- Location: g.Location,
- Ports: t.Ports,
- Protocols: t.Protocols,
- Options: t.Options,
- Transport: t.Type,
+ Host: g.Host,
+ IPAddress: g.IPAddress,
+ Location: g.Location,
+ Ports: t.Ports,
+ Protocols: t.Protocols,
+ Options: t.Options,
+ Transport: t.Type,
+ LocationName: eip.Locations[g.Location].Name,
+ CountryCode: eip.Locations[g.Location].CountryCode,
}
gws = append(gws, gateway)
}
diff --git a/pkg/vpn/bonafide/gateways.go b/pkg/vpn/bonafide/gateways.go
index d973530..f454d3c 100644
--- a/pkg/vpn/bonafide/gateways.go
+++ b/pkg/vpn/bonafide/gateways.go
@@ -16,14 +16,16 @@ const (
// A Gateway is a representation of gateways that is independent of the api version.
// If a given physical location offers different transports, they will appear as separate gateways.
type Gateway struct {
- Host string
- IPAddress string
- Location string
- Ports []string
- Protocols []string
- Options map[string]string
- Transport string
- Label string
+ Host string
+ IPAddress string
+ Location string
+ LocationName string
+ CountryCode string
+ Ports []string
+ Protocols []string
+ Options map[string]string
+ Transport string
+ Label string
}
/* TODO add a String method with a human representation: Label (cc) */
@@ -35,18 +37,24 @@ type gatewayDistance struct {
}
type gatewayPool struct {
- available []Gateway
+ available []Gateway
+ userChoice []byte
/* ranked is, for now, just an array of hostnames (fetched from the
geoip service). it should be a map in the future, to keep track of
quantitative metrics */
- ranked []string
- userChoice string
- locations map[string]location
+ ranked []string
+
+ /* TODO locations are just used to get the timezone for each gateway. I
+ * think it's easier to just merge that info into the version-agnostic
+ * Gateway, that is passed from the eipService, and do not worry with
+ * the location here */
+ locations map[string]Location
}
/* genLabels generates unique, human-readable labels for a gateway. It gives a serial
number to each gateway in the same location (paris-1, paris-2,...). The
current implementation will give a different label to each transport.
+ An alternative (to discuss) would be to give the same label to the same hostname.
*/
func (p *gatewayPool) genLabels() {
acc := make(map[string]int)
@@ -59,7 +67,7 @@ func (p *gatewayPool) genLabels() {
gw.Label = gw.Location + "-" + strconv.Itoa(acc[gw.Location])
p.available[i] = gw
}
- /* skip suffix if only one occurence */
+ /* skip suffix if only one occurrence */
for i, gw := range p.available {
if acc[gw.Location] == 1 {
gw.Label = gw.Location
@@ -102,11 +110,11 @@ func (p *gatewayPool) getGatewayByIP(ip string) (Gateway, error) {
}
func (p *gatewayPool) setAutomaticChoice() {
- p.userChoice = ""
+ p.userChoice = []byte("")
}
-func (p *gatewayPool) setUserChoice(label string) error {
- if !p.isValidLabel(label) {
+func (p *gatewayPool) setUserChoice(label []byte) error {
+ if !p.isValidLabel(string(label)) {
return errors.New("bonafide: not a valid label for gateway choice")
}
p.userChoice = label
@@ -132,7 +140,7 @@ func (p *gatewayPool) setRanking(hostnames []string) {
func (p *gatewayPool) getBest(transport string, tz, max int) ([]Gateway, error) {
gws := make([]Gateway, 0)
if len(p.userChoice) != 0 {
- gw, err := p.getGatewayByLabel(p.userChoice)
+ gw, err := p.getGatewayByLabel(string(p.userChoice))
gws = append(gws, gw)
return gws, err
} else if len(p.ranked) != 0 {
diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go
index 38a64a9..530f567 100644
--- a/pkg/vpn/openvpn.go
+++ b/pkg/vpn/openvpn.go
@@ -25,6 +25,7 @@ import (
"strconv"
"strings"
+ "0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide"
"0xacab.org/leap/shapeshifter"
)
@@ -244,6 +245,14 @@ func (b *Bitmask) ListGateways(provider string) ([]string, error) {
return gatewayNames, nil
}
+func (b *Bitmask) GetGatewayDetails(label string) (interface{}, error) {
+ gw, err := b.bonafide.GetGatewayDetails(label)
+ if err != nil {
+ return bonafide.Gateway{}, err
+ }
+ return gw, nil
+}
+
// UseGateway selects a gateway, by label, as the default gateway
func (b *Bitmask) UseGateway(label string) error {
b.bonafide.SetManualGateway(label)