summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjwijenbergh <jeroenwijenbergh@protonmail.com>2022-04-22 16:29:59 +0200
committerjwijenbergh <jeroenwijenbergh@protonmail.com>2022-04-22 16:29:59 +0200
commitb1d92b395322f2164ccfb44b0f7caebbaece6b62 (patch)
tree2133e4045b4af4d07a98674b7ae3a234670f0305
parent3a4ae2942b43923ff98fd2eca8878c3cf145686c (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--Makefile2
-rw-r--r--ci/docker/go-test.docker5
-rw-r--r--cli/go.mod7
-rw-r--r--cli/go.sum45
-rw-r--r--cmd/cli/main.go (renamed from cli/main.go)31
-rw-r--r--exports/Makefile2
-rw-r--r--exports/exports.go22
-rw-r--r--go.mod4
-rw-r--r--go.sum32
-rw-r--r--internal/api.go (renamed from src/api.go)6
-rw-r--r--internal/config.go43
-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)bin64 -> 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.go42
-rw-r--r--src/state.go108
-rw-r--r--state.go143
-rw-r--r--state_test.go (renamed from src/server_test.go)40
57 files changed, 407 insertions, 450 deletions
diff --git a/Makefile b/Makefile
index 36a19da..938e891 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/go.mod b/go.mod
index 2c73c42..88bb6f1 100644
--- a/go.mod
+++ b/go.mod
@@ -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
)
diff --git a/go.sum b/go.sum
index 1a3d3c8..d536cee 100644
--- a/go.sum
+++ b/go.sum
@@ -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
index 5d2ca5a..5d2ca5a 100644
--- a/src/test_data/server_list.json.blake2b
+++ b/internal/test_data/server_list.json.blake2b
Binary files differ
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"