diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-04-22 16:29:59 +0200 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-04-22 16:29:59 +0200 |
| commit | b1d92b395322f2164ccfb44b0f7caebbaece6b62 (patch) | |
| tree | 2133e4045b4af4d07a98674b7ae3a234670f0305 | |
| parent | 3a4ae2942b43923ff98fd2eca8878c3cf145686c (diff) | |
Refactor: Restructure project
- Add an internal folder where all the internal code lives
- Make a state.go and state_test.go for the public interface
This gives a more clear separation between functions and modules. It
also makes this a more typical Go project setup.
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | ci/docker/go-test.docker | 5 | ||||
| -rw-r--r-- | cli/go.mod | 7 | ||||
| -rw-r--r-- | cli/go.sum | 45 | ||||
| -rw-r--r-- | cmd/cli/main.go (renamed from cli/main.go) | 31 | ||||
| -rw-r--r-- | exports/Makefile | 2 | ||||
| -rw-r--r-- | exports/exports.go | 22 | ||||
| -rw-r--r-- | go.mod | 4 | ||||
| -rw-r--r-- | go.sum | 32 | ||||
| -rw-r--r-- | internal/api.go (renamed from src/api.go) | 6 | ||||
| -rw-r--r-- | internal/config.go | 43 | ||||
| -rw-r--r-- | internal/discovery.go (renamed from src/discovery.go) | 49 | ||||
| -rw-r--r-- | internal/fsm.go (renamed from src/fsm.go) | 108 | ||||
| -rw-r--r-- | internal/http.go (renamed from src/http.go) | 2 | ||||
| -rw-r--r-- | internal/log.go (renamed from src/log.go) | 27 | ||||
| -rw-r--r-- | internal/oauth.go (renamed from src/oauth.go) | 70 | ||||
| -rw-r--r-- | internal/openvpn.go (renamed from src/openvpn.go) | 2 | ||||
| -rw-r--r-- | internal/server.go (renamed from src/server.go) | 50 | ||||
| -rw-r--r-- | internal/test_data/empty (renamed from src/test_data/empty) | 0 | ||||
| -rw-r--r-- | internal/test_data/generate.sh (renamed from src/test_data/generate.sh) | 0 | ||||
| -rw-r--r-- | internal/test_data/generate_forged.py (renamed from src/test_data/generate_forged.py) | 0 | ||||
| -rw-r--r-- | internal/test_data/organization_list.json (renamed from src/test_data/organization_list.json) | 0 | ||||
| -rw-r--r-- | internal/test_data/organization_list.json.minisig (renamed from src/test_data/organization_list.json.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/organization_list.json.tc_servlist.minisig (renamed from src/test_data/organization_list.json.tc_servlist.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/other_list.json (renamed from src/test_data/other_list.json) | 0 | ||||
| -rw-r--r-- | internal/test_data/other_list.json.minisig (renamed from src/test_data/other_list.json.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/public.key (renamed from src/test_data/public.key) | 0 | ||||
| -rw-r--r-- | internal/test_data/random.txt (renamed from src/test_data/random.txt) | 0 | ||||
| -rw-r--r-- | internal/test_data/secret.key (renamed from src/test_data/secret.key) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json (renamed from src/test_data/server_list.json) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.blake2b (renamed from src/test_data/server_list.json.blake2b) | bin | 64 -> 64 bytes | |||
| -rw-r--r-- | internal/test_data/server_list.json.forged_keyid.minisig (renamed from src/test_data/server_list.json.forged_keyid.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.forged_pure.minisig (renamed from src/test_data/server_list.json.forged_pure.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.large_time.minisig (renamed from src/test_data/server_list.json.large_time.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.minisig (renamed from src/test_data/server_list.json.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.pure.minisig (renamed from src/test_data/server_list.json.pure.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_earliertime.minisig (renamed from src/test_data/server_list.json.tc_earliertime.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_emptyfile.minisig (renamed from src/test_data/server_list.json.tc_emptyfile.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_emptytime.minisig (renamed from src/test_data/server_list.json.tc_emptytime.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_latertime.minisig (renamed from src/test_data/server_list.json.tc_latertime.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_nofile.minisig (renamed from src/test_data/server_list.json.tc_nofile.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_nohashed.minisig (renamed from src/test_data/server_list.json.tc_nohashed.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_notime.minisig (renamed from src/test_data/server_list.json.tc_notime.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_orglist.minisig (renamed from src/test_data/server_list.json.tc_orglist.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_otherfile.minisig (renamed from src/test_data/server_list.json.tc_otherfile.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.tc_random.minisig (renamed from src/test_data/server_list.json.tc_random.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/server_list.json.wrong_key.minisig (renamed from src/test_data/server_list.json.wrong_key.minisig) | 0 | ||||
| -rw-r--r-- | internal/test_data/wrong_public.key (renamed from src/test_data/wrong_public.key) | 0 | ||||
| -rw-r--r-- | internal/test_data/wrong_secret.key (renamed from src/test_data/wrong_secret.key) | 0 | ||||
| -rw-r--r-- | internal/util.go (renamed from src/util.go) | 11 | ||||
| -rw-r--r-- | internal/verify.go (renamed from src/verify.go) | 2 | ||||
| -rw-r--r-- | internal/verify_test.go (renamed from src/verify_test.go) | 2 | ||||
| -rw-r--r-- | internal/wireguard.go (renamed from src/wireguard.go) | 2 | ||||
| -rw-r--r-- | src/config.go | 42 | ||||
| -rw-r--r-- | src/state.go | 108 | ||||
| -rw-r--r-- | state.go | 143 | ||||
| -rw-r--r-- | state_test.go (renamed from src/server_test.go) | 40 |
57 files changed, 407 insertions, 450 deletions
@@ -6,7 +6,7 @@ build: test: test-go test-wrappers test-go: - go test github.com/jwijenbergh/eduvpn-common/src + go test ./... WRAPPERS ?= $(notdir $(patsubst %/,%,$(wildcard wrappers/*/))) diff --git a/ci/docker/go-test.docker b/ci/docker/go-test.docker index 3e56f67..2e6bcd5 100644 --- a/ci/docker/go-test.docker +++ b/ci/docker/go-test.docker @@ -28,10 +28,11 @@ RUN go mod download && go mod verify WORKDIR /eduvpn/go # Copy go source -COPY ./src ./src +COPY *.go ./ +COPY ./internal ./internal # Copy selenium scripts COPY ./selenium_eduvpn.py ./selenium_eduvpn.py # Run the tests -CMD ["go", "test", "-mod=readonly", "github.com/jwijenbergh/eduvpn-common/src", "-v"] +CMD ["go", "test", "-mod=readonly", "./...", "-v"] diff --git a/cli/go.mod b/cli/go.mod deleted file mode 100644 index 0bf9161..0000000 --- a/cli/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/jwijenbergh/eduvpn-common/cli - -replace github.com/jwijenbergh/eduvpn-common => ../ - -go 1.16 - -require github.com/jwijenbergh/eduvpn-common v0.0.0-00010101000000-000000000000 diff --git a/cli/go.sum b/cli/go.sum deleted file mode 100644 index 3e1adbc..0000000 --- a/cli/go.sum +++ /dev/null @@ -1,45 +0,0 @@ -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b h1:ZGiXF8sz7PDk6RgkP+A/SFfUD0ZR/AgG6SpRNEDKZy8= -github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b/go.mod h1:hQmNrgofl+IY/8L+n20H6E6PWBBTokdsv+q49j0QhsU= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= -github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= -github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA= -golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc= -golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= -golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -golang.zx2c4.com/wireguard v0.0.0-20220202223031-3b95c81cc178 h1:Nrf94TOjrvW8nm6N3u2xtbnMZaZudNI9b8nIJH8p8qY= -golang.zx2c4.com/wireguard v0.0.0-20220202223031-3b95c81cc178/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68 h1:9c4/JVIQUc2qCJEEIiGIs3HmmnFjhPj4qHW4+Uj+u3U= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68/go.mod h1:8P32Ilp1kCpwB4ItaHyvSk4xAtnpQ+8gQVfg5WaO1TU= diff --git a/cli/main.go b/cmd/cli/main.go index d5c3aa8..1406175 100644 --- a/cli/main.go +++ b/cmd/cli/main.go @@ -1,14 +1,12 @@ package main import ( - "errors" "flag" "fmt" - "os" "os/exec" "strings" - eduvpn "github.com/jwijenbergh/eduvpn-common/src" + eduvpn "github.com/jwijenbergh/eduvpn-common" ) func openBrowser(urlString string) { @@ -25,37 +23,10 @@ func logState(oldState string, newState string, data string) { } } -func writeGraph(filename string) error { - state := eduvpn.GetVPNState() - - state.InitializeFSM() - - graph := state.GenerateGraph() - - f, err := os.Create(filename) - if err != nil { - return errors.New(fmt.Sprintf("Failed to create file %s with error %v", filename, err)) - } - - defer f.Close() - - f.WriteString(graph) - - fmt.Printf("Graph written to file: %s, use 'fdp %s -Tsvg > graph.svg' from graphviz to save to a svg file called graph.svg\n", filename, filename) - - return nil -} - func main() { - fileGraph := flag.String("dumpgraph", "", "Dump the FSM to a graphviz fdp file") urlArg := flag.String("url", "", "The url of the vpn") flag.Parse() - fileGraphString := *fileGraph - if fileGraphString != "" { - writeGraph(fileGraphString) - return - } urlString := *urlArg if urlString != "" { diff --git a/exports/Makefile b/exports/Makefile index 86dbec2..b833228 100644 --- a/exports/Makefile +++ b/exports/Makefile @@ -16,7 +16,7 @@ endif # Build shared library and remove lib prefix (if any) from header name # GOOS and GOARCH envvars are set by common.mk # This extra target prevents unnecessary rebuild -lib/$(GOOS)/$(GOARCH)/$(LIB_FILE): exports.go ../src/*.go +lib/$(GOOS)/$(GOARCH)/$(LIB_FILE): exports.go .. CGO_ENABLED=1 go build -o $@ -buildmode=c-shared $< mv lib/$(GOOS)/$(GOARCH)/$(LIB_PREFIX)$(LIB_NAME).h lib/$(GOOS)/$(GOARCH)/$(LIB_NAME).h || true # Normalize header name diff --git a/exports/exports.go b/exports/exports.go index 84cd571..aa6f5b6 100644 --- a/exports/exports.go +++ b/exports/exports.go @@ -14,7 +14,7 @@ void call_callback(PythonCB callback, const char* oldstate, const char* newstate */ import "C" import "unsafe" -import "github.com/jwijenbergh/eduvpn-common/src" +import "github.com/jwijenbergh/eduvpn-common" var P_StateCallback C.PythonCB @@ -63,7 +63,7 @@ func Connect(url *C.char) (*C.char, *C.char) { //export GetOrganizationsList func GetOrganizationsList() (*C.char, *C.char) { state := eduvpn.GetVPNState() - organizations, organizationsErr := state.GetOrganizationsList() + organizations, organizationsErr := state.GetDiscoOrganizations() return C.CString(organizations), C.CString(ErrorToString(organizationsErr)) } @@ -71,27 +71,15 @@ func GetOrganizationsList() (*C.char, *C.char) { //export GetServersList func GetServersList() (*C.char, *C.char) { state := eduvpn.GetVPNState() - servers, serversErr := state.GetServersList() + servers, serversErr := state.GetDiscoServers() return C.CString(servers), C.CString(ErrorToString(serversErr)) } //export SetProfileID func SetProfileID(data *C.char) *C.char { state := eduvpn.GetVPNState() - - if !state.InState(eduvpn.ASK_PROFILE) { - return C.CString("Invalid state for setting a profile") - } - - // Set current profile to id - profile_id := C.GoString(data) - - server, serverErr := state.Servers.GetCurrentServer() - if serverErr != nil { - return C.CString("No server found for setting a profile ID") - } - server.Profiles.Current = profile_id - return C.CString("") + profileErr := state.SetProfileID(C.GoString(data)) + return C.CString(ErrorToString(profileErr)) } //export FreeString @@ -4,6 +4,6 @@ go 1.15 require ( github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b - golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68 + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220420130459-88a4932fb60b ) @@ -7,30 +7,37 @@ github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2C github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA= -golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc= -golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -38,9 +45,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -golang.zx2c4.com/wireguard v0.0.0-20220202223031-3b95c81cc178 h1:Nrf94TOjrvW8nm6N3u2xtbnMZaZudNI9b8nIJH8p8qY= -golang.zx2c4.com/wireguard v0.0.0-20220202223031-3b95c81cc178/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68 h1:9c4/JVIQUc2qCJEEIiGIs3HmmnFjhPj4qHW4+Uj+u3U= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68/go.mod h1:8P32Ilp1kCpwB4ItaHyvSk4xAtnpQ+8gQVfg5WaO1TU= +golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0= +golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220420130459-88a4932fb60b h1:8Uvay8veN0RwnZlR6eCnLb0dJbMutFFAdKrXa4TAIk8= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220420130459-88a4932fb60b/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4= diff --git a/src/api.go b/internal/api.go index 93c1c42..718702b 100644 --- a/src/api.go +++ b/internal/api.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "encoding/json" @@ -17,7 +17,7 @@ func (server *Server) apiAuthenticated(method string, endpoint string, opts *HTT url := server.Endpoints.API.V3.API + endpoint // Ensure we have valid tokens - oauthErr := server.OAuth.EnsureTokens() + oauthErr := server.EnsureTokens() if oauthErr != nil { return nil, nil, oauthErr @@ -40,7 +40,7 @@ func (server *Server) apiAuthenticatedRetry(method string, endpoint string, opts // Only retry authenticated if we get a HTTP 401 if errors.As(bodyErr, &error) && error.Status == 401 { - GetVPNState().Log(LOG_INFO, fmt.Sprintf("API: Got HTTP error %v, retrying authenticated", error)) + server.Logger.Log(LOG_INFO, fmt.Sprintf("API: Got HTTP error %v, retrying authenticated", error)) // Tell the method that the token is expired server.OAuth.Token.ExpiredTimestamp = GenerateTimeSeconds() return server.apiAuthenticated(method, endpoint, opts) diff --git a/internal/config.go b/internal/config.go new file mode 100644 index 0000000..47f773e --- /dev/null +++ b/internal/config.go @@ -0,0 +1,43 @@ +package internal + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "path" +) + +type Config struct { + Name string + Directory string +} + +func (config *Config) Init(name string, directory string) { + config.Name = name + config.Directory = directory +} + +func (config *Config) GetFilename() string { + pathString := path.Join(config.Directory, config.Name) + return fmt.Sprintf("%s.json", pathString) +} + +func (config *Config) Save(readStruct interface{}) error { + configDirErr := EnsureDirectory(config.Directory) + if configDirErr != nil { + return configDirErr + } + jsonString, marshalErr := json.Marshal(readStruct) + if marshalErr != nil { + return marshalErr + } + return ioutil.WriteFile(config.GetFilename(), jsonString, 0o644) +} + +func (config *Config) Load(writeStruct interface{}) error { + bytes, readErr := ioutil.ReadFile(config.GetFilename()) + if readErr != nil { + return readErr + } + return json.Unmarshal(bytes, writeStruct) +} diff --git a/src/discovery.go b/internal/discovery.go index fa3cac6..8c0acc7 100644 --- a/src/discovery.go +++ b/internal/discovery.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "encoding/json" @@ -54,9 +54,11 @@ type ServersList struct { Timestamp int64 `json:"-"` } -type DiscoLists struct { +type Discovery struct { Organizations OrganizationList Servers ServersList + FSM *FSM + Logger *FileLogger } // Helper function that gets a disco json @@ -107,59 +109,64 @@ func (e *GetListError) Error() string { return fmt.Sprintf("failed getting disco list file %s with error %v", e.File, e.Err) } +func (discovery *Discovery) Init(fsm *FSM, logger *FileLogger) { + discovery.FSM = fsm + discovery.Logger = logger +} + // FIXME: Implement based on // https://github.com/eduvpn/documentation/blob/v3/SERVER_DISCOVERY.md // - [IMPLEMENTED] on "first launch" when offering the search for "Institute Access" and "Organizations"; // - [TODO] when the user tries to add new server AND the user did NOT yet choose an organization before; // - [TODO] when the authorization for the server associated with an already chosen organization is triggered, e.g. after expiry or revocation. -func (eduvpn *VPNState) DetermineOrganizationsUpdate() bool { - return string(eduvpn.DiscoList.Organizations.JSON) == "" +func (discovery *Discovery) DetermineOrganizationsUpdate() bool { + return string(discovery.Organizations.JSON) == "" } // https://github.com/eduvpn/documentation/blob/v3/SERVER_DISCOVERY.md // - [Implemented] The application MUST always fetch the server_list.json at application start. // - The application MAY refresh the server_list.json periodically, e.g. once every hour. -func (eduvpn *VPNState) DetermineServersUpdate() bool { +func (discovery *Discovery) DetermineServersUpdate() bool { // No servers, we should update - if string(eduvpn.DiscoList.Servers.JSON) == "" { + if string(discovery.Servers.JSON) == "" { return true } // 1 hour from the last update - should_update_time := eduvpn.DiscoList.Servers.Timestamp + 3600 + should_update_time := discovery.Servers.Timestamp + 3600 now := GenerateTimeSeconds() if now >= should_update_time { return true } - GetVPNState().Log(LOG_INFO, "No update needed for servers, 1h is not passed yet") + discovery.Logger.Log(LOG_INFO, "No update needed for servers, 1h is not passed yet") return false } // Get the organization list -func (eduvpn *VPNState) GetOrganizationsList() (string, error) { - if !eduvpn.DetermineOrganizationsUpdate() { - return string(eduvpn.DiscoList.Organizations.JSON), nil +func (discovery *Discovery) GetOrganizationsList() (string, error) { + if !discovery.DetermineOrganizationsUpdate() { + return string(discovery.Organizations.JSON), nil } file := "organization_list.json" - err := getDiscoFile(file, eduvpn.DiscoList.Organizations.Version, &eduvpn.DiscoList.Organizations) + err := getDiscoFile(file, discovery.Organizations.Version, &discovery.Organizations) if err != nil { // Return previous with an error - return string(eduvpn.DiscoList.Organizations.JSON), &GetListError{File: file, Err: err} + return string(discovery.Organizations.JSON), &GetListError{File: file, Err: err} } - return string(eduvpn.DiscoList.Organizations.JSON), nil + return string(discovery.Organizations.JSON), nil } // Get the server list -func (eduvpn *VPNState) GetServersList() (string, error) { - if !eduvpn.DetermineServersUpdate() { - return string(eduvpn.DiscoList.Servers.JSON), nil +func (discovery *Discovery) GetServersList() (string, error) { + if !discovery.DetermineServersUpdate() { + return string(discovery.Servers.JSON), nil } file := "server_list.json" - err := getDiscoFile(file, eduvpn.DiscoList.Servers.Version, &eduvpn.DiscoList.Servers) + err := getDiscoFile(file, discovery.Servers.Version, &discovery.Servers) if err != nil { // Return previous with an error - return string(eduvpn.DiscoList.Servers.JSON), &GetListError{File: file, Err: err} + return string(discovery.Servers.JSON), &GetListError{File: file, Err: err} } // Update servers timestamp - eduvpn.DiscoList.Servers.Timestamp = GenerateTimeSeconds() - return string(eduvpn.DiscoList.Servers.JSON), nil + discovery.Servers.Timestamp = GenerateTimeSeconds() + return string(discovery.Servers.JSON), nil } diff --git a/src/fsm.go b/internal/fsm.go index 223b42f..fadc7c9 100644 --- a/src/fsm.go +++ b/internal/fsm.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "fmt" @@ -90,10 +90,37 @@ type ( type FSM struct { States FSMStates Current FSMStateID + + // Info to be passed from the parent state + StateCallback func(string, string, string) + Logger *FileLogger + Debug bool } -func (eduvpn *VPNState) HasTransition(check FSMStateID) bool { - for _, transition_state := range eduvpn.FSM.States[eduvpn.FSM.Current] { +func (fsm *FSM) Init(callback func(string, string, string), logger *FileLogger, debug bool) { + fsm.States = FSMStates{ + DEREGISTERED: {{NO_SERVER, "Client registers"}}, + NO_SERVER: {{CHOSEN_SERVER, "User chooses a server"}}, + CHOSEN_SERVER: {{AUTHENTICATED, "Found tokens in config"}, {OAUTH_STARTED, "No tokens found in config"}}, + OAUTH_STARTED: {{AUTHENTICATED, "User authorizes with browser"}}, + AUTHENTICATED: {{OAUTH_STARTED, "Re-authenticate with OAuth"}, {REQUEST_CONFIG, "Client requests a config"}}, + REQUEST_CONFIG: {{ASK_PROFILE, "Multiple profiles found"}, {HAS_CONFIG, "Success, only one profile"}}, + ASK_PROFILE: {{HAS_CONFIG, "User chooses profile and success"}}, + HAS_CONFIG: {{CONNECTED, "OS reports connected"}}, + CONNECTED: {{AUTHENTICATED, "OS reports disconnected"}}, + } + fsm.Current = DEREGISTERED + fsm.StateCallback = callback + fsm.Logger = logger + fsm.Debug = debug +} + +func (fsm *FSM) InState(check FSMStateID) bool { + return check == fsm.Current +} + +func (fsm *FSM) HasTransition(check FSMStateID) bool { + for _, transition_state := range fsm.States[fsm.Current] { if transition_state.To == check { return true } @@ -102,16 +129,12 @@ func (eduvpn *VPNState) HasTransition(check FSMStateID) bool { return false } -func (eduvpn *VPNState) InState(check FSMStateID) bool { - return check == eduvpn.FSM.Current -} - -func (eduvpn *VPNState) writeGraph() { - graph := eduvpn.GenerateGraph() +func (fsm *FSM) writeGraph() { + graph := fsm.GenerateGraph() f, err := os.Create("debug.graph") if err != nil { - eduvpn.Log(LOG_INFO, fmt.Sprintf("Failed to write debug fsm graph with error %v", err)) + fsm.Logger.Log(LOG_INFO, fmt.Sprintf("Failed to write debug fsm graph with error %v", err)) } defer f.Close() @@ -119,52 +142,36 @@ func (eduvpn *VPNState) writeGraph() { f.WriteString(graph) } -func (eduvpn *VPNState) GoTransitionWithData(newState FSMStateID, data string) bool { - ok := eduvpn.HasTransition(newState) +func (fsm *FSM) GoTransitionWithData(newState FSMStateID, data string) bool { + ok := fsm.HasTransition(newState) if ok { - oldState := eduvpn.FSM.Current - eduvpn.FSM.Current = newState - if eduvpn.Debug { - eduvpn.writeGraph() + oldState := fsm.Current + fsm.Current = newState + if fsm.Debug { + fsm.writeGraph() } - eduvpn.StateCallback(oldState.String(), newState.String(), data) + fsm.StateCallback(oldState.String(), newState.String(), data) } return ok } -func (eduvpn *VPNState) GoTransition(newState FSMStateID) bool { - return eduvpn.GoTransitionWithData(newState, "") +func (fsm *FSM) GoTransition(newState FSMStateID) bool { + return fsm.GoTransitionWithData(newState, "") } -func (eduvpn *VPNState) generateDotGraph() string { - graph := `digraph eduvpn_fsm { -nodesep = 2; -remincross = false; -` - graph += "node[color=blue]; " + eduvpn.FSM.Current.String() + ";\n" - graph += "node [color=black];\n" - for state, transitions := range eduvpn.FSM.States { - for _, transition := range transitions { - graph += state.String() + " -> " + transition.To.String() + " [label=\"" + transition.Description + "\"]\n" - } - } - graph += "}" - return graph -} - -func (eduvpn *VPNState) generateMermaidGraph() string { +func (fsm *FSM) generateMermaidGraph() string { graph := "graph TD\n" - sorted_fsm := make(FSMStateIDSlice, 0, len(eduvpn.FSM.States)) - for state_id := range eduvpn.FSM.States { + sorted_fsm := make(FSMStateIDSlice, 0, len(fsm.States)) + for state_id := range fsm.States { sorted_fsm = append(sorted_fsm, state_id) } sort.Sort(sorted_fsm) for _, state := range sorted_fsm { - transitions := eduvpn.FSM.States[state] + transitions := fsm.States[state] for _, transition := range transitions { - if state == eduvpn.FSM.Current { + if state == fsm.Current { graph += "\nstyle " + state.String() + " fill:cyan\n" } else { graph += "\nstyle " + state.String() + " fill:white\n" @@ -175,23 +182,6 @@ func (eduvpn *VPNState) generateMermaidGraph() string { return graph } -func (eduvpn *VPNState) GenerateGraph() string { - return eduvpn.generateMermaidGraph() -} - -func (eduvpn *VPNState) InitializeFSM() { - eduvpn.FSM = FSM{ - States: FSMStates{ - DEREGISTERED: {{NO_SERVER, "Client registers"}}, - NO_SERVER: {{CHOSEN_SERVER, "User chooses a server"}}, - CHOSEN_SERVER: {{AUTHENTICATED, "Found tokens in config"}, {OAUTH_STARTED, "No tokens found in config"}}, - OAUTH_STARTED: {{AUTHENTICATED, "User authorizes with browser"}}, - AUTHENTICATED: {{OAUTH_STARTED, "Re-authenticate with OAuth"}, {REQUEST_CONFIG, "Client requests a config"}}, - REQUEST_CONFIG: {{ASK_PROFILE, "Multiple profiles found"}, {HAS_CONFIG, "Success, only one profile"}}, - ASK_PROFILE: {{HAS_CONFIG, "User chooses profile and success"}}, - HAS_CONFIG: {{CONNECTED, "OS reports connected"}}, - CONNECTED: {{AUTHENTICATED, "OS reports disconnected"}}, - }, - Current: DEREGISTERED, - } +func (fsm *FSM) GenerateGraph() string { + return fsm.generateMermaidGraph() } diff --git a/src/http.go b/internal/http.go index bbc866b..8ca8cb9 100644 --- a/src/http.go +++ b/internal/http.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "fmt" diff --git a/src/log.go b/internal/log.go index 7402e31..52c0f3d 100644 --- a/src/log.go +++ b/internal/log.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "fmt" @@ -36,31 +36,30 @@ func (e LogLevel) String() string { } } -func (eduvpn *VPNState) getLogFilename() string { - pathString := path.Join(eduvpn.ConfigDirectory, eduvpn.Name) - return fmt.Sprintf("%s.log", pathString) -} - -func (eduvpn *VPNState) InitLog(level LogLevel) error { - configDirErr := eduvpn.EnsureConfigDir() +func (logger *FileLogger) Init(level LogLevel, name string, directory string) error { + configDirErr := EnsureDirectory(directory) if configDirErr != nil { return configDirErr } - logFile, logOpenErr := os.OpenFile(eduvpn.getLogFilename(), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666) + logFile, logOpenErr := os.OpenFile(logger.getFilename(directory, name), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666) if logOpenErr != nil { return logOpenErr } log.SetOutput(logFile) - eduvpn.LogFile = FileLogger{Level: level, File: logFile} return nil } -func (eduvpn *VPNState) Log(level LogLevel, str string) { - if level >= eduvpn.LogFile.Level && eduvpn.LogFile.Level != LOG_NOTSET { +func (logger *FileLogger) getFilename(directory string, name string) string { + pathString := path.Join(directory, name) + return fmt.Sprintf("%s.log", pathString) +} + +func (logger *FileLogger) Log(level LogLevel, str string) { + if level >= logger.Level && logger.Level != LOG_NOTSET { log.Printf("[%s]: %s", level.String(), str) } } -func (eduvpn *VPNState) CloseLog() { - eduvpn.LogFile.File.Close() +func (logger *FileLogger) Close() { + logger.File.Close() } diff --git a/src/oauth.go b/internal/oauth.go index 263690e..1e728ca 100644 --- a/src/oauth.go +++ b/internal/oauth.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "context" @@ -56,6 +56,8 @@ type OAuth struct { Session OAuthExchangeSession `json:"-"` Token OAuthToken `json:"token"` TokenURL string `json:"token_url"` + Logger *FileLogger `json:"-"` + FSM *FSM `json:"-"` } // This structure gets passed to the callback for easy access to the current state @@ -215,12 +217,15 @@ func (oauth *OAuth) Callback(w http.ResponseWriter, req *http.Request) { go oauth.Session.Server.Shutdown(oauth.Session.Context) } -// Initializes the OAuth for eduvpn. -// It needs a vpn state that was gotten from `Register` -// It returns the authurl for the browser and an error if present -func (eduvpn *VPNState) InitializeOAuth() error { - if !eduvpn.HasTransition(OAUTH_STARTED) { - return errors.New(fmt.Sprintf("Failed starting oauth, invalid state %s", eduvpn.FSM.Current.String())) +func (oauth *OAuth) Init(fsm *FSM, logger *FileLogger) { + oauth.FSM = fsm + oauth.Logger = logger +} + +// Starts the OAuth exchange for eduvpn. +func (oauth *OAuth) start(name string, authorizationURL string, tokenURL string) error { + if !oauth.FSM.HasTransition(OAUTH_STARTED) { + return errors.New(fmt.Sprintf("Failed starting oauth, invalid state %s", oauth.FSM.Current.String())) } // Generate the state state, stateErr := genState() @@ -236,7 +241,7 @@ func (eduvpn *VPNState) InitializeOAuth() error { challenge := genChallengeS256(verifier) parameters := map[string]string{ - "client_id": eduvpn.Name, + "client_id": name, "code_challenge_method": "S256", "code_challenge": challenge, "response_type": "code", @@ -245,48 +250,41 @@ func (eduvpn *VPNState) InitializeOAuth() error { "redirect_uri": "http://127.0.0.1:8000/callback", } - server, serverErr := eduvpn.Servers.GetCurrentServer() - if serverErr != nil { - return errors.New("OAuth Initialize no server found") - } - authURL, urlErr := HTTPConstructURL(server.Endpoints.API.V3.Authorization, parameters) + authURL, urlErr := HTTPConstructURL(authorizationURL, parameters) if urlErr != nil { // shouldn't happen panic(urlErr) } // Fill the struct with the necessary fields filled for the next call to getting the HTTP client - oauthSession := OAuthExchangeSession{ClientID: eduvpn.Name, State: state, Verifier: verifier} - server.OAuth = OAuth{TokenURL: server.Endpoints.API.V3.Token, Session: oauthSession} - eduvpn.GoTransitionWithData(OAUTH_STARTED, authURL) + oauthSession := OAuthExchangeSession{ClientID: name, State: state, Verifier: verifier} + oauth.TokenURL = tokenURL + oauth.Session = oauthSession + oauth.FSM.GoTransitionWithData(OAUTH_STARTED, authURL) return nil } // Error definitions -func (eduvpn *VPNState) FinishOAuth() error { - if !eduvpn.HasTransition(AUTHENTICATED) { +func (oauth *OAuth) Finish() error { + if !oauth.FSM.HasTransition(AUTHENTICATED) { return errors.New("invalid state to finish oauth") } - server, serverErr := eduvpn.Servers.GetCurrentServer() - if serverErr != nil { - return errors.New("OAuth Initialize No server found") - } - tokenErr := server.OAuth.getTokensWithCallback() + tokenErr := oauth.getTokensWithCallback() if tokenErr != nil { return tokenErr } - eduvpn.GoTransition(AUTHENTICATED) + oauth.FSM.GoTransition(AUTHENTICATED) return nil } -func (state *VPNState) LoginOAuth() error { - authInitializeErr := state.InitializeOAuth() +func (oauth *OAuth) Login(name string, authorizationURL string, tokenURL string) error { + authInitializeErr := oauth.start(name, authorizationURL, tokenURL) if authInitializeErr != nil { return authInitializeErr } - oauthErr := state.FinishOAuth() + oauthErr := oauth.Finish() if oauthErr != nil { return oauthErr @@ -294,14 +292,10 @@ func (state *VPNState) LoginOAuth() error { return nil } -func (oauth *OAuth) Login() error { - return GetVPNState().LoginOAuth() -} - func (oauth *OAuth) NeedsRelogin() bool { // Access Token or Refresh Tokens empty, definitely needs a relogin if oauth.Token.Access == "" || oauth.Token.Refresh == "" { - GetVPNState().Log(LOG_INFO, "OAuth: Tokens are empty") + oauth.Logger.Log(LOG_INFO, "OAuth: Tokens are empty") return true } @@ -310,14 +304,14 @@ func (oauth *OAuth) NeedsRelogin() bool { // The tokens are not expired yet // No relogin is needed if !oauth.isTokensExpired() { - GetVPNState().Log(LOG_INFO, "OAuth: Tokens are not expired, re-login not needed") + oauth.Logger.Log(LOG_INFO, "OAuth: Tokens are not expired, re-login not needed") return false } refreshErr := oauth.getTokensWithRefresh() // We have obtained new tokens with refresh if refreshErr == nil { - GetVPNState().Log(LOG_INFO, "OAuth: Tokens could be re-acquired using the refresh token, re-login not needed") + oauth.Logger.Log(LOG_INFO, "OAuth: Tokens could be re-acquired using the refresh token, re-login not needed") return false } @@ -325,14 +319,6 @@ func (oauth *OAuth) NeedsRelogin() bool { return true } -func (oauth *OAuth) EnsureTokens() error { - if oauth.NeedsRelogin() { - GetVPNState().Log(LOG_INFO, "OAuth: Tokens are invalid, relogging in") - return oauth.Login() - } - return nil -} - type OAuthGenStateUnableError struct { Err error } diff --git a/src/openvpn.go b/internal/openvpn.go index 95e1328..1b2e626 100644 --- a/src/openvpn.go +++ b/internal/openvpn.go @@ -1,4 +1,4 @@ -package eduvpn +package internal func (server *Server) OpenVPNGetConfig() (string, error) { profile_id := server.Profiles.Current diff --git a/src/server.go b/internal/server.go index 3dca26b..eb7f8fe 100644 --- a/src/server.go +++ b/internal/server.go @@ -1,8 +1,9 @@ -package eduvpn +package internal import ( "encoding/json" "errors" + "fmt" ) type Server struct { @@ -11,6 +12,8 @@ type Server struct { OAuth OAuth `json:"oauth"` Profiles ServerProfileInfo `json:"profiles"` ProfilesRaw string `json:"profiles_raw"` + Logger *FileLogger `json:"-"` + FSM *FSM `json:"-"` } type Servers struct { @@ -30,7 +33,27 @@ func (servers *Servers) GetCurrentServer() (*Server, error) { return server, nil } -func (servers *Servers) EnsureServer(url string) *Server { +func (server *Server) Init(url string, fsm *FSM, logger *FileLogger) error { + server.BaseURL = url + server.FSM = fsm + server.Logger = logger + server.OAuth.Init(fsm, logger) + endpointsErr := server.GetEndpoints() + if endpointsErr != nil { + return endpointsErr + } + return nil +} + +func (server *Server) EnsureTokens() error { + if server.OAuth.NeedsRelogin() { + server.Logger.Log(LOG_INFO, "OAuth: Tokens are invalid, relogging in") + return server.Login() + } + return nil +} + +func (servers *Servers) EnsureServer(url string, fsm *FSM, logger *FileLogger) *Server { if servers.List == nil { servers.List = make(map[string]*Server) } @@ -39,9 +62,9 @@ func (servers *Servers) EnsureServer(url string) *Server { if !exists || server == nil { server = &Server{} - server.Initialize(url) - servers.List[url] = server } + server.Init(url, fsm, logger) + servers.List[url] = server servers.Current = url return server } @@ -75,13 +98,8 @@ type ServerEndpoints struct { V string `json:"v"` } -func (server *Server) Initialize(url string) error { - server.BaseURL = url - endpointsErr := server.GetEndpoints() - if endpointsErr != nil { - return endpointsErr - } - return nil +func (server *Server) Login() error { + return server.OAuth.Login("org.eduvpn.app.linux", server.Endpoints.API.V3.Authorization, server.Endpoints.API.V3.Token) } func (server *Server) NeedsRelogin() bool { @@ -129,7 +147,7 @@ func (server *Server) getCurrentProfile() (*ServerProfile, error) { } func (server *Server) getConfigWithProfile() (string, error) { - if !GetVPNState().HasTransition(HAS_CONFIG) { + if !server.FSM.HasTransition(HAS_CONFIG) { return "", errors.New("cannot get a config with a profile, invalid state") } profile, profileErr := server.getCurrentProfile() @@ -145,16 +163,16 @@ func (server *Server) getConfigWithProfile() (string, error) { } func (server *Server) askForProfileID() error { - if !GetVPNState().HasTransition(ASK_PROFILE) { + if !server.FSM.HasTransition(ASK_PROFILE) { return errors.New("cannot ask for a profile id, invalid state") } - GetVPNState().GoTransitionWithData(ASK_PROFILE, server.ProfilesRaw) + server.FSM.GoTransitionWithData(ASK_PROFILE, server.ProfilesRaw) return nil } func (server *Server) GetConfig() (string, error) { - if !GetVPNState().InState(REQUEST_CONFIG) { - return "", errors.New("cannot get a config, invalid state") + if !server.FSM.InState(REQUEST_CONFIG) { + return "", errors.New(fmt.Sprintf("cannot get a config, invalid state %s", server.FSM.Current.String())) } infoErr := server.APIInfo() diff --git a/src/test_data/empty b/internal/test_data/empty index e69de29..e69de29 100644 --- a/src/test_data/empty +++ b/internal/test_data/empty diff --git a/src/test_data/generate.sh b/internal/test_data/generate.sh index b1b4545..b1b4545 100644 --- a/src/test_data/generate.sh +++ b/internal/test_data/generate.sh diff --git a/src/test_data/generate_forged.py b/internal/test_data/generate_forged.py index 843b32d..843b32d 100644 --- a/src/test_data/generate_forged.py +++ b/internal/test_data/generate_forged.py diff --git a/src/test_data/organization_list.json b/internal/test_data/organization_list.json index 8c53044..8c53044 100644 --- a/src/test_data/organization_list.json +++ b/internal/test_data/organization_list.json diff --git a/src/test_data/organization_list.json.minisig b/internal/test_data/organization_list.json.minisig index 1fa546e..1fa546e 100644 --- a/src/test_data/organization_list.json.minisig +++ b/internal/test_data/organization_list.json.minisig diff --git a/src/test_data/organization_list.json.tc_servlist.minisig b/internal/test_data/organization_list.json.tc_servlist.minisig index a7fe41f..a7fe41f 100644 --- a/src/test_data/organization_list.json.tc_servlist.minisig +++ b/internal/test_data/organization_list.json.tc_servlist.minisig diff --git a/src/test_data/other_list.json b/internal/test_data/other_list.json index 25ba1a8..25ba1a8 100644 --- a/src/test_data/other_list.json +++ b/internal/test_data/other_list.json diff --git a/src/test_data/other_list.json.minisig b/internal/test_data/other_list.json.minisig index eaa2248..eaa2248 100644 --- a/src/test_data/other_list.json.minisig +++ b/internal/test_data/other_list.json.minisig diff --git a/src/test_data/public.key b/internal/test_data/public.key index 72676d3..72676d3 100644 --- a/src/test_data/public.key +++ b/internal/test_data/public.key diff --git a/src/test_data/random.txt b/internal/test_data/random.txt index b6fc4c6..b6fc4c6 100644 --- a/src/test_data/random.txt +++ b/internal/test_data/random.txt diff --git a/src/test_data/secret.key b/internal/test_data/secret.key index 6e4af37..6e4af37 100644 --- a/src/test_data/secret.key +++ b/internal/test_data/secret.key diff --git a/src/test_data/server_list.json b/internal/test_data/server_list.json index 67c4c8d..67c4c8d 100644 --- a/src/test_data/server_list.json +++ b/internal/test_data/server_list.json diff --git a/src/test_data/server_list.json.blake2b b/internal/test_data/server_list.json.blake2b Binary files differindex 5d2ca5a..5d2ca5a 100644 --- a/src/test_data/server_list.json.blake2b +++ b/internal/test_data/server_list.json.blake2b diff --git a/src/test_data/server_list.json.forged_keyid.minisig b/internal/test_data/server_list.json.forged_keyid.minisig index efa349d..efa349d 100644 --- a/src/test_data/server_list.json.forged_keyid.minisig +++ b/internal/test_data/server_list.json.forged_keyid.minisig diff --git a/src/test_data/server_list.json.forged_pure.minisig b/internal/test_data/server_list.json.forged_pure.minisig index a362504..a362504 100644 --- a/src/test_data/server_list.json.forged_pure.minisig +++ b/internal/test_data/server_list.json.forged_pure.minisig diff --git a/src/test_data/server_list.json.large_time.minisig b/internal/test_data/server_list.json.large_time.minisig index 79a2a52..79a2a52 100644 --- a/src/test_data/server_list.json.large_time.minisig +++ b/internal/test_data/server_list.json.large_time.minisig diff --git a/src/test_data/server_list.json.minisig b/internal/test_data/server_list.json.minisig index 143585b..143585b 100644 --- a/src/test_data/server_list.json.minisig +++ b/internal/test_data/server_list.json.minisig diff --git a/src/test_data/server_list.json.pure.minisig b/internal/test_data/server_list.json.pure.minisig index 57dccfc..57dccfc 100644 --- a/src/test_data/server_list.json.pure.minisig +++ b/internal/test_data/server_list.json.pure.minisig diff --git a/src/test_data/server_list.json.tc_earliertime.minisig b/internal/test_data/server_list.json.tc_earliertime.minisig index 03da710..03da710 100644 --- a/src/test_data/server_list.json.tc_earliertime.minisig +++ b/internal/test_data/server_list.json.tc_earliertime.minisig diff --git a/src/test_data/server_list.json.tc_emptyfile.minisig b/internal/test_data/server_list.json.tc_emptyfile.minisig index a7aa3ed..a7aa3ed 100644 --- a/src/test_data/server_list.json.tc_emptyfile.minisig +++ b/internal/test_data/server_list.json.tc_emptyfile.minisig diff --git a/src/test_data/server_list.json.tc_emptytime.minisig b/internal/test_data/server_list.json.tc_emptytime.minisig index d3ef01e..d3ef01e 100644 --- a/src/test_data/server_list.json.tc_emptytime.minisig +++ b/internal/test_data/server_list.json.tc_emptytime.minisig diff --git a/src/test_data/server_list.json.tc_latertime.minisig b/internal/test_data/server_list.json.tc_latertime.minisig index 8237123..8237123 100644 --- a/src/test_data/server_list.json.tc_latertime.minisig +++ b/internal/test_data/server_list.json.tc_latertime.minisig diff --git a/src/test_data/server_list.json.tc_nofile.minisig b/internal/test_data/server_list.json.tc_nofile.minisig index 3c1dcbe..3c1dcbe 100644 --- a/src/test_data/server_list.json.tc_nofile.minisig +++ b/internal/test_data/server_list.json.tc_nofile.minisig diff --git a/src/test_data/server_list.json.tc_nohashed.minisig b/internal/test_data/server_list.json.tc_nohashed.minisig index 1d140c1..1d140c1 100644 --- a/src/test_data/server_list.json.tc_nohashed.minisig +++ b/internal/test_data/server_list.json.tc_nohashed.minisig diff --git a/src/test_data/server_list.json.tc_notime.minisig b/internal/test_data/server_list.json.tc_notime.minisig index 39625c3..39625c3 100644 --- a/src/test_data/server_list.json.tc_notime.minisig +++ b/internal/test_data/server_list.json.tc_notime.minisig diff --git a/src/test_data/server_list.json.tc_orglist.minisig b/internal/test_data/server_list.json.tc_orglist.minisig index 7c2a3a8..7c2a3a8 100644 --- a/src/test_data/server_list.json.tc_orglist.minisig +++ b/internal/test_data/server_list.json.tc_orglist.minisig diff --git a/src/test_data/server_list.json.tc_otherfile.minisig b/internal/test_data/server_list.json.tc_otherfile.minisig index 58a29b2..58a29b2 100644 --- a/src/test_data/server_list.json.tc_otherfile.minisig +++ b/internal/test_data/server_list.json.tc_otherfile.minisig diff --git a/src/test_data/server_list.json.tc_random.minisig b/internal/test_data/server_list.json.tc_random.minisig index 7240980..7240980 100644 --- a/src/test_data/server_list.json.tc_random.minisig +++ b/internal/test_data/server_list.json.tc_random.minisig diff --git a/src/test_data/server_list.json.wrong_key.minisig b/internal/test_data/server_list.json.wrong_key.minisig index 5a83c0e..5a83c0e 100644 --- a/src/test_data/server_list.json.wrong_key.minisig +++ b/internal/test_data/server_list.json.wrong_key.minisig diff --git a/src/test_data/wrong_public.key b/internal/test_data/wrong_public.key index aa794d4..aa794d4 100644 --- a/src/test_data/wrong_public.key +++ b/internal/test_data/wrong_public.key diff --git a/src/test_data/wrong_secret.key b/internal/test_data/wrong_secret.key index 68e9092..68e9092 100644 --- a/src/test_data/wrong_secret.key +++ b/internal/test_data/wrong_secret.key diff --git a/src/util.go b/internal/util.go index 87340f9..02855c2 100644 --- a/src/util.go +++ b/internal/util.go @@ -1,7 +1,8 @@ -package eduvpn +package internal import ( "crypto/rand" + "os" "time" ) @@ -19,3 +20,11 @@ func GenerateTimeSeconds() int64 { current := time.Now() return current.Unix() } + +func EnsureDirectory(directory string) error { + mkdirErr := os.MkdirAll(directory, os.ModePerm) + if mkdirErr != nil { + return mkdirErr + } + return nil +} diff --git a/src/verify.go b/internal/verify.go index 3c87fe1..9128777 100644 --- a/src/verify.go +++ b/internal/verify.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "errors" diff --git a/src/verify_test.go b/internal/verify_test.go index fc78ec3..f980dc2 100644 --- a/src/verify_test.go +++ b/internal/verify_test.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "bufio" diff --git a/src/wireguard.go b/internal/wireguard.go index 2f1c41c..4ec12bd 100644 --- a/src/wireguard.go +++ b/internal/wireguard.go @@ -1,4 +1,4 @@ -package eduvpn +package internal import ( "fmt" diff --git a/src/config.go b/src/config.go deleted file mode 100644 index 6db3cb2..0000000 --- a/src/config.go +++ /dev/null @@ -1,42 +0,0 @@ -package eduvpn - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path" -) - -func (eduvpn *VPNState) EnsureConfigDir() error { - mkdirErr := os.MkdirAll(eduvpn.ConfigDirectory, os.ModePerm) - if mkdirErr != nil { - return mkdirErr - } - return nil -} - -func (eduvpn *VPNState) GetConfigName() string { - pathString := path.Join(eduvpn.ConfigDirectory, eduvpn.Name) - return fmt.Sprintf("%s.json", pathString) -} - -func (eduvpn *VPNState) WriteConfig() error { - configDirErr := eduvpn.EnsureConfigDir() - if configDirErr != nil { - return configDirErr - } - jsonString, marshalErr := json.Marshal(eduvpn) - if marshalErr != nil { - return marshalErr - } - return ioutil.WriteFile(eduvpn.GetConfigName(), jsonString, 0o644) -} - -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/state.go b/src/state.go deleted file mode 100644 index c0e512f..0000000 --- a/src/state.go +++ /dev/null @@ -1,108 +0,0 @@ -package eduvpn - -import ( - "errors" -) - -type VPNState struct { - // Info passed by the client - ConfigDirectory string `json:"-"` - Name string `json:"-"` - StateCallback func(string, string, string) `json:"-"` - StateCallbackData string `json:"-"` - - // The chosen server - Servers Servers `json:"servers"` - - // The list of servers and organizations from disco - DiscoList DiscoLists `json:"-"` - - // The file we keep open for logging - LogFile FileLogger `json:"-"` - - // The fsm - FSM FSM `json:"-"` - - // Whether to enable debugging - Debug bool `json:"-"` -} - -func (state *VPNState) Register(name string, directory string, stateCallback func(string, string, string), debug bool) error { - if !state.InState(DEREGISTERED) { - return errors.New("app already registered") - } - state.InitializeFSM() - state.Name = name - state.ConfigDirectory = directory - state.StateCallback = stateCallback - state.Debug = debug - - LogLevel := LOG_WARNING - - if debug { - LogLevel = LOG_INFO - } - - // Initialize the logger - state.InitLog(LogLevel) - - // Try to load the previous configuration - if state.LoadConfig() != nil { - // This error can be safely ignored, as when the config does not load, the struct will not be filled - state.Log(LOG_INFO, "Previous configuration not found") - } - state.GoTransition(NO_SERVER) - return nil -} - -func (state *VPNState) Deregister() error { - // Close the log file - state.CloseLog() - - // Write the config - state.WriteConfig() - - // Re-initialize the servers and FSM - state.Servers = Servers{} - state.InitializeFSM() - return nil -} - -func (state *VPNState) Connect(url string) (string, error) { - // New server chosen, ensure the server is fresh - server := state.Servers.EnsureServer(url) - // Make sure we are in the chosen state if available - state.GoTransition(CHOSEN_SERVER) - // Relogin with oauth - // This moves the state to authenticated - if server.NeedsRelogin() { - loginErr := state.LoginOAuth() - - if loginErr != nil { - return "", loginErr - } - } else { // OAuth was valid, ensure we are in the authenticated state - state.GoTransition(AUTHENTICATED) - } - - state.GoTransition(REQUEST_CONFIG) - - config, configErr := server.GetConfig() - - if configErr != nil { - return "", configErr - } else { - state.GoTransition(HAS_CONFIG) - } - - return config, nil -} - -var VPNStateInstance *VPNState - -func GetVPNState() *VPNState { - if VPNStateInstance == nil { - VPNStateInstance = &VPNState{} - } - return VPNStateInstance -} diff --git a/state.go b/state.go new file mode 100644 index 0000000..bafdfb9 --- /dev/null +++ b/state.go @@ -0,0 +1,143 @@ +package eduvpn + +import ( + "errors" + "github.com/jwijenbergh/eduvpn-common/internal" +) + +type VPNState struct { + // The chosen server + Servers internal.Servers `json:"servers"` + + // The list of servers and organizations from disco + Discovery internal.Discovery `json:"-"` + + // The fsm + FSM internal.FSM `json:"-"` + + // The logger + Logger internal.FileLogger `json:"-"` + + // The config + Config internal.Config `json:"-"` + + // Whether to enable debugging + Debug bool `json:"-"` +} + +var VPNStateInstance *VPNState + +func GetVPNState() *VPNState { + if VPNStateInstance == nil { + VPNStateInstance = &VPNState{} + } + return VPNStateInstance +} + +func (state *VPNState) Register(name string, directory string, stateCallback func(string, string, string), debug bool) error { + if !state.FSM.InState(internal.DEREGISTERED) { + return errors.New("app already registered") + } + // Initialize the logger + logLevel := internal.LOG_WARNING + + if debug { + logLevel = internal.LOG_INFO + } + + loggerErr := state.Logger.Init(logLevel, name, directory) + if loggerErr != nil { + return errors.New("Failed to create a logger") + } + + // Initialize the FSM + state.FSM.Init(stateCallback, &state.Logger, debug) + state.Debug = debug + + // Initialize the Config + state.Config.Init(name, directory) + + // Initialize Discovery + state.Discovery.Init(&state.FSM, &state.Logger) + + // Try to load the previous configuration + if state.Config.Load(&state) != nil { + // This error can be safely ignored, as when the config does not load, the struct will not be filled + state.Logger.Log(internal.LOG_INFO, "Previous configuration not found") + } + state.FSM.GoTransition(internal.NO_SERVER) + return nil +} + +func (state *VPNState) Deregister() error { + // Close the log file + state.Logger.Close() + + // Save the config + state.Config.Save(&state) + + // Empty out fsm + state.FSM = internal.FSM{} + return nil +} + +func (state *VPNState) Connect(url string) (string, error) { + if state.FSM.InState(internal.DEREGISTERED) { + return "", errors.New("app not registered") + } + // New server chosen, ensure the server is fresh + server := state.Servers.EnsureServer(url, &state.FSM, &state.Logger) + // Make sure we are in the chosen state if available + state.FSM.GoTransition(internal.CHOSEN_SERVER) + // Relogin with oauth + // This moves the state to authenticated + if server.NeedsRelogin() { + loginErr := server.Login() + + if loginErr != nil { + return "", loginErr + } + } else { // OAuth was valid, ensure we are in the authenticated state + state.FSM.GoTransition(internal.AUTHENTICATED) + } + + state.FSM.GoTransition(internal.REQUEST_CONFIG) + + config, configErr := server.GetConfig() + + if configErr != nil { + return "", configErr + } else { + state.FSM.GoTransition(internal.HAS_CONFIG) + } + + return config, nil +} + +func (state *VPNState) GetDiscoOrganizations() (string, error) { + if state.FSM.InState(internal.DEREGISTERED) { + return "", errors.New("app not registered") + } + return state.Discovery.GetOrganizationsList() +} + + +func (state *VPNState) GetDiscoServers() (string, error) { + if state.FSM.InState(internal.DEREGISTERED) { + return "", errors.New("app not registered") + } + return state.Discovery.GetServersList() +} + +func (state *VPNState) SetProfileID(profileID string) error { + if !state.FSM.InState(internal.ASK_PROFILE) { + return errors.New("Invalid state for setting a profile") + } + + server, serverErr := state.Servers.GetCurrentServer() + if serverErr != nil { + return errors.New("No server found for setting a profile ID") + } + server.Profiles.Current = profileID + return nil +} diff --git a/src/server_test.go b/state_test.go index ccf58f6..d5d0b11 100644 --- a/src/server_test.go +++ b/state_test.go @@ -11,6 +11,8 @@ import ( "strings" "testing" "time" + + "github.com/jwijenbergh/eduvpn-common/internal" ) func runCommand(t *testing.T, errBuffer *strings.Builder, name string, args ...string) error { @@ -29,7 +31,7 @@ func LoginOAuthSelenium(t *testing.T, url string) { // We could use the go selenium library // But it does not support the latest selenium v4 just yet var errBuffer strings.Builder - err := runCommand(t, &errBuffer, "python3", "../selenium_eduvpn.py", url) + err := runCommand(t, &errBuffer, "python3", "selenium_eduvpn.py", url) if err != nil { t.Errorf("Login OAuth with selenium script failed with error %v and stderr %s", err, errBuffer.String()) } @@ -42,7 +44,7 @@ func StateCallback(t *testing.T, oldState string, newState string, data string) } func Test_server(t *testing.T) { - state := GetVPNState() + state := &VPNState{} // Do not verify because during testing, the cert is self-signed http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} @@ -58,17 +60,17 @@ func Test_server(t *testing.T) { } } -func test_connect_oauth_parameter(t *testing.T, parameters URLParameters, expectedErr interface{}) { - state := GetVPNState() - state.Deregister() +func test_connect_oauth_parameter(t *testing.T, parameters internal.URLParameters, expectedErr interface{}) { + state := &VPNState{} + configDirectory := "test_oauth_parameters" // Do not verify because during testing, the cert is self-signed http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Register("org.eduvpn.app.linux", "configsnologin", func(oldState string, newState string, data string) { + state.Register("org.eduvpn.app.linux", configDirectory, func(oldState string, newState string, data string) { if newState == "OAuth_Started" { baseURL := "http://127.0.0.1:8000/callback" - url, err := HTTPConstructURL(baseURL, parameters) + url, err := internal.HTTPConstructURL(baseURL, parameters) if err != nil { t.Errorf("Error: Constructing url %s with parameters %s", baseURL, fmt.Sprint(parameters)) } @@ -85,17 +87,17 @@ func test_connect_oauth_parameter(t *testing.T, parameters URLParameters, expect func Test_connect_oauth_parameters(t *testing.T) { var ( - failedCallbackParameterError *OAuthFailedCallbackParameterError - failedCallbackStateMatchError *OAuthFailedCallbackStateMatchError + failedCallbackParameterError *internal.OAuthFailedCallbackParameterError + failedCallbackStateMatchError *internal.OAuthFailedCallbackStateMatchError ) tests := []struct { expectedErr interface{} - parameters URLParameters + parameters internal.URLParameters }{ - {&failedCallbackParameterError, URLParameters{}}, - {&failedCallbackParameterError, URLParameters{"code": "42"}}, - {&failedCallbackStateMatchError, URLParameters{"code": "42", "state": "21"}}, + {&failedCallbackParameterError, internal.URLParameters{}}, + {&failedCallbackParameterError, internal.URLParameters{"code": "42"}}, + {&failedCallbackStateMatchError, internal.URLParameters{"code": "42", "state": "21"}}, } for _, test := range tests { @@ -117,9 +119,7 @@ func Test_token_expired(t *testing.T) { } // Get a vpn state - state := GetVPNState() - - state.Deregister() + state := &VPNState{} // Do not verify because during testing, the cert is self-signed http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} @@ -165,13 +165,11 @@ func Test_token_expired(t *testing.T) { } func Test_token_invalid(t *testing.T) { - state := GetVPNState() + state := &VPNState{} // Do not verify because during testing, the cert is self-signed http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Deregister() - state.Register("org.eduvpn.app.linux", "configsinvalid", func(old string, new string, data string) { StateCallback(t, old, new, data) }, false) @@ -184,8 +182,8 @@ func Test_token_invalid(t *testing.T) { // Fake connect and then back to authenticated so that we can re-authenticate // Going to authenticated fakes a disconnect - state.GoTransition(CONNECTED) - state.GoTransition(AUTHENTICATED) + state.FSM.GoTransition(internal.CONNECTED) + state.FSM.GoTransition(internal.AUTHENTICATED) dummy_value := "37" |
