Skip to content

Commit

Permalink
add onyphe check
Browse files Browse the repository at this point in the history
  • Loading branch information
yvesago committed Jun 5, 2024
1 parent 4cb7a8c commit 5ced6e7
Show file tree
Hide file tree
Showing 3 changed files with 409 additions and 0 deletions.
148 changes: 148 additions & 0 deletions check/onyphe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package check

import (
"encoding/json"
"fmt"
"net"
"sort"
"strings"
"strconv"

"github.com/jreisinger/checkip"
)

type onyphe struct {
Text string `json:"text"`
Vulns []string `json:"vulns"`
Results onypheData `json:"results"`
}

type onypheData []struct {
OS string `json:"os"`
OsVendor string `json:"osvendor"`
//Version string `json:"version"`
Port interface{} `json:"port"`
Protocol string `json:"protocol"`
Product string `json:"product"`
Transport string `json:"transport"` // tcp, udp
}

var onypheUrl = "https://www.onyphe.io/api/v2"

// Onyphe gets generic information from api.onyphe.io.
func Onyphe(ipaddr net.IP) (checkip.Result, error) {
result := checkip.Result{
Name: "onyphe.io",
Type: checkip.TypeInfoSec,
}

apiKey, err := getConfigValue("ONYPHE_API_KEY")
if err != nil {
return result, newCheckError(err)
}
if apiKey == "" {
return result, nil
}

headers := map[string]string{
"Authorization": "bearer " + apiKey,
"Accept": "application/json",
//"Content-Type": "application/x-www-form-urlencoded",
}
var onyphe onyphe
apiURL := fmt.Sprintf("%s/simple/datascan/%s", onypheUrl, ipaddr)
if err := defaultHttpClient.GetJson(apiURL, headers, map[string]string{}, &onyphe); err != nil {
return result, newCheckError(err)
}

for _, d := range onyphe.Results {
var port string
switch v := d.Port.(type) {
case float64:
port = fmt.Sprintf("%d", int(v))
case string:
port = v
}
if port != "80" && port != "443" && port != "53" { // undecidable ports
result.Malicious = true
}
}

result.Info = onyphe

return result, nil
}

type byPortO onypheData

func (x byPortO) Len() int { return len(x) }
func (x byPortO) Less(i, j int) bool {
var portI float64
var portJ float64
switch v := x[i].Port.(type) {
case float64:
portI = v
case string:
portI, _ = strconv.ParseFloat(v, 64)
}
switch v := x[j].Port.(type) {
case float64:
portJ = v
case string:
portJ, _ = strconv.ParseFloat(v, 64)
}
return portI < portJ
}

func (x byPortO) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

// Info returns interesting information from the check.
func (o onyphe) Summary() string {
var portInfo []string
service := make(map[string]int)
sort.Sort(byPortO(o.Results))
for _, d := range o.Results {
var os string
if d.OS != "" {
os = d.OS
}

var osvendor string
if d.OsVendor != "" {
osvendor = d.OsVendor
}

var product string
if d.Product != "" {
product = d.Product + " "
}

var port string
switch v := d.Port.(type) {
case float64:
port = fmt.Sprintf("%d", int(v))
case string:
port = v
}

sport := fmt.Sprintf("%s/%s", d.Transport, port)
service[sport]++

if service[sport] > 1 {
continue
}

if os == "" && osvendor == "" {
portInfo = append(portInfo, fmt.Sprintf("%s %s/%s", d.Protocol, d.Transport, port))
} else {
ss := nonEmpty(os, osvendor)
portInfo = append(portInfo, fmt.Sprintf("%s %s/%s %s(%s)", d.Protocol, d.Transport, port, product, strings.Join(ss, ", ")))
}
}

return fmt.Sprintf("Open: %s", strings.Join(portInfo, ", "))
}

func (o onyphe) Json() ([]byte, error) {
return json.Marshal(o)
}
63 changes: 63 additions & 0 deletions check/onyphe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package check

import (
"net"
"net/http"
"testing"

"github.com/jreisinger/checkip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestOnyphe(t *testing.T) {

apiKey, err := getConfigValue("CENSYS_KEY")
if err != nil || apiKey == "" {
return
}
apiSec, err := getConfigValue("CENSYS_SEC")
if err != nil || apiSec == "" {
return
}

t.Run("given valid response then result and no error is returned", func(t *testing.T) {
handlerFn := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
rw.Write(loadResponse(t, "onyphe_response.json"))
})

testUrl := setMockHttpClient(t, handlerFn)
setOnypheUrl(t, testUrl)

result, err := Onyphe(net.ParseIP("118.25.6.39"))
require.NoError(t, err)
assert.Equal(t, "onyphe.io", result.Name)
assert.Equal(t, checkip.TypeInfoSec, result.Type)
assert.Equal(t, true, result.Malicious)
assert.Equal(t, "Open: snmp udp/161 (RouterOS, Mikrotik), winbox tcp/8291 (Linux Kernel, Linux)", result.Info.Summary())
})


t.Run("given non 2xx response then error is returned", func(t *testing.T) {
handlerFn := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
})

testUrl := setMockHttpClient(t, handlerFn)
setOnypheUrl(t, testUrl)

_, err := Onyphe(net.ParseIP("118.25.6.39"))
require.Error(t, err)
})
}

// --- test helpers ---

func setOnypheUrl(t *testing.T, testUrl string) {
url := onypheUrl
onypheUrl = testUrl
t.Cleanup(func() {
onypheUrl = url
})
}
Loading

0 comments on commit 5ced6e7

Please sign in to comment.