Add Analyze method to the Dissector interface and MizuEntry to the extension API

This commit is contained in:
M. Mert Yildiran 2021-08-20 21:34:44 +03:00
parent 3b0502180f
commit c668680f54
No known key found for this signature in database
GPG Key ID: D42ADB236521BF7A
11 changed files with 152 additions and 138 deletions

View File

@ -125,8 +125,13 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
// } else { // } else {
// rlog.Errorf("Error when creating HTTP entry") // rlog.Errorf("Error when creating HTTP entry")
// } // }
baseEntry := extension.Dissector.Summarize(item) resolvedSource, resolvedDestionation := resolveIP(item.ConnectionInfo)
mizuEntry := extension.Dissector.Analyze(item, primitive.NewObjectID().Hex(), resolvedSource, resolvedDestionation)
baseEntry := extension.Dissector.Summarize(mizuEntry)
fmt.Printf("baseEntry: %+v\n", baseEntry) fmt.Printf("baseEntry: %+v\n", baseEntry)
fmt.Printf("mizuEntry: %+v\n", mizuEntry)
mizuEntry.EstimatedSizeBytes = getEstimatedEntrySizeBytes(mizuEntry)
database.CreateEntry(mizuEntry)
baseEntryBytes, _ := models.CreateBaseEntryWebSocketMessage(baseEntry) baseEntryBytes, _ := models.CreateBaseEntryWebSocketMessage(baseEntry)
BroadcastToBrowserClients(baseEntryBytes) BroadcastToBrowserClients(baseEntryBytes)
} }
@ -139,14 +144,7 @@ func StartReadingOutbound(outboundLinkChannel <-chan *tap.OutboundLink) {
} }
} }
func saveHarToDb(entry *har.Entry, connectionInfo *tapApi.ConnectionInfo) { func resolveIP(connectionInfo *tapApi.ConnectionInfo) (resolvedSource string, resolvedDestination string) {
entryBytes, _ := json.Marshal(entry)
serviceName, urlPath := getServiceNameFromUrl(entry.Request.URL)
entryId := primitive.NewObjectID().Hex()
var (
resolvedSource string
resolvedDestination string
)
if k8sResolver != nil { if k8sResolver != nil {
unresolvedSource := connectionInfo.ClientIP unresolvedSource := connectionInfo.ClientIP
resolvedSource = k8sResolver.Resolve(unresolvedSource) resolvedSource = k8sResolver.Resolve(unresolvedSource)
@ -165,32 +163,7 @@ func saveHarToDb(entry *har.Entry, connectionInfo *tapApi.ConnectionInfo) {
} }
} }
} }
return resolvedSource, resolvedDestination
mizuEntry := models.MizuEntry{
EntryId: entryId,
Entry: string(entryBytes), // simple way to store it and not convert to bytes
Service: serviceName,
Url: entry.Request.URL,
Path: urlPath,
Method: entry.Request.Method,
Status: entry.Response.Status,
RequestSenderIp: connectionInfo.ClientIP,
Timestamp: entry.StartedDateTime.UnixNano() / int64(time.Millisecond),
ResolvedSource: resolvedSource,
ResolvedDestination: resolvedDestination,
IsOutgoing: connectionInfo.IsOutgoing,
}
mizuEntry.EstimatedSizeBytes = getEstimatedEntrySizeBytes(mizuEntry)
database.CreateEntry(&mizuEntry)
// baseEntry := models.BaseEntryDetails{}
// if err := models.GetEntry(&mizuEntry, &baseEntry); err != nil {
// return
// }
// baseEntry.Rules = models.RunValidationRulesState(*entry, serviceName)
// baseEntry.Latency = entry.Timings.Receive
// baseEntryBytes, _ := models.CreateBaseEntryWebSocketMessage(&baseEntry)
// BroadcastToBrowserClients(baseEntryBytes)
} }
func getServiceNameFromUrl(inputUrl string) (string, string) { func getServiceNameFromUrl(inputUrl string) (string, string) {
@ -204,7 +177,7 @@ func CheckIsServiceIP(address string) bool {
} }
// gives a rough estimate of the size this will take up in the db, good enough for maintaining db size limit accurately // gives a rough estimate of the size this will take up in the db, good enough for maintaining db size limit accurately
func getEstimatedEntrySizeBytes(mizuEntry models.MizuEntry) int { func getEstimatedEntrySizeBytes(mizuEntry *tapApi.MizuEntry) int {
sizeBytes := len(mizuEntry.Entry) sizeBytes := len(mizuEntry.Entry)
sizeBytes += len(mizuEntry.EntryId) sizeBytes += len(mizuEntry.EntryId)
sizeBytes += len(mizuEntry.Service) sizeBytes += len(mizuEntry.Service)

View File

@ -16,6 +16,8 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/martian/har" "github.com/google/martian/har"
"github.com/romana/rlog" "github.com/romana/rlog"
tapApi "github.com/up9inc/mizu/tap/api"
) )
func GetEntries(c *gin.Context) { func GetEntries(c *gin.Context) {
@ -31,7 +33,7 @@ func GetEntries(c *gin.Context) {
order := database.OperatorToOrderMapping[entriesFilter.Operator] order := database.OperatorToOrderMapping[entriesFilter.Operator]
operatorSymbol := database.OperatorToSymbolMapping[entriesFilter.Operator] operatorSymbol := database.OperatorToSymbolMapping[entriesFilter.Operator]
var entries []models.MizuEntry var entries []tapApi.MizuEntry
database.GetEntriesTable(). database.GetEntriesTable().
Order(fmt.Sprintf("timestamp %s", order)). Order(fmt.Sprintf("timestamp %s", order)).
Where(fmt.Sprintf("timestamp %s %v", operatorSymbol, entriesFilter.Timestamp)). Where(fmt.Sprintf("timestamp %s %v", operatorSymbol, entriesFilter.Timestamp)).
@ -80,7 +82,7 @@ func GetHARs(c *gin.Context) {
timestampTo = entriesFilter.To timestampTo = entriesFilter.To
} }
var entries []models.MizuEntry var entries []tapApi.MizuEntry
database.GetEntriesTable(). database.GetEntriesTable().
Where(fmt.Sprintf("timestamp BETWEEN %v AND %v", timestampFrom, timestampTo)). Where(fmt.Sprintf("timestamp BETWEEN %v AND %v", timestampFrom, timestampTo)).
Order(fmt.Sprintf("timestamp %s", order)). Order(fmt.Sprintf("timestamp %s", order)).
@ -207,7 +209,7 @@ func GetFullEntries(c *gin.Context) {
} }
func GetEntry(c *gin.Context) { func GetEntry(c *gin.Context) {
var entryData models.MizuEntry var entryData tapApi.MizuEntry
database.GetEntriesTable(). database.GetEntriesTable().
Where(map[string]string{"entryId": c.Param("entryId")}). Where(map[string]string{"entryId": c.Param("entryId")}).
First(&entryData) First(&entryData)
@ -219,20 +221,21 @@ func GetEntry(c *gin.Context) {
"msg": "Can't get entry details", "msg": "Can't get entry details",
}) })
} }
fullEntryWithPolicy := models.FullEntryWithPolicy{} fmt.Printf("entryData: %+v\n", entryData)
if err := models.GetEntry(&entryData, &fullEntryWithPolicy); err != nil { // fullEntryWithPolicy := models.FullEntryWithPolicy{}
c.JSON(http.StatusInternalServerError, map[string]interface{}{ // if err := models.GetEntry(&entryData, &fullEntryWithPolicy); err != nil {
"error": true, // c.JSON(http.StatusInternalServerError, map[string]interface{}{
"msg": "Can't get entry details", // "error": true,
}) // "msg": "Can't get entry details",
} // })
c.JSON(http.StatusOK, fullEntryWithPolicy) // }
c.JSON(http.StatusOK, entryData)
} }
func DeleteAllEntries(c *gin.Context) { func DeleteAllEntries(c *gin.Context) {
database.GetEntriesTable(). database.GetEntriesTable().
Where("1 = 1"). Where("1 = 1").
Delete(&models.MizuEntry{}) Delete(&tapApi.MizuEntry{})
c.JSON(http.StatusOK, map[string]string{ c.JSON(http.StatusOK, map[string]string{
"msg": "Success", "msg": "Success",

View File

@ -2,16 +2,18 @@ package database
import ( import (
"fmt" "fmt"
"mizuserver/pkg/utils"
"time"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
"mizuserver/pkg/models"
"mizuserver/pkg/utils" tapApi "github.com/up9inc/mizu/tap/api"
"time"
) )
const ( const (
DBPath = "./entries.db" DBPath = "./entries.db"
OrderDesc = "desc" OrderDesc = "desc"
OrderAsc = "asc" OrderAsc = "asc"
LT = "lt" LT = "lt"
@ -19,8 +21,8 @@ const (
) )
var ( var (
DB *gorm.DB DB *gorm.DB
IsDBLocked = false IsDBLocked = false
OperatorToSymbolMapping = map[string]string{ OperatorToSymbolMapping = map[string]string{
LT: "<", LT: "<",
GT: ">", GT: ">",
@ -40,7 +42,7 @@ func GetEntriesTable() *gorm.DB {
return DB.Table("mizu_entries") return DB.Table("mizu_entries")
} }
func CreateEntry(entry *models.MizuEntry) { func CreateEntry(entry *tapApi.MizuEntry) {
if IsDBLocked { if IsDBLocked {
return return
} }
@ -51,14 +53,13 @@ func initDataBase(databasePath string) *gorm.DB {
temp, _ := gorm.Open(sqlite.Open(databasePath), &gorm.Config{ temp, _ := gorm.Open(sqlite.Open(databasePath), &gorm.Config{
Logger: &utils.TruncatingLogger{LogLevel: logger.Warn, SlowThreshold: 500 * time.Millisecond}, Logger: &utils.TruncatingLogger{LogLevel: logger.Warn, SlowThreshold: 500 * time.Millisecond},
}) })
_ = temp.AutoMigrate(&models.MizuEntry{}) // this will ensure table is created _ = temp.AutoMigrate(&tapApi.MizuEntry{}) // this will ensure table is created
return temp return temp
} }
func GetEntriesFromDb(timestampFrom int64, timestampTo int64) []tapApi.MizuEntry {
func GetEntriesFromDb(timestampFrom int64, timestampTo int64) []models.MizuEntry {
order := OrderDesc order := OrderDesc
var entries []models.MizuEntry var entries []tapApi.MizuEntry
GetEntriesTable(). GetEntriesTable().
Where(fmt.Sprintf("timestamp BETWEEN %v AND %v", timestampFrom, timestampTo)). Where(fmt.Sprintf("timestamp BETWEEN %v AND %v", timestampFrom, timestampTo)).
Order(fmt.Sprintf("timestamp %s", order)). Order(fmt.Sprintf("timestamp %s", order)).
@ -70,4 +71,3 @@ func GetEntriesFromDb(timestampFrom int64, timestampTo int64) []models.MizuEntry
} }
return entries return entries
} }

View File

@ -1,16 +1,17 @@
package database package database
import ( import (
"log"
"os"
"strconv"
"time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/romana/rlog" "github.com/romana/rlog"
"github.com/up9inc/mizu/shared" "github.com/up9inc/mizu/shared"
"github.com/up9inc/mizu/shared/debounce" "github.com/up9inc/mizu/shared/debounce"
"github.com/up9inc/mizu/shared/units" "github.com/up9inc/mizu/shared/units"
"log" tapApi "github.com/up9inc/mizu/tap/api"
"mizuserver/pkg/models"
"os"
"strconv"
"time"
) )
const percentageOfMaxSizeBytesToPrune = 15 const percentageOfMaxSizeBytesToPrune = 15
@ -99,7 +100,7 @@ func pruneOldEntries(currentFileSize int64) {
if bytesToBeRemoved >= amountOfBytesToTrim { if bytesToBeRemoved >= amountOfBytesToTrim {
break break
} }
var entry models.MizuEntry var entry tapApi.MizuEntry
err = DB.ScanRows(rows, &entry) err = DB.ScanRows(rows, &entry)
if err != nil { if err != nil {
rlog.Errorf("Error scanning db row: %v", err) rlog.Errorf("Error scanning db row: %v", err)
@ -111,7 +112,7 @@ func pruneOldEntries(currentFileSize int64) {
} }
if len(entryIdsToRemove) > 0 { if len(entryIdsToRemove) > 0 {
GetEntriesTable().Where(entryIdsToRemove).Delete(models.MizuEntry{}) GetEntriesTable().Where(entryIdsToRemove).Delete(tapApi.MizuEntry{})
// VACUUM causes sqlite to shrink the db file after rows have been deleted, the db file will not shrink without this // VACUUM causes sqlite to shrink the db file after rows have been deleted, the db file will not shrink without this
DB.Exec("VACUUM") DB.Exec("VACUUM")
rlog.Errorf("Removed %d rows and cleared %s", len(entryIdsToRemove), units.BytesToHumanReadable(bytesToBeRemoved)) rlog.Errorf("Removed %d rows and cleared %s", len(entryIdsToRemove), units.BytesToHumanReadable(bytesToBeRemoved))

View File

@ -21,33 +21,10 @@ import (
"github.com/up9inc/mizu/tap" "github.com/up9inc/mizu/tap"
) )
type DataUnmarshaler interface { func GetEntry(r *tapApi.MizuEntry, v tapApi.DataUnmarshaler) error {
UnmarshalData(*MizuEntry) error
}
func GetEntry(r *MizuEntry, v DataUnmarshaler) error {
return v.UnmarshalData(r) return v.UnmarshalData(r)
} }
type MizuEntry struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
Entry string `json:"entry,omitempty" gorm:"column:entry"`
EntryId string `json:"entryId" gorm:"column:entryId"`
Url string `json:"url" gorm:"column:url"`
Method string `json:"method" gorm:"column:method"`
Status int `json:"status" gorm:"column:status"`
RequestSenderIp string `json:"requestSenderIp" gorm:"column:requestSenderIp"`
Service string `json:"service" gorm:"column:service"`
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
Path string `json:"path" gorm:"column:path"`
ResolvedSource string `json:"resolvedSource,omitempty" gorm:"column:resolvedSource"`
ResolvedDestination string `json:"resolvedDestination,omitempty" gorm:"column:resolvedDestination"`
IsOutgoing bool `json:"isOutgoing,omitempty" gorm:"column:isOutgoing"`
EstimatedSizeBytes int `json:"-" gorm:"column:estimatedSizeBytes"`
}
func NewApplicableRules(status bool, latency int64) tapApi.ApplicableRules { func NewApplicableRules(status bool, latency int64) tapApi.ApplicableRules {
ar := tapApi.ApplicableRules{} ar := tapApi.ApplicableRules{}
ar.Status = status ar.Status = status
@ -63,26 +40,7 @@ type FullEntryDetailsExtra struct {
har.Entry har.Entry
} }
// func (bed *BaseEntryDetails) UnmarshalData(entry *MizuEntry) error { func (fed *FullEntryDetails) UnmarshalData(entry *tapApi.MizuEntry) error {
// entryUrl := entry.Url
// service := entry.Service
// if entry.ResolvedDestination != "" {
// entryUrl = utils.SetHostname(entryUrl, entry.ResolvedDestination)
// service = utils.SetHostname(service, entry.ResolvedDestination)
// }
// bed.Id = entry.EntryId
// bed.Url = entryUrl
// bed.Service = service
// bed.Path = entry.Path
// bed.StatusCode = entry.Status
// bed.Method = entry.Method
// bed.Timestamp = entry.Timestamp
// bed.RequestSenderIp = entry.RequestSenderIp
// bed.IsOutgoing = entry.IsOutgoing
// return nil
// }
func (fed *FullEntryDetails) UnmarshalData(entry *MizuEntry) error {
if err := json.Unmarshal([]byte(entry.Entry), &fed.Entry); err != nil { if err := json.Unmarshal([]byte(entry.Entry), &fed.Entry); err != nil {
return err return err
} }
@ -93,7 +51,7 @@ func (fed *FullEntryDetails) UnmarshalData(entry *MizuEntry) error {
return nil return nil
} }
func (fedex *FullEntryDetailsExtra) UnmarshalData(entry *MizuEntry) error { func (fedex *FullEntryDetailsExtra) UnmarshalData(entry *tapApi.MizuEntry) error {
if err := json.Unmarshal([]byte(entry.Entry), &fedex.Entry); err != nil { if err := json.Unmarshal([]byte(entry.Entry), &fedex.Entry); err != nil {
return err return err
} }
@ -195,7 +153,7 @@ type FullEntryWithPolicy struct {
Service string `json:"service"` Service string `json:"service"`
} }
func (fewp *FullEntryWithPolicy) UnmarshalData(entry *MizuEntry) error { func (fewp *FullEntryWithPolicy) UnmarshalData(entry *tapApi.MizuEntry) error {
if err := json.Unmarshal([]byte(entry.Entry), &fewp.Entry); err != nil { if err := json.Unmarshal([]byte(entry.Entry), &fewp.Entry); err != nil {
return err return err
} }

View File

@ -33,9 +33,9 @@ type TcpID struct {
} }
type GenericMessage struct { type GenericMessage struct {
IsRequest bool IsRequest bool `json:"is_request"`
CaptureTime time.Time CaptureTime time.Time `json:"capture_time"`
Payload interface{} Payload interface{} `json:"payload"`
} }
type RequestResponsePair struct { type RequestResponsePair struct {
@ -54,7 +54,8 @@ type Dissector interface {
Register(*Extension) Register(*Extension)
Ping() Ping()
Dissect(b *bufio.Reader, isClient bool, tcpID *TcpID, emitter Emitter) Dissect(b *bufio.Reader, isClient bool, tcpID *TcpID, emitter Emitter)
Summarize(item *OutputChannelItem) *BaseEntryDetails Analyze(item *OutputChannelItem, entryId string, resolvedSource string, resolvedDestination string) *MizuEntry
Summarize(entry *MizuEntry) *BaseEntryDetails
} }
type Emitting struct { type Emitting struct {
@ -73,6 +74,25 @@ func (e *Emitting) Emit(item *OutputChannelItem) {
e.OutputChannel <- item e.OutputChannel <- item
} }
type MizuEntry struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
Entry string `json:"entry,omitempty" gorm:"column:entry"`
EntryId string `json:"entryId" gorm:"column:entryId"`
Url string `json:"url" gorm:"column:url"`
Method string `json:"method" gorm:"column:method"`
Status int `json:"status" gorm:"column:status"`
RequestSenderIp string `json:"requestSenderIp" gorm:"column:requestSenderIp"`
Service string `json:"service" gorm:"column:service"`
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
Path string `json:"path" gorm:"column:path"`
ResolvedSource string `json:"resolvedSource,omitempty" gorm:"column:resolvedSource"`
ResolvedDestination string `json:"resolvedDestination,omitempty" gorm:"column:resolvedDestination"`
IsOutgoing bool `json:"isOutgoing,omitempty" gorm:"column:isOutgoing"`
EstimatedSizeBytes int `json:"-" gorm:"column:estimatedSizeBytes"`
}
type BaseEntryDetails struct { type BaseEntryDetails struct {
Id string `json:"id,omitempty"` Id string `json:"id,omitempty"`
Url string `json:"url,omitempty"` Url string `json:"url,omitempty"`
@ -91,3 +111,22 @@ type ApplicableRules struct {
Latency int64 `json:"latency,omitempty"` Latency int64 `json:"latency,omitempty"`
Status bool `json:"status,omitempty"` Status bool `json:"status,omitempty"`
} }
type DataUnmarshaler interface {
UnmarshalData(*MizuEntry) error
}
func (bed *BaseEntryDetails) UnmarshalData(entry *MizuEntry) error {
entryUrl := entry.Url
service := entry.Service
bed.Id = entry.EntryId
bed.Url = entryUrl
bed.Service = service
bed.Path = entry.Path
bed.StatusCode = entry.Status
bed.Method = entry.Method
bed.Timestamp = entry.Timestamp
bed.RequestSenderIp = entry.RequestSenderIp
bed.IsOutgoing = entry.IsOutgoing
return nil
}

View File

@ -27,7 +27,12 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, em
// TODO: Implement // TODO: Implement
} }
func (d dissecting) Summarize(item *api.OutputChannelItem) *api.BaseEntryDetails { func (d dissecting) Analyze(item *api.OutputChannelItem, entryId string, resolvedSource string, resolvedDestination string) *api.MizuEntry {
// TODO: Implement
return nil
}
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
// TODO: Implement // TODO: Implement
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -80,7 +81,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, em
} }
} }
func (d dissecting) Summarize(item *api.OutputChannelItem) *api.BaseEntryDetails { func (d dissecting) Analyze(item *api.OutputChannelItem, entryId string, resolvedSource string, resolvedDestination string) *api.MizuEntry {
fmt.Printf("pair.Request.Payload: %+v\n", item.Pair.Request.Payload) fmt.Printf("pair.Request.Payload: %+v\n", item.Pair.Request.Payload)
fmt.Printf("item.Pair.Response.Payload: %+v\n", item.Pair.Response.Payload) fmt.Printf("item.Pair.Response.Payload: %+v\n", item.Pair.Response.Payload)
var host string var host string
@ -92,13 +93,40 @@ func (d dissecting) Summarize(item *api.OutputChannelItem) *api.BaseEntryDetails
} }
request := item.Pair.Request.Payload.(map[string]interface{}) request := item.Pair.Request.Payload.(map[string]interface{})
response := item.Pair.Response.Payload.(map[string]interface{}) response := item.Pair.Response.Payload.(map[string]interface{})
entryBytes, _ := json.Marshal(item.Pair)
service := fmt.Sprintf("http://%s", host)
return &api.MizuEntry{
EntryId: entryId,
Entry: string(entryBytes),
Url: fmt.Sprintf("%s%s", service, request["url"].(string)),
Method: request["method"].(string),
Status: int(response["status"].(float64)),
RequestSenderIp: item.ConnectionInfo.ClientIP,
Service: service,
Timestamp: item.Timestamp,
Path: request["url"].(string),
ResolvedSource: resolvedSource,
ResolvedDestination: resolvedDestination,
IsOutgoing: item.ConnectionInfo.IsOutgoing,
}
}
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
return &api.BaseEntryDetails{ return &api.BaseEntryDetails{
Url: fmt.Sprintf("http://%s%s", host, request["url"].(string)), Id: entry.EntryId,
RequestSenderIp: item.ConnectionInfo.ClientIP, Url: entry.Url,
Path: request["url"].(string), RequestSenderIp: entry.RequestSenderIp,
StatusCode: int(response["status"].(float64)), Service: entry.Service,
Method: request["method"].(string), Path: entry.Path,
Timestamp: item.Timestamp, StatusCode: entry.Status,
Method: entry.Method,
Timestamp: entry.Timestamp,
IsOutgoing: entry.IsOutgoing,
Latency: 0,
Rules: api.ApplicableRules{
Latency: 0,
Status: false,
},
} }
} }

View File

@ -27,7 +27,12 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, em
// TODO: Implement // TODO: Implement
} }
func (d dissecting) Summarize(item *api.OutputChannelItem) *api.BaseEntryDetails { func (d dissecting) Analyze(item *api.OutputChannelItem, entryId string, resolvedSource string, resolvedDestination string) *api.MizuEntry {
// TODO: Implement
return nil
}
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
// TODO: Implement // TODO: Implement
return nil return nil
} }

View File

@ -29,7 +29,7 @@ const HarEntryTitle: React.FC<any> = ({har}) => {
const classes = useStyles(); const classes = useStyles();
const {log: {entries}} = har; const {log: {entries}} = har;
const {response, request, timings: {receive}} = entries[0].entry; const {response, request} = JSON.parse(entries[0].entry);
const {status, statusText, bodySize} = response; const {status, statusText, bodySize} = response;
@ -42,7 +42,7 @@ const HarEntryTitle: React.FC<any> = ({har}) => {
</div> </div>
<div style={{margin: "0 18px", opacity: 0.5}}>{formatSize(bodySize)}</div> <div style={{margin: "0 18px", opacity: 0.5}}>{formatSize(bodySize)}</div>
<div style={{marginRight: 18, opacity: 0.5}}>{status} {statusText}</div> <div style={{marginRight: 18, opacity: 0.5}}>{status} {statusText}</div>
<div style={{marginRight: 18, opacity: 0.5}}>{Math.round(receive)}ms</div> {/* <div style={{marginRight: 18, opacity: 0.5}}>{Math.round(receive)}ms</div> */}
<div style={{opacity: 0.5}}>{'rulesMatched' in entries[0] ? entries[0].rulesMatched?.length : '0'} Rules Applied</div> <div style={{opacity: 0.5}}>{'rulesMatched' in entries[0] ? entries[0].rulesMatched?.length : '0'} Rules Applied</div>
</div>; </div>;
}; };

View File

@ -6,7 +6,9 @@ import {HAREntryTableSection, HAREntryBodySection, HAREntryTablePolicySection} f
const MIME_TYPE_KEY = 'mimeType'; const MIME_TYPE_KEY = 'mimeType';
const HAREntryDisplay: React.FC<any> = ({har, entry, isCollapsed: initialIsCollapsed, isResponseMocked}) => { const HAREntryDisplay: React.FC<any> = ({har, entry, isCollapsed: initialIsCollapsed, isResponseMocked}) => {
const {request, response, timings: {receive}} = entry; const {request, response} = JSON.parse(entry);
console.log('request:', request)
console.log('response:', response)
const rulesMatched = har.log.entries[0].rulesMatched const rulesMatched = har.log.entries[0].rulesMatched
const TABS = [ const TABS = [
{tab: 'request'}, {tab: 'request'},
@ -26,28 +28,28 @@ const HAREntryDisplay: React.FC<any> = ({har, entry, isCollapsed: initialIsColla
{!initialIsCollapsed && <div className={styles.body}> {!initialIsCollapsed && <div className={styles.body}>
<div className={styles.bodyHeader}> <div className={styles.bodyHeader}>
<Tabs tabs={TABS} currentTab={currentTab} onChange={setCurrentTab} leftAligned/> <Tabs tabs={TABS} currentTab={currentTab} onChange={setCurrentTab} leftAligned/>
{request?.url && <a className={styles.endpointURL} href={request.url} target='_blank' rel="noreferrer">{request.url}</a>} {request?.url && <a className={styles.endpointURL} href={request.payload.url} target='_blank' rel="noreferrer">{request.payload.url}</a>}
</div> </div>
{ {
currentTab === TABS[0].tab && <React.Fragment> currentTab === TABS[0].tab && <React.Fragment>
<HAREntryTableSection title={'Headers'} arrayToIterate={request.headers}/> <HAREntryTableSection title={'Headers'} arrayToIterate={request.payload.headers}/>
<HAREntryTableSection title={'Cookies'} arrayToIterate={request.cookies}/> <HAREntryTableSection title={'Cookies'} arrayToIterate={request.payload.cookies}/>
{request?.postData && <HAREntryBodySection content={request.postData} encoding={request.postData.comment} contentType={request.postData[MIME_TYPE_KEY]}/>} {request.payload?.postData && <HAREntryBodySection content={request.payload.postData} encoding={request.payload.postData.comment} contentType={request.payload.postData[MIME_TYPE_KEY]}/>}
<HAREntryTableSection title={'Query'} arrayToIterate={request.queryString}/> <HAREntryTableSection title={'Query'} arrayToIterate={request.payload.queryString}/>
</React.Fragment> </React.Fragment>
} }
{currentTab === TABS[1].tab && <React.Fragment> {currentTab === TABS[1].tab && <React.Fragment>
<HAREntryTableSection title={'Headers'} arrayToIterate={response.headers}/> <HAREntryTableSection title={'Headers'} arrayToIterate={response.payload.headers}/>
<HAREntryBodySection content={response.content} encoding={response.content?.encoding} contentType={response.content?.mimeType}/> <HAREntryBodySection content={response.payload.content} encoding={response.payload.content?.encoding} contentType={response.payload.content?.mimeType}/>
<HAREntryTableSection title={'Cookies'} arrayToIterate={response.cookies}/> <HAREntryTableSection title={'Cookies'} arrayToIterate={response.payload.cookies}/>
</React.Fragment>} </React.Fragment>}
{currentTab === TABS[2].tab && <React.Fragment> {currentTab === TABS[2].tab && <React.Fragment>
<HAREntryTablePolicySection service={har.log.entries[0].service} title={'Rule'} latency={receive} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/> <HAREntryTablePolicySection service={har.log.entries[0].service} title={'Rule'} latency={0} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/>
</React.Fragment>} </React.Fragment>}
</div>} </div>}
</div>; </div>;