summaryrefslogtreecommitdiff
path: root/state.go
blob: 249adc37ae426170b0cd47a4ec159cc95f52ef57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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 the state
	state = &VPNState{}
	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, serverErr := state.Servers.EnsureServer(url, &state.FSM, &state.Logger)

	if serverErr != nil {
		return "", serverErr
	}
	// 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
}