summaryrefslogtreecommitdiff
path: root/cmd/cli/main.go
blob: 497e354d6a1dca6de9275d127c010c943f74ce05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package main

import (
	"flag"
	"fmt"
	"os/exec"
	"strings"

	"github.com/eduvpn/eduvpn-common/client"
	"github.com/eduvpn/eduvpn-common/types"
	"github.com/eduvpn/eduvpn-common/internal/server"
)

type ServerTypes int8

const (
	ServerTypeInstituteAccess ServerTypes = iota
	ServerTypeSecureInternet
	ServerTypeCustom
)

// Open a browser with xdg-open
func openBrowser(url interface{}) {
	urlString, ok := url.(string)

	if !ok {
		return
	}
	fmt.Printf("OAuth: Initialized with AuthURL %s\n", urlString)
	fmt.Println("OAuth: Opening browser with xdg-open...")
	cmdErr := exec.Command("xdg-open", urlString).Start()
	if cmdErr != nil {
		fmt.Println("OAuth: Browser opened with xdg-open...")
	}
}

// Ask for a profile in the command line
func sendProfile(state *client.Client, data interface{}) {
	fmt.Printf("Multiple VPN profiles found. Please select a profile by entering e.g. 1")
	serverProfiles, ok := data.(*server.ServerProfileInfo)

	if !ok {
		fmt.Println("Invalid data type")
		return
	}

	var profiles string

	for index, profile := range serverProfiles.Info.ProfileList {
		profiles += fmt.Sprintf("\n%d - %s", index+1, profile.DisplayName)
	}

	// Show the profiles
	fmt.Println(profiles)

	var chosenProfile int
	_, scanErr := fmt.Scanf("%d", &chosenProfile)

	if scanErr != nil || chosenProfile <= 0 ||
		chosenProfile > len(serverProfiles.Info.ProfileList) {
		fmt.Println("invalid profile chosen, please retry")
		sendProfile(state, data)
		return
	}

	profile := serverProfiles.Info.ProfileList[chosenProfile-1]
	fmt.Println("Sending profile ID", profile.ID)
	profileErr := state.SetProfileID(profile.ID)

	if profileErr != nil {
		fmt.Println("Failed setting profile with error", profileErr)
	}
}

// The callback function
// If OAuth is started we open the browser with the Auth URL
// If we ask for a profile, we send the profile using command line input
// Note that this has an additional argument, the vpn state which was wrapped into this callback function below
func stateCallback(
	state *client.Client,
	oldState client.FSMStateID,
	newState client.FSMStateID,
	data interface{},
) {
	if newState == client.STATE_OAUTH_STARTED {
		openBrowser(data)
	}

	if newState == client.STATE_ASK_PROFILE {
		sendProfile(state, data)
	}
}

// Get a config for Institute Access or Secure Internet Server
func getConfig(state *client.Client, url string, serverType ServerTypes) (string, string, error) {
	if !strings.HasPrefix(url, "http") {
		url = "https://" + url
	}
	// Prefer TCP is set to False
	if serverType == ServerTypeInstituteAccess {
		_, addErr := state.AddInstituteServer(url)
		if addErr != nil {
			return "", "", addErr
		}
		return state.GetConfigInstituteAccess(url, false)
	} else if serverType == ServerTypeCustom {
		_, addErr := state.AddCustomServer(url)
		if addErr != nil {
			return "", "", addErr
		}
		return state.GetConfigCustomServer(url, false)
	}
	_, addErr := state.AddSecureInternetHomeServer(url)
	if addErr != nil {
		return "", "", addErr
	}
	return state.GetConfigSecureInternet(url, false)
}

// Get a config for a single server, Institute Access or Secure Internet
func printConfig(url string, serverType ServerTypes) {
	state := &client.Client{}

	registerErr := state.Register(
		"org.client.app.linux",
		"configs",
		"en",
		func(old client.FSMStateID, new client.FSMStateID, data interface{}) {
			stateCallback(state, old, new, data)
		},
		true,
	)
	if registerErr != nil {
		fmt.Printf("Register error: %v", registerErr)
		return
	}

	defer state.Deregister()

	config, _, configErr := getConfig(state, url, serverType)

	if configErr != nil {
		// Show the usage of tracebacks and causes
		fmt.Println("Error getting config:", types.GetErrorTraceback(configErr))
		fmt.Println("Error getting config, cause:", types.GetErrorCause(configErr))
		return
	}

	fmt.Println("Obtained config", config)
}

// The main function
// It parses the arguments and executes the correct functions
func main() {
	customUrlArg := flag.String("get-custom", "", "The url of a custom server to connect to")
	urlArg := flag.String("get-institute", "", "The url of an institute to connect to")
	secureInternet := flag.String("get-secure", "", "Gets secure internet servers")
	flag.Parse()

	// Connect to a VPN by getting an Institute Access config
	customUrlString := *customUrlArg
	urlString := *urlArg
	secureInternetString := *secureInternet
	if customUrlString != "" {
		printConfig(customUrlString, ServerTypeCustom)
		return
	} else if urlString != "" {
		printConfig(urlString, ServerTypeInstituteAccess)
		return
	} else if secureInternetString != "" {
		printConfig(secureInternetString, ServerTypeSecureInternet)
		return
	}
	flag.PrintDefaults()
}