-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.go
142 lines (124 loc) · 3.8 KB
/
handlers.go
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
package main
import (
"encoding/json"
"net/http"
"os"
"strconv"
"strings"
"github.com/ainghazal/torii/share"
"github.com/ainghazal/torii/vpn"
"github.com/gorilla/mux"
bolt "go.etcd.io/bbolt"
)
type httpHandler func(http.ResponseWriter, *http.Request)
func randomEndpointDescriptor(w http.ResponseWriter, r *http.Request) {
providerName := getParam(paramProvider, r)
if !vpn.IsKnownProvider(providerName) {
http.Error(w, errNotFoundStr, http.StatusNotFound)
return
}
p := vpn.Providers[providerName]
cfg, err := renderConfigForProvider(p, randomEndpointPicker())
if err != nil {
http.Error(w, errorString(err), http.StatusGatewayTimeout)
return
}
json.NewEncoder(w).Encode(cfg)
}
func byCountryEndpointDescriptor(w http.ResponseWriter, r *http.Request) {
providerName := getParam(paramProvider, r)
if !vpn.IsKnownProvider(providerName) {
http.Error(w, errNotFoundStr, http.StatusNotFound)
return
}
cc := getParam(paramCountryCode, r)
p := vpn.Providers[providerName]
cfg, err := renderConfigForProvider(p, byCountryEndpointPicker(cc, 1))
if err != nil {
http.Error(w, errorString(err), http.StatusGatewayTimeout)
return
}
json.NewEncoder(w).Encode(cfg)
}
// newCustomProviderFromExperiment returns a "custom" provider from a given
// experiment spec.
// This is a little bit hacky for the time being.
// the goal is to be able to provide a deterministic (set of) remotes, to be
// able to easily test and replicate anomalies etc. Only one remote now, coming
// from the form.
// we generate a provider "on the fly" and construct a single remote that is
// assoiated with it. The usage of some of the fields (like cc) is a little
// handwavy for now, but it serves my purpose well.
func newCustomProviderFromExperiment(exp *share.Experiment) vpn.Provider {
// this assumes we're given a remote in the experiment definition.
p := vpn.NewCustomProvider(exp.Provider)
p.CustomName = exp.Provider + "-" + exp.Name
if exp.Provider != "unknown" {
// This is tricky, I need a registry mechanism to include
// auth for my own endpoints. all of them should identify as
// "unknown" for the experiment, but we need a handle
// internally.
refProvider := vpn.Providers[exp.Provider]
p.AuthFromProvider(refProvider)
}
remoteParts := strings.Split(exp.EndpointRemote, ":")
// TODO be defensive, validate
ip := remoteParts[0]
port := remoteParts[1]
customEndpoint := &vpn.Endpoint{
Label: exp.Name,
IP: ip,
Port: port,
Proto: "openvpn", //only one for now
Transport: "tcp",
Obfuscation: "none",
CountryCode: exp.CountryCode, // this could be a wrong one, need to check against the canonical list
}
p.AddEndpoint(customEndpoint)
return p
}
func DescriptorByUUIDHandler(db *bolt.DB) httpHandler {
return func(w http.ResponseWriter, r *http.Request) {
uuid := getParam("uuid", r)
exp := share.GetExperimentByUUID(db, uuid)[0]
var cfg *config
var err error
var p vpn.Provider
if exp.EndpointRemote != "" {
p = newCustomProviderFromExperiment(exp)
cfg, err = renderConfigForProvider(p, randomEndpointPicker())
} else {
p := vpn.Providers[exp.Provider]
cc := exp.CountryCode
max := exp.Max
cfg, err = renderConfigForProvider(p, byCountryEndpointPicker(cc, strToIntOrOne(max)))
}
if err != nil {
http.Error(w, errorString(err), http.StatusGatewayTimeout)
return
}
json.NewEncoder(w).Encode(cfg)
}
}
func strToIntOrOne(s string) int {
maxInt := 1
if s != "" {
mi, err := strconv.Atoi(s)
if err == nil {
maxInt = mi
}
}
return maxInt
}
func errorString(err error) string {
if os.Getenv("DEBUG") == "1" {
return err.Error()
}
return errTryAgainStr
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(msgHomeStr))
}
func getParam(param string, r *http.Request) string {
return mux.Vars(r)[param]
}