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
|
package eduvpn
import (
"encoding/json"
"io/ioutil"
"net/http"
"fmt"
)
// Struct that defines the json format for
// url: "https://disco.eduvpn.org/v2/organization_list.json"
type organizations struct {
V uint64 `json:"v"`
OrganizationList []struct {
DisplayName struct {
En string `json:"en"`
} `json:"display_name"`
OrgId string `json:"org_id"`
SecureInternetHome string `json:"secure_internet_home"`
KeywordList struct {
En string `json:"en"`
} `json:"keyword_list"`
} `json:"organization_list"`
}
// Struct that defines the json format for
// url: "https://disco.eduvpn.org/v2/server_list.json"
type servers struct {
V uint64 `json:"v"`
ServerList []struct {
BaseUrl string `json:"base_url"`
CountryCode string `json:"country_code"`
PublicKeyList []string `json:"public_key_list"`
ServerType string `json:"secure_internet"`
SupportContact []string `json:"support_contact"`
} `json:"server_list"`
}
func getFileUrl(url string) ([]byte, bool) {
// Do a Get request to the specified url
resp, reqErr := http.Get(url)
if reqErr != nil {
fmt.Println("error making request")
return nil, false
}
// Close the response body at the end
defer resp.Body.Close()
// Check if http response code is ok
if resp.StatusCode != http.StatusOK {
return nil, false
}
// Read the body
body, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
fmt.Println("error reading body of request")
return nil, false
}
return body, true
}
// Helper function that gets a disco json
// TODO: Verify signature
func getDiscoJson(jsonFile string, structure interface{}) bool {
// Get json data
fileUrl := "https://disco.eduvpn.org/v2/" + jsonFile
fileBody, fileSuccess := getFileUrl(fileUrl)
if !fileSuccess {
fmt.Println("error getting file")
}
// Get signature
sigUrl := fileUrl + ".minisig"
sigBody, sigSuccess := getFileUrl(sigUrl)
if !sigSuccess {
fmt.Println("error getting signature")
return false
}
// Verify signature
// TODO: Handle this by keeping track of the previous sign time
// Wrappers must do this?
var previousSigTime uint64 = 0
forcePrehash := false
verifySuccess, verifyErr := Verify(string(sigBody), fileBody, jsonFile, previousSigTime, forcePrehash)
if !verifySuccess || verifyErr != nil {
fmt.Printf("signature is invalid with error: %s\n", verifyErr)
return false
}
// Parse the json using the predefined struct
error := json.Unmarshal([]byte(fileBody), &structure)
if error != nil {
fmt.Println("error parsing server json")
return false
}
return true
}
// Global maps that are used for storing info
var organizationsMap = map[uint64]organizations{}
var serversMap = map[uint64]servers{}
// Get the organization list
// Returns the unix timestamp of the data
func GetOrganizationsList() uint64 {
organizations := organizations{}
success := getDiscoJson("organization_list.json", &organizations)
if success {
organizationsMap[organizations.V] = organizations
}
return organizations.V
}
// Get the server list
// Return the unix timestamp of the data
func GetServerList() uint64 {
servers := servers{}
success := getDiscoJson("server_list.json", &servers)
if success {
serversMap[servers.V] = servers
}
return servers.V
}
|