Skip to content
Snippets Groups Projects
Unverified Commit 1bd2637e authored by Kali Kaneko's avatar Kali Kaneko
Browse files

[feat] expose set transport

webapi mainly for tests, but it's usable too
parent c6c0209a
No related branches found
No related tags found
No related merge requests found
...@@ -48,6 +48,11 @@ func UseTransport(transport string) { ...@@ -48,6 +48,11 @@ func UseTransport(transport string) {
backend.UseTransport(transport) backend.UseTransport(transport)
} }
//export GetTransport
func GetTransport() *C.char {
return (*C.char)(backend.GetTransport())
}
//export Quit //export Quit
func Quit() { func Quit() {
backend.Quit() backend.Quit()
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
<file>assets/icon/png/white/vpn_wait_1.png</file> <file>assets/icon/png/white/vpn_wait_1.png</file>
<file>assets/icon/png/white/vpn_wait_2.png</file> <file>assets/icon/png/white/vpn_wait_2.png</file>
<file>assets/icon/png/white/vpn_wait_3.png</file> <file>assets/icon/png/white/vpn_wait_3.png</file>
<file>assets/img/bird.jpg</file>
<file alias="providers.json">providers/providers.json</file> <file alias="providers.json">providers/providers.json</file>
</qresource> </qresource>
......
...@@ -52,6 +52,16 @@ void Backend::useAutomaticGateway() ...@@ -52,6 +52,16 @@ void Backend::useAutomaticGateway()
UseAutomaticGateway(); UseAutomaticGateway();
} }
void Backend::useTransport(QString transport)
{
UseTransport(toGoStr(transport));
}
QString Backend::getTransport()
{
return QString(GetTransport());
}
void Backend::login(QString username, QString password) void Backend::login(QString username, QString password)
{ {
Login(toGoStr(username), toGoStr(password)); Login(toGoStr(username), toGoStr(password));
......
...@@ -38,6 +38,8 @@ public slots: ...@@ -38,6 +38,8 @@ public slots:
void donateSeen(); void donateSeen();
void useLocation(QString username); void useLocation(QString username);
void useAutomaticGateway(); void useAutomaticGateway();
void useTransport(QString transport);
QString getTransport();
void login(QString username, QString password); void login(QString username, QString password);
void resetError(QString errlabel); void resetError(QString errlabel);
void resetNotification(QString label); void resetNotification(QString label);
......
...@@ -8,9 +8,9 @@ import Qt.labs.platform 1.0 ...@@ -8,9 +8,9 @@ import Qt.labs.platform 1.0
ApplicationWindow { ApplicationWindow {
id: app id: app
visible: true visible: true
width: 500 width: 300
height: 600 height: 600
maximumWidth: 600 maximumWidth: 300
minimumWidth: 300 minimumWidth: 300
maximumHeight: 500 maximumHeight: 500
minimumHeight: 300 minimumHeight: 300
...@@ -24,17 +24,20 @@ ApplicationWindow { ...@@ -24,17 +24,20 @@ ApplicationWindow {
console.debug(msg) console.debug(msg)
} }
// TODO get a nice background color for this mainwindow. It should be customizable. // TODO refactor into discrete components.
// TODO refactorize all this mess into discrete components.
TabBar { TabBar {
id: bar id: bar
width: parent.width width: parent.width
TabButton { TabButton {
text: qsTr("Info") text: qsTr("Status")
} }
TabButton { TabButton {
text: qsTr("Location") text: qsTr("Location")
} }
TabButton {
text: qsTr("Bridges")
}
} }
StackLayout { StackLayout {
...@@ -47,93 +50,121 @@ ApplicationWindow { ...@@ -47,93 +50,121 @@ ApplicationWindow {
id: infoTab id: infoTab
anchors.centerIn: parent anchors.centerIn: parent
Column { Rectangle {
id: background
anchors.fill: parent;
anchors.topMargin: 40;
Image {
source: "qrc:/assets/img/bird.jpg";
fillMode: Image.PreserveAspectCrop;
anchors.fill: parent;
opacity: 0.8;
}
}
Item {
id: connBox
anchors.centerIn: parent anchors.centerIn: parent
spacing: 5
Text { width: 300
id: mainStatus height: 300
text: "off"
font.pixelSize: 26
anchors.horizontalCenter: parent.horizontalCenter
}
Text { Rectangle {
id: mainCurrentGateway anchors.fill: parent
text: "" color: "white"
font.pixelSize: 20 opacity: 0.3
anchors.horizontalCenter: parent.horizontalCenter layer.enabled: true
} }
SwitchDelegate { Column {
id: vpntoggle anchors.centerIn: parent
spacing: 5
text: qsTr("") Text {
checked: false id: mainStatus
anchors.horizontalCenter: parent.horizontalCenter text: "off"
font.pixelSize: 26
anchors.horizontalCenter: parent.horizontalCenter
}
Connections { Text {
function onCheckedChanged() { id: mainCurrentGateway
if (vpntoggle.checked == true text: ""
&& ctx.status == "off") { font.pixelSize: 20
backend.switchOn() anchors.horizontalCenter: parent.horizontalCenter
} }
if (vpntoggle.checked === false
&& ctx.status == "on") { SwitchDelegate {
backend.switchOff()
id: vpntoggle
text: qsTr("")
checked: false
anchors.horizontalCenter: parent.horizontalCenter
Connections {
function onCheckedChanged() {
if (vpntoggle.checked == true
&& ctx.status == "off") {
backend.switchOn()
}
if (vpntoggle.checked === false
&& ctx.status == "on") {
backend.switchOff()
}
} }
} }
}
contentItem: Text { contentItem: Text {
rightPadding: vpntoggle.indicator.width + vpntoggle.spacing rightPadding: vpntoggle.indicator.width + vpntoggle.spacing
text: vpntoggle.text text: vpntoggle.text
font: vpntoggle.font font: vpntoggle.font
opacity: enabled ? 1.0 : 0.3 opacity: enabled ? 1.0 : 0.5
color: vpntoggle.down ? "#17a81a" : "#21be2b" color: vpntoggle.down ? "#17a81a" : "#21be2b"
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
indicator: Rectangle { indicator: Rectangle {
implicitWidth: 48 implicitWidth: 48
implicitHeight: 26 implicitHeight: 26
x: vpntoggle.width - width - vpntoggle.rightPadding x: vpntoggle.width - width - vpntoggle.rightPadding
y: parent.height / 2 - height / 2 y: parent.height / 2 - height / 2
radius: 13
color: vpntoggle.checked ? "#17a81a" : "transparent"
border.color: vpntoggle.checked ? "#17a81a" : "#cccccc"
Rectangle {
x: vpntoggle.checked ? parent.width - width : 0
width: 26
height: 26
radius: 13 radius: 13
color: vpntoggle.down ? "#cccccc" : "#ffffff" color: vpntoggle.checked ? "#17a81a" : "transparent"
border.color: vpntoggle.checked ? (vpntoggle.down ? "#17a81a" : "#21be2b") : "#999999" border.color: vpntoggle.checked ? "#17a81a" : "#cccccc"
Rectangle {
x: vpntoggle.checked ? parent.width - width : 0
width: 26
height: 26
radius: 13
color: vpntoggle.down ? "#cccccc" : "#ffffff"
border.color: vpntoggle.checked ? (vpntoggle.down ? "#17a81a" : "#21be2b") : "#999999"
}
} }
}
background: Rectangle { background: Rectangle {
implicitWidth: 100 implicitWidth: 100
implicitHeight: 40 implicitHeight: 40
visible: vpntoggle.down || vpntoggle.highlighted visible: vpntoggle.down || vpntoggle.highlighted
color: vpntoggle.down ? "#bdbebf" : "#eeeeee" color: vpntoggle.down ? "#17a81a" : "#eeeeee"
}
} // end switchdelegate
Text {
id: manualOverrideWarning
font.pixelSize: 10
color: "grey"
text: qsTr("Location has been manually set.")
anchors.horizontalCenter: parent.horizontalCenter
visible: isManualLocation()
} }
} // end switchdelegate } // end column
} // end inner item
Text { } // end outer item
id: manualOverrideWarning
font.pixelSize: 10
color: "grey"
text: qsTr("Location has been manually set.")
anchors.horizontalCenter: parent.horizontalCenter
visible: isManualLocation()
}
}
}
Item { Item {
...@@ -148,7 +179,7 @@ ApplicationWindow { ...@@ -148,7 +179,7 @@ ApplicationWindow {
RadioButton { RadioButton {
id: autoSelectionButton id: autoSelectionButton
checked: !isManualLocation() checked: !isManualLocation()
text: qsTr("Best") text: qsTr("Recommended")
onClicked: backend.useAutomaticGateway() onClicked: backend.useAutomaticGateway()
} }
RadioButton { RadioButton {
...@@ -163,7 +194,7 @@ ApplicationWindow { ...@@ -163,7 +194,7 @@ ApplicationWindow {
visible: manualSelectionButton.checked visible: manualSelectionButton.checked
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
model: [qsTr("Best")] model: [qsTr("Recommended")]
onActivated: { onActivated: {
console.debug("Selected gateway:", currentText) console.debug("Selected gateway:", currentText)
backend.useLocation(currentText.toString()) backend.useLocation(currentText.toString())
...@@ -200,6 +231,45 @@ ApplicationWindow { ...@@ -200,6 +231,45 @@ ApplicationWindow {
} }
} // end column } // end column
} // end item } // end item
Item {
id: bridgesTab
anchors.centerIn: parent
width: parent.width
Column {
anchors.centerIn: parent
spacing: 10
width: parent.width
CheckBox {
checked: false
text: qsTr("Use obfs4 bridges")
font.pixelSize: 14
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
id: bridgesInfo
width: 250
color: "grey"
text: qsTr("Select a bridge only if you know that you need it to evade censorship in your country or local network.")
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
}
Text {
id: bridgeReconnect
width: 250
font.pixelSize: 12
color: "red"
text: qsTr("The change will take effect next time you connect to the VPN.")
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
visible: true
}
} // end column
} // end item
} // end stacklayout } // end stacklayout
Connections { Connections {
......
...@@ -83,6 +83,10 @@ func UseTransport(label string) { ...@@ -83,6 +83,10 @@ func UseTransport(label string) {
ctx.bm.UseTransport(label) ctx.bm.UseTransport(label)
} }
func GetTransport() *C.char {
return C.CString(ctx.bm.GetTransport())
}
func Quit() { func Quit() {
if ctx.autostart != nil { if ctx.autostart != nil {
ctx.autostart.Disable() ctx.autostart.Disable()
......
...@@ -57,7 +57,8 @@ type connectionCtx struct { ...@@ -57,7 +57,8 @@ type connectionCtx struct {
func (c *connectionCtx) toJson() ([]byte, error) { func (c *connectionCtx) toJson() ([]byte, error) {
statusMutex.Lock() statusMutex.Lock()
if c.bm != nil { if c.bm != nil {
c.Locations = c.bm.ListLocationFullness("openvpn") transport := c.bm.GetTransport()
c.Locations = c.bm.ListLocationFullness(transport)
c.CurrentGateway = c.bm.GetCurrentGateway() c.CurrentGateway = c.bm.GetCurrentGateway()
c.CurrentLocation = c.bm.GetCurrentLocation() c.CurrentLocation = c.bm.GetCurrentLocation()
c.CurrentCountry = c.bm.GetCurrentCountry() c.CurrentCountry = c.bm.GetCurrentCountry()
......
...@@ -49,7 +49,7 @@ func webGatewaySet(w http.ResponseWriter, r *http.Request) { ...@@ -49,7 +49,7 @@ func webGatewaySet(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "ParseForm() err: %v", err) fmt.Fprintf(w, "ParseForm() err: %v", err)
return return
} }
gwLabel := r.FormValue("gw") gwLabel := r.FormValue("transport")
fmt.Fprintf(w, "selected gateway: %s\n", gwLabel) fmt.Fprintf(w, "selected gateway: %s\n", gwLabel)
ctx.bm.UseGateway(gwLabel) ctx.bm.UseGateway(gwLabel)
// TODO make sure we don't tear the fw down on reconnect... // TODO make sure we don't tear the fw down on reconnect...
...@@ -63,23 +63,48 @@ func webGatewaySet(w http.ResponseWriter, r *http.Request) { ...@@ -63,23 +63,48 @@ func webGatewaySet(w http.ResponseWriter, r *http.Request) {
} }
func webGatewayList(w http.ResponseWriter, r *http.Request) { func webGatewayList(w http.ResponseWriter, r *http.Request) {
locationJson, err := json.Marshal(ctx.bm.ListLocationFullness("openvpn")) transport := ctx.bm.GetTransport()
locationJson, err := json.Marshal(ctx.bm.ListLocationFullness(transport))
if err != nil { if err != nil {
fmt.Fprintf(w, "Error converting json: %v", err) fmt.Fprintf(w, "Error converting json: %v", err)
} }
fmt.Fprintf(w, string(locationJson)) fmt.Fprintf(w, string(locationJson))
} }
// TODO
func webTransportGet(w http.ResponseWriter, r *http.Request) { func webTransportGet(w http.ResponseWriter, r *http.Request) {
t, err := json.Marshal(ctx.bm.GetTransport())
if err != nil {
fmt.Fprintf(w, "Error converting json: %v", err)
}
fmt.Fprintf(w, string(t))
} }
// TODO
func webTransportSet(w http.ResponseWriter, r *http.Request) { func webTransportSet(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
t := r.FormValue("transport")
if isValidTransport(t) {
fmt.Fprintf(w, "Selected transport: %s\n", t)
go ctx.bm.SetTransport(string(t))
} else {
fmt.Fprintf(w, "Unknown transport: %s\n", t)
}
default:
fmt.Fprintf(w, "Only POST supported.")
}
} }
// TODO
func webTransportList(w http.ResponseWriter, r *http.Request) { func webTransportList(w http.ResponseWriter, r *http.Request) {
t, err := json.Marshal([]string{"openvpn", "obfs4"})
if err != nil {
fmt.Fprintf(w, "Error converting json: %v", err)
}
fmt.Fprintf(w, string(t))
} }
func webQuit(w http.ResponseWriter, r *http.Request) { func webQuit(w http.ResponseWriter, r *http.Request) {
...@@ -97,10 +122,19 @@ func enableWebAPI(port int) { ...@@ -97,10 +122,19 @@ func enableWebAPI(port int) {
http.Handle("/vpn/gw/get", CheckAuth(http.HandlerFunc(webGatewayGet), token)) http.Handle("/vpn/gw/get", CheckAuth(http.HandlerFunc(webGatewayGet), token))
http.Handle("/vpn/gw/set", CheckAuth(http.HandlerFunc(webGatewaySet), token)) http.Handle("/vpn/gw/set", CheckAuth(http.HandlerFunc(webGatewaySet), token))
http.Handle("/vpn/gw/list", CheckAuth(http.HandlerFunc(webGatewayList), token)) http.Handle("/vpn/gw/list", CheckAuth(http.HandlerFunc(webGatewayList), token))
//http.Handle("/vpn/transport/get", CheckAuth(http.HandlerFunc(webTransportGet), token)) http.Handle("/vpn/transport/get", CheckAuth(http.HandlerFunc(webTransportGet), token))
//http.Handle("/vpn/transport/set", CheckAuth(http.HandlerFunc(webTransportSet), token)) http.Handle("/vpn/transport/set", CheckAuth(http.HandlerFunc(webTransportSet), token))
//http.Handle("/vpn/transport/list", CheckAuth(http.HandlerFunc(webTransportList), token)) http.Handle("/vpn/transport/list", CheckAuth(http.HandlerFunc(webTransportList), token))
http.Handle("/vpn/status", CheckAuth(http.HandlerFunc(webStatus), token)) http.Handle("/vpn/status", CheckAuth(http.HandlerFunc(webStatus), token))
http.Handle("/vpn/quit", CheckAuth(http.HandlerFunc(webQuit), token)) http.Handle("/vpn/quit", CheckAuth(http.HandlerFunc(webQuit), token))
http.ListenAndServe(":"+strconv.Itoa(port), nil) http.ListenAndServe(":"+strconv.Itoa(port), nil)
} }
func isValidTransport(t string) bool {
for _, b := range []string{"openvpn", "obfs4"} {
if b == t {
return true
}
}
return false
}
...@@ -30,6 +30,8 @@ type Bitmask interface { ...@@ -30,6 +30,8 @@ type Bitmask interface {
ListLocationFullness(protocol string) map[string]float64 ListLocationFullness(protocol string) map[string]float64
UseGateway(name string) UseGateway(name string)
UseAutomaticGateway() UseAutomaticGateway()
GetTransport() string
SetTransport(string) error
GetCurrentGateway() string GetCurrentGateway() string
GetCurrentLocation() string GetCurrentLocation() string
GetCurrentCountry() string GetCurrentCountry() string
......
...@@ -121,26 +121,8 @@ func (b *Bitmask) listenShapeErr() { ...@@ -121,26 +121,8 @@ func (b *Bitmask) listenShapeErr() {
func (b *Bitmask) startOpenVPN() error { func (b *Bitmask) startOpenVPN() error {
arg := []string{} arg := []string{}
// Empty transport means we get only the openvpn gateways if b.GetTransport() == "obfs4" {
if b.transport == "" { gateways, err := b.bonafide.GetGateways("obfs4")
arg = b.openvpnArgs
gateways, err := b.bonafide.GetGateways("openvpn")
if err != nil {
return err
}
err = b.launch.firewallStart(gateways)
if err != nil {
return err
}
for _, gw := range gateways {
for _, port := range gw.Ports {
arg = append(arg, "--remote", gw.IPAddress, port, "tcp4")
}
}
} else {
// For now, obf4 is the only supported Pluggable Transport
gateways, err := b.bonafide.GetGateways(b.transport)
if err != nil { if err != nil {
return err return err
} }
...@@ -164,6 +146,22 @@ func (b *Bitmask) startOpenVPN() error { ...@@ -164,6 +146,22 @@ func (b *Bitmask) startOpenVPN() error {
proxyArgs := strings.Split(proxy, ":") proxyArgs := strings.Split(proxy, ":")
arg = append(arg, "--remote", proxyArgs[0], proxyArgs[1], "tcp4") arg = append(arg, "--remote", proxyArgs[0], proxyArgs[1], "tcp4")
arg = append(arg, "--route", gw.IPAddress, "255.255.255.255", "net_gateway") arg = append(arg, "--route", gw.IPAddress, "255.255.255.255", "net_gateway")
} else {
arg = b.openvpnArgs
gateways, err := b.bonafide.GetGateways("openvpn")
if err != nil {
return err
}
err = b.launch.firewallStart(gateways)
if err != nil {
return err
}
for _, gw := range gateways {
for _, port := range gw.Ports {
arg = append(arg, "--remote", gw.IPAddress, port, "tcp4")
}
}
} }
arg = append(arg, arg = append(arg,
"--verb", "3", "--verb", "3",
...@@ -171,8 +169,8 @@ func (b *Bitmask) startOpenVPN() error { ...@@ -171,8 +169,8 @@ func (b *Bitmask) startOpenVPN() error {
"--management", openvpnManagementAddr, openvpnManagementPort, "--management", openvpnManagementAddr, openvpnManagementPort,
"--ca", b.getTempCaCertPath(), "--ca", b.getTempCaCertPath(),
"--cert", b.certPemPath, "--cert", b.certPemPath,
"--key", b.certPemPath, "--key", b.certPemPath)
"--persist-tun") //"--persist-tun")
return b.launch.openvpnStart(arg...) return b.launch.openvpnStart(arg...)
} }
...@@ -330,6 +328,23 @@ func (b *Bitmask) UseTransport(transport string) error { ...@@ -330,6 +328,23 @@ func (b *Bitmask) UseTransport(transport string) error {
return nil return nil
} }
func (b *Bitmask) GetTransport() string {
if b.transport == "obfs4" {
return "obfs4"
} else {
return "openvpn"
}
}
func (b *Bitmask) SetTransport(t string) error {
if t != "openvpn" && t != "obfs4" {
return errors.New("Transport not supported: " + t)
}
log.Println("Setting transport to", t)
b.transport = t
return nil
}
func (b *Bitmask) getTempCertPemPath() string { func (b *Bitmask) getTempCertPemPath() string {
return path.Join(b.tempdir, "openvpn.pem") return path.Join(b.tempdir, "openvpn.pem")
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment