From 76cacf3d60e3dbfcb6fcb82558d9d79f6d068fb8 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Wed, 17 Mar 2021 17:15:19 +0100 Subject: wip: select by city from the gui --- gui/qml/main.qml | 26 +------------ pkg/backend/status.go | 45 ++++++++++++---------- pkg/backend/webapi.go | 4 +- pkg/bitmask/bitmask.go | 2 +- pkg/vpn/bonafide/bonafide.go | 15 +++++--- pkg/vpn/bonafide/gateways.go | 92 ++++++++++++++++---------------------------- pkg/vpn/openvpn.go | 20 +++------- pkg/vpn/status.go | 4 +- 8 files changed, 79 insertions(+), 129 deletions(-) diff --git a/gui/qml/main.qml b/gui/qml/main.qml index fd5421a..9a0e111 100644 --- a/gui/qml/main.qml +++ b/gui/qml/main.qml @@ -4,10 +4,8 @@ import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.0 import QtQuick.Controls 1.4 -//import QtQuick.Extras 1.2 import Qt.labs.platform 1.0 -//as LabsPlatform Window { id: app visible: true @@ -90,6 +88,7 @@ Window { target: jsonModel onDataChanged: { ctx = JSON.parse(jsonModel.getJson()) + console.debug(jsonModel.getJson()) gwSelector.model = Object.keys(ctx.gateways) if (ctx.donateDialog == 'true') { @@ -277,29 +276,6 @@ Window { /* a minimal segfault for submenu */ // Menu {} - /* this segfaults too (but it's the way to do dynamic item creation */ - - /* - Menu { - id: manualGatewaysSubmenu - title: qsTr("Manual Gateways") - enabled: true - - Instantiator { - id: manualGatewayInstantiator - //model: settings.recentFiles - - delegate: MenuItem { - text: "test gateway" - } - - onObjectAdded: manualGatewaysSubmenu.insertItem(index, object) - onObjectRemoved: manualGatewaysSubmenu.removeItem(object) - } - - MenuSeparator {} - } - */ MenuSeparator {} MenuItem { diff --git a/pkg/backend/status.go b/pkg/backend/status.go index 20128ca..cfc68d1 100644 --- a/pkg/backend/status.go +++ b/pkg/backend/status.go @@ -33,33 +33,36 @@ 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"` - Gateways map[string]bonafide.Gateway `json:"gateways"` - CurrentGateway string `json:"currentGateway"` - bm bitmask.Bitmask - autostart bitmask.Autostart - cfg *config.Config + 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"` + /* XXX rename to GatewaysByCity */ + Gateways map[string]bonafide.Gateway `json:"gateways"` + CurrentGateway string `json:"currentGateway"` + bm bitmask.Bitmask + autostart bitmask.Autostart + cfg *config.Config } 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) + /* FIXME this returns hostnames, could return bonafide gateway directly */ + gateways, _ := c.bm.ListGatewaysByCity("openvpn") + log.Println(">>> got gws for cities", gateways) + for city, host := range gateways { + gw, _ := c.bm.GetGatewayDetails(host) + c.Gateways[city] = gw.(bonafide.Gateway) } c.CurrentGateway = c.bm.GetCurrentGateway() } diff --git a/pkg/backend/webapi.go b/pkg/backend/webapi.go index 11abc24..a19d933 100644 --- a/pkg/backend/webapi.go +++ b/pkg/backend/webapi.go @@ -64,9 +64,9 @@ func webGatewaySet(w http.ResponseWriter, r *http.Request) { } func webGatewayList(w http.ResponseWriter, r *http.Request) { - gws, err := ctx.bm.ListGateways(ctx.Provider) + gws, err := ctx.bm.ListGatewaysByCity(ctx.Provider) if err != nil { - fmt.Fprintf(w, "ListGateways() err: %v", err) + fmt.Fprintf(w, "ListGatewaysByCity() err: %v", err) } gwJson, _ := json.Marshal(gws) fmt.Fprintf(w, string(gwJson)) diff --git a/pkg/bitmask/bitmask.go b/pkg/bitmask/bitmask.go index 6d5fa33..e284541 100644 --- a/pkg/bitmask/bitmask.go +++ b/pkg/bitmask/bitmask.go @@ -26,7 +26,7 @@ type Bitmask interface { GetStatus() (string, error) InstallHelpers() error VPNCheck() (helpers bool, priviledge bool, err error) - ListGateways(provider string) ([]string, error) + ListGatewaysByCity(provider string) (map[string]string, error) UseGateway(name string) error GetCurrentGateway() string GetGatewayDetails(label string) (interface{}, error) diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go index 561c2bb..f0726b8 100644 --- a/pkg/vpn/bonafide/bonafide.go +++ b/pkg/vpn/bonafide/bonafide.go @@ -192,7 +192,7 @@ func (b *Bonafide) maybeInitializeEIP() error { return err } b.gateways = newGatewayPool(b.eip) - b.fetchGatewayRanking() + b.fetchGatewaysFromMenshen() } return nil } @@ -224,8 +224,13 @@ 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) PickGatewayForCities() (map[string]string, error) { + return b.gateways.pickGatewayForCities(), nil +} + +func (b *Bonafide) GetGatewayDetails(host string) (Gateway, error) { + gw, err := b.gateways.getGatewayByHost(host) + return gw, err } func (b *Bonafide) SetManualGateway(label string) { @@ -241,7 +246,7 @@ func (b *Bonafide) GetGatewayByIP(ip string) (Gateway, error) { } /* TODO this still needs to be called periodically */ -func (b *Bonafide) fetchGatewayRanking() error { +func (b *Bonafide) fetchGatewaysFromMenshen() error { /* FIXME in float deployments, geolocation is served on gemyip.domain/json, with a LE certificate, but in riseup is served behind the api certificate. So this is a workaround until we streamline that behavior */ resp, err := b.client.Post(config.GeolocationAPI, "", nil) @@ -272,7 +277,7 @@ func (b *Bonafide) fetchGatewayRanking() error { } log.Println("Got sorted gateways:", geo.SortedGateways) - b.gateways.setRanking(geo.SortedGateways) + b.gateways.setRecommendedGateways(geo.SortedGateways) return nil } diff --git a/pkg/vpn/bonafide/gateways.go b/pkg/vpn/bonafide/gateways.go index f1694a2..fa92661 100644 --- a/pkg/vpn/bonafide/gateways.go +++ b/pkg/vpn/bonafide/gateways.go @@ -33,27 +33,24 @@ type Load struct { Fullness string } -type gatewayDistance struct { - gateway Gateway - distance int -} - -/* a map between locations and hostnames, to be able to select by city */ -type cityMap struct { - gws map[string][]string -} - +/* func (g *cityMap) Get(key string) []string { if val, ok := g.gws[key]; ok { return val } - return make([]string, 0) +} +*/ + +/* gatewayDistance is used in the timezone distance fallback */ +type gatewayDistance struct { + gateway Gateway + distance int } type gatewayPool struct { available []Gateway userChoice []byte - byCity cityMap + byCity map[string][]string /* recommended is an array of hostnames, fetched from the old geoip service. * this should be deprecated in favor of recommendedWithLoad when new menshen is deployed */ @@ -70,9 +67,14 @@ type gatewayPool struct { func (p *gatewayPool) populateCityList() { for _, gw := range p.available { loc := gw.Location - gws := p.cityMap.Get(loc) - p.cityMap[loc] = append(gws, gw.Host) + gws := p.byCity[loc] + if len(gws) == 0 { + p.byCity[loc] = []string{gw.Host} + } else { + p.byCity[loc] = append(gws, gw.Host) + } } + log.Println(p.byCity) } func (p *gatewayPool) getCities() []string { @@ -89,12 +91,23 @@ func (p *gatewayPool) isValidCity(city string) bool { return valid } +/* returns a map of city: hostname for the ui to use */ +func (p *gatewayPool) pickGatewayForCities() map[string]string { + cities := p.getCities() + cm := make(map[string]string) + for _, city := range cities { + gw, _ := p.getRandomGatewayByCity(city) + cm[city] = gw.Host + } + return cm +} + /* this method should only be used if we have no usable menshen list */ func (p *gatewayPool) getRandomGatewayByCity(city string) (Gateway, error) { if !p.isValidCity(city) { return Gateway{}, errors.New("bonafide: BUG not a valid city: " + city) } - gws := p.byCity.Get(city) + gws := p.byCity[city] if len(gws) == 0 { return Gateway{}, errors.New("bonafide: BUG no gw for city " + city) } @@ -109,54 +122,14 @@ func (p *gatewayPool) getRandomGatewayByCity(city string) (Gateway, error) { return Gateway{}, errors.New("bonafide: BUG should not reach here") } -/* 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) - for i, gw := range p.available { - if _, count := acc[gw.Location]; !count { - acc[gw.Location] = 1 - } else { - acc[gw.Location] += 1 - } - gw.Label = gw.Location + "-" + strconv.Itoa(acc[gw.Location]) - p.available[i] = gw - } - for i, gw := range p.available { - if acc[gw.Location] == 1 { - gw.Label = gw.Location - p.available[i] = gw - } - } -} -*/ - -/* -func (p *gatewayPool) getLabels() []string { - labels := make([]string, 0) +func (p *gatewayPool) getGatewayByHost(host string) (Gateway, error) { for _, gw := range p.available { - labels = append(labels, gw.Label) - } - return labels -} - -func (p *gatewayPool) isValidLabel(label string) bool { - labels := p.getLabels() - valid := stringInSlice(label, labels) - return valid -} - -func (p *gatewayPool) getGatewayByLabel(label string) (Gateway, error) { - for _, gw := range p.available { - if gw.Label == label { + if gw.Host == host { return gw, nil } } - return Gateway{}, errors.New("bonafide: not a valid label") + return Gateway{}, errors.New("bonafide: not a valid host name") } -*/ func (p *gatewayPool) getGatewayByIP(ip string) (Gateway, error) { for _, gw := range p.available { @@ -179,7 +152,7 @@ func (p *gatewayPool) setUserChoice(city []byte) error { return nil } -func (p *gatewayPool) setRanking(hostnames []string) { +func (p *gatewayPool) setRecommendedGateways(hostnames []string) { hosts := make([]string, 0) for _, gw := range p.available { hosts = append(hosts, gw.Host) @@ -277,6 +250,7 @@ func newGatewayPool(eip *eipService) *gatewayPool { p := gatewayPool{} p.available = eip.getGateways() p.locations = eip.Locations + p.byCity = make(map[string][]string, 0) p.populateCityList() return &p } diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go index 530f567..1857476 100644 --- a/pkg/vpn/openvpn.go +++ b/pkg/vpn/openvpn.go @@ -231,22 +231,14 @@ func (b *Bitmask) VPNCheck() (helpers bool, privilege bool, err error) { return b.launch.check() } -// ListGateways return the labels of the gateways (only for transport=openvpn, at the moment) -// TODO return other transports too -func (b *Bitmask) ListGateways(provider string) ([]string, error) { - gateways, err := b.bonafide.GetAllGateways("openvpn") - if err != nil { - return nil, err - } - gatewayNames := make([]string, len(gateways)) - for i, gw := range gateways { - gatewayNames[i] = gw.Label - } - return gatewayNames, nil +func (b *Bitmask) ListGatewaysByCity(transport string) (map[string]string, error) { + /* TODO filter by transport */ + gwForCities, err := b.bonafide.PickGatewayForCities() + return gwForCities, err } -func (b *Bitmask) GetGatewayDetails(label string) (interface{}, error) { - gw, err := b.bonafide.GetGatewayDetails(label) +func (b *Bitmask) GetGatewayDetails(host string) (interface{}, error) { + gw, err := b.bonafide.GetGatewayDetails(host) if err != nil { return bonafide.Gateway{}, err } diff --git a/pkg/vpn/status.go b/pkg/vpn/status.go index 005db7e..870bb1f 100644 --- a/pkg/vpn/status.go +++ b/pkg/vpn/status.go @@ -77,7 +77,7 @@ func (b *Bitmask) eventHandler(eventCh <-chan openvpn.Event) { gw, err := b.bonafide.GetGatewayByIP(ip) if err == nil { b.onGateway = gw - log.Println("Connected to gateway:", b.onGateway.Label) + log.Println("Connected to gateway:", b.onGateway.Host) } else { log.Println("ERROR: connected to unknown gateway", ip) } @@ -87,7 +87,7 @@ func (b *Bitmask) eventHandler(eventCh <-chan openvpn.Event) { } func (b *Bitmask) GetCurrentGateway() string { - return b.onGateway.Label + return b.onGateway.Host } func (b *Bitmask) getOpenvpnState() (string, error) { -- cgit v1.2.3