From b7b19b7195366dbacc4078b5b7a3fc6a3ad7889b Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Thu, 25 Nov 2021 13:45:54 +0100 Subject: [feat] expose snowflake in preferences it will be disabled if Tor not present, for now --- gui/api.md | 6 ++++ gui/backend.go | 5 ++++ gui/components/Preferences.qml | 63 ++++++++++++++++++++++++++++++++---------- gui/gui.qrc | 1 + gui/handlers.cpp | 5 ++++ gui/handlers.h | 1 + pkg/backend/api.go | 9 +++++- pkg/backend/status.go | 7 ++++- pkg/bitmask/bitmask.go | 1 + pkg/config/gui.go | 10 +++++++ pkg/snowflake/tor.go | 15 ++++++++++ pkg/vpn/main.go | 8 +++++- 12 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 gui/api.md create mode 100644 pkg/snowflake/tor.go diff --git a/gui/api.md b/gui/api.md new file mode 100644 index 0000000..eb11ec6 --- /dev/null +++ b/gui/api.md @@ -0,0 +1,6 @@ +# how to add an action to the api + +1. declare it in `handlers.h` +2. define it in `handlers.cpp` +3. export it in `backend.go` +4. move to `pkg/backend/api.go` and implement what's needed from there diff --git a/gui/backend.go b/gui/backend.go index 5c07cda..516ef4a 100644 --- a/gui/backend.go +++ b/gui/backend.go @@ -58,6 +58,11 @@ func SetUDP(udp bool) { backend.SetUDP(udp) } +//export SetSnowflake +func SetSnowflake(snowflake bool) { + backend.SetSnowflake(snowflake) +} + //export Quit func Quit() { backend.Quit() diff --git a/gui/components/Preferences.qml b/gui/components/Preferences.qml index f205358..fcd742f 100644 --- a/gui/components/Preferences.qml +++ b/gui/components/Preferences.qml @@ -91,10 +91,23 @@ ThemedPage { } } + Label { + text: qsTr("Traffic is obfuscated to bypass blocks.") + font.family: "Monospace" + color: "gray" + visible: true + wrapMode: Text.Wrap + font.pixelSize: Theme.fontSize - 4 + Layout.leftMargin: 35 + Layout.rightMargin: 15 + Layout.bottomMargin: 5 + Layout.preferredWidth: 240 + } + MaterialCheckBox { id: useSnowflake - //wrapMode: Label.Wrap - text: qsTr("Use Snowflake (experimental)") + //wrapMode: Text.Wrap + text: qsTr("Use Snowflake bootstrap") enabled: false checked: false HoverHandler { @@ -102,6 +115,23 @@ ThemedPage { } Layout.leftMargin: 10 Layout.rightMargin: 10 + Layout.preferredWidth: 240 + onClicked: { + doUseSnowflake(checked) + } + } + + Label { + text: qsTr("Snowflake needs Tor installed in your system.") + font.family: "Monospace" + color: "gray" + visible: true + wrapMode: Text.Wrap + font.pixelSize: Theme.fontSize - 4 + Layout.leftMargin: 35 + Layout.rightMargin: 15 + Layout.bottomMargin: 5 + Layout.preferredWidth: 240 } Label { @@ -109,10 +139,11 @@ ThemedPage { font.bold: true Layout.leftMargin: 10 Layout.rightMargin: 10 + Layout.topMargin: 8 } Label { - text: qsTr("UDP can make the VPN faster, but it might be blocked on certain networks") + text: qsTr("UDP can make the VPN faster. It might be blocked on certain networks.") width: parent.width color: "gray" visible: true @@ -200,22 +231,18 @@ ThemedPage { function useBridges(value) { if (value == true) { - console.debug("use obfs4") backend.setTransport("obfs4") } else { - console.debug("use regular") backend.setTransport("openvpn") } } function doUseUDP(value) { - if (value == true) { - console.debug("use udp") - backend.setUDP(true) - } else { - console.debug("use tcp") - backend.setUDP(false) - } + backend.setUDP(value) + } + + function doUseSnowflake(value) { + backend.setSnowflake(value) } function getBoxHeight() { @@ -226,11 +253,17 @@ ThemedPage { if (ctx && ctx.transport == "obfs4") { useBridgesCheckBox.checked = true } - if (ctx && ctx.udp == "true") { - useUDP.checked = true - } if (ctx && ctx.offersUdp == "false") { useUDP.enabled = false } + if (ctx && ctx.offersUdp && ctx.udp == "true") { + useUDP.checked = true + } + if (ctx && ctx.hasTor == "true") { + useSnowflake.enabled = true + } + if (ctx && ctx.hasTor && ctx.snowflake == "true") { + useSnowflake.checked = true + } } } diff --git a/gui/gui.qrc b/gui/gui.qrc index b32c708..c36f5c5 100644 --- a/gui/gui.qrc +++ b/gui/gui.qrc @@ -34,6 +34,7 @@ components/VPNState.qml components/InitErrors.qml components/ErrorBox.qml + components/MotdBox.qml resources/icon-noshield.svg diff --git a/gui/handlers.cpp b/gui/handlers.cpp index b1d060b..4f855ef 100644 --- a/gui/handlers.cpp +++ b/gui/handlers.cpp @@ -62,6 +62,11 @@ void Backend::setUDP(bool udp) SetUDP(udp); } +void Backend::setSnowflake(bool snowflake) +{ + SetSnowflake(snowflake); +} + QString Backend::getTransport() { return QString(GetTransport()); diff --git a/gui/handlers.h b/gui/handlers.h index 55dd32d..82678c0 100644 --- a/gui/handlers.h +++ b/gui/handlers.h @@ -40,6 +40,7 @@ public slots: void useAutomaticGateway(); void setTransport(QString transport); void setUDP(bool udp); + void setSnowflake(bool snowflake); QString getTransport(); void login(QString username, QString password); void resetError(QString errlabel); diff --git a/pkg/backend/api.go b/pkg/backend/api.go index d7dcbb3..6d5ceee 100644 --- a/pkg/backend/api.go +++ b/pkg/backend/api.go @@ -94,12 +94,19 @@ func SetTransport(label string) { } func SetUDP(udp bool) { - log.Println("DEBUG setting UDP") + log.Printf("DEBUG udp:%v\n", udp) ctx.cfg.SetUseUDP(udp) ctx.bm.UseUDP(udp) go trigger(OnStatusChanged) } +func SetSnowflake(snowflake bool) { + log.Printf("DEBUG snowflake:%v\n", snowflake) + ctx.cfg.SetUseSnowflake(snowflake) + ctx.bm.UseSnowflake(snowflake) + go trigger(OnStatusChanged) +} + func GetTransport() *C.char { return C.CString(ctx.bm.GetTransport()) } diff --git a/pkg/backend/status.go b/pkg/backend/status.go index 2ed5cfd..de6364f 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/snowflake" ) const ( @@ -57,6 +58,8 @@ type connectionCtx struct { IsReady bool `json:"isReady"` CanUpgrade bool `json:"canUpgrade"` Motd string `json:"motd"` + HasTor bool `json:"hasTor"` + UseSnowflake bool `json:"snowflake"` bm bitmask.Bitmask autostart bitmask.Autostart cfg *config.Config @@ -73,11 +76,13 @@ func (c *connectionCtx) toJson() ([]byte, error) { c.CurrentCountry = c.bm.GetCurrentCountry() c.BestLocation = c.bm.GetBestLocation(transport) c.Transport = transport - c.UseUDP = c.cfg.UDP // TODO initialize bitmask too + c.UseUDP = c.cfg.UDP // TODO initialize bitmask param? c.OffersUDP = c.bm.OffersUDP() + c.UseSnowflake = c.cfg.Snowflake // TODO initialize bitmask param? c.ManualLocation = c.bm.IsManualLocation() c.CanUpgrade = c.bm.CanUpgrade() c.Motd = c.bm.GetMotd() + c.HasTor = snowflake.HasTor() } defer statusMutex.Unlock() b, err := json.Marshal(c) diff --git a/pkg/bitmask/bitmask.go b/pkg/bitmask/bitmask.go index 80b502e..0c2a344 100644 --- a/pkg/bitmask/bitmask.go +++ b/pkg/bitmask/bitmask.go @@ -36,6 +36,7 @@ type Bitmask interface { GetTransport() string SetTransport(string) error UseUDP(bool) error + UseSnowflake(bool) error OffersUDP() bool GetCurrentGateway() string GetCurrentLocation() string diff --git a/pkg/config/gui.go b/pkg/config/gui.go index 6004d20..1d23018 100644 --- a/pkg/config/gui.go +++ b/pkg/config/gui.go @@ -42,12 +42,14 @@ type Config struct { UserStoppedVPN bool DisableAutostart bool UDP bool + Snowflake bool } SkipLaunch bool Obfs4 bool DisableAutostart bool StartVPN bool UDP bool + Snowflake bool } // ParseConfig reads the configuration from the configuration file @@ -66,6 +68,8 @@ func ParseConfig() *Config { conf.Obfs4 = conf.file.Obfs4 conf.DisableAutostart = conf.file.DisableAutostart conf.StartVPN = !conf.file.UserStoppedVPN + conf.UDP = conf.file.UDP + conf.Snowflake = conf.file.Snowflake return &conf } @@ -104,6 +108,12 @@ func (c *Config) SetUseUDP(val bool) error { return c.save() } +func (c *Config) SetUseSnowflake(val bool) error { + c.Snowflake = val + c.file.Snowflake = val + return c.save() +} + func (c *Config) save() error { f, err := os.Create(configPath) if err != nil { diff --git a/pkg/snowflake/tor.go b/pkg/snowflake/tor.go new file mode 100644 index 0000000..4f4c4e4 --- /dev/null +++ b/pkg/snowflake/tor.go @@ -0,0 +1,15 @@ +package snowflake + +import ( + "errors" + "os" +) + +func exists(path string) bool { + _, err := os.Stat(path) + return !errors.Is(err, os.ErrNotExist) +} + +func HasTor() bool { + return exists("/usr/sbin/tor") +} diff --git a/pkg/vpn/main.go b/pkg/vpn/main.go index 176c86f..da6caf1 100644 --- a/pkg/vpn/main.go +++ b/pkg/vpn/main.go @@ -43,6 +43,7 @@ type Bitmask struct { certPemPath string openvpnArgs []string udp bool + snowflake bool offersUdp bool failed bool canUpgrade bool @@ -68,7 +69,7 @@ func Init() (*Bitmask, error) { bonafide.Gateway{}, bonafide.Gateway{}, statusCh, nil, bf, launch, "", nil, "", []string{}, - false, false, false, false, + false, false, false, false, false, []motd.Message{}, ""} // FIXME multiprovider: need to pass provider name early on // XXX we want to block on these, but they can timeout if we're blocked. @@ -151,6 +152,11 @@ func (b *Bitmask) UseUDP(udp bool) error { return nil } +func (b *Bitmask) UseSnowflake(s bool) error { + b.snowflake = s + return nil +} + func (b *Bitmask) OffersUDP() bool { return b.bonafide.IsUDPAvailable() } -- cgit v1.2.3