From 324202a50e440cac36a756d6a2628ebadd2f8d70 Mon Sep 17 00:00:00 2001 From: Jeroen Wijenbergh Date: Mon, 21 Mar 2022 17:16:28 +0100 Subject: Update python and add basic config support --- cli/main.go | 27 +++++++++++++++---------- exports/exports.go | 26 +++++++++--------------- src/config.go | 34 ++++++++++++++++++++++++++++++++ src/oauth.go | 8 ++++---- src/server.go | 6 +++--- src/state.go | 10 ++++++---- wrappers/python/eduvpncommon/__init__.py | 11 ++--------- wrappers/python/eduvpncommon/main.py | 22 ++++++++------------- 8 files changed, 83 insertions(+), 61 deletions(-) create mode 100644 src/config.go diff --git a/cli/main.go b/cli/main.go index 3c66804..d5b51e8 100644 --- a/cli/main.go +++ b/cli/main.go @@ -14,8 +14,8 @@ func openBrowser(urlString string) { exec.Command("xdg-open", urlString).Start() } -func logState(oldState string, newState string) { - log.Printf("State: %s -> State: %s\n", oldState, newState) +func logState(oldState string, newState string, data string) { + log.Printf("State: %s -> State: %s with data %s\n", oldState, newState, data) } func main() { @@ -34,21 +34,28 @@ func main() { state := eduvpn.GetVPNState() - eduvpn.Register(state, "org.eduvpn.app.linux", logState) + eduvpn.Register(state, "org.eduvpn.app.linux", "configs", logState) state.Server = &eduvpn.Server{} serverInitializeErr := state.Server.Initialize(urlString) if serverInitializeErr != nil { log.Fatal(serverInitializeErr) } - authURL, err := state.InitializeOAuth() - if err != nil { - log.Fatal(err) + if state.LoadConfig() != nil { + authURL, err := state.InitializeOAuth() + if err != nil { + log.Fatal(err) + } + openBrowser(authURL) + oauthErr := state.FinishOAuth() + if oauthErr != nil { + log.Fatal(oauthErr) + } } - openBrowser(authURL) - oauthErr := state.FinishOAuth() - if oauthErr != nil { - log.Fatal(oauthErr) + + writeErr := state.WriteConfig() + if writeErr != nil { + log.Fatal(writeErr) } wireguardKey, wireguardErr := eduvpn.WireguardGenerateKey() diff --git a/exports/exports.go b/exports/exports.go index f0883a8..0bed7ba 100644 --- a/exports/exports.go +++ b/exports/exports.go @@ -3,46 +3,38 @@ package main /* #include -typedef void (*PythonCB)(const char* oldstate, const char* newstate); +typedef void (*PythonCB)(const char* oldstate, const char* newstate, const char* data); // FIXME: Remove this, see: https://stackoverflow.com/questions/58606884/multiple-definition-when-using-cgo __attribute__((weak)) -void call_callback(PythonCB callback, const char* oldstate, const char* newstate) +void call_callback(PythonCB callback, const char* oldstate, const char* newstate, const char* data) { - callback(oldstate, newstate); + callback(oldstate, newstate, data); } */ import "C" import "unsafe" - import "github.com/jwijenbergh/eduvpn-common/src" var P_StateCallback C.PythonCB -func StateCallback(old_state string, new_state string) { +func StateCallback(old_state string, new_state string, data string) { if P_StateCallback == nil { return } oldState_c := C.CString(old_state) newState_c := C.CString(new_state) - C.call_callback(P_StateCallback, oldState_c, newState_c) + data_c := C.CString(data) + C.call_callback(P_StateCallback, oldState_c, newState_c, data_c) C.free(unsafe.Pointer(oldState_c)) C.free(unsafe.Pointer(newState_c)) + C.free(unsafe.Pointer(data_c)) } //export Register -func Register(name *C.char, url *C.char, stateCallback C.PythonCB) { +func Register(name *C.char, config_directory *C.char, stateCallback C.PythonCB) { P_StateCallback = stateCallback - eduvpn.Register(eduvpn.GetVPNState(), C.GoString(name), C.GoString(url), StateCallback) -} - -//export InitializeOAuth -func InitializeOAuth() (*C.char, *C.char) { - url, err := eduvpn.InitializeOAuth(eduvpn.GetVPNState()) - if err != nil { - return nil, C.CString(err.Error()) - } - return C.CString(url), nil + eduvpn.Register(eduvpn.GetVPNState(), C.GoString(name), C.GoString(config_directory), StateCallback) } //export FreeString diff --git a/src/config.go b/src/config.go new file mode 100644 index 0000000..0b7c1c7 --- /dev/null +++ b/src/config.go @@ -0,0 +1,34 @@ +package eduvpn + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" +) + +func (eduvpn *VPNState) GetConfigName() string { + pathString := path.Join(eduvpn.ConfigDirectory, eduvpn.Name) + return fmt.Sprintf("%s.json", pathString) +} + +func (eduvpn *VPNState) WriteConfig() error { + mkdirErr := os.MkdirAll(eduvpn.ConfigDirectory, os.ModePerm) + if mkdirErr != nil { + return mkdirErr + } + jsonString, marshalErr := json.Marshal(eduvpn) + if marshalErr != nil { + return marshalErr + } + return ioutil.WriteFile(eduvpn.GetConfigName(), jsonString, 0644) +} + +func (eduvpn *VPNState) LoadConfig() error { + bytes, readErr := ioutil.ReadFile(eduvpn.GetConfigName()) + if readErr != nil { + return readErr + } + return json.Unmarshal(bytes, eduvpn) +} diff --git a/src/oauth.go b/src/oauth.go index 063034b..eb93c00 100644 --- a/src/oauth.go +++ b/src/oauth.go @@ -54,9 +54,9 @@ func genVerifier() (string, error) { } type OAuth struct { - Session *OAuthExchangeSession - Token *OAuthToken - TokenURL string + Session *OAuthExchangeSession `json:"-"` + Token *OAuthToken `json:"token"` + TokenURL string `json:"token_url"` } // This structure gets passed to the callback for easy access to the current state @@ -85,7 +85,7 @@ type OAuthToken struct { Refresh string `json:"refresh_token"` Type string `json:"token_type"` Expires int64 `json:"expires_in"` - ExpiredTimestamp int64 + ExpiredTimestamp int64 `json:"expires_in_timestamp"` } // Gets an authenticated HTTP client by obtaining refresh and access tokens diff --git a/src/server.go b/src/server.go index 6f809c6..627843f 100644 --- a/src/server.go +++ b/src/server.go @@ -5,9 +5,9 @@ import ( ) type Server struct { - BaseURL string - Endpoints *ServerEndpoints - OAuth *OAuth + BaseURL string `json:"base_url"` + Endpoints *ServerEndpoints `json:"endpoints"` + OAuth *OAuth `json:"oauth"` } type ServerEndpointList struct { diff --git a/src/state.go b/src/state.go index 582dd5a..6f06860 100644 --- a/src/state.go +++ b/src/state.go @@ -2,16 +2,18 @@ package eduvpn type VPNState struct { // Info passed by the client - Name string + ConfigDirectory string `json:"-"` + Name string `json:"-"` // The chosen server - Server *Server + Server *Server `json:"server"` } -func Register(state *VPNState, name string, stateCallback func(string, string)) error { +func Register(state *VPNState, name string, directory string, stateCallback func(string, string, string)) error { state.Name = name + state.ConfigDirectory = directory - stateCallback("START", "REGISTER") + stateCallback("START", "REGISTERED", "test data") return nil } diff --git a/wrappers/python/eduvpncommon/__init__.py b/wrappers/python/eduvpncommon/__init__.py index c21f8d4..a5efb40 100644 --- a/wrappers/python/eduvpncommon/__init__.py +++ b/wrappers/python/eduvpncommon/__init__.py @@ -19,17 +19,10 @@ _libfile = f"{_lib_prefixes[_os]}{_libname}{_lib_suffixes[_os]}" # Library should have been copied to the lib/ folder lib = cdll.LoadLibrary(str(pathlib.Path(__file__).parent / "lib" / _libfile)) -# Data types -class DataError(Structure): - _fields_ = [('data', c_void_p), - ('error', c_int64)] - -GOCB_StateChange = CFUNCTYPE(None, c_char_p, c_char_p) - +VPNStateChange = CFUNCTYPE(None, c_char_p, c_char_p, c_char_p) # Exposed functions -lib.Register.argtypes, lib.Register.restype = [c_char_p, c_char_p, GOCB_StateChange], None +lib.Register.argtypes, lib.Register.restype = [c_char_p, VPNStateChange], None # We have to use c_void_p instead of c_char_p to free it properly # See https://stackoverflow.com/questions/13445568/python-ctypes-how-to-free-memory-getting-invalid-pointer-error -lib.InitializeOAuth.argtypes, lib.InitializeOAuth.restype = [], c_void_p lib.FreeString.argtypes, lib.FreeString.restype = [c_void_p], None diff --git a/wrappers/python/eduvpncommon/main.py b/wrappers/python/eduvpncommon/main.py index b8278ad..f7afa17 100644 --- a/wrappers/python/eduvpncommon/main.py +++ b/wrappers/python/eduvpncommon/main.py @@ -1,22 +1,16 @@ -from . import lib, GOCB_StateChange +from . import lib, VPNStateChange from ctypes import * -@GOCB_StateChange -def state_change(old, new): - print(f"Python: State change {old.decode()} {new.decode()}") - -def InitializeOAuth(): - ptr = lib.InitializeOAuth() - value = cast(ptr, c_char_p).value - authURL = value.decode() - lib.FreeString(ptr) - return authURL +@VPNStateChange +def state_change(old, new, data): + print(f"Python: State change {old.decode()} {new.decode()} DATA {data.decode()}") # Registers the python app with the GO code # name: The name of the app to be registered # url: The url of the server to connect to, FIXME: To be removed # state_callback: The callback to trigger whenever a state is changed, FIXME: Remove whenever this wrapper has implemented callbacks using function decorations -def Register(name, url, state_callback): +def Register(name, config_directory, state_callback): name_bytes = name.encode('utf-8') - url_bytes = url.encode('utf-8') - lib.Register(name_bytes, url_bytes, state_callback) + dir_bytes = config_directory.encode('utf-8') + lib.Register(name_bytes, config_directory, state_callback) + -- cgit v1.2.3