Skip to content

Commit 48ecd31

Browse files
committed
Refactor: Support multiple profiles with multiple UUIDs
1 parent 3a64c4a commit 48ecd31

File tree

10 files changed

+184
-73
lines changed

10 files changed

+184
-73
lines changed

cmd/geteduroam-notifcheck/main.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ const usage = `Usage of %s:
2323
Log file location: %s
2424
`
2525

26+
func hasValidProfile(uuids []string) bool {
27+
for _, uuid := range uuids {
28+
con, err := nm.PreviousCon(uuid)
29+
if err != nil {
30+
slog.Error("no connection with uuid", "uuid", uuid, "error", err)
31+
continue
32+
}
33+
if con == nil {
34+
slog.Error("connection is nil")
35+
continue
36+
}
37+
return true
38+
}
39+
return false
40+
}
41+
2642
func main() {
2743
program := "geteduroam-notifcheck"
2844
lpath, err := log.Location(program)
@@ -37,20 +53,16 @@ func main() {
3753
slog.Error("no previous state", "error", err)
3854
return
3955
}
40-
con, err := nm.PreviousCon(cfg.UUID)
41-
if err != nil {
42-
slog.Error("no connection with uuid", "uuid", cfg.UUID, "error", err)
56+
if cfg.Validity == nil {
57+
slog.Info("validity is nil")
4358
return
4459
}
45-
if con == nil {
46-
slog.Error("connection is nil")
60+
if !hasValidProfile(cfg.UUIDs) {
61+
slog.Info("no valid profiles found")
4762
return
48-
}
4963

50-
if cfg.Validity == nil {
51-
slog.Info("validity is nil")
52-
return
5364
}
65+
5466
valid := *cfg.Validity
5567
now := time.Now()
5668
diff := valid.Sub(now)

internal/config/config.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import (
1414

1515
// Config is the main structure for the configuration
1616
type Config struct {
17+
UUIDs []string `json:"uuids"`
18+
Validity *time.Time `json:"validity,omitempty"`
19+
}
20+
21+
// V1 is the main structure for the old configuration where we only supported one SSID and profile
22+
type V1 struct {
1723
UUID string `json:"uuid"`
1824
Validity *time.Time `json:"validity,omitempty"`
1925
}
@@ -22,7 +28,8 @@ type Config struct {
2228
type Versioned struct {
2329
// Config is the versioned configuration
2430
// It is versioned so that we can change the version and migrate older configs in the future
25-
Config Config `json:"v1"`
31+
ConfigV1 *V1 `json:"v1,omitempty"`
32+
Config *Config `json:"v2,omitempty"`
2633
}
2734

2835
// Directory returns the directory where the config files are stored
@@ -83,7 +90,16 @@ func Load() (*Config, error) {
8390
return nil, err
8491
}
8592
utils.Verbosef("Reading config file %s", p)
86-
return &v.Config, nil
93+
// If a v1 config is found, migrate it to a v2 one if that is empty
94+
hasV1 := v.ConfigV1 != nil && v.ConfigV1.UUID != ""
95+
hasV2 := v.Config != nil && len(v.Config.UUIDs) > 0
96+
if hasV1 && !hasV2 {
97+
return &Config{
98+
UUIDs: []string{v.ConfigV1.UUID},
99+
Validity: v.ConfigV1.Validity,
100+
}, nil
101+
}
102+
return v.Config, nil
87103
}
88104

89105
// Write writes the configuration to the state
@@ -92,7 +108,7 @@ func (c Config) Write() (err error) {
92108
// This is so that we can in the future migrate configs if we drastically change the format
93109
// marshal the config
94110
v := &Versioned{
95-
Config: c,
111+
Config: &c,
96112
}
97113
b, err := json.Marshal(&v)
98114
if err != nil {

internal/config/config_test.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestWrite(t *testing.T) {
2323
dir := t.TempDir()
2424
mockDir(t, dir)
2525
c := &Config{
26-
UUID: "test",
26+
UUIDs: []string{"test"},
2727
}
2828
err := c.Write()
2929
if err != nil {
@@ -39,7 +39,7 @@ func TestWrite(t *testing.T) {
3939
t.Fatalf("failed when reading config file: %v", err)
4040
}
4141
got := string(r)
42-
want := `{"v1":{"uuid":"test"}}`
42+
want := `{"v2":{"uuids":["test"]}}`
4343
if got != want {
4444
t.Fatalf("config not as expected, got: %v, want: %v", got, want)
4545
}
@@ -57,10 +57,17 @@ func TestLoad(t *testing.T) {
5757
wantc: nil,
5858
wanterr: "json: cannot unmarshal string into Go value of type config.Versioned",
5959
},
60+
{
61+
filename: "old.json",
62+
wantc: &Config{
63+
UUIDs: []string{"test"},
64+
},
65+
wanterr: "",
66+
},
6067
{
6168
filename: "valid.json",
6269
wantc: &Config{
63-
UUID: "test",
70+
UUIDs: []string{"test"},
6471
},
6572
wanterr: "",
6673
},
@@ -70,12 +77,12 @@ func TestLoad(t *testing.T) {
7077
// mock the config name
7178
configName = curr.filename
7279
gotc, goterr := Load()
80+
if utils.ErrorString(goterr) != curr.wanterr {
81+
t.Fatalf("expected config error not equal to want, got: %v, want: %v", goterr, curr.wanterr)
82+
}
7383
// to compare structs we can use deepequal
7484
if !reflect.DeepEqual(gotc, curr.wantc) {
7585
t.Fatalf("expected config not equal to want, got: %v, want: %v", gotc, curr.wantc)
7686
}
77-
if utils.ErrorString(goterr) != curr.wanterr {
78-
t.Fatalf("expected config error not equal to want, got: %v, want: %v", goterr, curr.wanterr)
79-
}
8087
}
8188
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"v1": {"uuid": "test"}}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"v1": {"uuid": "test"}}
1+
{"v2": {"uuids": ["test"]}}

internal/eap/eap.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -269,20 +269,21 @@ func (am *AuthenticationMethod) preferredInnerAuthType() (inner.Type, error) {
269269
return inner.None, errors.New("no viable inner authentication method found")
270270
}
271271

272-
// SSIDSettings returns the first valid SSID and the MinRSNProto associated with it
273-
// It loops through the credential applicability list and gets the first valid candidate
272+
// SSIDSettings returns the all valid SSIDs and the MinRSNProto associated with it
273+
// It loops through the credential applicability list and gets all valid candidate
274274
// The candidate filtering was based on https://github.com/geteduroam/windows-app/blob/f11f00dee3eb71abd38537e18881463f83b180d3/EduroamConfigure/EapConfig.cs#L84
275275
// A candidate is valid if:
276276
// - MinRSNProto is not empty, TODO: shouldn't we just default to CCMP?
277277
// - The SSID is not empty
278278
// - The MinRSNProto is NOT TKIP as that is insecure
279-
func (p *EAPIdentityProvider) SSIDSettings() (string, string, error) {
279+
func (p *EAPIdentityProvider) SSIDSettings() ([]network.SSID, error) {
280280
if p.CredentialApplicability == nil {
281-
return "", "", errors.New("no Credential Applicability found")
281+
return nil, errors.New("no Credential Applicability found")
282282
}
283283
if len(p.CredentialApplicability.IEEE80211) < 1 {
284-
return "", "", errors.New("no IEE80211 section found")
284+
return nil, errors.New("no IEE80211 section found")
285285
}
286+
var ssids []network.SSID
286287
for _, i := range p.CredentialApplicability.IEEE80211 {
287288
if i == nil {
288289
slog.Warn("Credential applicability IEEE80211 is nil")
@@ -307,10 +308,15 @@ func (p *EAPIdentityProvider) SSIDSettings() (string, string, error) {
307308
slog.Warn("MinRSNProto is not TKIP", "minRSNProto", i.MinRSNProto)
308309
continue
309310
}
310-
311-
return i.SSID, i.MinRSNProto, nil
311+
ssids = append(ssids, network.SSID{
312+
Value: i.SSID,
313+
MinRSN: i.MinRSNProto,
314+
})
315+
}
316+
if len(ssids) == 0 {
317+
return nil, errors.New("no viable SSID entries found")
312318
}
313-
return "", "", errors.New("no viable SSID entry found")
319+
return ssids, nil
314320
}
315321

316322
// isValid returns whether or not a certificate is valid by checking if the encoding is base64 and the format is `format`
@@ -466,7 +472,7 @@ func (am *AuthenticationMethod) NonTLSNetwork(base network.Base) (network.Networ
466472
}
467473

468474
// Network gets a network for an authentication method, the SSID and MinRSN are strings that are based to the network
469-
func (am *AuthenticationMethod) Network(ssid string, minrsn string, pinfo network.ProviderInfo) (network.Network, error) {
475+
func (am *AuthenticationMethod) Network(ssids []network.SSID, pinfo network.ProviderInfo) (network.Network, error) {
470476
// We check if the eap method is valid
471477
if am.EAPMethod == nil || !method.IsValid(am.EAPMethod.Type) {
472478
return nil, errors.New("no EAP method")
@@ -490,8 +496,7 @@ func (am *AuthenticationMethod) Network(ssid string, minrsn string, pinfo networ
490496
base := network.Base{
491497
Certs: *CA,
492498
ProviderInfo: pinfo,
493-
SSID: ssid,
494-
MinRSN: minrsn,
499+
SSIDs: ssids,
495500
ServerIDs: sid,
496501
}
497502

@@ -590,14 +595,14 @@ func (eap *EAPIdentityProviderList) Network() (network.Network, error) {
590595
slog.Debug("Error getting AuthMethods", "error", err)
591596
return nil, err
592597
}
593-
ssid, minrsn, err := p.SSIDSettings()
598+
ssids, err := p.SSIDSettings()
594599
if err != nil {
595600
slog.Debug("Error getting SSIDSettings", "error", err)
596601
return nil, err
597602
}
598603
pinfo := p.PInfo()
599604
for _, m := range methods {
600-
n, err := m.Network(ssid, minrsn, pinfo)
605+
n, err := m.Network(ssids, pinfo)
601606
if err != nil {
602607
slog.Error("Error getting ProviderInfo", "error", err)
603608
continue

internal/eap/eap_test.go

+16-18
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,14 @@ func testProviderInfo(t *testing.T, eip *EAPIdentityProvider, pi network.Provide
4444
}
4545

4646
type ssidSettingsTest struct {
47-
SSID string
48-
MinRSN string
49-
err string
47+
SSIDs []network.SSID
48+
err string
5049
}
5150

5251
func testSSIDSettings(t *testing.T, eip *EAPIdentityProvider, settings ssidSettingsTest) {
53-
gotSSID, gotRSN, gotErr := eip.SSIDSettings()
54-
if gotSSID != settings.SSID {
55-
t.Fatalf("SSID is not equal, got: %v, want: %v", gotSSID, settings.SSID)
56-
}
57-
if gotRSN != settings.MinRSN {
58-
t.Fatalf("Min RSN is not equal, got: %v, want: %v", gotRSN, settings.MinRSN)
52+
gotSSIDs, gotErr := eip.SSIDSettings()
53+
if !reflect.DeepEqual(gotSSIDs, settings.SSIDs) {
54+
t.Fatalf("SSIDs is not equal, got: %v, want: %v", gotSSIDs, settings.SSIDs)
5955
}
6056
gotErrS := utils.ErrorString(gotErr)
6157
if gotErrS != settings.err {
@@ -111,18 +107,22 @@ func TestParse(t *testing.T) {
111107
Description: "eVA",
112108
},
113109
ssidTest: ssidSettingsTest{
114-
SSID: "eduroam",
115-
MinRSN: "CCMP",
116-
err: "",
110+
SSIDs: []network.SSID{{
111+
Value: "eduroam",
112+
MinRSN: "CCMP",
113+
}},
114+
err: "",
117115
},
118116
netTest: networkTest{
119117
n: &network.NonTLS{
120118
Base: network.Base{
121119
AnonIdentity: "[email protected]",
122120
Certs: mustParseCert(t,
123121
"MIIDtzCCAp+gAwIBAgIUCVQbKTO9PsqghECzGPqq6Fiy8REwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCUFtc3RlcmRhbTEQMA4GA1UECgwHVGVzdGluZzENMAsGA1UECwwEVGVzdDESMBAGA1UEAwwJVGVzdCB0ZXN0MB4XDTIzMDUyNDEzNTUxMFoXDTMzMDUyMTEzNTUxMFowazELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCUFtc3RlcmRhbTEQMA4GA1UECgwHVGVzdGluZzENMAsGA1UECwwEVGVzdDESMBAGA1UEAwwJVGVzdCB0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyLqG9yuMhbVC5y9zofPDLeCDIUVjgPbxXHtM6uveBUtqG4PxDkTczOlYN1IsYRh2iLNRYY4cqYZ1qtW+1CZaFVowhUMbTR7Y8Ik10CrCJQqoGq1CIICBd50wTFBLU2MZU3LQTwKYb5VQgbCMvRVHWdQOYg5GSlgdJRtIbzV1d+Q7+N5jiEBsT6psSu2gBduF1ueGICKe6Fk+ckOHDpwjVGeNIxnN2hJ5ft3WReDJ7fcHLMx7lNS+ZeY35LtpYiT6I8RGlMh2bu9hMTY1jXNbEqqZ2/5TmjVygS7BEMrVage9K2I5eM8++yX27OV3Di/SM3q/RVIcu1lNKaSj0IxXhwIDAQABo1MwUTAdBgNVHQ4EFgQU0M2QAnLWEDSFdFLCm5OxvVA9D1swHwYDVR0jBBgwFoAU0M2QAnLWEDSFdFLCm5OxvVA9D1swDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHHdxGNUmyZa4ER9oqSalwVy9W5y1cNr4VpxBbxJe/fBPp+xdtnYRbz1/93LwcA+bTJlvT8ez2ijOJj5QODrgeVy5r4p5/1cABnJhsszk6ffJy/n5vIqo9jp8+7ZTFGxm1QQAOoZfJM+3ft8ZFf5e8Vjh090QV2OZvV69sey+TvfAlNMVotf/CaA2zA/j4z2bmWdrLAc5VVrb1Mil4z7LHhL62oOwXrS85zuoVBQVMbh5tnYgzMnbuy0hmMDg3ClkmSQTqzPyEi0SjhqKjgLgyVa47myhxvr1y77k0rZBRzkSEMsopu+ANYoVKRpw7gmjgMmXWzvdNlbD6RgpGlR4iA=="),
124-
SSID: "eduroam",
125-
MinRSN: "CCMP",
122+
SSIDs: []network.SSID{{
123+
Value: "eduroam",
124+
MinRSN: "CCMP",
125+
}},
126126
ServerIDs: []string{
127127
"edu.nl",
128128
},
@@ -165,13 +165,11 @@ func TestParse(t *testing.T) {
165165
},
166166
providerInfoTest: network.ProviderInfo{},
167167
ssidTest: ssidSettingsTest{
168-
SSID: "",
169-
MinRSN: "",
170-
err: "no viable SSID entry found",
168+
err: "no viable SSID entries found",
171169
},
172170
netTest: networkTest{
173171
n: nil,
174-
err: "no viable SSID entry found",
172+
err: "no viable SSID entries found",
175173
},
176174
},
177175
}

internal/handler/handler.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ func (h Handlers) Configure(eap []byte) (*time.Time, error) {
5252
if err != nil {
5353
return nil, err
5454
}
55-
var uuid string
55+
var uuids []string
5656

5757
// get the previous UUID if the config can be loaded
5858
c, err := config.Load()
5959
if err == nil {
60-
uuid = c.UUID
60+
uuids = c.UUIDs
6161
}
6262

6363
var valid *time.Time
@@ -72,7 +72,7 @@ func (h Handlers) Configure(eap []byte) (*time.Time, error) {
7272
t.Credentials.Username = username
7373
t.Credentials.Password = password
7474
}
75-
uuid, err = nm.Install(*t, uuid)
75+
uuids, err = nm.Install(*t, uuids)
7676
case *network.TLS:
7777
// if a PKCS12 file is uploaded by the user we expect it to be not base64 encoded
7878
b64 := t.RawPKCS12 != ""
@@ -90,17 +90,20 @@ func (h Handlers) Configure(eap []byte) (*time.Time, error) {
9090
}
9191
v := t.Validity()
9292
valid = &v
93-
uuid, err = nm.InstallTLS(*t, uuid)
93+
uuids, err = nm.InstallTLS(*t, uuids)
9494
default:
9595
panic("unsupported network")
9696
}
9797
if err != nil {
98-
slog.Debug("Error installing network", "error", err)
99-
return nil, err
98+
if len(uuids) == 0 {
99+
slog.Error("Error installing network", "error", err)
100+
return nil, err
101+
}
102+
slog.Info("One of the networks failed to install", "error", err)
100103
}
101104
// save the config with the uuid
102105
nc := config.Config{
103-
UUID: uuid,
106+
UUIDs: uuids,
104107
Validity: valid,
105108
}
106109
err = nc.Write()

internal/network/network.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,20 @@ type ProviderInfo struct {
4040
Terms string
4141
}
4242

43+
// SSID is the pair of value and min RSN proto
44+
type SSID struct {
45+
// Value is the SSID
46+
Value string
47+
// MinRSN is the minimum RSN proto
48+
MinRSN string
49+
}
50+
4351
// Base is the definition that each network always has
4452
type Base struct {
4553
// Certs is the list of CA certificates that are used
4654
Certs cert.Certs
47-
// SSID is the name of the network
48-
SSID string
49-
// MinRSN is the minimum RSN proto
50-
MinRSN string
55+
// SSIDs are the list of SSIDs
56+
SSIDs []SSID
5157
// ServerIDs is the list of server names
5258
ServerIDs []string
5359
// ProviderInfo is the ProviderInfo info

0 commit comments

Comments
 (0)