Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

catname on the IDS seems to sometimes be an array of strings #113

Merged
merged 7 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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{} {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to read about what this does. hm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

powers the gofakeit stuff for running the integration tests in unpoller/unpoller

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)
}
Loading