Skip to content

Commit

Permalink
Merge pull request #53 from thirdmartini/feature/allusers
Browse files Browse the repository at this point in the history
Add support for alluser
  • Loading branch information
davidnewhall authored Aug 13, 2021
2 parents 3dccfdb + 78deb26 commit 82e0d2c
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 1 deletion.
4 changes: 4 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const (
APIClientDPI string = "/api/s/%s/stat/stadpi"
// APIClientPath is Unifi Clients API Path.
APIClientPath string = "/api/s/%s/stat/sta"
// APIAllUserPath is Unifi Insight all previous Clients API Path.
APIAllUserPath string = "/api/s/%s/stat/alluser"
// APINetworkPath is where we get data about Unifi networks.
APINetworkPath string = "/api/s/%s/rest/networkconf"
// APIDevicePath is where we get data about Unifi devices.
Expand All @@ -36,6 +38,8 @@ const (
APILoginPath string = "/api/login"
// APILoginPathNew is how we log into UDM 5.12.55+.
APILoginPathNew string = "/api/auth/login"
// APILogoutPath is how we logout from UDM.
APILogoutPath string = "/api/logout"
// APIEventPathIDS returns Intrusion Detection/Prevention Systems Events.
APIEventPathIDS string = "/api/s/%s/stat/ips/event"
// APIEventPathAlarms contains the site alarms.
Expand Down
34 changes: 33 additions & 1 deletion unifi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
var (
ErrAuthenticationFailed = fmt.Errorf("authentication failed")
ErrInvalidStatusCode = fmt.Errorf("invalid status code from server")
ErrNoParams = fmt.Errorf("requedted PUT with no parameters")
ErrNoParams = fmt.Errorf("requested PUT with no parameters")
ErrInvalidSignature = fmt.Errorf("certificate signature does not match")
)

Expand Down Expand Up @@ -142,6 +142,13 @@ func (u *Unifi) Login() error {
return nil
}

// Logout closes the current session.
func (u *Unifi) Logout() error {
// a post is needed for logout
_, err := u.PostJSON(APILogoutPath)
return err
}

// with the release of controller version 5.12.55 on UDM in Jan 2020 the api paths
// changed and broke this library. This function runs when `NewUnifi()` is called to
// check if this is a newer controller or not. If it is, we set new to true.
Expand Down Expand Up @@ -279,6 +286,20 @@ func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error)
return req, nil
}

// UniReqPost is the Post call equivalent to UniReq.
func (u *Unifi) UniReqPost(apiPath string, params string) (*http.Request, error) {
apiPath = u.path(apiPath)

req, err := http.NewRequest(http.MethodPost, u.URL+apiPath, bytes.NewBufferString("")) //nolint:noctx
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}

u.setHeaders(req, params)

return req, nil
}

// GetJSON returns the raw JSON from a path. This is useful for debugging.
func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) {
req, err := u.UniReq(apiPath, strings.Join(params, " "))
Expand All @@ -300,6 +321,17 @@ func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) {
return u.do(req)
}

// PostJSON uses a POST call and returns the raw JSON in the same way as GetData
// Use this if you want to change data via the REST API.
func (u *Unifi) PostJSON(apiPath string, params ...string) ([]byte, error) {
req, err := u.UniReqPost(apiPath, strings.Join(params, " "))
if err != nil {
return []byte{}, err
}

return u.do(req)
}

func (u *Unifi) do(req *http.Request) ([]byte, error) {
var (
cancel func()
Expand Down
71 changes: 71 additions & 0 deletions users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package unifi

import (
"fmt"
"strings"
)

// GetUsers returns a response full of clients that connected to the UDM within the provided amount of time
// using the insight historical connection data set.
func (u *Unifi) GetUsers(sites []*Site, hours int) ([]*User, error) {
data := make([]*User, 0)

for _, site := range sites {
var (
response struct {
Data []*User `json:"data"`
}
params = fmt.Sprintf(`{ "type": "all:", "conn": "all", "within":%d }`, hours)
)

u.DebugLog("Polling Controller, retrieving UniFi Users, site %s ", site.SiteName)

clientPath := fmt.Sprintf(APIAllUserPath, site.Name)
if err := u.GetData(clientPath, &response, params); err != nil {
return nil, err
}

for i, d := range response.Data {
// Add special SourceName value.
response.Data[i].SourceName = u.URL
// Add the special "Site Name" to each client. This becomes a Grafana filter somewhere.
response.Data[i].SiteName = site.SiteName
// Fix name and hostname fields. Sometimes one or the other is blank.
response.Data[i].Hostname = strings.TrimSpace(pick(d.Hostname, d.Name, d.Mac))
response.Data[i].Name = strings.TrimSpace(pick(d.Name, d.Hostname))
}

data = append(data, response.Data...)
}

return data, nil
}

// User defines the metadata available for previously connected clients.
type User struct {
SourceName string `json:"-"`
SiteName string `json:"-"`
ID string `json:"_id"`
Mac string `json:"mac"`
SiteID string `json:"site_id"`
Oui string `json:"oui,omitempty"`
IsGuest bool `json:"is_guest"`
FirstSeen FlexInt `json:"first_seen,omitempty"`
LastSeen FlexInt `json:"last_seen,omitempty"`
IsWired bool `json:"is_wired,omitempty"`
Hostname string `json:"hostname,omitempty"`
Duration FlexInt `json:"duration,omitempty"`
TxBytes FlexInt `json:"tx_bytes,omitempty"`
TxPackets FlexInt `json:"tx_packets,omitempty"`
RxBytes FlexInt `json:"rx_bytes,omitempty"`
RxPackets FlexInt `json:"rx_packets,omitempty"`
WifiTxAttempts FlexInt `json:"wifi_tx_attempts,omitempty"`
TxRetries FlexInt `json:"tx_retries,omitempty"`
UsergroupID string `json:"usergroup_id,omitempty"`
Name string `json:"name,omitempty"`
Note string `json:"note,omitempty"`
Noted FlexBool `json:"noted,omitempty"`
Blocked FlexBool `json:"blocked,omitempty"`
DevIDOverride FlexInt `json:"dev_id_override,omitempty"`
FingerprintOverride FlexBool `json:"fingerprint_override,omitempty"`
}

0 comments on commit 82e0d2c

Please sign in to comment.