ntgr/internal/netgear/netgear.go

95 lines
2.9 KiB
Go
Raw Permalink Normal View History

2022-03-07 23:14:24 +00:00
package netgear
import (
"encoding/json"
"fmt"
"git.wbrawner.com/wbrawner/ntgr/internal/netrc"
"io"
"log"
"net/http"
)
type DeviceList struct {
NumberOfDevices int `json:"numberOfDevices"`
Mode string `json:"mode"`
ConnDevices []struct {
CheckDev int `json:"checkDev"`
Mac string `json:"mac"`
Scene string `json:"scene"`
Mark string `json:"mark"`
Connection string `json:"connection"`
Priority int `json:"priority"`
PriorityStr string `json:"priorityStr"`
CurBarDownStr string `json:"curBarDownStr"`
CurBarUpStr string `json:"curBarUpStr"`
DownloadSpeedStr string `json:"downloadSpeedStr"`
UploadSpeedStr string `json:"uploadSpeedStr"`
Type string `json:"type"`
Model string `json:"model"`
Name string `json:"name"`
IP string `json:"ip"`
} `json:"connDevices"`
}
// login will attempt to authenticate with the router to perform a subsequent
// request. That request can be executed in the onSuccess function
func login[T interface{}](credentials netrc.NetrcCredential, onSuccess func(netrc.NetrcCredential) T) T {
req, err := http.NewRequest("GET", credentials.HttpHost(), nil)
if err != nil {
log.Fatalln("Failed to create request")
}
req.Header.Set(
"Authorization",
fmt.Sprintf("Basic %s", credentials.Base64()),
)
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalln("Failed to send first login request")
}
if res.StatusCode == 200 {
return onSuccess(credentials)
}
// if the first login attempt fails, it'll return an XSRF_TOKEN cookie
// that we'll need to set for the second request. it's only needed for
// the login request to succeed, and subsequent requests won't need it
// anymore
req.Header.Set(
"Cookie",
res.Header.Get("Set-Cookie"),
)
res, err = http.DefaultClient.Do(req)
if err != nil || res.StatusCode != 200 {
log.Fatalln("Failed to send second login request")
}
return onSuccess(credentials)
}
func ListDevices(credentials netrc.NetrcCredential) DeviceList {
log.Println("loading device list...")
req, err := http.NewRequest("GET", credentials.HttpHostWithPath("/ajax/devices_table_result"), nil)
if err != nil {
log.Fatalln("Failed to create request")
}
req.Header.Set(
"Authorization",
fmt.Sprintf("Basic %s", credentials.Base64()),
)
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalf("failed to list devices: %v\n", err)
}
if res.StatusCode != 200 {
// if loading the device list fails, then we need to log in
// first
log.Println("listing devices failed, attempting login")
return login(credentials, ListDevices)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
var devices DeviceList
if err = json.Unmarshal(body, &devices); err != nil {
log.Fatalln("Failed to parse JSON response from router")
}
return devices
}