github.com/jlowellwofford/u-root@v1.0.0/cmds/wifi/server.go (about) 1 // Copyright 2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "html/template" 11 "io" 12 "io/ioutil" 13 "log" 14 "net/http" 15 16 "github.com/gorilla/mux" 17 "github.com/u-root/u-root/pkg/sos" 18 "github.com/u-root/u-root/pkg/wifi" 19 ) 20 21 const ( 22 DefHtmlPage = ` 23 <head> 24 <style> 25 table { 26 font-family: arial, sans-serif; 27 border-collapse: collapse; 28 width: 100%; 29 } 30 31 td, th { 32 border: 1px solid #dddddd; 33 text-align: left; 34 padding: 8px; 35 } 36 37 input { 38 font-size: 120%; 39 } 40 </style> 41 <script> 42 function sendConnect(elem, index) { 43 replaceWithConnecting(elem); 44 disableOtherButtons(elem); 45 essid = document.getElementById("essid".concat(index)).innerHTML 46 pass = document.getElementById("pass".concat(index)) ? 47 document.getElementById("pass".concat(index)).value : "" 48 id = document.getElementById("id".concat(index)) ? 49 document.getElementById("id".concat(index)).value : "" 50 fetch("http://localhost:{{.Port}}/connect", { 51 method: 'Post', 52 headers: { 53 'Accept': 'application/json', 54 'Content-Type': 'application/json' 55 }, 56 body: JSON.stringify({ 57 Essid: essid, 58 Pass: pass, 59 Id: id 60 }) 61 }) 62 .then(r => r.json()) 63 .then( s => { 64 if (s !== null) { 65 alert(s.Error); 66 window.location.reload(); 67 } 68 else { 69 window.location.reload(); 70 } 71 }) 72 .catch(err => alert(err)) 73 } 74 75 function replaceWithConnecting(elem) { 76 connectingTxt = document.createTextNode("Connecting..."); 77 elem.style.display = "none"; 78 elem.parentNode.appendChild(connectingTxt); 79 } 80 81 function sendRefresh(elem) { 82 elem.setAttribute("disabled", "true"); 83 elem.setAttribute("value","Refreshing"); 84 disableOtherButtons(elem); 85 fetch("http://localhost:{{.Port}}/refresh", { 86 method: 'Post' 87 }) 88 .then(r => r.json()) 89 .then( s => { 90 if (s !== null) { 91 alert(s.Error); 92 window.location.reload(); 93 } 94 else { 95 window.location.reload(); 96 } 97 }) 98 .catch(err => alert(err)) 99 } 100 101 function disableOtherButtons(elem) { 102 btns = document.getElementsByClassName("btn"); 103 for (let btn of btns) { 104 if (btn === elem) { 105 continue; 106 } 107 btn.setAttribute("disabled", "true"); 108 } 109 } 110 </script> 111 </head> 112 <body> 113 {{$NoEnc := 0}} 114 {{$WpaPsk := 1}} 115 {{$WpaEap := 2}} 116 {{$connectedEssid := .ConnectedEssid}} 117 {{$connectingEssid := .ConnectingEssid}} 118 <h1>Please choose your Wifi</h1> 119 <table style="width:100%"> 120 <tr> 121 <th>Essid</th> 122 <th>Identity</th> 123 <th>Password / Passphrase</th> 124 <th><input type="submit" class="btn" onclick=sendRefresh(this) value="Refresh"></th> 125 </tr> 126 {{range $idx, $opt := .WifiOpts}} 127 {{if eq $opt.AuthSuite $NoEnc}} 128 <tr> 129 <td id="essid{{$idx}}">{{$opt.Essid}}</td> 130 <td></td> 131 <td></td> 132 {{if and (eq $connectedEssid $opt.Essid) (ne $connectedEssid "")}} 133 <td>Connected</td> 134 {{else if and (and (eq $connectingEssid $opt.Essid) (ne $connectingEssid "")) (ne $connectingEssid $connectedEssid) }} 135 <td>Connecting...</td> 136 {{else}} 137 <td><input type="submit" class="btn" onclick="sendConnect(this, {{$idx}})" value="Connect"></td> 138 {{end}} 139 </tr> 140 {{else if eq $opt.AuthSuite $WpaPsk}} 141 <tr> 142 <td id="essid{{$idx}}">{{$opt.Essid}}</td> 143 <td></td> 144 <td><input type="password" id="pass{{$idx}}"></td> 145 {{if and (eq $connectedEssid $opt.Essid) (ne $connectedEssid "")}} 146 <td>Connected</td> 147 {{else if and (and (eq $connectingEssid $opt.Essid) (ne $connectingEssid "")) (ne $connectingEssid $connectedEssid) }} 148 <td>Connecting...</td> 149 {{else}} 150 <td><input type="submit" class="btn" onclick="sendConnect(this, {{$idx}})" value="Connect"></td> 151 {{end}} 152 </tr> 153 {{else if eq $opt.AuthSuite $WpaEap}} 154 <tr> 155 <td id="essid{{$idx}}">{{$opt.Essid}}</td> 156 <td><input type="text" id="id{{$idx}}"></td> 157 <td><input type="password" id="pass{{$idx}}"></td> 158 {{if and (eq $connectedEssid $opt.Essid) (ne $connectedEssid "")}} 159 <td>Connected</td> 160 {{else if and (and (eq $connectingEssid $opt.Essid) (ne $connectingEssid "")) (ne $connectingEssid $connectedEssid) }} 161 <td>Connecting...</td> 162 {{else}} 163 <td><input type="submit" class="btn" onclick="sendConnect(this, {{$idx}})" value="Connect"></td> 164 {{end}} 165 </tr> 166 {{else}} 167 <tr> 168 <td id="essid{{$idx}}">{{$opt.Essid}}</td> 169 <td colspan="3">Not a supported protocol</td> 170 </tr> 171 {{end}} 172 {{else}} 173 <td colspan="4">No essids found</td> 174 {{end}} 175 </table> 176 177 {{if and (ne $connectingEssid "") (ne $connectingEssid $connectedEssid) }} 178 <script>disableOtherButtons(null)</script> 179 {{end}} 180 </body> 181 ` 182 ) 183 184 var ( 185 Port uint 186 ) 187 188 type WifiServer struct { 189 service *WifiService 190 } 191 192 func userInputValidation(essid, pass, id string) ([]string, error) { 193 switch { 194 case essid != "" && pass != "" && id != "": 195 return []string{essid, pass, id}, nil 196 case essid != "" && pass != "" && id == "": 197 return []string{essid, pass}, nil 198 case essid != "" && pass == "" && id == "": 199 return []string{essid}, nil 200 default: 201 return nil, fmt.Errorf("Invalid user input") 202 } 203 } 204 205 func (ws WifiServer) refreshHandle(w http.ResponseWriter, r *http.Request) { 206 if err := ws.service.Refresh(); err != nil { 207 w.WriteHeader(http.StatusInternalServerError) 208 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 209 return 210 } 211 json.NewEncoder(w).Encode(nil) 212 } 213 214 type ConnectJsonMsg struct { 215 Essid string 216 Pass string 217 Id string 218 } 219 220 func (ws WifiServer) connectHandle(w http.ResponseWriter, r *http.Request) { 221 var msg ConnectJsonMsg 222 decoder := json.NewDecoder(r.Body) 223 defer r.Body.Close() 224 if err := decoder.Decode(&msg); err != nil { 225 log.Printf("error: %v", err) 226 w.WriteHeader(http.StatusBadRequest) 227 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 228 return 229 } 230 a, err := userInputValidation(msg.Essid, msg.Pass, msg.Id) 231 if err != nil { 232 log.Printf("error: %v", err) 233 w.WriteHeader(http.StatusBadRequest) 234 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 235 return 236 } 237 238 if err := ws.service.Connect(a); err != nil { 239 log.Printf("error: %v", err) 240 w.WriteHeader(http.StatusInternalServerError) 241 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 242 return 243 } 244 // Connect Successful 245 json.NewEncoder(w).Encode(nil) 246 } 247 248 func (ws WifiServer) displayStateHandle(w http.ResponseWriter, r *http.Request) { 249 s := ws.service.GetState() 250 displayWifi(w, s.NearbyWifis, s.CurEssid, s.ConnectingEssid) 251 } 252 253 func (ws WifiServer) buildRouter() *mux.Router { 254 r := mux.NewRouter() 255 r.HandleFunc("/", ws.displayStateHandle).Methods("GET") 256 r.HandleFunc("/refresh", ws.refreshHandle).Methods("POST") 257 r.HandleFunc("/connect", ws.connectHandle).Methods("POST") 258 r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir(sos.HTMLPath("css"))))) 259 return r 260 } 261 262 func (ws WifiServer) Start() { 263 defer ws.service.Shutdown() 264 listener, port, err := sos.GetListener() 265 if err != nil { 266 log.Fatalf("error: %v", err) 267 } 268 Port = port 269 fmt.Println(sos.StartServiceServer(ws.buildRouter(), "wifi", listener, Port)) 270 } 271 272 func displayWifi(wr io.Writer, wifiOpts []wifi.Option, connectedEssid, connectingEssid string) error { 273 wifiData := struct { 274 WifiOpts []wifi.Option 275 ConnectedEssid string 276 ConnectingEssid string 277 Port uint 278 }{wifiOpts, connectedEssid, connectingEssid, Port} 279 280 var tmpl *template.Template 281 file, err := ioutil.ReadFile(sos.HTMLPath("wifi.html")) 282 if err == nil { 283 html := string(file) 284 tmpl = template.Must(template.New("name").Parse(html)) 285 } else { 286 tmpl = template.Must(template.New("name").Parse(DefHtmlPage)) 287 } 288 return tmpl.Execute(wr, wifiData) 289 } 290 291 func NewWifiServer(service *WifiService) *WifiServer { 292 return &WifiServer{ 293 service: service, 294 } 295 }