Skip to content

Commit

Permalink
Merge pull request #113 from unpoller/unet-upgrade-8-1-113
Browse files Browse the repository at this point in the history
catname on the IDS seems to sometimes be an array of strings
  • Loading branch information
platinummonkey committed Apr 3, 2024
2 parents e0ffab8 + 3963cca commit 7496eff
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 56 deletions.
17 changes: 9 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ jobs:
test:
strategy:
matrix:
go: ["1.20"]
go: ["1.21"]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}

Expand All @@ -33,18 +33,19 @@ jobs:
lint:
strategy:
matrix:
go: ["1.20"]
go: ["1.21"]
os: [ubuntu-latest]
name: lint
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
cache: false
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.53
version: v1.54
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v3
- uses: actions/setup-go@v5
with:
go-version: '>=1.20.5'
go-version: '>=1.21.0'
cache: true
- uses: goreleaser/goreleaser-action@v4
with:
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/unpoller/unifi

go 1.19
go 1.21

toolchain go1.22.1

require (
github.com/brianvoe/gofakeit/v6 v6.28.0
Expand Down
84 changes: 42 additions & 42 deletions ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,48 @@ import (

// IDS holds an Intrusion Prevention System Event.
type IDS struct {
AppProto string `json:"app_proto,omitempty"`
Archived FlexBool `json:"archived"`
Catname string `json:"catname"`
Datetime time.Time `fake:"{recent_time}" json:"datetime"`
DestIP string `fake:"{ipv4address}" json:"dest_ip"`
DestIPGeo IPGeo `json:"dstipGeo"`
DestPort int `fake:"{port}" json:"dest_port,omitempty"`
DstIPASN string `fake:"{address}" json:"dstipASN"`
DstIPCountry string `fake:"{country}" json:"dstipCountry"`
DstMAC string `fake:"{macaddress}" json:"dst_mac"`
EventType string `json:"event_type"`
FlowID int64 `json:"flow_id"`
Host string `json:"host"`
ID string `fake:"{uuid}" json:"_id"`
InIface string `json:"in_iface"`
InnerAlertAction string `json:"inner_alert_action"`
InnerAlertCategory string `json:"inner_alert_category"`
InnerAlertGID int64 `json:"inner_alert_gid"`
InnerAlertRev int64 `json:"inner_alert_rev"`
InnerAlertSeverity int64 `json:"inner_alert_severity"`
InnerAlertSignature string `json:"inner_alert_signature"`
InnerAlertSignatureID int64 `json:"inner_alert_signature_id"`
Key string `fake:"{uuid}" json:"key"`
Msg string `fake:"{buzzword}" json:"msg"`
Proto string `json:"proto"`
SiteID string `fake:"{uuid}" json:"site_id"`
SiteName string `json:"-"`
SourceIPGeo IPGeo `json:"srcipGeo"`
SourceName string `json:"-"`
SrcIP string `fake:"{ipv4address}" json:"src_ip"`
SrcIPASN string `fake:"{address}" json:"srcipASN"`
SrcIPCountry string `fake:"{country}" json:"srcipCountry"`
SrcMAC string `fake:"{macaddress}" json:"src_mac"`
SrcPort int `fake:"{port}" json:"src_port,omitempty"`
Subsystem string `json:"subsystem"`
Time int64 `fake:"{timestamp}" json:"time"`
Timestamp int64 `fake:"{timestamp}" json:"timestamp"`
USGIP string `fake:"{ipv4address}" json:"usgip"`
USGIPASN string `fake:"{address}" json:"usgipASN"`
USGIPCountry string `fake:"{country}" json:"usgipCountry"`
USGIPGeo IPGeo `json:"usgipGeo"`
UniqueAlertID string `json:"unique_alertid"`
AppProto string `json:"app_proto,omitempty"`
Archived FlexBool `json:"archived"`
Catname FlexString `json:"catname"`
Datetime time.Time `fake:"{recent_time}" json:"datetime"`
DestIP string `fake:"{ipv4address}" json:"dest_ip"`
DestIPGeo IPGeo `json:"dstipGeo"`
DestPort int `fake:"{port}" json:"dest_port,omitempty"`
DstIPASN string `fake:"{address}" json:"dstipASN"`
DstIPCountry string `fake:"{country}" json:"dstipCountry"`
DstMAC string `fake:"{macaddress}" json:"dst_mac"`
EventType string `json:"event_type"`
FlowID int64 `json:"flow_id"`
Host string `json:"host"`
ID string `fake:"{uuid}" json:"_id"`
InIface string `json:"in_iface"`
InnerAlertAction string `json:"inner_alert_action"`
InnerAlertCategory string `json:"inner_alert_category"`
InnerAlertGID int64 `json:"inner_alert_gid"`
InnerAlertRev int64 `json:"inner_alert_rev"`
InnerAlertSeverity int64 `json:"inner_alert_severity"`
InnerAlertSignature string `json:"inner_alert_signature"`
InnerAlertSignatureID int64 `json:"inner_alert_signature_id"`
Key string `fake:"{uuid}" json:"key"`
Msg string `fake:"{buzzword}" json:"msg"`
Proto string `json:"proto"`
SiteID string `fake:"{uuid}" json:"site_id"`
SiteName string `json:"-"`
SourceIPGeo IPGeo `json:"srcipGeo"`
SourceName string `json:"-"`
SrcIP string `fake:"{ipv4address}" json:"src_ip"`
SrcIPASN string `fake:"{address}" json:"srcipASN"`
SrcIPCountry string `fake:"{country}" json:"srcipCountry"`
SrcMAC string `fake:"{macaddress}" json:"src_mac"`
SrcPort int `fake:"{port}" json:"src_port,omitempty"`
Subsystem string `json:"subsystem"`
Time int64 `fake:"{timestamp}" json:"time"`
Timestamp int64 `fake:"{timestamp}" json:"timestamp"`
USGIP string `fake:"{ipv4address}" json:"usgip"`
USGIPASN string `fake:"{address}" json:"usgipASN"`
USGIPCountry string `fake:"{country}" json:"usgipCountry"`
USGIPGeo IPGeo `json:"usgipGeo"`
UniqueAlertID string `json:"unique_alertid"`
}

// GetIDS returns Intrusion Detection Systems events for a list of Sites.
Expand Down
100 changes: 98 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func init() {
}

var ErrCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt")
var ErrCannotUnmarshalFlexString = fmt.Errorf("cannot unmarshal to FlexString")

// This is a list of unifi API paths.
// The %s in each string must be replaced with a Site.Name.
Expand Down Expand Up @@ -289,6 +290,101 @@ type ServerStatus struct {
UUID string `fake:"{uuid}" json:"uuid"`
}

type FlexString struct {
Val string
Arr []string
hintIsArray bool
}

func NewFlexString(v string) *FlexString {
return &FlexString{
Val: v,
Arr: []string{v},
hintIsArray: false,
}
}

func NewFlexStringArray(v []string) *FlexString {
return &FlexString{
Val: strings.Join(v, ", "),
Arr: v,
hintIsArray: true,
}
}

// UnmarshalJSON converts a string or number to an integer.
// Generally, do not call this directly, it's used in the json interface.
func (f *FlexString) UnmarshalJSON(b []byte) error {
var ust interface{}

if err := json.Unmarshal(b, &ust); err != nil {
return fmt.Errorf("json unmarshal: %w", err)
}

switch i := ust.(type) {
case []interface{}:
f.hintIsArray = true
// try to cast to string
for _, v := range i {
if s, ok := v.(string); ok {
f.Arr = append(f.Arr, s)
}
}

f.Val = strings.Join(f.Arr, ", ")
case []string:
f.hintIsArray = true
f.Val = strings.Join(i, ", ")
f.Arr = i
case string:
f.Val = i
f.Arr = []string{i}
case nil:
// noop, consider it empty values
default:
return fmt.Errorf("%v: %w", b, ErrCannotUnmarshalFlexString)
}

return nil
}

func (f FlexString) MarshalJSON() ([]byte, error) {
// array case
if f.hintIsArray {
return json.Marshal(f.Arr)
}

// plain string case
return json.Marshal(f.Val)
}

func (f FlexString) String() string {
return f.Val
}

func (f FlexString) Fake(faker *gofakeit.Faker) interface{} {
randValue := math.Min(math.Max(0.1, math.Abs(faker.Rand.Float64())), 120)
s := fmt.Sprintf("fake-%0.2f", randValue)

if faker.Rand.Intn(2) == 0 {
// plain string value
return FlexString{
Val: s,
Arr: []string{s},
}
}

// array case
s2 := fmt.Sprintf("fake-%0.2f-2", randValue)
s3 := fmt.Sprintf("fake-%0.2f-3", randValue)
arr := []string{s, s2, s3}

return FlexString{
Val: strings.Join(arr, ", "),
Arr: arr,
}
}

// FlexInt provides a container and unmarshalling for fields that may be
// numbers or strings in the Unifi API.
type FlexInt struct {
Expand All @@ -304,7 +400,7 @@ func NewFlexInt(v float64) *FlexInt {
}

// UnmarshalJSON converts a string or number to an integer.
// Generally, do call this directly, it's used in the json interface.
// Generally, do not call this directly, it's used in the json interface.
func (f *FlexInt) UnmarshalJSON(b []byte) error {
var unk interface{}

Expand Down Expand Up @@ -451,7 +547,7 @@ func NewFlexTemp(v float64) *FlexTemp {
}

// UnmarshalJSON converts a string or number to an integer.
// Generally, do call this directly, it's used in the json interface.
// Generally, do not call this directly, it's used in the json interface.
func (f *FlexTemp) UnmarshalJSON(b []byte) error {
var unk interface{}

Expand Down
25 changes: 25 additions & 0 deletions types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,28 @@ func TestFlexInt(t *testing.T) {
a.EqualValues(10, val3.Int())
a.EqualValues(10, val3.Int64())
}

func TestFlexString(t *testing.T) {
t.Parallel()
a := assert.New(t)

var r struct {
JustString unifi.FlexString `json:"just_string"`
SingleArrayString unifi.FlexString `json:"single_array_string"`
MultiArrayString unifi.FlexString `json:"multi_array_string"`
}
// no errors unmarshalling
a.Nil(json.Unmarshal([]byte(`{"just_string": "foo", "single_array_string": ["bar"], "multi_array_string": ["baz", "foo"]}`), &r))

// simple string
a.Equal("foo", r.JustString.Val)
a.EqualValues([]string{"foo"}, r.JustString.Arr)

// single array string
a.Equal("bar", r.SingleArrayString.Val)
a.EqualValues([]string{"bar"}, r.SingleArrayString.Arr)

// multi array string
a.Equal("baz, foo", r.MultiArrayString.Val)
a.EqualValues([]string{"baz", "foo"}, r.MultiArrayString.Arr)
}

0 comments on commit 7496eff

Please sign in to comment.